fix(devx): check:error-status-conformance derives wire producers past the REST door's translating arms (#15749) - #15762
Conversation
`check:error-status-conformance` read `DuplicateRecordError`'s `readonly status = 409` as "the runtime can emit HTTP 409 for DUPLICATE_RECORD", so direction A required a scanned page to publish 409 for a code that never crosses HTTP. Per the #14723 ruling that code is the engine's in-process identity; the REST door answers `UNIQUE_VIOLATION` on every route. `deriveDoorTranslations` reads those arms out of the door's own source — a guard on `error?.code` / `error?.name` whose `{ status, body: { code } }` terminal answers a different code — never a hand-written list. R1 skips a class the door translates away and REPORTS it in a new `translated` census; a translated code is kept out of the unpinned census too, since the door pins the answer under its wire spelling. Pinned in `--self-test` battery 26 (8 cases): the arm-less negative control still produces, the guard's class name is load-bearing, a `code: error.code` arm translates nothing, and an untranslated code is untouched. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
…ror-status-in-process-only-codes
|
ACCEPT — PR #15762 (head The deriver change is what the ruling asked for and nothing else: Measured by this seat (detached probe worktree at
Flip + arm when both required jobs report success on Generated by Claude Code |
|
Flipped ready + auto-merge enabled (06:57Z, Generated by Claude Code |
Brings in #15762 (#15749), the error-status-conformance deriver fix that stops counting a door-translated in-process class as a wire producer. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
Fixes #15749
Unblocks #15631
Gate-script only:
scripts/check-error-status-conformance.mjsand its--self-test. Nothing underpackages/**,content/docs/**,.github/**, andscripts/error-status-unpinned-baseline.jsonis untouched (see "Baseline" below). Verified at6cdb96f58.The defect
The deriver read
DuplicateRecordError'sreadonly status = 409(packages/objectql/src/duplicate-record-error.ts) as "the runtime can emit HTTP 409 forDUPLICATE_RECORD" — its only producer, verbatim from--reportonorigin/main:Per the maintainer ruling on #14723 that code is the engine's in-process identity: the REST door answers
UNIQUE_VIOLATIONon every route (structuredCodeAnswer's arm inpackages/rest/src/error-response.ts:992;toRowApiErrorinpackages/metadata-protocol/src/protocol.tsandtoFailedResultinpackages/rest/src/import-runner.tsapply the identical two-part gate to a batch row and an import row). So direction A required a page to publish 409 for a code that never crosses HTTP — the gate was green because the catalog published that claim, and correcting the page is what turned it red.What changed
deriveDoorTranslations(sources)reads the translating arms out of the door's own source — a guard testingerror?.code === 'FROM'(and, when the arm names one, the throwing class'serror?.name === 'Class') whose{ status, body: { code: 'TO' } }terminal answers a different code. Never a hand-written list of codes: that would be the second copy of a table this file's header argues against. Braces are walked on the structural projection for the reason R5b exists — the arms build their bodies with conditional spreads.Derived repo-wide today: exactly one translation,
DUPLICATE_RECORD(classDuplicateRecordError) →UNIQUE_VIOLATIONatpackages/rest/src/error-response.ts:992.Three bounds keep the exclusion narrow, each pinned in
--self-test:sendErrordoor, a{ code, status }terminal, an assignment pair) keeps it a wire producer. That is what "every path from its throw to HTTP goes through a translating arm" means in the only terms a deriver can read.translatedcensus prints on every run, and says when a page still publishes an entry for the translated code. A translated code is also kept out of the unpinned census: that census exists for a doc claim nothing pins, and here the door pins the answer, under its wire spelling.Reading 1 — the unmodified tree (this branch), before and after
Both runs
node scripts/check-error-status-conformance.mjs, exit code captured before any pipe.origin/main)315 producer site(s) derived314 producer site(s) derived26 code(s) with a derived producer, 27 (code, status) pair(s)25 code(s) with a derived producer, 26 (code, status) pair(s)DUPLICATE_RECORD@409 was one code and one pairunpinned: 26 … (baselined: 26)unpinned: 26 … (baselined: 26)New line, after:
Verdict,
EXIT=0:✓ every derivable runtime status is documented, and every documented status is reachable.Reading 2 — the purpose: PR #15750's tree
content/docs/api/error-catalog.mdxtaken fromclaude/issue-15631-15632-error-docs-wire-shape(447fcf93c) and applied in the worktree without committing it (git apply, doc blobdc208c30e→25772cfdb, 2 hunks, proved on disk), gate run with cwd pinned to the worktree, then reverted (git checkout HEAD --; doc blob back todc208c30e,git diff HEADempty).origin/main's copy of the script) on that same tree —EXIT=1:EXIT=0:✓ every derivable runtime status is documented, and every documented status is reachable.314 producer site(s),25 code(s) … 26 (code, status) pair(s),unpinned: 26 … (baselined: 26), and the census NOTE correctly absent — nothing on that tree documentsDUPLICATE_RECORDany more.The "bare
### DUPLICATE_RECORDheading" green was refused and is not used anywhere here.Ablation — both halves of the change, trap-guarded, absolute paths
Each leg: mutate, prove the mutation landed on disk (marker count + blob hash differs from the
HEADblob), run, restore withgit checkout HEAD -- ABSOLUTE_PATH, prove the restore (marker count 0, blob back to theHEADblob2696baad0,git diff HEADempty), re-run. No build step is involved — the gate is a.mjsrun directly, there is nodist/between the edit and the run.--self-testderiveDoorTranslationsreturns[](derivation neutralised)EXIT=126,26b,26gEXIT=0!translatedCodes.has(code)guard removed fromreconcileEXIT=126cEXIT=1—✗ DUPLICATE_RECORD: documented with an HTTP status, but no producer declares one …EXIT=0, 58 casesEXIT=0Leg 2 is also the answer to "why not just let it fall into the unpinned census": without the exclusion this branch would red
maintoday and the only remedy the gate offers is admitting a row intoscripts/error-status-unpinned-baseline.json— the MAINTAINER-ONLY weakening path — which #15750 would then immediately have to ratchet back down.Honest note on leg 1: cases
26c,26d,26e,26f,26hstay green under it. They are not discriminators of that leg (with no exclusion the code has a producer, so it is not unpinned either) — they are the controls, and26cdiscriminates leg 2.Self-test
node scripts/check-error-status-conformance.mjs --self-test— 50 cases before, 58 after,EXIT=0. New battery26 — a code the DOOR TRANSLATES away is not a wire producer: derived from(floor 8, roster floor raised 26 → 27):26a class whose code the door translates is NOT a wire producer26bthe excluded declaration is REPORTED, with the arm that translates it26ca still-catalogued translated code is kept OUT of the unpinned census (this ismain's state today)26dthe WIRE code the arm answers keeps its producer at the arm's status26ePOSITIVE CONTROL: an untranslated code (TIMEOUT@504) keeps its producer and reconciles26fNEGATIVE CONTROL: with no translating arm the same class IS a wire producer26gthe guard's CLASS is load-bearing: another class speaking the code keeps its producer26han arm that answerscode: error.code(the capability gates) translates nothingBaseline
scripts/error-status-unpinned-baseline.jsonis not edited:unpinned: 26 (baselined: 26)before and after, no row added and none removed. Another seat's draft #15708 removes one row there; this branch does not touch the file, so there is nothing to merge against it.Gates run at
6cdb96f58Family derived with
node scripts/pm/dispatch-gates.mjs --changed --commands --repo objectstack-ai/objectstack(EXIT=0, change set1 path(s)vs merge base66e68adc6, derived from this repo's tree — not a hand list). All 29 runnable commands were run, exit code captured before any pipe: 23 exit 0, 6 NOT MEASURED.NOT MEASURED, by the prerequisite each one names — this box has no
node_modulesfor them (re-run with the workspacenode_moduleslinked in, same result):node packages/lint/scripts/check-reference-carrier-shape.mjs(and--self-test) — exit 3,PREREQUISITE NOT MET — the dependency typescript is not installednode scripts/check-ci-filter-parity.mjs— exit 3, dependencyyamlnode scripts/check-closing-keyword-parity.mjs(and--self-test) — exit 3, dependencyyamlnode scripts/check-comment-mask-corpus.mjs— exit 1,Cannot find package '@typescript-eslint/parser'pnpm check:driver-memory-census— exit 3, dependencytypescriptGreen and load-bearing here:
pnpm check:error-status-conformance(self-test + gate),pnpm check:nul-bytes,pnpm check:entry-guard,pnpm check:ratchet-remedy-authority,pnpm check:parse-guard,pnpm check:pm-dispatch-gates,node scripts/check-self-test-wired.mjs,node scripts/check-declaration-mirrors.mjs,node scripts/check-whole-set-label-write.mjs,node scripts/pm/bare-root-worklist.mjs --self-test.node scripts/pm/check-governed-merges.mjs --test scripts/check-error-status-conformance.mjs—✅ NOT governed — ordinary queue landing applies to a PR with exactly this file list.Changeset
None,
skip-changeset. AGENTS.md: apatchchangeset is owed by "a bug fix in a released package … ⛔ neverskip-changeset: that label is for a diff that publishes nothing from any released package." This diff is one repo-internal CI gate script; no released package publishes a byte of it.🤖 Generated with Claude Code
https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
Generated by Claude Code