Skip to content

feat(spec): register driver-memory as a UNIQUE_VIOLATION emitter in the error-code ledger - #13354

Merged
os-elon merged 2 commits into
mainfrom
claude/issue-13254-unique-violation-ledger-row
Aug 30, 2026
Merged

feat(spec): register driver-memory as a UNIQUE_VIOLATION emitter in the error-code ledger#13354
os-elon merged 2 commits into
mainfrom
claude/issue-13254-unique-violation-ledger-row

Conversation

@os-project-manager

Copy link
Copy Markdown
Collaborator

Fixes#13254

Adds the one provenance row the ledger was missing: @objectstack/driver-memory as an emitter of UNIQUE_VIOLATION. Pure append — a new owner key naming one already-registered code.

The premise, re-verified on the base rather than recalled

Branched from origin/main at 881f8d8e, which contains both ordering edges the card required:

Both halves of the card's premise then measured on that base:

  • The row is absent.grep -n 'driver-memory\|UNIQUE_VIOLATION' packages/spec/src/api/error-code-ledger.zod.ts returns exactly one line — 250: 'UNIQUE_VIOLATION',, the @objectstack/rest registration. There is no @objectstack/driver-memory owner key anywhere in the file. (The R+37 unlock comment deliberately declined to assert this, having grepped a guessed path; this is the re-verification it asked for, against the real file.)
  • The emitter is real, and its wire identity is read off the producer, not invented:
    • packages/drivers/driver-memory/src/memory-unique-constraint.ts:210export const UNIQUE_VIOLATION_CODE = 'UNIQUE_VIOLATION';
    • packages/drivers/driver-memory/src/memory-unique-constraint.ts:213export const UNIQUE_VIOLATION_STATUS = 409;
    • packages/drivers/driver-memory/src/memory-unique-constraint.ts:500-506conflictRefusal(), the single place both declaration surfaces are stamped: err.code = UNIQUE_VIOLATION_CODE; err.status = UNIQUE_VIOLATION_STATUS;
    • packages/drivers/driver-memory/src/index.ts:31-32 — both constants re-exported from the package entry.
    • Pinned by value on both surfaces: memory-unique-constraint.test.ts:63-65 and memory-declared-index-unique.test.ts:85-87 each assert codeandstatus, and then the literal 'UNIQUE_VIOLATION'.

So the row's fields are copied from landed reality: package @objectstack/driver-memory, code UNIQUE_VIOLATION, status 409.

What changed

packages/spec/src/api/error-code-ledger.zod.ts — one new owner key placed beside @objectstack/driver-sql, grouping the two drivers, with a comment in the form the file's existing rows use: the producer and its stamping function, the second-emitter note the header's "provenance, not identity" rule calls for, and the wire-reachability argument in the shape @objectstack/driver-sql's own row makes (an ordinary create/update on an object with a unique field reaches InMemoryDriver.create on a server already serving HTTP, and resolveThrownHttpError puts the driver's code/status on the envelope — the same test #8035 applied when it unregistered MONGODB_MULTI_TENANT_UNSUPPORTED for failing it).

Nothing else moves. No code's identity, status, casing or union membership changes; no other package's rows are touched; the ledger's shape and admission mechanism are untouched.

No generated product moves, and that is measured, not assumed

pnpm --filter @objectstack/spec check:generated (after a real build, per the stale-dist caveat) prints "All 14 generated artifacts are up to date", every one of the 14 individually green. That is the expected result rather than a missing step: the generated reference pages enumerate the deduped union, and UNIQUE_VIOLATION was already in it. Confirmed from the other side too — content/docs/references/api/error-code-ledger.mdx contains no owner key at all (grep for driver-sql, @objectstack/rest, ERROR_CODE_LEDGER returns nothing), so per-package rows have no rendered surface to drift.

Contrast the precedent commit 5b3ff63c, which registered a genuinely new code and therefore did move error-code-ledger.mdx and contract.mdx by one line each.

Verification

