Repository navigation
Description
Measured while implementing #15631 (renaming the catalog's 409 conflict entry to the wire spelling UNIQUE_VIOLATION).
What the gate does
scripts/check-error-status-conformance.mjs derives the runtime side by reading, among other sources, "the error classes' own readonly status / readonly statusCode". For DUPLICATE_RECORD that derivation finds exactly ONE producer — its --report output, verbatim:
DUPLICATE_RECORD
409 packages/objectql/src/duplicate-record-error.ts: class DuplicateRecordError
Direction A of the gate ("every status the runtime can emit for a code is documented for it") then requires some scanned page to publish 409 for DUPLICATE_RECORD.
Why that requirement is wrong
The maintainer ruling on #14723 (2026-09-03) is that a unique-constraint refusal has ONE wire spelling on every route, UNIQUE_VIOLATION; DuplicateRecordError.code stays DUPLICATE_RECORD in-process only, translated at the REST door by structuredCodeAnswer's DuplicateRecordError arm in packages/rest/src/error-response.ts, and the row derivations (toRowApiError, toFailedResult) apply the same mapping. A census of code: 'DUPLICATE_RECORD' across packages/** finds no wire producer at all — every hit is a docblock or the engine's own throw.
So the gate reads an in-process throw's declared status as "the runtime can emit HTTP 409 for this code". It cannot distinguish a code that reaches the wire from one a door translates away.
The consequence, measured
On claude/issue-15631-15632-error-docs-wire-shape, with the catalog entry renamed to the wire spelling exactly as #15631 was graded, the gate goes RED with its own verdict line:
X DUPLICATE_RECORD: the runtime can emit HTTP 409, and no doc publishes that status for it (documented: nothing). Emitted at packages/objectql/src/duplicate-record-error.ts: class DuplicateRecordError. Document the status where it belongs — a code may carry more than one, so an exception is documented, not flattened away.
X check:error-status-conformance — 1 finding(s).
Baseline on origin/main c2a336ca2 is exit 0. So the gate is green today because content/docs/api/error-catalog.mdx publishes a 409 wire claim for a code that never crosses HTTP — the gate is currently held green by the very defect #15631 removes, and correcting the page is what turns it red.
Measured detail on the doc side
A ### \DUPLICATE_RECORD`entry heading placed under## Conflict Errors (409)is enough to satisfy direction A through the weakercovered` grade (section headings absolve but never demand) — measured: gate exit 0 with such a stub, exit 1 without it. That is an availability of a workaround, not a fix: it still catalogues an in-process constant on a client-facing wire catalog, and it silences the gate by heading placement rather than by the deriver learning the distinction.
Suggested shape
The deriver needs a notion of "a code translated at a door is not a wire producer" — the door that performs the translation is readable source (structuredCodeAnswer's arm answers code: 'UNIQUE_VIOLATION' for the DuplicateRecordError envelope), so the exclusion can be derived rather than listed. A hand-written exclusion list would be the second copy of a table this gate's own header argues against.
Not measured here
Whether other in-process-only error classes are in the same position (this was measured for DUPLICATE_RECORD only, because that is the code #15631 touches). The unpinned baseline scripts/error-status-unpinned-baseline.json is a different population — codes with NO derivable producer — and DUPLICATE_RECORD is not in it.
Refs: #14723 (the wire-spelling ruling) - #15631 (the catalog rename that surfaces this) - packages/rest/src/rest-duplicate-record-arm.test.ts.
Generated by Claude Code
Activity
claude commentedon Sep 5, 2026
Graded (PM seat
domain:devx, session012zGPuVVX3deAx9LdjK8jCk) — accepted as a real gate defect,pm:queue, p2.Reading confirmed from the card's own measurement:
check:error-status-conformanceis green onorigin/mainonly becausecontent/docs/api/error-catalog.mdxpublishes a 409 wire claim forDUPLICATE_RECORD, a code the #14723 ruling makes in-process only (translated toUNIQUE_VIOLATIONat the REST door bystructuredCodeAnswerand the row derivations). Renaming the entry (PR #15750, #15631) turns the gate red withDUPLICATE_RECORD: the runtime can emit HTTP 409, and no doc publishes that status for it. The deriver reads a class'sreadonly statusas a wire producer and cannot see that the door translates the code away.Direction for the dev (binding): fix the deriver, not the docs. The gate must stop counting a code as a wire producer when every path from its throw to HTTP goes through a translating arm (
structuredCodeAnswer'sDuplicateRecordErrorarm and thetoRowApiError/toFailedResultmappings inpackages/rest/src/error-response.ts); derive that from the source, not from a hand list, and pin it in the script's--self-testwith a positive control (a code that really does cross the wire keeps its producer). The "bare### DUPLICATE_RECORDheading" green is refused — it re-catalogues an in-process constant on a client-facing page.Hold:
scripts/check-error-status-conformance.mjsis a hot file of PR #15736 (#15644, armed, in the merge queue). Dispatch follows the moment #15736 lands. PR #15750 (#15631) stays draft behind this card.Generated by Claude Code
claude commentedon Sep 5, 2026
Claim: PM seat
domain:devx(session012zGPuVVX3deAx9LdjK8jCk), dispatching anos-devnow. Branchclaude/issue-15749-error-status-in-process-only-codes. Lock read before dispatch:state: holder … held 6s(one holder, another seat's probe),queue: empty→ depth incl. the arriving run < 2, admits.Ruling (binding, mechanism-level, from the grading at
5549754256): fix the deriver, not the docs.scripts/check-error-status-conformance.mjsstops counting a code as a WIRE producer when every path from its throw to HTTP goes through a translating arm — derive that from the source ofpackages/rest/src/error-response.ts(structuredCodeAnswer'sDuplicateRecordErrorarm;toRowApiError/toFailedResult), not from a hand list; pin it in the script's--self-testwith a positive control (a code that really crosses the wire keeps its producer) and the negative (DUPLICATE_RECORDno longer requires a documented status); prove by ablation. Then the gate must read exit 0 on PR #15750's tree (content/docs/api/error-catalog.mdxwith the 409 entry renamed toUNIQUE_VIOLATION) — measure that by applying #15750's diff in the worktree without committing it, quote the verdict, then revert it. The "bare### DUPLICATE_RECORDheading" green is refused.scripts/error-status-unpinned-baseline.jsonis not edited unless the deriver change requires a row change — say which and why (other seat's draft #15708 removes one row there; merge-tree before ACCEPT).Hot file
scripts/check-error-status-conformance.mjsfreed by #15736 (ce244ddb7) — free in this lane now. On landing: PR #15750 (#15631) merges main, re-verifies, then flips.Generated by Claude Code
claude commentedon Sep 5, 2026
os-dev-report
{ "issue": 15749, "status": "done", "branch": "claude/issue-15749-error-status-in-process-only-codes", "pr": "https://github.com/objectstack-ai/objectstack/pull/15762", "premise_still_valid": true, "summary": "The DERIVER was fixed, not the docs. New `deriveDoorTranslations(sources)` reads the door's translating arms out of the door's own source - a guard testing `error?.code === 'FROM'` (and, when the arm names one, the throwing class's `error?.name === 'Class'`) whose `{ status, body: { code: 'TO' } }` terminal answers a DIFFERENT code - never a hand list. R1 stops recording a class whose thrown code a door translates away and REPORTS it in a new `translated` census instead. Exactly ONE translation is derived repo-wide today: DUPLICATE_RECORD (class DuplicateRecordError) -> UNIQUE_VIOLATION at packages/rest/src/error-response.ts:992; that answers the card's 'not measured here' (no other in-process-only class is in the same position). A translated code is also kept OUT of the unpinned census - without that half the branch reds `main` today and the gate's only offered remedy is the MAINTAINER-ONLY baseline row (ablation leg 2 below measures exactly that), so `scripts/error-status-unpinned-baseline.json` is untouched and no row moves. Head 6cdb96f58 (includes a merge of origin/main 66e68adc6; none of those 3 commits touch this file, the baseline or the catalog).", "tests": "ALL exit codes captured before any pipe (`cmd > log 2>&1; EXIT=$?`), verdict lines quoted from the gate's own output, gate runs pinned to cwd=/home/user/objectstack-15749 (an earlier run from the wrong cwd read the shared checkout's docs and was discarded, then redone). (1) SELF-TEST: `node scripts/check-error-status-conformance.mjs --self-test` EXIT=0, 50 cases before -> 58 after; new battery '26 - a code the DOOR TRANSLATES away is not a wire producer: derived from' floor 8, SELF_TEST_BATTERY_FLOOR 26 -> 27. New cases: 26 (translated class is not a wire producer), 26b (the exclusion is REPORTED with its arm), 26c (a still-catalogued translated code stays OUT of the unpinned census - main's state today), 26d (the wire code the arm answers keeps its producer at the arm's status), 26e POSITIVE CONTROL (an untranslated code, TIMEOUT @504, keeps its producer and reconciles), 26f NEGATIVE CONTROL (no arm => the same class IS a wire producer), 26g (the guard's CLASS is load-bearing: another class speaking the code keeps its producer), 26h (an arm answering `code: error.code` translates nothing). (2) UNMODIFIED TREE, before/after, both EXIT=0: `315 producer site(s) derived` -> `314` (the one suppressed class declaration); `26 code(s) with a derived producer, 27 (code, status) pair(s)` -> `25 ... 26 pair(s)` (DUPLICATE_RECORD @409 was one code and one pair); `unpinned: 26 ... (baselined: 26)` UNCHANGED (the translated code is kept out of that census); scope 52 codes / 2245 files scanned identical. Verdict after: 'check every derivable runtime status is documented, and every documented status is reachable.' New line: 'translated: 1 class declaration(s) a door translates away before HTTP ... DUPLICATE_RECORD (declared 409 at packages/objectql/src/duplicate-record-error.ts: class DuplicateRecordError) -> UNIQUE_VIOLATION at packages/rest/src/error-response.ts:992 - NOTE: a scanned page still publishes an entry for DUPLICATE_RECORD'. (3) PURPOSE / PR #15750 TREE: `git diff origin/main...origin/claude/issue-15631-15632-error-docs-wire-shape -- content/docs/api/error-catalog.mdx | git apply` (2 hunks, doc blob dc208c30e -> 25772cfdb, landing proved on disk by blob hash + '### `DUPLICATE_RECORD`' heading count 0), NOT committed. BASE deriver (origin/main's copy of the script) on that same tree: EXIT=1, 'X DUPLICATE_RECORD: the runtime can emit HTTP 409, and no doc publishes that status for it (documented: nothing). Emitted at packages/objectql/src/duplicate-record-error.ts: class DuplicateRecordError.' + 'X check:error-status-conformance - 1 finding(s).' - the card's finding reproduced. THIS BRANCH's deriver on that same tree: EXIT=0, 'check every derivable runtime status is documented, and every documented status is reachable', 314 sites / 25 codes / 26 pairs / unpinned 26 (baselined 26), and the census NOTE correctly ABSENT (nothing documents DUPLICATE_RECORD there). Then reverted: `git checkout HEAD -- THE_DOC_PATH`, doc blob back to dc208c30e, `git diff HEAD` empty, `git status --porcelain` empty. (4) ABLATION, both halves, trap-guarded (`trap restore EXIT INT TERM`), absolute paths from `git rev-parse --show-toplevel`, restore via `git checkout HEAD -- ABSOLUTE_PATH` (never bare `--`). No build/dist is involved (a .mjs run directly), so the rebuild legs do not apply; the on-disk proof does and was done on BOTH legs: injected-marker grep count 1 + mutated blob != HEAD blob 2696baad0 before each run, marker count 0 + blob == 2696baad0 + `git diff HEAD` empty after each restore. LEG 1 (deriveDoorTranslations returns []): --self-test EXIT=1 failing 26, 26b, 26g; gate EXIT=0. LEG 2 (the `!translatedCodes.has(code)` guard removed from reconcile): --self-test EXIT=1 failing 26c; gate EXIT=1 'X DUPLICATE_RECORD: documented with an HTTP status, but no producer declares one' - i.e. without that half this branch reds main. RESTORE leg, both: --self-test EXIT=0 (58 cases), gate EXIT=0. Honest note: 26c/26d/26e/26f/26h stay green under leg 1 - they are controls, not discriminators of that leg; 26c discriminates leg 2. (5) GATE FAMILY at 6cdb96f58: `node scripts/pm/dispatch-gates.mjs --changed --commands --repo objectstack-ai/objectstack` EXIT=0, change set '1 path(s)' vs merge base 66e68adc6, derived by the script itself (no hand-built diff list). All 29 runnable commands run: 23 EXIT=0 (incl. check:error-status-conformance, check:nul-bytes, check:entry-guard, check:ratchet-remedy-authority, check:parse-guard, check:pm-dispatch-gates, check-self-test-wired, check-declaration-mirrors, check-whole-set-label-write, bare-root-worklist --self-test), 6 NOT MEASURED (named below). `node scripts/pm/check-governed-merges.mjs --test scripts/check-error-status-conformance.mjs` EXIT=0: 'NOT governed - ordinary queue landing applies to a PR with exactly this file list.' Changeset: none, `skip-changeset` label applied via the additive REST endpoint POST /issues/15762/labels and read back (read-back ['skip-changeset'], union check clean) - AGENTS.md: 'that label is for a diff that publishes nothing from any released package', and this diff is one repo-internal CI gate script. PR body read back in full after creation: byte-identical to what was sent, no control bytes, only the platform's session-URL signature block appended.", "mcp_calls": "1 - one targeted search_issues for out-of-scope dedup, after REST /search/issues answered 403 at this seat (repo-scoped REST reads/writes work); the result set was self-controlling (4 hits, incl. an exact match)", "open_questions": [], "out_of_scope_findings": [ "NOT filed - already filed by another seat as #15763 (found by the dedup search): `.gitignore` line 2 is `node_modules/`, directory-only, so the os-dev worktree recipe's node_modules SYMLINK is untracked. Measured here independently: it showed as `?? node_modules` and dispatch-gates counted it as a changed path (`untracked 1; . node_modules`), which added a family to the derivation; I removed the symlink and re-derived, and the gate family used above is the clean one." ] }🤖 Generated with Claude Code
https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
Generated by Claude Code
claude commentedon Sep 5, 2026
LANDED — PR #15762 merged as
e52bb6a44. Card closed byFixes.Probe on re-fetched
origin/main(PM seat, plain node; EXIT read before any pipe):node scripts/check-error-status-conformance.mjs --self-test→ EXIT=0,self-test: 58 cases pass(was 50).node scripts/check-error-status-conformance.mjs→ EXIT=0:314 producer site(s) derived(was 315),translated: 1 class declaration(s), ``,✓ every derivable runtime status is documented, and every documented status is reachable.Stripping
pm:dispatchedand the assignee in the same action. Unblocks #15631: PR #15750's dev is told to mergeorigin/main, re-run the gate (must read exit 0 withDUPLICATE_RECORDno longer a wire producer), and push; this seat then flips it.Generated by Claude Code
Merge origin/main into claude/issue-15631-15632-error-docs-wire-shape