Uh oh!
There was an error while loading. Please reload this page.
feat(spec): mechanical standard-synonym admission gate on the error-code ledger, with recorded waivers - #8450
Conversation
…ode ledger (#8211) Option C per the #8211 adjudication (2026-08-12): the ledger header's 'use the standard catalog instead of registering a synonym' rule gets teeth. standardSynonymOf() is a closed two-prong detector (HTTP reason-phrase alias via HttpStatusErrorCodeMap; token-subset of a standard member's name); standardSynonymViolations() is the admission gate's engine; STANDARD_SYNONYM_WAIVERS grandfathers the pre-gate synonyms (CONFLICT, NOT_FOUND, FORBIDDEN, INTERNAL, and UNAUTHORIZED which the detector surfaced) with recorded reasons naming the member each shadows. No wire change; consolidation (option B) stays deferred. The suite pins that the gate rejects a newly-introduced synonym on both prongs — a detector that only passes on today's tree is the failure mode this closes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012MNV7ZSCjNfA38eDCjsXQL
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
📓 Docs Drift CheckThis PR changes 1 package(s): 106 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
⛔ 7 release-owned page(s) also reference the affected code. These are read-only:
|
…nd strictness-ledger counts for the synonym-gate exports (#8211) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012MNV7ZSCjNfA38eDCjsXQL
…relay after #8457) Discharges the os-regen deferral from the origin/main merge: api-surface, export-origins, reference docs, strictness-ledger counts re-derived on the merged base so the union carries both #8457's entries and the #8211 synonym-gate exports. gen:openapi re-run after the chain per the script's warning. Sibling assertions green (datasource-config-placeholder-refused registered; placeholderFree/containsUnresolvedPlaceholder body present). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012MNV7ZSCjNfA38eDCjsXQL
Uh oh!
There was an error while loading. Please reload this page.
…ins to Iso839-Iso844 (#7751) Main's #8211 (PR #8450) took Iso838; the six object-* pins renumber to the next free ids on the merged tree (ids are claims about pins, not positions — renumbering unmerged pins is legal). Pin count 825 + 6 = 831, asserted by the count case, not arithmetic. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012MNV7ZSCjNfA38eDCjsXQL
Fixes#8211
Implements the adjudicated option C (2026-08-12): the ledger header's "if the condition is generic, use the standard catalog instead of registering a synonym" rule was prose only — the admission gate rejected a code only when it was literally a
StandardErrorCodemember, which is why four semantic synonyms accumulated without anyone deciding to allow them. This PR makes the rule mechanical, with recorded waivers. No wire value changes; nothing unregisters — consolidation (option B) stays deferred, undecided, until a specific code has a measured victim.The mechanism (closed, mechanical — no NLP fuzz)
standardSynonymOf(code)inpackages/spec/src/api/error-code-ledger.zod.tsflags a registered code as a semantic synonym of a standard-catalog member on two prongs, each reproducible from the file alone:HttpStatusErrorCodeMapmaps to a standard member (FORBIDDEN→ 403 →PERMISSION_DENIED). Judged against the explicit map only, never the bucket fallback — soPAYLOAD_TOO_LARGE(413, no covering member) is deliberately NOT flagged._-token of the code appears in one standard member's name (CONFLICT⊆RESOURCE_CONFLICT,INTERNAL⊆INTERNAL_ERROR): the code says nothing the member's own name does not already say. Domain-prefixed codes (FORM_NOT_FOUND) carry a token no member has and pass — exactly the shape the registration instructions endorse.standardSynonymViolations(ledger, waivers)reports every unwaived synonym registration; the admission suite inerror-code-ledger.test.tsasserts it is empty on the real ledger. A waiver (STANDARD_SYNONYM_WAIVERS, schemaStandardSynonymWaiverSchema) admits exactly the(code, shadows)pair it records and must carry a non-empty reason — admission becomes a decision on the record, never drift. Stale waivers (code unregistered, or no longer detected as a synonym of the named member) fail the suite.The hard pin the cli seat demanded
A detector that only passes on today's tree is the exact failure mode this card closes — the prose rule also "passed" on every tree. The suite pins that the same function that gates the real ledger goes red when a newly-introduced synonym lands, once per prong (
TOO_MANY_REQUESTS→RATE_LIMIT_EXCEEDED;RATE_LIMIT→RATE_LIMIT_EXCEEDED), plus the waiver-admits / wrong-member-does-not-admit pair, plus the reverse direction (dropping theFORBIDDENwaiver reddens all three registering packages).Grandfathered: the ruled four, plus one the detector surfaced
Measured over the full ledger, the detector flags five existing codes and zero false positives: the four the card named (
CONFLICT,NOT_FOUND,FORBIDDEN,INTERNAL) plusUNAUTHORIZED(401 reason-phrase spelling ofUNAUTHENTICATED's condition, registered by@objectstack/rest). Narrowing the criterion to exclude it would have been tuning the detector to the ruling's list — the failure mode above wearing a different hat. It is grandfathered by a fifth waiver with the same rationale (wire value kept; consolidation deferred); flagged for the veto window in the round report. #8211's option-B question for it, as for the other four, remains open.One rule, two doors (#8087 — remains open, not addressed here)
The ledger header now states the shared rule once: this gate is the admission door; the dispatcher door is ruled separately (#8087, option B-as-a-gate) and its gate is not yet built — until it lands,
resolveThrownHttpError(@objectstack/types, PR #8088) carriescodenarrowed /declaredCodeverbatim across the gap. Wording in the header cross-references both.Fork-clause check
No wire-visible change anywhere: the ledger rows,
REGISTERED_ERROR_CODES, andErrorCodeare byte-identical in meaning; all additions are new exports (standardSynonymOf,standardSynonymViolations,StandardSynonymWaiverSchema,StandardSynonymWaiver,STANDARD_SYNONYM_WAIVERS) — hence aminorchangeset on@objectstack/spec. The row shape is untouched (waivers are a separate table), so no ledger consumer can be affected; out-of-package references to the ledger in source are comments only.ADR-0122:
StandardSynonymWaiverisz.input; isomorphism pinned asIso838intype-alias-convention.pin.test.ts(824 → 825, measured: no defaults/transforms anywhere in the tree).Verification
Full
@objectstack/specsuite + typecheck +check:generatedrun serialized behind the shared verification lock; gate results recorded in the dev report on #8211. Light gates green locally:check:adr-anchors,check:changeset-gate-self-tests,check:cross-package-test-inputs,check:docs-audit-scope,check:error-code-casing,check:merge-driver,check:spec-parsed-alias,check:type-source-resolution,check:nul-bytes,check:query-options-erasure,check:type-check-coverage,check:release-body,check:objectui-changeset, changeset-no-major.Generated by Claude Code