From 5cb0261d85a91a9fc8d50df03e50a57197803843 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 30 Aug 2026 05:53:45 +0000 Subject: [PATCH 1/2] feat(spec): register driver-memory as a UNIQUE_VIOLATION emitter in the 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 Claude-Session: https://claude.ai/code/session_01KX8wnyjStaZcuMyAMNsy3N --- .../spec/src/api/error-code-ledger.zod.ts | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/packages/spec/src/api/error-code-ledger.zod.ts b/packages/spec/src/api/error-code-ledger.zod.ts index b09da99697..f804174b4f 100644 --- a/packages/spec/src/api/error-code-ledger.zod.ts +++ b/packages/spec/src/api/error-code-ledger.zod.ts @@ -669,6 +669,32 @@ export const ERROR_CODE_LEDGER = { 'SUGGESTION_NOT_FOUND', 'SUGGESTION_STATE', // suggestion exists but is not in a confirmable/dismissable state ], + '@objectstack/driver-memory': [ + // [#13254] Provenance for the in-memory driver's uniqueness refusal, which + // #13197 (field-level `unique`) and #13239 (declared `indexes[]` entries) + // made real: a colliding write is REFUSED rather than landed. Stamped in + // ONE place for both declaration surfaces — `conflictRefusal` + // (`packages/drivers/driver-memory/src/memory-unique-constraint.ts`), + // `code: 'UNIQUE_VIOLATION'` / `status: 409` via the package's exported + // `UNIQUE_VIOLATION_CODE` / `UNIQUE_VIOLATION_STATUS`. + // + // Second EMITTER of the code `@objectstack/rest` already registers for the + // SQL conflict; the wire identity is deliberately the SAME, so a suite that + // swaps this driver for SQLite sees ONE envelope. Per this file's header, a + // code emitted by several packages is listed once per emitting package — + // provenance, not identity. + // + // Wire-reachable by the test the "Retiring a code" section above applies + // (#8035): 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. This row adds provenance ONLY: the code was already registered, + // so the union, its casing and every other package's rows are unchanged. + // Registered late for exactly the reason the row is worth having — no + // admission rule checks WHO emits, so an unlisted emitter is invisible to + // every gate the repo has. + 'UNIQUE_VIOLATION', + ], '@objectstack/driver-sql': [ // [#11991] The #11756 ruling's refusal (maintainer, 2026-08-25, verbatim // 「同意」 on 「C,但 pgnative 归入 Postgres 家族」): a knex client this From 659abf7782a362360a2196f8370292b149bdf2ff Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 30 Aug 2026 05:53:45 +0000 Subject: [PATCH 2/2] chore(changeset): driver-memory UNIQUE_VIOLATION provenance row Co-Authored-By: Claude Claude-Session: https://claude.ai/code/session_01KX8wnyjStaZcuMyAMNsy3N --- ...-memory-unique-violation-provenance-row.md | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .changeset/driver-memory-unique-violation-provenance-row.md diff --git a/.changeset/driver-memory-unique-violation-provenance-row.md b/.changeset/driver-memory-unique-violation-provenance-row.md new file mode 100644 index 0000000000..f0d85cbff7 --- /dev/null +++ b/.changeset/driver-memory-unique-violation-provenance-row.md @@ -0,0 +1,25 @@ +--- +"@objectstack/spec": patch +--- + +feat(spec): register `@objectstack/driver-memory` as an emitter of `UNIQUE_VIOLATION` in the error-code ledger (#13254) + +`ERROR_CODE_LEDGER` (ADR-0112 D3) lists a code once per emitting package — +its own header calls those rows "provenance, not identity", and they are how a +reader answers "who produces this code?". + +Since the in-memory driver started enforcing uniqueness (field-level `unique`, +and object-level declared `indexes[]` entries carrying `unique`), a colliding +write is refused with `code: 'UNIQUE_VIOLATION'` / `status: 409` — stamped in +one place for both declaration surfaces by `conflictRefusal` in +`packages/drivers/driver-memory/src/memory-unique-constraint.ts` — while +`@objectstack/driver-memory` had no row at all. No gate could see that: the +ledger's admission rules check casing, duplication and shadowing, never who +emits, and the code itself was already registered by `@objectstack/rest`, so +union membership, `ApiErrorSchema` parsing and +`check:dispatcher-error-vocabulary` were all green over the gap. + +Pure provenance append: one new owner key naming the one code. No code's +identity, status, casing or union membership changes, no other package's rows +are touched, and the generated reference products are unchanged because the +deduped union they enumerate is unchanged.