All of the following ran on the final head 659abf77, heavy runs serialised through scripts/pm/os-verify-lock.sh. Verdict lines are the gates' own, not a captured $?:

  • pnpm --filter '@objectstack/spec...' build — exit 0; check-dts-emitted: @objectstack/spec - 34/34 declared declaration file(s) present.
  • pnpm --filter @objectstack/spec check:generatedAll 14 generated artifacts are up to date.
  • pnpm check:dispatcher-error-vocabularyOK — 22 unregistered code-stamping site(s), all classified; 1 awaiting a ledger entry (#8846). (that pending entry is pre-existing and unrelated; scope line: 2103 non-test sources, 298 registered codes)
  • pnpm check:error-code-casingno unlisted lowercase error codes in 5010 scanned file(s) (ADR-0112).
  • pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 src/api/error-code-ledger.test.ts src/api/errors.test.ts src/api/contract.test.ts src/api/error-catalog-docs.test.tsTest Files 4 passed (4) / Tests 102 passed (102). These are the admission-rule pins: SCREAMING_SNAKE, per-package duplication, standard-catalog shadowing, owner-key shape, the deduped-sorted-union identity, and the [finding] @objectstack/rest registers four generic synonyms the standard catalog already covers (CONFLICT, NOT_FOUND, FORBIDDEN, INTERNAL) — contract call, not a cleanup #8211 synonym gate.
  • pnpm --filter @objectstack/driver-memory testTest Files 31 passed (31) / Tests 905 passed (905). The consumer check the dispatch asked for: the row agrees with the emitter's readings and nothing in the producing package turned red.
  • pnpm --filter @objectstack/spec run typecheck — exit 0; check:test-typecheck: OK.
  • pnpm lint (eslint . --no-inline-config, repo-wide, not narrowed) — exit 0.
  • The gate family re-derived from the actual diff with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (which reads its own change set from the merge base — 2 paths). Its 34 derived families were run: all green except three that measured nothing and say so in their own words — check-dev-prereqs and check-doc-formula-expressions reported PREREQUISITE NOT MET on an unbuilt workspace (the latter re-run green after building @objectstack/formula and @objectstack/lint), and check-test-completeness exited 3 with PREREQUISITE NOT MET — this gate grades a saved turbo run test log, which its own text records as NOT MEASURED locally and not a finding.
  • pnpm check:nul-bytesOK (scanned 7401 text file(s) ... no raw ASCII control bytes).

Changeset

patch on @objectstack/spec, not minor: the exported ERROR_CODE_LEDGER value gains a key, but RegisteredErrorCode, REGISTERED_ERROR_CODES and the ErrorCode union are byte-for-byte unchanged — no new vocabulary reaches any client. (The 5b3ff63c precedent took minor because it added a code.)

Clause-② and review posture

The PATH limb fires — the diff touches packages/spec/src/** — so this PR stays DRAFT and carries needs:contract-review on both carriers. This seat does not flip it ready, does not enqueue it, and does not clear the label; the review chain owns that. The card's own text ruled the same, and the content limb is the narrow one: a provenance row registers an already-landed refusal and changes no accept/reject behaviour.

The sweep the card asked for — reported, not widened

The card asked whether any other emitter is missing a row, and to report rather than widen. A read-only literal scan over the 71 workspace packages under packages/** found five further packages stamping a registered code their own owner key does not list (four of them literal HTTP envelopes), plus one SDK-side sub-class. None of it is in this diff. Filed separately as #13353, with the per-site table, the triage that discarded the ledger's already-explained "door, not producer" cases, and the note that the recurring fix is a gate nobody has.


Generated by Claude Code

…he error-code ledger
ERROR_CODE_LEDGER lists a code once per emitting package -- provenance, not
identity. driver-memory refuses a colliding write with code UNIQUE_VIOLATION /
status 409 (conflictRefusal, memory-unique-constraint.ts), stamped in one place
for both the field-level and the declared-index surface, and had no owner key.
Pure append: one new owner key naming one already-registered code. No shape,
mechanism, or other package's rows touched; the deduped union is unchanged, so
no generated reference product moves.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KX8wnyjStaZcuMyAMNsy3N
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec, touching 1 documentable anchor(s).

4 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/api/client-sdk.mdx(via ERROR_CODE_LEDGER (symbol))
  • content/docs/api/error-catalog.mdx(via ERROR_CODE_LEDGER (symbol))
  • content/docs/api/error-handling-server.mdx(via ERROR_CODE_LEDGER (symbol))
  • content/docs/kernel/contracts/data-engine.mdx(via ERROR_CODE_LEDGER (symbol))

1 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v17.mdx(via ERROR_CODE_LEDGER (symbol))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 126 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 2331b1ed8779b8abbda1494cdd249bbf43352a49packageMentionDocs.

Which tree this was computed on

This run read content/docs from 880a405fc553cdd3f6e30a3338b7ce0ae6385944 — the merge of head 659abf7782a362360a2196f8370292b149bdf2ff into base 2331b1ed8779b8abbda1494cdd249bbf43352a49, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 880a405fc553cdd3f6e30a3338b7ce0ae6385944 && git checkout 880a405fc553cdd3f6e30a3338b7ce0ae6385944
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 2331b1ed8779b8abbda1494cdd249bbf43352a49 659abf7782a362360a2196f8370292b149bdf2ff && git checkout -B drift-repro 2331b1ed8779b8abbda1494cdd249bbf43352a49 && git merge --no-ff 659abf7782a362360a2196f8370292b149bdf2ff
node scripts/docs-audit/affected-docs.mjs --json 2331b1ed8779b8abbda1494cdd249bbf43352a49

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 2331b1ed8779b8abbda1494cdd249bbf43352a49 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tooling labels Aug 30, 2026
Merged via the queue into main with commit c09451bAug 30, 2026
41 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/stooling

Projects

None yet

2 participants

@os-project-manager@claude