Uh oh!
There was an error while loading. Please reload this page.
feat(spec): register FLOW_CONVERSION_CONFLICT in the ADR-0112 ledger (#9567 half 1) - #9582
Conversation
…9567 half 1) `saveMetaItem`'s flow-conversion rename guard (protocol.ts:12674-12682) has thrown a live 409 FLOW_CONVERSION_CONFLICT since ADR-0078 landed -- already SCREAMING_SNAKE, so this is an ordinary ADR-0112 D3 ledger admission under @objectstack/metadata-protocol. It was invisible to check:dispatcher-error-vocabulary's scan because the site stamps the code through a cast rather than the bare-identifier `assign` shape the scan matched. Regenerated the two docs that mirror the ledger (content/docs/references/api/ contract.mdx, error-code-ledger.mdx) via gen:schema + gen:docs; check:generated and check:docs both confirm no other artifact moved. Half 2 of #9567 (`owd_widening_forbidden`) is measurement-only in this PR -- see the PR description -- so this PR does not close the issue. Part of #9567
📓 Docs Drift CheckThis PR changes 2 package(s): 3 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 1 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 119 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin ffa4cc0339bf23ded235db8199d2098dea69f74e && git checkout ffa4cc0339bf23ded235db8199d2098dea69f74e
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin e8dba8a8a2bb680eaa1ee62d91b0bc402bec9094 8a3b4b4ae9bbfadcc25af66e643d5b8e0c172bdd && git checkout -B drift-repro e8dba8a8a2bb680eaa1ee62d91b0bc402bec9094 && git merge --no-ff 8a3b4b4ae9bbfadcc25af66e643d5b8e0c172bdd
node scripts/docs-audit/affected-docs.mjs --json e8dba8a8a2bb680eaa1ee62d91b0bc402bec9094
|
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 32140228186 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 失败的 job(日志抽取,best effort):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
…w-conversion-conflict-ledger
Uh oh!
There was an error while loading. Please reload this page.
os-sam
commented
Aug 18, 2026
⛔ This PR is ejecting the PRs queued behind it — one paired file is missing
Queue build 32140254326 went red and ejected #9597 — a two-file showcase-i18n change ( The chain, measured on |
…on row (#9567) #9460 landed on main (PR #9573) while this branch's registration PR was in the merge queue, adding a pending-registration row for FLOW_CONVERSION_CONFLICT to dispatcher-error-vocabulary.ts's UNREGISTERED_CODE_SITES. That collided with this branch's ledger admission of the same code -- a registered code with a pending-registration row still on file fails the #8087 conformance gate in the direction the row's own docs describe ("a pending-registration row whose code is registered fails the gate in the other direction"). Ratchets the row out following the #8846/#9246 precedent exactly: delete the discharged row, fold a one-line note into the running log at the top of UNREGISTERED_CODE_SITES. owd_widening_forbidden -- the #9460 batch's other new row -- stays pending; its lowercase spelling is a naming decision for the maintainer (#9567 half 2), not a plain admission, and is untouched. node scripts/check-dispatcher-error-vocabulary.mjs: PENDING_LEDGER_REGISTRATION 2 -> 1 (only owd_widening_forbidden remains). error-envelope.conformance.test.ts (the #8087 pin): 51/51 passing. error-code-ledger.test.ts: 17/17 passing. check:generated: all 13 artifacts still up to date after the merge. Part of #9567
Uh oh!
There was an error while loading. Please reload this page.
Part of #9567
This PR delivers half 1 only (the
FLOW_CONVERSION_CONFLICTledger admission). Half 2 (owd_widening_forbidden) is measurement-only below — no edits, no decision made — and the issue stays open for the maintainer's decision box.Half 1 —
FLOW_CONVERSION_CONFLICTledger admissionProducer receipt —
packages/metadata-protocol/src/protocol.ts:12674-12682:Already SCREAMING_SNAKE (ADR-0112 D1 satisfied), so this is an ordinary admission. Registered under
@objectstack/metadata-protocolinpackages/spec/src/api/error-code-ledger.zod.ts(alphabetically betweenDESTRUCTIVE_CHANGEandINVALID_METADATA), following the[#issue] … — em-dash clausecomment style the #9411 landing (26e70fbff) set.Message-prefix inconsistency (on-card, recorded per the dispatch note): the thrown message spells the code lowercase —
[flow_conversion_conflict]— while the stamped.codeis SCREAMING_SNAKE. The producer lives inpackages/metadata-protocol, outside this ledger PR's surface, so left untouched; noted in the ledger comment for the next reader.What the admission required, and what it did NOT (at dispatch time):
error-code-ledger.zod.ts: +1 row (this PR).packages/runtime/src/dispatcher-error-vocabulary.ts: no row existed there for this code onorigin/mainat dispatch time — see the Addendum below for what changed.content/docs/references/api/contract.mdxand.../error-code-ledger.mdxmirror the ledger and were regenerated (gen:schemathengen:docs);check:generatedandcheck:docsboth confirm all other generated artifacts are unaffected.StandardErrorCodeenum change, no catalog-bijection edit, nothing touching [finding]error-catalog.mdxpublishes some error statuses only in prose or a JSON example, socheck:error-status-conformancegrades them as nothing — three entries publish no status it can read at all #9266's escalated entries.Half 2 —
owd_widening_forbidden: MEASUREMENT ONLY (no edits made)Question: does the existing #9106/#9232 demote ruling's scope already cover the REST meta door (
PUT /api/v1/meta/object/:name)?Answer: No — genuinely outside the ruled scope, confirmed by both the ADR text and the code.
ADR-0112's own amendment text states the scope explicitly (
docs/adr/0112-error-code-vocabulary-and-ledger.md:122):The [Decision] The dispatcher's
error.codehas a limb authored by TENANTS at runtime — registration cannot close it, and ADR-0112 does not say what should happen there #9106 landing commit (2f65b1b42) touches zero files underpackages/rest/— onlypackages/runtime,packages/types,packages/spec(HttpDispatcher.errorFromThrown,dispatcher-plugin'serrorResponseBase,endpoint-executor'sendpointErrorAnswer).Traced the actual route:
PUT /api/v1/meta/:type/:name(packages/rest/src/rest-server.ts:4949-5121) catches intohandleRouteError(packages/rest/src/error-response.ts:1380), which callsresolveErrorResponse(same file,:1181). That function readserror.status/error.codedirectly and builds{ error: safeMsg, code: error.code, … }—codeat the body's top level, exactly the "flatsendThrownErrordialect" the ADR names as out of scope. It never callsresolveThrownHttpError. (resolveThrownHttpErroris used only inhttp-dispatcher.ts,dispatcher-plugin.ts,endpoint-executor.ts,package-routes.ts, and the hono adapter — never inerror-response.ts.)packages/rest/src/meta-object-owd-gate.test.ts:391,412pins exactly this:expect(res._json?.code).toBe('owd_widening_forbidden')— the raw lowercase code, unnarrowed, at the top level — confirming the flat dialect is what's live on this route today. This corrects the [finding]check:dispatcher-error-vocabularycannot see a lowercase thrown code —plugin-security's liveowd_widening_forbiddenwas never swept #9460 issue body's claim that the flat door already demotes it (the Two live wire codes are outside the ADR-0112 vocabulary, newly measured:FLOW_CONVERSION_CONFLICT(409) andowd_widening_forbidden(403) #9567 issue's ownerror.codehas a limb authored by TENANTS at runtime — registration cannot close it, and ADR-0112 does not say what should happen there #9106 diff, and the route's own code+test).#9232("packages/rest's flatsendThrownErrorstill puts a thrown error'scodeon the wire un-narrowed") is open, is exactly this question, and already has an in-flight PR (#9459, open) attempting to close it as its own separate decision.Conclusion: the REST meta door is genuinely outside the #9106 ruled scope, not merely un-swept within it. Bringing it under the demote rule is not declared-contract restoration — it's the still-undecided #9232/#9459 work. The A/B spelling fork for
owd_widening_forbidden(rename toOWD_WIDENING_FORBIDDENvs. keep lowercase and let a future flat-door demote answer it) is correctly left to the maintainer's decision inbox, per the PM's claim comment. No edits made for half 2; itspending-registrationrow is untouched by the addendum below (see there).Reverse verification (half 1, at dispatch time)
Committed the ledger row, then
git checkout HEAD~1 -- packages/spec/src/api/error-code-ledger.zod.tsto revert it and re-rancheck:dispatcher-error-vocabulary:293 registered codes (240 ledger + 53 standard),0 awaiting a ledger entry.292 registered codes (239 ledger + 53 standard),0 awaiting a ledger entry— unchanged pass/fail, exactly as predicted (the site is invisible to the current scan shape either way; only the registered-code count moves).Restored the row (
git checkout HEAD -- …), re-confirmed293 registered codes,0 awaiting a ledger entry,error-code-ledger.test.ts17/17 passing.Tests / gates (initial pass, at head
57ac54b8d)pnpm --filter @objectstack/spec test— 409 test files / 10937 tests passed (full package run; the ledger-scopederror-code-ledger.test.tsalso re-run standalone: 17/17 passed).pnpm --filter @objectstack/spec typecheck— passed (tsc --noEmit+ scripts + test-typecheck, debt ledger unchanged at 55 files / 263 errors).node scripts/check-dispatcher-error-vocabulary.mjs— OK, 293 registered codes, 0 pending.node scripts/check-error-code-casing.mjs— OK, no lowercase codes in 4212 files.node scripts/check-cross-package-test-inputs.mjs— OK.node scripts/check-nul-bytes.mjs— OK.pnpm --filter @objectstack/lint run check:doc-formula-expressions— OK (24 self-test cases + live pass).pnpm --filter @objectstack/spec run check:empty-state / check:liveness / check:strictness-ledger / check:variant-docs— all OK, unaffected.node scripts/docs-audit/check-affected-docs.mjs— self-test OK.pnpm check:type-source-resolution,pnpm check:spec-parsed-alias,pnpm check:merge-driver(self-tests) — all OK.pnpm --filter @objectstack/spec run check:docs— OK aftergen:schema+gen:docs.pnpm --filter @objectstack/spec run check:generated— all 13 generated artifacts up to date (ran afterpnpm --filter @objectstack/spec build).pnpm --filter @objectstack/spec run check:authorable-surface— OK (unrelated informational note aboutauthorable-surface.base.jsonvs. the current anchor commit, shallow-checkout limitation, pre-existing).Addendum — merge-queue interaction, fixed and re-verified (head
8a3b4b4ae)#9460landed onmainas PR #9573 (c8e85fc5e) after this PR's CI ran, adding apending-registrationrow forFLOW_CONVERSION_CONFLICTatpackages/runtime/src/dispatcher-error-vocabulary.ts:365. The merge group (this PR's registration + main's new pending row) then trippederror-envelope.conformance.test.ts's #8087 pin: apending-registrationrow for a code that is now registered fails that gate in the direction its own docs describe ("apending-registrationrow whose code is registered fails the gate in the other direction").Fix: merged
origin/maininto this branch (clean, no conflicts —fb0a442f0), then dischargedFLOW_CONVERSION_CONFLICT's row per the exact#8846/#9246precedent (5d4f3d5d8): delete the discharged row, fold a one-line note into the running ratchet log at the top ofUNREGISTERED_CODE_SITES.owd_widening_forbidden— the #9460 batch's other new row — stays pending and untouched: its lowercase spelling is a naming decision for the maintainer (half 2 above), not a plain admission.Local re-verification, all green:
node scripts/check-dispatcher-error-vocabulary.mjs—PENDING_LEDGER_REGISTRATIONdropped 2 → 1 as expected (onlyowd_widening_forbiddenremains);293 registered codes,17 unregistered code-stamping site(s), all classified.error-envelope.conformance.test.ts(the The dispatcher emits unregisterederror.codevalues verbatim — three suites pin bodies thatApiErrorSchemawould reject #8087 pin,packages/runtime) — 51/51 passing.error-code-ledger.test.ts(packages/spec) — 17/17 passing.pnpm --filter @objectstack/spec run check:generated— all 13 artifacts still up to date after the merge (ran after rebuilding@objectstack/spec'sdist/).pnpm --filter @objectstack/spec run check:docs— OK, no doc drift from the merge.node scripts/check-nul-bytes.mjs— OK.Pushed as a plain (non-force) push:
57ac54b8d..8a3b4b4ae. New head:8a3b4b4ae.Generated by Claude Code