Repository navigation
Description
Surfaced by the contract-review-tier review of PR #18706 (the #18110 + #18555 delivery) and filed by the domain:services seat, session_01QGMBhvUoyD8t5zY8xHQhnP. ⛔ Unlabelled for domain:* and ungraded on purpose — routing and grading are the triage seat's.
engine.execute return in the two executors, per its governing ruling. This card exists so the remaining half is tracked rather than implied-fixed by the release note.
Measured, ⛔ not read off the code
Driven with a scratch probe (subflow → a pausing node → a refusing end) by the reviewer at PR head af0edd84f:
| leg | measured result |
|---|---|
Delegated resume — engine.resume(parentRunId) |
parent returns { success: true, successMessage: … }, parent run row records completed, and the downstream node ran. ⇒ the identical fail-open shape #18110 fixes, still open here. |
Up-bubble — engine.resume(childRunId) |
child row records refused, but the parent stays paused and remains in listSuspendedRuns() indefinitely. |
Call sites behind it:
packages/services/service-automation/src/engine.ts:6266–6350— the delegated-resume branch tests onlypaused/!success, so arefusedchild falls through the ordinary success exit (exactly the branch-set shape the two fixed executors had).engine.ts:6676—bubbleToParentis called only on the completion path; the refusal arm at:6696returns without bubbling, which is why the parent is never resolved either way.
⭐ Why this is worth a card rather than a note
engine.ts:6689–6693 describes the resumed leg, in its own words, as 「the one a screen flow actually takes」 — so the uncovered leg is the common one for the feature that made refused reachable at all (#15788). The two halves also fail differently: the delegated leg loses the refusal silently (fail-open), while the up-bubble leg strands a run in paused (a leak, visible in listSuspendedRuns()).
⛔ What this card does NOT claim
- ⛔ It does not say [finding] service-automation: a
subflowchild that endsrefusedis rolled up by the parent as an ordinary success — the refusal reaches nobody #18110/[finding] service-automation:maprolls arefusedchild up as an ordinary success too — the same fail-open shape as #18110, second file #18555 are wrong or incomplete against their ruling — that ruling named the two executors and the delivery matched it exactly. - ⛔ It does not prescribe the fix. Whether the resume path reuses the same
FlowRefusalSignalchannel that PR added, or whether the up-bubble arm should bubble a refusal, is a design question that touches the engine's resume machinery. ⚠️ It may intersect the region/rethrow territory that [Decision] service-automation: should a refusingendINSIDE a structured region propagate out and terminate the run, or stay a loud refusal at the region boundary? #18112's ruling deliberately left closed (option B not implemented, no container taught to rethrow). Whoever picks this up should read that ruling first.
Dedupe words
resumed leg refused rollup · bubbleToParent refusal arm no bubble · engine.resume parentRunId refused child · parent stays paused listSuspendedRuns · 18110 synchronous leg only
Filed at 2026-09-17T16:23Z. ⛔ No domain:*, no priority, no pm-state — deliberately bare for the triage sweep's disjunction ①. Evidence provenance: the at-tier (claude-fable-5-1, confirmed from the reviewer's transcript) clause-② review of PR #18706, advisory A2.
Generated by Claude Code
Activity
docs(service-automation): name the follow-up card for the resumed leg…
huangyiirene commentedon Sep 18, 2026
Deferred this round — serial behind #18881, and the fold-or-serial question answered explicitly
domain:servicesseat (#6021) ·session_019hBqDVrwbijUCoK9qsss2E· R1 · written 2026-09-18T21:47Z. ⛔ Report-only: no label written, no claim taken, this card keepspm:queueand stays dispatchable. Board readings taken at this fire.Why this is written now rather than when the card is picked up
This card and #18881 are both p1, both
pm:queue, and both land inpackages/services/service-automation/src/engine.ts. That is a shared hot file between two queued cards, so the protocol requires this seat to answer fold or serial out loud rather than let a default happen. #18881 was dispatched this fire; this card was not. The reasoning is recorded here so the next seat inherits a decision, ⛔ not a silence.Fold-or-serial — SERIAL, and two of the five gates fail
loop/parallel/try_catchdurably suspends and the run reports success with nothing run. This card is a resume-leg rollup defect: a child that pauses and then refuses is either lost fail-open (delegated resume) or strands its parent inpaused(up-bubble). Same file, same subsystem — ⛔ not the same defect and not the same repair. Same keyword is ⛔ not gate ①.service-automation, bothengine.ts.⇒ Two independent gate failures. ⛔ Not foldable. They run serial, #18881 first.
🔴 The re-pricing question the next dispatch must answer BEFORE this card goes out
⛔ Do not dispatch this card on the estimate that stands today. When #18881's PR lands, its dev's report must be read against this card with the mandatory question:
This is not a formality here — #18881 adds a named structured failure when a contained node durably suspends. If that failure fires on the shape this card's probe drives, part of this card may already be closed by it. ⭐ The seat's own guess is that it does NOT — this card's probe is
subflow→ pausing node → refusingend, which need not sit inside a structured region at all — but that is a guess, ⛔ not a reading, and it is recorded here as a falsifiable assumption rather than a premise.Readings this seat took at 2026-09-18T21:40Z that this card should not have to re-take
endINSIDE a structured region propagate out and terminate the run, or stay a loud refusal at the region boundary? #18112 isclosed/completed. The card warns it 「may intersect the region/rethrow territory that [Decision] service-automation: should a refusingendINSIDE a structured region propagate out and terminate the run, or stay a loud refusal at the region boundary? #18112's ruling deliberately left closed (option B not implemented, no container taught to rethrow)」 — ⇒ that ruling is closed and must be read before this card is dispatched, exactly as the card asks.mapinside a contained region leaves its progress state behind — later loop iterations skip items and the exhausted map returnssuccesshaving run nothing #15646 is stillopen, and its spec half landed as78436637(feat(spec)!: a structured region body refuses a pause-capable node and an 'end' node #18688) onorigin/main.subflowchild that endsrefusedis rolled up by the parent as an ordinary success — the refusal reaches nobody #18110/[finding] service-automation:maprolls arefusedchild up as an ordinary success too — the same fail-open shape as #18110, second file #18555 / PR fix(service-automation): on the synchronous path, a child run that refuses stops its parent, insubflowand inmapalike #18706, is merged as5762eaf7.subflowand inmapalike #18706 …… 另起一张 PR,并让两条腿各有一条能变红的钉」 ⇒ two legs, two pins. A delivery that reddens only one leg is incomplete on its face.Generated by Claude Code
huangyiirene commentedon Sep 19, 2026
Claim: PM loop round 1
Session:
session_019hBqDVrwbijUCoK9qsss2EBranch:
claude/issue-18714-resumed-leg-refusal-rollupWorktree:
objectstack-issue-18714Domain:
domain:servicesSeat:
domain:services#1File surface:
packages/services/service-automation/src/+.changeset/(stop on breach; explain in the report)Container & model:
M,mode:subagent,model: default judgment tier (opus)— this act'sdispatch-gates.mjs --repo objectstack-ai/objectstack --tier packages/services/service-automation/src/engine.tsreturned verbatim 「no path-derived mandate: the surface hits none of the 3 declared glob(s) … floor sonnet · default opus · ceiling fable」. Kept at default: the card names two legs and ⛔ does not prescribe the fix, so the mechanism is a live design judgment.Clause-②: no
Thread-read: 5736595238
Serial constraints cleared:
the hot file is engine.ts. Its previous holder #18881 MERGED as PR #19140 (verified on origin/main with controls), which is what unblocks this card. Lane pm:dispatched now = #18336 (this seat's, surface core/security + plugin-auth + plugin-security + organizations test ⇒ disjoint from service-automation) and #16506 (⛔ another seat's, on src/email-service.queue-delivery.test.ts ⇒ disjoint). ⛔ No sibling card pins behaviour this one asserts.🔴 Re-pricing against the card that was blocking it — the mandatory question, answered from measurement
⭐ Unaffected. ⛔ Not a guess this time — when this card was deferred, this seat wrote that its probe 「need not sit inside a structured region at all」 and explicitly marked that a guess, not a reading. It is now measured on
origin/mainafter #19140 landed:isRegionSuspensionRefusalcall sites inengine.ts:214), the one-refusal-one-failure suppression (:9528), and a re-throw (:10111)bubbleToParentsites:6689), defined at:7067; the refusal arm's structure is unchanged⇒ #18881 fires inside
runRegion/executeNode. Neither of this card's two legs is touched, so its cost, its shape and its two-pin acceptance all stand as filed. ⛔ The estimate is ⛔ not carried over from filing time — it is re-taken here.engine.ts:10111now re-throws onisRegionSuspensionRefusal. A run that resumes into a structured region can now meet that error type on a path this card is rewriting. ⇒ check whether the resume legs need to handle it, and say what you found. This seat did ⛔ not establish that they do.Standing constraints carried from the card and its triage
subflowand inmapalike #18706 …… 另起一张 PR,并让两条腿各有一条能变红的钉」 ⇒ two legs, two pins. A delivery that reddens only one leg is incomplete on its face.endINSIDE a structured region propagate out and terminate the run, or stay a loud refusal at the region boundary? #18112 isclosed/completed(measured 2026-09-18T21:40Z). The card warns it 「may intersect the region/rethrow territory that [Decision] service-automation: should a refusingendINSIDE a structured region propagate out and terminate the run, or stay a loud refusal at the region boundary? #18112's ruling deliberately left closed」 ⇒ read that ruling before choosing a mechanism.subflowchild that endsrefusedis rolled up by the parent as an ordinary success — the refusal reaches nobody #18110/[finding] service-automation:maprolls arefusedchild up as an ordinary success too — the same fail-open shape as #18110, second file #18555, PR fix(service-automation): on the synchronous path, a child run that refuses stops its parent, insubflowand inmapalike #18706) is merged as5762eaf7.Written by this seat at 2026-09-19T00:40Z. Seat post: #6021.
Generated by Claude Code
wip: #18714 resumed-leg refusal rollup
huangyiirene commentedon Sep 19, 2026
os-dev-report
{
"issue": 18714,
"status": "done",
"branch": "claude/issue-18714-resumed-leg-refusal-rollup",
"pr": "#19158",
"session": "session_019hBqDVrwbijUCoK9qsss2E",
"premise_still_valid": true,
"summary": "Both resumed legs of the subflow chain now roll a child run's REFUSAL up to its parent. The delegated-resume block (engine.resume(parentRunId)) records the refusal when the child it drives answers status 'refused'; bubbleToParent gains a refusal argument so a child resumed directly (engine.resume(childRunId)) also resolves its parent instead of leaving it parked. Both arms hand the refusal to ONE throw site inside the resume's traversal try-block, past claimAdvance/forgetSuspendedRun and before the traversal, which raises the existing internal FlowRefusalSignal so the run terminates through the single finishRefusedRun chokepoint: parent row reads 'refused', carries the child's rendered refusalMessage, fires no successMessage, walks no out-edge, and keeps the child's #4354 rollup. Multi-level chains resolve by the same induction completions already use. ISSUE BODY: no sanitizer truncation — the body ends on its intact dedupe-words section and footer, and both comments plus the PM claim read whole. CLAIM VERIFIED: newest Claim: comment 5737929003 names this branch. ASSIGNEE: set by the PM to huangyiirene before dispatch; this run never wrote it.",
"tests": "ABLATION (two legs, one at a time, via scripts/ablation-replace.mjs — anchor-must-hit, on-disk blob proof, proven restore). The pins resolve ./engine.js from package SOURCE (in-package relative import, no dist on the resolution path), which the reddening itself demonstrates. LEG 1, delete the delegated-leg detection: tool printed 'anchor 1 to 0, blob 90ccd6c29edf to fe1d7763fc67'; result 4 failed | 7 passed; the four reds are all leg-1: "expected undefined to be 'refused'" (twice), "expected undefined to be 'Refused: vip is not eligible'", and "expected [ 'child-work', 'downstream' ] to deeply equal [ 'child-work' ]"; every leg-2 assertion and both controls GREEN. LEG 2, delete the up-bubble of the refusal: 'anchor 1 to 0, blob 90ccd6c29edf to 6098b376281a'; result 3 failed | 8 passed; the three reds are all leg-2: "expected 'paused' to be 'refused'" (twice, on the parent's run row and on its summary) and "expected true to be false" (hasSuspendedRun on the parent); every leg-1 assertion and both controls GREEN. Two DISTINCT failure signatures — wrong-answer fail-open versus leaked-run — not one measurement restated. Both restore legs printed 'ok restored: blob == HEAD (90ccd6c29edf) and
git diff HEADis empty', and git status --porcelain was empty after each. TWO leg-2 assertions are measured green on BOTH sides and are annotated in the file as such, so no reader mistakes them for pins: the downstream-did-not-run one, kept as the pin on the WRONG fix of bubbling the refusal as a completion; and the child-envelope invariance one. SUITES: pnpm --filter @objectstack/service-automation test printed 'Test Files 140 passed (140)' and 'Tests 1671 passed (1671)', exit 0 — so the synchronous leg (#18110 and #18555), the region refusal (#18881) and the retryable delegated resume-bag codes (#14379) keep their pins. pnpm --filter @objectstack/service-automation typecheck exit 0 including check:test-typecheck ('0 file(s) / 0 error(s)'). New pin file alone: 'Test Files 1 passed (1)' and 'Tests 11 passed (11)'. All heavy runs went through scripts/pm/os-verify-lock.sh with OS_VERIFY_LOCK_SLOT=issue-18714; every verdict read off its printed 'VERDICT command-exit' line, never a bare exit variable after a pipe.","gates": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (NO paths passed; change set derived from merge base 6819dcb) yielded 59 commands. ALL 59 RUN, exit codes landed to disk, reconciled with --ran: 'dispatch-gates --ran: 59 derived famil(ies) accounted for — 59 run, 0 NOT-MEASURED (a DERIVED zero — all 59 recorded an exit code and none of them is 3)', exit 0. Two gates first answered exit 3 PREREQUISITE NOT MET (pnpm check:dual-build-cjs-loads and pnpm check:type-check-debt — both demand a built closure); after 'pnpm exec turbo run build --filter=./packages/* --filter=./packages// --concurrency=2' (72/72 tasks successful, exit 0) both were re-run and answered exit 0 ('104 published require entry point(s) across 67 package(s) load' and '4 ledger entr(ies) re-measured, 53 raw tsc error(s) total, none above its recorded number'). REPO-LEVEL SCAN, run whole and NOT narrowed: pnpm lint (eslint . --no-inline-config) exit 0 on the final commit b2203ba. pnpm check:nul-bytes green, plus a hand grep -naP over the three changed files for control bytes: zero hits. CLAUSE-2: node scripts/pm/check-clause2-carriers.mjs --pair 19158 exit 0, verdict 'the clause-② declaration is readable in the fixed spelling and both carriers agree, and its diff carries no widening tell' — card claim and PR body both DECLARED 'no'. NO needs:contract-review is owed on this PR and none is present on it. REMOTE CI on PR head b2203ba: 34 check runs completed, 31 success / 3 skipped / 0 failure — all SEVEN required contexts GREEN (Lint & Repo Gates, TypeScript Type Check, Test Core, Dogfood Regression Gate, Build Core, Temporal Conformance (live PG + MySQL), Governed Surface Queue Guard). Not a substitute for CI's own account: the 51 artifact-roster families, 11 declared-wide families, 5 path-scheduled CI jobs and the always-runs tail sit outside the derived 59, as the tool states.",
"line_budget": "NOT APPLICABLE — the diff touches no skills/** package and no published SKILL.md, so no line ratchet is owed and none was paid. Diff size for the record: 3 files, +525/-4 versus origin/main — engine.ts +184/-4 (two detection arms, one shared throw site, one module-private interface, docblocks), resumed-leg-refusal-rollup.test.ts +318 (new), .changeset/18714-resumed-leg-refusal-rollup.md +27 (new). The auto-labeler put size/l on the PR; that is another actor's write and was left alone.",
"deviations": "NONE that narrow verification: the repo-level lint ran whole rather than narrowed, and all 59 derived gate families ran with zero NOT-MEASURED. Two deliberate, declared choices worth the seat's eye. (1) The two resumed legs share ONE throw site and one terminal chokepoint, so a mutation AT THE SHARED SITE would redden both pins. The legs are kept independently dissolvable by their own detection arms, which is exactly what the two ablations above mutate; the two-pin acceptance should be read against those, not against the shared site. (2) The changeset is a patch, not a minor: nothing published moves (ChildRunRefusal is module-private, resumeInternal and bubbleToParent are private), which is also why Clause-2 is 'no'. No label was written from here, per the dispatch's write budget. No PR body PATCH was issued — the body was written once, at creation, and read back byte-identical. FILE SURFACE HELD: packages/services/service-automation/src/ plus .changeset/ and nothing else; zero packages/spec.",
"files_changed": [
"packages/services/service-automation/src/engine.ts",
"packages/services/service-automation/src/resumed-leg-refusal-rollup.test.ts",
".changeset/18714-resumed-leg-refusal-rollup.md"
],
"zone2_findings": "ASSUMPTION 1 (the blocker #18881 / PR #19140 does not change this card) — CONFIRMED by re-measurement, not carried over. On origin/main isRegionSuspensionRefusal has exactly 3 sites in engine.ts (import :214, the one-refusal-one-failure suppression :9528, the inner-boundary rethrow :10111); on this branch the same 3, shifted to :214 / :9704 / :10287 by my insertions. NONE is on the resume or up-bubble path. bubbleToParent was called on the completion path only (:6689 on main); my change adds exactly one more call site and changes nothing about the existing one. Negative control: a bogus token grep returned 0 hits, exit 1. ASSUMPTION 2 (the NEW :10111 rethrow adjacency — a question, not a fence) — ANSWERED: the resume legs do NOT need to handle it. The two predicates are structurally disjoint. FlowRegionSuspensionRefusalError is an Error subclass branded with a registered Symbol.for and carries no __flowRefused; FlowRefusalSignal is a non-Error sentinel carrying __flowRefused and no symbol. Neither isRefusalSignal nor isRegionSuspensionRefusal can answer true for the other's value. A run that resumes INTO a structured region and meets the region refusal still falls to resumeInternal's generic failure arm and is failed, which is #18881's intended outcome; my arms sit above that and never intercept it. Held by the full package suite staying green, region-durable-suspension-refusal and nested-region-parity included. ASSUMPTION 3 (the card's line numbers have drifted) — CONFIRMED, and re-located by behaviour rather than by number: the delegated-resume branch the card cited at :6266-6350 is the correlation.startsWith('subflow:') block, and the bubble arm it cited at :6676 / :6696 is the completion-path bubbleToParent call and the isRefusalSignal catch arm beside it. ASSUMPTION 4 (whether to reuse PR #18706's FlowRefusalSignal channel) — MEASURED and REUSED, and it is the right channel: both existing producers of a refusal already unwind through it to finishRefusedRun, the resume path already carries an isRefusalSignal catch arm, and reusing it means the resumed legs mint no second unwinding protocol, no second terminal exit and no new vocabulary.",
"issue_18112_reading": "READ IN FULL — the card plus its single ruling comment (hotlong, 2026-09-17, director batch #146 item 2, maintainer 「146 同意」). What it CLOSED: letter A — a refusing end inside a structured region stays a loud failure at the region boundary, plus the authoring-time refusal folded into #15646. What it deliberately left CLOSED: option B — teaching try_catch (and parallel / map) to RETHROW the refusal instead of catching it, and the paired decision about the in-flight siblings of a parallel gateway; B 'reopens only with #3267's 「支持」, for both signals together'. MY MECHANISM STAYS OUTSIDE IT on all three counts: (a) it teaches no container to rethrow — runRegion, try_catch, parallel, loop and the map executor are untouched by this diff; (b) it decides nothing about parallel siblings; (c) it adds no engine surface. It also cannot reach that territory by construction: a region body runs synchronously inside the enclosing run and cannot carry a durable pause at all (#3267 禁, enforced at authoring by #18688 and at runtime by #18881), so the shape this card fixes — a run PARKED at a subflow or map node awaiting a child — can never be inside a region body. The two arms are on the top-level durable-resume machinery only.",
"mcp_calls": "0 — no MCP GitHub tool was called, read or write. Every GitHub read and write went through the REST proxy with curl and GITHUB_TOKEN.",
"api_writes": "2 — POST /repos/objectstack-ai/objectstack/pulls (draft PR #19158) and POST /repos//issues/18714/comments (this report). No label write, no PATCH, no POST /issues. The three git pushes to the feature branch are git, not REST writes.",
"open_questions": [],
"out_of_scope_findings": [
"noted, not filed: the delegated-resume block special-cases the 'subflow:' correlation only, so a map parent reaches its child's outcome exclusively through the up-bubble. Consistent, covered by leg 2, and a shape of the two node types rather than a defect — none of the three filing classes. Successor: none known.",
"noted, not filed: bubbleToParent's per-outcome #4632 grading (the stranded error arm versus the functional warn arm) is unreached on a refusal, because a refused parent answers success true. That is correct — a refusal is not a degradation — but it means the strand-recording arm stays exercised only from the completion side, by the existing subflow-bubble-strand-log-level pin. Observation, not a defect. Successor: none known.",
"noted, not filed: the docs-drift bot named two RELEASE-OWNED pages (content/docs/releases/v16.mdx and v17/17-0.mdx) as naming AutomationEngine. Read-only by AGENTS.md; nothing in them is falsified by this change (no rename, no removal, no advertised behaviour withdrawn), and no edit was made. Successor: the release seat, at release time."
]
}
Generated by Claude Code
huangyiirene commentedon Sep 19, 2026
ACCEPT — PR #19158, reviewed against GitHub and the tree, ⛔ not against the report
domain:servicesseat (#6021) ·session_019hBqDVrwbijUCoK9qsss2E· R1 · written 2026-09-19T01:30Z. Reviewed headb2203ba3b7.Checklist — each line a reading this seat took
main✓ · first lineFixes #18714✓ ·Clause-②: noline-initial ✓/pulls/19158/files)packages/services/service-automation/src/+.changeset/— ⛔ nothing outside; ⛔ zeropackages/specsrc/index.tsis not in the diff, andChildRunRefusal/resumeInternal/bubbleToParenteach resolve 0 times in the package entry. Control on the same instrument: that entry carries 26exportlines ⇒ the zeros are readings. Nothing published moves.--pair 19158no, no widening tellBuild Docs,Console Pin Gate,Packed-tarball smoke (opt-in))os-dev-reporton the issue (5738255926) ✓ ·mcp_calls0 · api_writes 2, exactly the budget ✓🔴 The acceptance that mattered: two legs, two pins — triage's non-negotiable
Triage's instruction was verbatim 「另起一张 PR,并让两条腿各有一条能变红的钉」. Checked structurally, ⛔ not on the report's word: the suite is 11 tests laid out as
defect leg 1/control leg 1/defect leg 2/control leg 2— each leg has its own defect block and its own control.The two ablations produce genuinely different signatures, which is what makes them two measurements rather than one restated:
expected undefined to be 'refused'— the refusal is lost, fail-openexpected 'paused' to be 'refused'+hasSuspendedRuntrue — the parent is leaked⇒ wrong-answer versus leaked-run. Exactly the two failure modes the card describes, and each ablation left the other leg's assertions and both controls green.
⭐ The disclosure that earns the most trust here is the one against the deliverer's own interest: the dev declared that the two legs share one throw site, so a mutation there would redden both pins — and that the two-pin property therefore has to be read against the detection arms, which is what the ablations mutate. ⛔ It did not let the shared chokepoint pass as though the pins were independent everywhere. It also annotated two assertions as green-on-both-sides so no later reader mistakes them for pins.
Zone-2 assumptions — both answered, one by falsifying the question
isRegionSuspensionRefusalstill has 3 sites, none on the resume or up-bubble path.:10111re-throw adjacency — asked as a question, ⛔ not a fence): answered, and the answer is no. The two predicates are structurally disjoint —FlowRegionSuspensionRefusalErroris anErrorsubclass branded with a registeredSymbol.forand carries no__flowRefused;FlowRefusalSignalis a non-Errorsentinel carrying__flowRefusedand no symbol. Neither detector can answer true for the other's value. ⇒ ⭐ the right outcome for a question dispatched as a question: it was investigated and closed with a mechanism, ⛔ not deferred and ⛔ not turned into speculative work.endINSIDE a structured region propagate out and terminate the run, or stay a loud refusal at the region boundary? #18112 read in full and the mechanism stays outside it on three counts — no container taught to rethrow, nothing decided about parallel siblings, no engine surface added. Plus a structural argument: a region body runs synchronously and cannot carry a durable pause at all, so the parked-at-a-subflow shape this card fixes can never be inside one.Changeset
patch, notminor— nothing published moves, which is the same fact that makesClause-②: nohonest. Consistent.Out-of-scope findings — placed
Three
noted, not filed, each with its successor named, and this seat agrees none meets the three filing classes: thesubflow:-only correlation special-case (a shape of the two node types, covered by leg 2) ·bubbleToParent's per-outcome grading being unreached on a refusal (correct — a refusal is not a degradation) · the docs-drift bot naming two release-owned pages, correctly left alone since nothing in them is falsified andcontent/docs/releases/**is ⛔ never edited in a code PR.⇒ ready + enqueued.
Generated by Claude Code
huangyiirene commentedon Sep 19, 2026
✅ Landed — PR #19158 MERGED, verified on
origin/main, half-state cleareddomain:servicesseat (#6021) ·session_019hBqDVrwbijUCoK9qsss2E· R1 · written 2026-09-19T02:02Z.(#19158)in the commit log(#19136)(#99999)mainChildRunRefusalsites inengine.tsClause-②: nostill holds AFTER landing — the refusal type in the package entryexportlines)⇒ the delivery is on
main, and the clause-② declaration is true of the landed code, ⛔ not merely of the declaration.Half-state cleared
Closed
completedstill carryingpm:dispatched+ assignee. Nowpriority:p1,domain:services, 0 assignees. ⛔ Cleared with this note, ⛔ not silently.What landed
A child flow that durably pauses and only then refuses now rolls that refusal up to its parent on both resumed legs — the delegated resume (which used to lose it fail-open, reporting
completedand walking the out-edge) and the up-bubble (which used to strand the parentpausedinlistSuspendedRuns()forever). Both arms hand the refusal to one throw site and terminate through the existingfinishRefusedRunchokepoint, so no second unwinding protocol and no new vocabulary were minted.⭐ Triage's non-negotiable — 「两条腿各有一条能变红的钉」 — was met and measured: the two ablations produce different signatures (
expected undefined to be 'refused'= lost;expected 'paused' to be 'refused'+ a livehasSuspendedRun= leaked), each leaving the other leg green.Generated by Claude Code
fix(service-automation): a durable suspension inside a structured reg…
fix(service-automation): a resumed child's refusal rolls up on both l…