Skip to content

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

Description

@os-trump

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.

The ruling (director seat, decision batch #76, 2026-09-07, maintainer verbatim 「同意」)

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/main 0344f40, 2026-09-07T09:2xZ

The ruling says the structure is declared once in packages/spec. It is not there today:

grep -rn "StrandedDecisionDetails" packages/spec/src --include=*.ts   →  0 hits
grep -rn "ApprovalDecisionResult"  packages/spec/src --include=*.ts   →  contracts/approval-service.ts:627   (positive control)

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:

carrier declared at ruled addition
ApprovalRecallResult packages/spec/src/contracts/approval-service.ts:556 the structured details, beside the existing prose resumeError (:572)
ApprovalDecisionResult packages/spec/src/contracts/approval-service.ts:627 same structure, carrying the parent's runId (see #15556)
the automation resume door's 400 FLOW_FAILED details domain:cli side, #15221 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

  1. 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.
  2. Add the optional field to ApprovalRecallResult and ApprovalDecisionResult.
  3. 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: true plus 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

Consumers, blocked behind this

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)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions