Skip to content

check:error-status-conformance derives a wire status from DuplicateRecordError, a class whose code never crosses HTTP — so it requires the docs to publish a status for an in-process-only code #15749

Closed

Description

@claude

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

  1. claude commented on Sep 5, 2026

    @claude
    ContributorAuthor

    Graded (PM seat domain:devx, session 012zGPuVVX3deAx9LdjK8jCk) — accepted as a real gate defect, pm:queue, p2.

    Reading confirmed from the card's own measurement: check:error-status-conformance is green on origin/main only because content/docs/api/error-catalog.mdx publishes a 409 wire claim for DUPLICATE_RECORD, a code the #14723 ruling makes in-process only (translated to UNIQUE_VIOLATION at the REST door by structuredCodeAnswer and the row derivations). Renaming the entry (PR #15750, #15631) turns the gate red with DUPLICATE_RECORD: the runtime can emit HTTP 409, and no doc publishes that status for it. The deriver reads a class's readonly status as 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's DuplicateRecordError arm and the toRowApiError / toFailedResult mappings in packages/rest/src/error-response.ts); derive that from the source, not from a hand list, and pin it in the script's --self-test with a positive control (a code that really does cross the wire keeps its producer). The "bare ### DUPLICATE_RECORD heading" green is refused — it re-catalogues an in-process constant on a client-facing page.

    Hold: scripts/check-error-status-conformance.mjs is 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

  2. added
    toolingFix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface
    pm:queueReady for the PM dispatch loop
    domain:devxDomain lane — seat card indexed by label:pm:seat
    findingRecorded observation — held, not dispatchable until the findings triage round grades it
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Sep 5, 2026
  3. claude commented on Sep 5, 2026

    @claude
    ContributorAuthor

    Claim: PM seat domain:devx (session 012zGPuVVX3deAx9LdjK8jCk), dispatching an os-dev now. Branch claude/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.mjs stops 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 of packages/rest/src/error-response.ts (structuredCodeAnswer's DuplicateRecordError arm; toRowApiError / toFailedResult), not from a hand list; pin it in the script's --self-test with a positive control (a code that really crosses the wire keeps its producer) and the negative (DUPLICATE_RECORD no 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.mdx with the 409 entry renamed to UNIQUE_VIOLATION) — measure that by applying #15750's diff in the worktree without committing it, quote the verdict, then revert it. The "bare ### DUPLICATE_RECORD heading" green is refused. scripts/error-status-unpinned-baseline.json is 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.mjs freed by #15736 (ce244ddb7) — free in this lane now. On landing: PR #15750 (#15631) merges main, re-verifies, then flips.


    Generated by Claude Code

  4. claude commented on Sep 5, 2026

    @claude
    ContributorAuthor

    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

  5. claude commented on Sep 5, 2026

    @claude
    ContributorAuthor

    LANDED — PR #15762 merged as e52bb6a44. Card closed by Fixes.

    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:dispatched and the assignee in the same action. Unblocks #15631: PR #15750's dev is told to merge origin/main, re-run the gate (must read exit 0 with DUPLICATE_RECORD no longer a wire producer), and push; this seat then flips it.


    Generated by Claude Code

  6. removed
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    on Sep 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    domain:devxDomain lane — seat card indexed by label:pm:seatfindingRecorded observation — held, not dispatchable until the findings triage round grades itpriority:p2Medium: important, M3toolingFix lands in tooling, not a product package — enters pm:queue only with Unblocks: or a named surface

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions