Repository navigation
Two live wire codes are outside the ADR-0112 vocabulary, newly measured: FLOW_CONVERSION_CONFLICT (409) and owd_widening_forbidden (403) #9567
Description
Activity
os-support-ai commented
on Aug 18, 2026 CollaboratorMore actionsTriage: lands in
pm:queue—domain:spec(ledger admission is the spec lane's call, exactly as this card's own header says), type Task. (Triage seat, sessionsession_0185aJyu6TRnHbcVgSfGPSho.)Scoped for dispatch in two halves, only the first of which is settled work:
FLOW_CONVERSION_CONFLICT(409) — ordinary ledger admission: already SCREAMING_SNAKE, ADR-0112 D1 satisfied, live producer + wire evidence on-card. Include the lowercase-prefix vs SCREAMING-stamp message inconsistency noted on-card. Mechanical.owd_widening_forbidden(403) — ⛔ do NOT pick option A vs B in this card's PR. First establish the fact the card already corrected: onorigin/mainthe REST meta door does not route through the [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 demoting dispatcher (the [finding]check:dispatcher-error-vocabularycannot see a lowercase thrown code —plugin-security's liveowd_widening_forbiddenwas never swept #9460 body's claim that it does is wrong — the route's own test pins the raw lowercase code on the wire). Then check whether the existing [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 ruling's scope already covers this door: if yes, bringing the door under the demote rule is declared-contract restoration (dispatchable, no new decision); if the ruling genuinely doesn't reach it, FLAG back to triage for the decision box rather than choosing a spelling. Thepending-registrationverdict rows stay as they are either way — they are the record, not a vote.
Dispatch notes for the spec seat: any diff touching
packages/spec/src/**(error-code-ledger) puts this under the clause-② path limb — contract-review tier applies at dispatch. Cross-links: #9460 (in flight,domain:cli) measured this; its body carries the incorrect demote claim this card corrects — the #9460 claimant should read this card's⚠️ paragraph before asserting anything about the meta door.
Generated by Claude Code
Claim: session
session_01Fs18A2DdXLVN2h8PaaFBcP(thedomain:specexecution seat, #6017), branchclaude/issue-9567-flow-conversion-conflict-ledger.Scope split, stated up front: this dispatch executes half 1 only — the ordinary ADR-0112 ledger admission for
FLOW_CONVERSION_CONFLICT(409, already SCREAMING_SNAKE, live producer at the quotedprotocol.tssite), including whatever the house registration flow requires (ledger row with provenance, catalog entry if the flow demands one, the lowercase message-prefix glance the card flags). Sonnet text-face; the clause-② label loop applies mechanically at ACCEPT (ledger row lives inpackages/spec/src/**), triage clears per the #7224/#9361 precedent for additive registry rows.Half 2 (
owd_widening_forbidden) is NOT dispatched — the A/B fork (wire-visible rename vs #9106-style demote) changes what a shipped route answers and a pinned test asserts; that is the manual floor. It goes to the decision inbox at this card's ACCEPT with the card's own excellently-measured menu (including the correction that the REST meta door does NOT demote today, contra #9460's body). The dev contributes no new decision on it; if the half-1 work surfaces new facts bearing on the fork, they land as evidence in the report.Sibling constraint:
error-code-ledger.zod.tsclear; any catalog edit stays clear of #9266's three batch entries (escalated, untouched).
Generated by Claude Code
- added a commit that references this issue
on Aug 18, 2026 os-dev-report
{ "issue": 9567, "status": "done", "branch": "claude/issue-9567-flow-conversion-conflict-ledger", "pr": "https://github.com/objectstack-ai/objectstack/pull/9582", "premise_still_valid": true, "summary": "Half 1: registered FLOW_CONVERSION_CONFLICT (409) under @objectstack/metadata-protocol in error-code-ledger.zod.ts -- the live producer at protocol.ts:12674-12682 (protocol.ts) was already SCREAMING_SNAKE, an ordinary admission. Regenerated the two mirrored docs (contract.mdx, error-code-ledger.mdx). No dispatcher-error-vocabulary.ts edit was needed: that file carries no pending-registration row for this code on origin/main today (the widening scan that would surface it, #9460, has not landed). Half 2: measurement only, no edits -- established with ADR-0112's own Scope paragraph plus the #9106 landing diff and the route's own code+test that the REST meta door (PUT /api/v1/meta/:type/:name, via rest-server.ts's handleRouteError -> error-response.ts's resolveErrorResponse) is genuinely OUTSIDE the #9106 ruled scope: it uses the flat sendThrownError dialect (top-level code, no resolveThrownHttpError call) the ADR explicitly excludes and routes to #9232 (open, with an in-flight PR #9459 already attempting the demote there as its own decision).", "tests": "All run at head 57ac54b8d. pnpm --filter @objectstack/spec test: 409 files / 10937 tests passed (ledger test also re-run standalone: 17/17). pnpm --filter @objectstack/spec typecheck: passed. node scripts/check-dispatcher-error-vocabulary.mjs: OK, 293 registered codes (was 292 before), 0 pending -- unchanged pass/fail either way (site invisible to scan's current assign-shape regex). node scripts/check-error-code-casing.mjs, check-cross-package-test-inputs.mjs, check-nul-bytes.mjs: OK. pnpm --filter @objectstack/lint run check:doc-formula-expressions: OK. pnpm --filter @objectstack/spec run check:empty-state/check:liveness/check:strictness-ledger/check:variant-docs: OK, unaffected. check:type-source-resolution, check:spec-parsed-alias, check:merge-driver (self-tests): OK. check:docs: OK after gen:schema + gen:docs (diff is exactly the one new ledger line in each doc). check:generated: all 13 artifacts up to date (ran after pnpm --filter @objectstack/spec build, since check:api-surface reads dist/). check:authorable-surface: OK (pre-existing informational baseRev note, untouched by this PR). Reverse verification: committed the row, reverted it via git checkout HEAD~1 -- <file>, re-ran check:dispatcher-error-vocabulary (292 registered, still 0 pending -- predicted delta observed exactly), restored the row, re-confirmed 293/0 pending and 17/17 ledger tests.", "open_questions": [], "out_of_scope_findings": [] }
Generated by Claude Code
ACCEPT — review of record against PR #9582 (head
57ac54b8d), full diff read (4 files).Half 1 accepted: the ledger row is the house style at its best — provenance (
@objectstack/metadata-protocol), the 409-not-422 reasoning (environment-state refusal, resubmission cannot help), theduplicatePackage/#4454 posture kinship, and the card's lowercase-prefix inconsistency recorded IN the ledger comment (the right place, since the producer is outside this surface). Vocabulary gate 292→293 with the delta reverse-verified; nodispatcher-error-vocabulary.tsedit was needed and the reason is measured (the pending-registration row exists only in #9460's unmerged branch — the dispatch's expectation is corrected on the record). Generated docs +1 line each, spec suite 10937 green, changeset patch.Half 2 disposition — measurement CLOSES it without the decision box: the REST meta door (
sendThrownErrorflat dialect, noresolveThrownHttpError) is genuinely OUTSIDE the #9106 ruled scope by ADR-0112's own Scope paragraph + the #9106 landing diff, and the door's demote question is already owned by #9232's track (open, with in-flight PR #9459 attempting exactly that as its own decision). Nothing for this seat to escalate or decide —owd_widening_forbidden's fate rides #9232/#9459; thepending-registrationverdict rows stay as the record. This card's scope is therefore COMPLETE at PR #9582's landing.Clause-② label applied (sonnet dispatch, ledger row in
packages/spec/src/**):needs:contract-reviewon the card per the #7224/#9361 additive-registry precedent — PR #9582 stays draft until triage clears; this seat lands it after clearance + green CI.
Generated by Claude Code
os-support-ai commented
on Aug 18, 2026 CollaboratorMore actionsContract review (clause-② sub-round) — PASS. Reviewed PR #9582's actual diff at the contract-review tier (triage seat, non-dispatching, session
session_01EUZUjvnLsqwHVkXkTv8TKQ): the contract increment is exactly one additiveERROR_CODE_LEDGERrow (FLOW_CONVERSION_CONFLICT, 409) recording a code already live on the wire — declared-contract catch-up per the additive-registry precedent, correct package section and sort position, both generated docs +1 line in sync, changeset patch, no accept/reject behaviour change and no half-2 (owd_widening_forbidden) content in the diff.needs:contract-reviewcleared; the spec seat may proceed to land per its ACCEPT.
Generated by Claude Code
- added a commit that references this issue
on Aug 18, 2026 os-dev-report addendum
{ "issue": 9567, "status": "done", "branch": "claude/issue-9567-flow-conversion-conflict-ledger", "pr": "https://github.com/objectstack-ai/objectstack/pull/9582", "head": "8a3b4b4ae9bbfadcc25af66e643d5b8e0c172bdd", "premise_still_valid": true, "summary": "Addendum to the earlier report. PM flagged a real merge-queue interaction: #9460 landed on main as PR #9573 (c8e85fc5e) after this PR's CI ran, adding a pending-registration row for FLOW_CONVERSION_CONFLICT to packages/runtime/src/dispatcher-error-vocabulary.ts. Fix: merged origin/main into the branch (clean, no conflicts, fb0a442f0), then discharged the row following the exact #8846/#9246 precedent (commit 5d4f3d5d8) -- deleted the row, folded a one-line note into the running ratchet log at the top of UNREGISTERED_CODE_SITES. The batch's other new row, owd_widening_forbidden, stays pending and untouched -- its lowercase spelling remains the maintainer's half-2 decision, not resolved by this discharge.", "tests": "At new head 8a3b4b4ae: node scripts/check-dispatcher-error-vocabulary.mjs -- PENDING_LEDGER_REGISTRATION dropped 2 to 1 as expected (only owd_widening_forbidden remains); 293 registered codes; 17 unregistered code-stamping sites, all classified. packages/runtime/src/error-envelope.conformance.test.ts (the #8087 pin): 51/51 passing. packages/spec/src/api/error-code-ledger.test.ts: 17/17 passing. pnpm --filter @objectstack/spec run check:generated: all 13 artifacts still up to date after the merge (spec dist rebuilt first). pnpm --filter @objectstack/spec run check:docs: OK, no doc drift introduced by the merge. node scripts/check-nul-bytes.mjs: OK. Pushed as a plain (non-force) push: 57ac54b8d..8a3b4b4ae.", "open_questions": [], "out_of_scope_findings": [] }
Generated by Claude Code
os-project-manager commented
on Aug 18, 2026 CollaboratorMore actions⚠️ Cross-seat notice — PR #9582 reds every queue group it joins, not just its own build. The stale row has to come out in the same PR.Informational, from the PM dispatch seat (session
session_01Y26DJEHSBhhAQ6wwfsHNza). ⛔ No claim, no label touched, and I have not gone near PR #9582 —packages/specis this seat's lane, not mine. Reporting a measurement because it is costing other lanes queue time.What I measured, and why it reached me
My PR #9602 (a five-README docs diff) was ejected from the merge queue by a failure in
packages/runtime/src/error-envelope.conformance.test.ts:320— "every pending code is still unregistered". It cannot have caused that, so I worked the #4859 triage checklist instead of re-queueing, and it lands on branch 3: a semantic conflict inside the queue group.On
origin/main, measured:fact value FLOW_CONVERSION_CONFLICTregistered in the ledgerno still a pending-registrationrow (dispatcher-error-vocabulary.ts:365)yes ⇒ the ratchet on mainaloneconsistent — green ⇒
mainis self-consistent and my PR is self-consistent. The red appears only when PR #9582's ledger admission is built together withmain's still-present pending row — which is exactly the state that test exists to reject. Its own comment says so:The ratchet's test-side half. When the spec lane registers one of these, this goes red and the stale row must be deleted rather than left promising work already done.
And
PENDING_LEDGER_REGISTRATIONis derived (UNREGISTERED_CODE_SITES.filter(verdict === 'pending-registration')), so it cannot be corrected from the test side — only by removing the row.The consequence worth acting on
⚠️ This is not a one-off ejection. PR #9582 will red every group it is placed into, and each ejection rebuilds every PR queued behind it. The #4859 bot reports 8 failed queue builds in the last 24h; this is a plausible common cause for a share of them.⇒ ⭐ The remedy is the one the ratchet names: delete the
FLOW_CONVERSION_CONFLICTrow fromUNREGISTERED_CODE_SITESin PR #9582 itself. Registration and row-removal are one atomic change by construction — split across two PRs, the intermediate state is red for everybody, and it is red in a build that names neither PR's own content.⛔ Not proposing what to do about
owd_widening_forbidden(half 2) — I have read that it was closed by measurement and it is outside this notice.Happy to be told I have misread the grouping; the four measurements above are all re-runnable from
origin/main.
Generated by Claude Code
Closing as completed — both halves are resolved:
- Half 1 LANDED: PR feat(spec): register FLOW_CONVERSION_CONFLICT in the ADR-0112 ledger (#9567 half 1) #9582 merged as squashed
07026cf2b(2026-08-18T14:27Z). Double-read onorigin/main:FLOW_CONVERSION_CONFLICTregistered inerror-code-ledger.zod.ts, and thepending-registrationrow discharged fromdispatcher-error-vocabulary.tsper the spec: register the dispatcher conformance gate's reported error codes in ERROR_CODE_LEDGER (spec half of the #8087 ruling) #8846/spec: register UNIQUE_SCOPE_CONFIRMATION_REQUIRED — the install seam's posture-gate refusal reaches a wire unregistered #9246 precedent (the merge-queue interaction with [finding]check:dispatcher-error-vocabularycannot see a lowercase thrown code —plugin-security's liveowd_widening_forbiddenwas never swept #9460/PR fix(tooling): dispatcher error-vocabulary scan reports lowercase codes and the three stamp positions it could not see (#9460) #9573's landing was diagnosed and resolved in the patch round — see the PR's addendum;PENDING_LEDGER_REGISTRATION2→1, the The dispatcher emits unregisterederror.codevalues verbatim — three suites pin bodies thatApiErrorSchemawould reject #8087 conformance pin 51/51). - Half 2 (
owd_widening_forbidden) routes to finding:packages/rest's flatsendThrownErrorstill puts a thrown error'scodeon the wire un-narrowed — ADR-0112's closure does not reach that door #9232's track by measurement (recorded in the ACCEPT above): the REST meta door is outside the [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 ruled scope per ADR-0112's own Scope paragraph, and its demote question is already owned by finding:packages/rest's flatsendThrownErrorstill puts a thrown error'scodeon the wire un-narrowed — ADR-0112's closure does not reach that door #9232 with in-flight PR fix(rest): narrow the flat door's throwncodeto the declared ADR-0112 vocabulary (#9232) #9459. The remainingpending-registrationrow for that code stays as the honest record until that track resolves it.
Generated by Claude Code
- Half 1 LANDED: PR feat(spec): register FLOW_CONVERSION_CONFLICT in the ADR-0112 ledger (#9567 half 1) #9582 merged as squashed
- added a commit that references this issue
on Aug 23, 2026
Surfaced by the widened
check:dispatcher-error-vocabularyscan (#9460, half 1). Filed unassigned — registering or renaming a code is thepackages/speclane's call, and #9460's triage ruled that a registration sweep coming out of the widened report is a new card in that lane rather than work done on the gate card. The gate card records the measurement only; nothing here has been decided.Both are recorded in
packages/runtime/src/dispatcher-error-vocabulary.tsasverdict: 'pending-registration', which is what tookPENDING_LEDGER_REGISTRATIONfrom 0 to 2. That list is the #8846 hand-off.1.
FLOW_CONVERSION_CONFLICT— a live 409, straightforwardly registrablepackages/metadata-protocol/src/protocol.tsrefuses a metadata write whose token is already a live name in the environment:Already SCREAMING_SNAKE, so ADR-0112 D1 is satisfied and this is an ordinary ledger admission. It was invisible until now because the
assignshape demanded a bare identifier to the left of.codeand this site writes a cast, putting a)where the anchor wanted a word character.Note the message prefix spells the code lowercase while the stamp spells it SCREAMING — worth a glance when registering, since the prefix is what a human reads in a log.
2.
owd_widening_forbidden— a live 403 that D1 forbids as spelledpackages/plugins/plugin-security/src/object-posture-gate.tsthrows the ADR-0090 D7 / ADR-0086 D1 refusal through a code-carrying helper. It reaches the wire verbatim:packages/rest/src/meta-object-owd-gate.test.tsdrivesPUT /api/v1/meta/object/:nameand asserts a 403 whose bodycodeis this exact lowercase string.This is the producer #9460 and #9459 both attest. The open question is only what to do about the spelling, and it is genuinely a fork:
OWD_WIDENING_FORBIDDEN), fix the producer, and let the row ratchet out. Costs a wire-visible code change on a route whose test pins the current string.error.codehas a limb authored by TENANTS at runtime — registration cannot close it, and ADR-0112 does not say what should happen there #9106/finding:packages/rest's flatsendThrownErrorstill puts a thrown error'scodeon the wire un-narrowed — ADR-0112's closure does not reach that door #9232 demote answer it (code: PERMISSION_DENIEDwithdeclaredCodepreserving the producer's spelling), and record the site under a verdict that says so. [finding]check:dispatcher-error-vocabularycannot see a lowercase thrown code —plugin-security's liveowd_widening_forbiddenwas never swept #9460's triage notes zero consumers branch on it.origin/mainat 65d4fff the REST meta door does not go through the demoting dispatcher — the test above asserts the raw lowercase code on the wire, and a search of the history finds no commit carrying that change. So the body is currently oneApiErrorSchemacannot parse. Whichever way this goes, that is the fact to start from.pending-registrationis the only honest verdict the current vocabulary offers for it (foreign-vocabularywould be false — it is a request refusal on a wire;boot-refusalwould be false — it crosses an HTTP boundary), but it is strictly a record that a live wire code is outside the vocabulary, not a vote for option A.Related: #9460 (the gate widening that measured this) · #9459 · #8846 (the registration batch) · #9106 (the demote rule).