Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .changeset/driver-memory-unique-violation-provenance-row.md
Original file line number Diff line number Diff line change
@@ -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.
26 changes: 26 additions & 0 deletions packages/spec/src/api/error-code-ledger.zod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading