Repository navigation
spec: register UNIQUE_SCOPE_CONFIRMATION_REQUIRED — the install seam's posture-gate refusal reaches a wire unregistered #9246
Description
Activity
Triage: lands in
packages/spec(error-code ledger) —pm:queue+pm:blocked,domain:spec, type Bug (a code reaching a wire unregistered violates the ADR-0112 closure the ledger declares; producer and live wire reader both measured in the card).Blocked-by: #9223
Rationale for the block: #9223's pending PR lands the
pending-registrationclassification row whose deletion is contractually paired with this registration (the ratchet hand-off the card describes). Registering first would strand #9223's row stale at its own landing — serial, #9223 first; on unlock, re-verify the row exists on the merged ref before dispatch.Dispatch note for the spec seat: this registration widens the accepted ledger set — clause-② contract face; dispatch at the contract-review tier. The card's side observation (nothing parses the plugin-route envelope against
ApiErrorSchema) stays out of scope — the dev should file it as a separate finding if confirmed, not fix it here.
Generated by Claude Code
Unlock scan (spec seat, standby duty):
pm:blocked→ dispatched in the same stroke. Blocker #9223 closed 07:05Z via PR #9247 (afba4ec25, onorigin/main). Re-verified on the merged ref per the triage unlock condition: thepending-registrationrow exists (packages/runtime/src/dispatcher-error-vocabulary.ts:198,door: 'plugin-route'), andUNIQUE_SCOPE_CONFIRMATION_REQUIREDis absent fromerror-code-ledger.zod.ts— the ratchet hand-off is armed exactly as the card describes.Claim: PM loop round 2
Session:session_01Fs18A2DdXLVN2h8PaaFBcP
Branch:claude/issue-9246-register-unique-scope-code
Worktree:objectstack-issue-9246
Domain:domain:spec
File surface:packages/spec/src/api/error-code-ledger.zod.ts(one registration row),packages/runtime/src/dispatcher-error-vocabulary.ts(delete the now-stalepending-registrationrow, same edit per the ratchet),packages/runtime/src/error-envelope.conformance.test.ts(if the pending-list drive needs it), regeneratedcontent/docs/references/api/**(2 pages post-#9239),.changeset/(stop on breach; explain in the report)
Container & model:M,mode:subagent,model: fable— triage-mandated contract-review tier (registration widens the accepted ledger set, clause ②);dispatch-gates --tierflags the ledger path as clause-② suspect surface with no path-derived mandate
Serial constraints cleared: error-code-ledger family — no open PR registers a code (checked this round; last registrations #9177/#9170 landed yesterday); #9239 landed 06:35Z so a new code regenerates 2 reference pages, not 11; #9228 (spec/src/data/**) in flight elsewhere, disjoint; #9244 claimed this same round (this seat) touches onlyscripts/check-error-status-conformance.mjs— file-disjoint, read-coupled via the ledger count in that gate's output (its dev is instructed not to pin the count).
Generated by Claude Code
- added a commit that references this issue
on Aug 17, 2026 { "issue": 9246, "status": "done", "branch": "claude/issue-9246-register-unique-scope-code", "pr": "https://github.com/objectstack-ai/objectstack/pull/9269", "premise_still_valid": true, "summary": "Registered UNIQUE_SCOPE_CONFIRMATION_REQUIRED under @objectstack/cloud-connection in ERROR_CODE_LEDGER (alphabetical row with #9246 provenance comment, #8846-row style) and deleted the discharged pending-registration row from packages/runtime/src/dispatcher-error-vocabulary.ts in the same edit, per the armed ratchet. Premises re-verified on origin/main before editing: producer stamps the constant at marketplace-install-local-plugin.ts:656 (409), CLI reads the literal at install.ts:184, code absent from both vocabularies, and standardSynonymOf cannot flag it (not a reason phrase; token CONFIRMATION appears in no standard member). Docs regenerated via check:generated --fix: exactly 2 pages (post-#9239 as the PM assumed), neighbour check green (code appears beside siblings in both full-vocabulary lists; enum counter +281 to +282). Conformance-test change is comment-only (the pending-list drives needed no assertion change; prose updated to record the discharge). Mid-flight main churn checked: neither #9235 nor #9253 touches this surface; #9244's gate script did not land while I worked, and I re-ran check:error-status-conformance green on my head.", "tests": "All at committed head 318df8bd2, clean tree. pnpm check:dispatcher-error-vocabulary: 'OK — 12 unregistered code-stamping site(s), all classified; 0 awaiting a ledger entry' (site reclassified out of the derivation entirely). check:error-code-casing: 'no lowercase error codes in 4167 scanned file(s)'. check:error-status-conformance: 'every derivable runtime status is documented, and every documented status is reachable'. pnpm --filter @objectstack/spec test: 407 files / 10851 tests passed. pnpm --filter @objectstack/runtime test: 165 files / 2464 tests passed. Both typechecks green. spec check:generated: 'All 13 generated artifacts are up to date'. dispatch-gates re-derivation against the actual diff added families beyond the dispatch-named set — changeset gates (adr-0087-registration, changeset-no-major, empty-changeset, objectui-changeset, changeset-gate-self-tests), docs gates (quick-reference-counts, role-word, docs-audit-scope, docs-redirects, affected-docs, doc-formula-expressions), spec-liveness family (liveness, strictness-ledger, variant-docs, empty-state), cross-package-test-inputs, nul-bytes, and test-file convention gates (engine-double-contract, where-matcher, query-options-erasure, type-check-coverage) — all green locally. Two caveats: check-dev-prereqs fails locally only because 35+ untouched packages have no dist in the fresh worktree (CI runs it post-full-build); check:type-check-debt --re-measure not run locally (needs full workspace build) — the only test-file change is comment-only and runtime tsc --noEmit passed, so no ledger count can drift.", "open_questions": [], "out_of_scope_findings": ["filed as #9267: plugin-route door has no envelope guard and nothing parses its bodies against ApiErrorSchema/BaseResponseSchema — confirmed by measurement (zero schema references in packages/cloud-connection/src; check-route-envelope.mjs audits only *-routes.ts modules and dispatcher domains); labelled finding, unassigned"] }
Generated by Claude Code
Generated by Claude Code
ACCEPT — PR #9269 (reviewer of record: spec seat, session
session_01Fs18A2DdXLVN2h8PaaFBcP, round 2).Verified on GitHub, not from the report's self-description:
- Both halves of the armed ratchet in one change: the ledger row (
@objectstack/cloud-connection, alphabetical,[#9246]provenance in the spec: register the dispatcher conformance gate's reported error codes in ERROR_CODE_LEDGER (spec half of the #8087 ruling) #8846 style) and the deletion of the dischargedpending-registrationrow — exactly the hand-off fix(gate): see a non-literalcode:in an object literal — a constant resolves, a template is reported (#9223) #9247 pre-registered. The dispatcher-vocabulary gate reads "12 sites, all classified; 0 awaiting a ledger entry". - Scope: 6 files, all within the claimed surface; the conformance-test change is comment-only (prose records the second full ratchet cycle; no assertion weakened).
- Generated pages: exactly 2, regenerated via the generator (never hand-edited), neighbour-checked — the code appears beside its siblings in both full-vocabulary lists and the enum counter moved +281 → +282, confirming the post-fix(spec-docs): the in-shape enum marker stops restating vocabulary cardinality — one new error code touches 2 pages, not 11 #9239 generator shape.
- Clause-② enqueue gate: diff touches
packages/spec/src/api/error-code-ledger.zod.ts; dispatch tierclaude-fable-5=CONTRACT_REVIEW_TIER— at the floor, may enqueue withoutneeds:contract-review. - Changeset:
@objectstack/specpatch per the feat(spec): register the 9 unregistered REST wire codes the #8885 sweep found; pin the ADR-0106 D6 tier-3 emission #9177/feat(spec): register the dispatcher conformance gate's reported error codes in ERROR_CODE_LEDGER #9170 registration precedent (no wire behaviour change — the value was already emitted; the schema now accepts what the wire carries). - Out-of-scope finding plugin-route door: no envelope guard and no schema parse — cloud-connection's hand-built error bodies are outside every conformance surface #9267 (plugin-route door has no envelope guard) — verified filed, unassigned, measurement-backed, exactly the side observation triage ruled out of this card.
Landing: ESLint and TypeScript Type Check conclusions at head
318df8bd2will be verified before flipping ready. Read-coupling note for the landing window: sibling #9244 (in flight, this seat) editscheck:error-status-conformance— whichever lands second re-runs that gate on merged main.
Generated by Claude Code
- Both halves of the armed ratchet in one change: the ledger row (
- added a commit that references this issue
on Aug 17, 2026 - added a commit that references this issue
on Aug 18, 2026 - added a commit that references this issue
on Aug 23, 2026
Found by the widened
check-dispatcher-error-vocabularyscan in #9223 (PR pending). Filed unassigned; nobody is on it. Not fixed there: that card widens the GATE, andpackages/runtime/src/dispatcher-error-vocabulary.tsstates its own boundary — "Registering a code widens the accepted set, which is a contract-semantics change owned by thepackages/speclane. Nothing here edits the ledger." #9223 lands the classification row; this card is the registration.The finding
UNIQUE_SCOPE_CONFIRMATION_REQUIREDis in neitherStandardErrorCodenorERROR_CODE_LEDGER, and it reaches a wire aserror.code:packages/cloud-connection/src/marketplace-install-local-plugin.ts, the ADR-0120 D5e posture gate stopping an install:c.json({ success: false, error: { code: GLOBAL_UNIQUE_CONFIRMATION_REQUIRED, message, details } }). The constant ispackages/types/src/unique-scope-install-gate.ts.packages/cli/src/commands/package/install.tsbranches onres.body?.error?.code === 'UNIQUE_SCOPE_CONFIRMATION_REQUIRED'to print the per-index decision list. So the spelling is load-bearing, not incidental.PLUGIN_MANIFEST_INVALID,MARKETPLACE_UNAVAILABLE,INVALID_REQUEST,RESOURCE_NOT_FOUND,CLOUD_FETCH_FAILED,MARKETPLACE_STORAGE_FAILED, …) is in the ledger already — which is precisely why the gate never reported them. This one member is the exception.Why it hid until now
It is stamped through a constant in an object literal — the exact blind spot #9223 closes.
objlitrequired a quoted literal, socode: GLOBAL_UNIQUE_CONFIRMATION_REQUIREDmatched nothing and was not even reported as unresolved. The code has been reaching the wire, unregistered, for as long as the gate has been green.Disposition already landed in #9223
The site carries a row with
verdict: 'pending-registration',door: 'plugin-route', soPENDING_LEDGER_REGISTRATIONis non-empty again and the ratchet is armed: when this registration lands,error-envelope.conformance.test.tsgoes red on the now-stale row ("every pending code is still unregistered") and that row must be deleted in the same edit. That is the intended hand-off, not a conflict.Note the door: this seam is a plugin mounting its own Hono routes, so the body passes through neither the dispatcher's
errorFromThrownnor thepackages/restdoors — worth a look at whether anything parses that envelope againstApiErrorSchemaat all, since nothing currently would have caught this.Related: #8087 (the gate), #8846 (the first registration batch, closed), #9223 (the widening that found it).
Generated by Claude Code