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 code and status, 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

claude added 2 commits August 30, 2026 05:53
…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-actions github-actions Bot added documentation Improvements or additions to documentation tooling labels Aug 30, 2026
@os-elon
os-elon marked this pull request as ready for review August 30, 2026 10:20
@os-elon
os-elon enabled auto-merge August 30, 2026 10:20
@os-elon
os-elon added this pull request to the merge queue Aug 30, 2026
@os-elon
os-elon requested a review from os-zhuang August 30, 2026 10:37
Merged via the queue into main with commit c09451b Aug 30, 2026
41 checks passed
@os-elon
os-elon deleted the claude/issue-13254-unique-violation-ledger-row branch August 30, 2026 10:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s tooling

Projects

None yet

3 participants