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
spec(contracts): declare the machine-readable stranded-resume details once, and add the optional carrier field to the three doors ruled in decision batch #76 #16559
Cross-seat transfer filed by the domain:services execution seat (session session_012zTkyNHJ7TkuN2oXtP5x37, os-trump, seat post #6021, R24) into the domain:spec queue. Reason for the transfer is mechanical, not preference: the ruled change edits packages/spec, and 「凡触 packages/spec 一律转 domain:spec 座位,不论谁需要它」. ⛔ This seat writes nothing in spec. domain:* / type / priority are pre-filled and are triage's to correct.
This is the contract-first half of a ruling that already exists. It is not a proposal — the shape below was ruled; what is left is declaring it.
Recorded on #16472, quoted rather than paraphrased:
The rule. When a resume failure is told to the caller, it is told in a machine-readable shape: a registered error code, the runId of the run that is actually stranded, and repairable. The door's status code does not change because of it: a decision whose own run advanced still answers success, with the failure behind it carried on the success envelope as an optional, additive field.
Spec: one optional structure declared once in packages/spec and reused by the three carriers; Clause-②: yes (public surface grows) ⇒ needs:contract-review on the landing PRs; @objectstack/spec minor.
⛔ Not B (throwing mirrors #13807 onto a class the maintainer did not rule, and contradicts recall's landed semantics); ⛔ not C alone (an operator learns, a caller cannot).
Why this card exists — measured on origin/main0344f40, 2026-09-07T09:2xZ
The ruling says the structure is declared once in packages/spec. It is not there today:
The zero is a real zero: the same grep over the same tree finds the neighbouring contract symbol, so the population was read.
The structure lives instead at packages/types/src/stranded-decision.ts:67 (StrandedDecisionDetails, with its strandedDecisionDetails(err) recogniser at :109 and a CARRIER symbol at :96). Its only shipped consumer today is packages/rest/src/rest-server.ts:12520, presence-gated.
And the carriers the ruling names are spec interfaces:
status + repairable inside the existing code's details
⇒ Adding the ruled optional field to either approval carrier is an edit to packages/spec, which is why the two domain:services cards cannot start until this lands.
What this card asks for
Declare the structure once in packages/spec, as the ruling words it. Whether that is a new declaration in contracts/ or a promotion of the existing packages/types shape is this lane's call, not the filer's — ⚠️ note only that packages/types/src/stranded-decision.ts already has a recogniser and a carrier symbol with a shipped packages/rest consumer, so a second, divergent declaration would be the failure mode to avoid.
Add the optional field to ApprovalRecallResult and ApprovalDecisionResult.
Widen resumeError's docblock. Today it reads "Why the run was not resumed, when resumed is false" (:571-573, and the same sentence recurs at :595, :623, :649). Batch 🔗 Broken links detected in documentation #76 makes resumed: trueplus a carried failure a legal shape, so that sentence goes false at every site. ⚠️Search for the predicate, do not enumerate from the four line numbers above — this seat has been bitten by exactly that (seat [PM seat] domain:services — 🟢 session_012zTkyNHJ7TkuN2oXtP5x37 (os-trump) · R25 派发中 · 在飞 3 · 本轮落地 4 · 决策箱 0(三张全裁)· 队列 9 · ⛔ 本席低于契约复审档 #6021 correction 85: "When a fact goes false, search for every sentence asserting it. ⛔ Do not enumerate the ones you remember writing."). The four resumeError sites are a starting population, not the answer.
Contract discipline this card inherits
Clause-②: yes — the ruling says so in as many words (public surface grows). ⇒ needs:contract-review on the landing PR, and the review must run at CONTRACT_REVIEW_TIER (claude-fable-5-1, read from scripts/pm/dispatch-gates.mjs:10023 this round).
Both domain:services cards are being set pm:blocked with Blocked-by: pointing here in the same round this card is filed.
Refs
#16472 (the ruling, closed on it) · #15556 · #15970 · #15221 · #16404 (the error-code ledger rule the ruling defers to) · #15555 (the false-negative class the absence rule protects) · #13807 (the decide-door precedent whose envelope shape this generalises)
Cross-seat transfer filed by the
domain:servicesexecution seat (sessionsession_012zTkyNHJ7TkuN2oXtP5x37,os-trump, seat post #6021, R24) into thedomain:specqueue. Reason for the transfer is mechanical, not preference: the ruled change editspackages/spec, and 「凡触packages/spec一律转domain:spec座位,不论谁需要它」. ⛔ This seat writes nothing in spec.domain:*/ type / priority are pre-filled and are triage's to correct.This is the contract-first half of a ruling that already exists. It is not a proposal — the shape below was ruled; what is left is declaring it.
The ruling (director seat, decision batch #76, 2026-09-07, maintainer verbatim 「同意」)
Recorded on #16472, quoted rather than paraphrased:
⛔ Not B (throwing mirrors #13807 onto a class the maintainer did not rule, and contradicts
recall's landed semantics); ⛔ not C alone (an operator learns, a caller cannot).Why this card exists — measured on
origin/main0344f40, 2026-09-07T09:2xZThe ruling says the structure is declared once in
packages/spec. It is not there today:The zero is a real zero: the same grep over the same tree finds the neighbouring contract symbol, so the population was read.
The structure lives instead at
packages/types/src/stranded-decision.ts:67(StrandedDecisionDetails, with itsstrandedDecisionDetails(err)recogniser at:109and aCARRIERsymbol at:96). Its only shipped consumer today ispackages/rest/src/rest-server.ts:12520, presence-gated.And the carriers the ruling names are spec interfaces:
ApprovalRecallResultpackages/spec/src/contracts/approval-service.ts:556resumeError(:572)ApprovalDecisionResultpackages/spec/src/contracts/approval-service.ts:627runId(see #15556)400 FLOW_FAILEDdetailsdomain:cliside, #15221status+repairableinside the existing code's details⇒ Adding the ruled optional field to either approval carrier is an edit to
packages/spec, which is why the twodomain:servicescards cannot start until this lands.What this card asks for
packages/spec, as the ruling words it. Whether that is a new declaration incontracts/or a promotion of the existingpackages/typesshape is this lane's call, not the filer's —packages/types/src/stranded-decision.tsalready has a recogniser and a carrier symbol with a shippedpackages/restconsumer, so a second, divergent declaration would be the failure mode to avoid.ApprovalRecallResultandApprovalDecisionResult.resumeError's docblock. Today it reads "Why the run was not resumed, whenresumedis false" (:571-573, and the same sentence recurs at:595,:623,:649). Batch 🔗 Broken links detected in documentation #76 makesresumed: trueplus a carried failure a legal shape, so that sentence goes false at every site.resumeErrorsites are a starting population, not the answer.Contract discipline this card inherits
Clause-②: yes— the ruling says so in as many words (public surface grows). ⇒needs:contract-reviewon the landing PR, and the review must run atCONTRACT_REVIEW_TIER(claude-fable-5-1, read fromscripts/pm/dispatch-gates.mjs:10023this round).@objectstack/specminor, per the ruling.no, #15963 landsyes, and they are the same class #16404, and if a consumer needs a distinct code to branch, that is its own card with its own business case.inspectStrandedRequestsnow over-reports: it keys onstatus === 'failed'while the platform gained an authoritative strand discriminator — a cascade-failed run the engine calls NOT stranded is reported as one #15358 measured the harm shape when a classifier reads an absent discriminator as a negative, and it is the service-automation: a throw betweenjournalConsumedSuspensionand thestatus: 'stranded'stamp makes a REPAIRABLE strand reportrepairable: false— the operator is told not to attempt a repair that works #15555 false-negative class.Consumers, blocked behind this
bubbleToParentfailure is swallowed, so an approval decision answers 200resumed: truewhile the run behind it is stranded — #13807's three-outcome shape, one level up #15556 (domain:services) — thebubbleToParentdoor half; carries the parent'srunId, not the healthy child's.recallwhose resume strands reports it as an ordinary non-failure — norepairablediscriminator, where the identical strand throughdecidecarries one #15970 (domain:services) —recall;ApprovalRecallResultis already a per-outcome report, so this is an added field on an existing report, not a new report.status: 'stranded'verdict — the wire mirror's member is unreachable on the wire #15221 (domain:cli) — the resume door's400 FLOW_FAILEDdetails.Both
domain:servicescards are being setpm:blockedwithBlocked-by:pointing here in the same round this card is filed.Refs
#16472 (the ruling, closed on it) · #15556 · #15970 · #15221 · #16404 (the error-code ledger rule the ruling defers to) · #15555 (the false-negative class the absence rule protects) · #13807 (the
decide-door precedent whose envelope shape this generalises)