You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
finding: packages/rest's flat sendThrownError still puts a thrown error's code on the wire un-narrowed — ADR-0112's closure does not reach that door #9232
Found while implementing #9106 (the demote at the dispatcher/actions door). Filed unassigned, not fixed there: #9106's ruled scope named the actions door and the shared resolver, and the claim for it explicitly fenced off packages/rest/src/error-response.ts as #9098's surface.
The measurement
The 2026-08-16 ruling on #9106 says error.code is a closed vocabulary at every door, and #9106 delivers that for the three exits that read resolveThrownHttpError (HttpDispatcher.errorFromThrown, dispatcher-plugin's errorResponseBase, endpoint-executor's endpointErrorAnswer) plus the direct-mount package registrar.
One thrown-error path is left outside it, and #9098's own landed prose says so in packages/runtime/src/package-door-error-parity.test.ts, verbatim:
THROWN errors: NOT narrowed, deliberately and symmetrically with this door. sendThrownError passes a caught error's code through verbatim; narrowing that is an ADR-0112 public-contract decision, not an internal typing one.
That sentence was true when it landed. #9106 changed the half it rests on — the dispatcher door narrows now — so the stated symmetry is gone and packages/rest's flat responder is the one thrown path that still emits an unregistered spelling.
Why it is narrower than it looks (and why it is still worth a card)
The flat dialect puts code at the body's top level ({ error: 'message', code: 'X' }), not in error.code. So it is arguably not the field ADR-0112 D4 closes, which is why #9106 did not reach it by construction rather than by oversight. Two reasons it is still a real card:
Whether the answer is (a) narrow the flat door too and add a declaredCode sibling, (b) converge the envelope position first and let the vocabulary follow, or (c) rule the top-level code a different field that ADR-0112 does not govern, and say so in the ADR. That is a public-contract decision, per #9098's own note.
Stale citation to fix while here
#9098's prose and the #9106 ADR amendment both point at #7035 as the open envelope-position finding. #7035 is closed (completed 2026-08-10, PR #7293) and was only about three /meta 501 handlers. The envelope-convergence line needs a live card to point at — this one, or a dedicated envelope card if triage prefers to split them.
Not reproduced as a client-visible break
No consumer branch on an unregistered top-level code from that door was found: the #9106 precondition sweep classified every out-of-vocabulary SCREAMING_SNAKE literal on the consumer surfaces (client, client-react, examples, qa, the objectui checkout) and none was an error.code-class read. So this is a contract-coherence card, not an outage.
Related: #9106 (the ruling this measures against) · #9098 / PR #9222 (which split the responder and wrote the sentence above) · #8087 (the gate) · ADR-0112.
Found while implementing #9106 (the demote at the dispatcher/actions door). Filed unassigned, not fixed there: #9106's ruled scope named the actions door and the shared resolver, and the claim for it explicitly fenced off
packages/rest/src/error-response.tsas #9098's surface.The measurement
The 2026-08-16 ruling on #9106 says
error.codeis a closed vocabulary at every door, and #9106 delivers that for the three exits that readresolveThrownHttpError(HttpDispatcher.errorFromThrown,dispatcher-plugin'serrorResponseBase,endpoint-executor'sendpointErrorAnswer) plus the direct-mount package registrar.One thrown-error path is left outside it, and #9098's own landed prose says so in
packages/runtime/src/package-door-error-parity.test.ts, verbatim:That sentence was true when it landed. #9106 changed the half it rests on — the dispatcher door narrows now — so the stated symmetry is gone and
packages/rest's flat responder is the one thrown path that still emits an unregistered spelling.Why it is narrower than it looks (and why it is still worth a card)
The flat dialect puts
codeat the body's top level ({ error: 'message', code: 'X' }), not inerror.code. So it is arguably not the field ADR-0112 D4 closes, which is why #9106 did not reach it by construction rather than by oversight. Two reasons it is still a real card:error.codehas a limb authored by TENANTS at runtime — registration cannot close it, and ADR-0112 does not say what should happen there #9106 amendment, ADR-0112 reads "closed at every door". An agent reading it, then reading asendThrownErrorbody, sees a contradiction and has no way to tell which one is authoritative — the exact AI-error-resistance failure [Decision] The dispatcher'serror.codehas a limb authored by TENANTS at runtime — registration cannot close it, and ADR-0112 does not say what should happen there #9106 was filed to remove, moved one door over.check:dispatcher-error-vocabularysweeps only the PLATFORM producers of that path. It cannot reach a code that is not written in this repo — the same construction limit that produced [Decision] The dispatcher'serror.codehas a limb authored by TENANTS at runtime — registration cannot close it, and ADR-0112 does not say what should happen there #9106's tenant-authored limb.Deliberately not decided here
Whether the answer is (a) narrow the flat door too and add a
declaredCodesibling, (b) converge the envelope position first and let the vocabulary follow, or (c) rule the top-levelcodea different field that ADR-0112 does not govern, and say so in the ADR. That is a public-contract decision, per #9098's own note.Stale citation to fix while here
#9098's prose and the #9106 ADR amendment both point at #7035 as the open envelope-position finding. #7035 is closed (completed 2026-08-10, PR #7293) and was only about three
/meta501 handlers. The envelope-convergence line needs a live card to point at — this one, or a dedicated envelope card if triage prefers to split them.Not reproduced as a client-visible break
No consumer branch on an unregistered top-level
codefrom that door was found: the #9106 precondition sweep classified every out-of-vocabulary SCREAMING_SNAKE literal on the consumer surfaces (client,client-react,examples,qa, the objectui checkout) and none was anerror.code-class read. So this is a contract-coherence card, not an outage.Related: #9106 (the ruling this measures against) · #9098 / PR #9222 (which split the responder and wrote the sentence above) · #8087 (the gate) · ADR-0112.