Found while delivering the services half of #13937 (branch claude/issue-13937-stranded-run-operator-verb). ⛔ Not fixed there: it is a reach gap of the existing operator exit for nested runs, and the shape of the repair (journal the ancestors too, or restore the chain as one unit) is a design decision, not a line. Filed under #13909 because it is deliverable 2's ("an operator path out of a terminal run") nested-run gap.
The reading, on origin/main 50d6c92
resumeInternal's catch arm journals the consumed suspension of THE RUN THAT THREW (journalConsumedSuspension) — the input restoreConsumedSuspension puts back. For a nested run, the ancestors are then handled on both paths without any journal:
- Up-bubble path (
skipBubble === false): failAncestors walks $parentRunId and calls failSuspendedRun on each suspended ancestor.
- Delegation path (parent resumed first, child resumed with
skipBubble === true): the parent frame sees !childRes.success with no retryable code and calls failSuspendedRun(run, ...) on itself.
failSuspendedRun is forgetSuspendedRun(run, 'failed') plus a failed log record — it journals NOTHING. So after a child strands:
- the child is stranded and restorable (
status: 'stranded' on its result; restoreConsumedSuspension(CHILD_RUN_ID) answers restored: true);
- every ancestor is recorded
failed with its pause consumed and no snapshot: restoreConsumedSuspension(PARENT_RUN_ID) answers NO_CONSUMED_SUSPENSION, and the parent's own resume result (delegation path) carries no status at all — it is neither stranded nor repairable, and must not be stamped stranded (nothing can re-arm it);
- restoring and resuming the child completes the child, whose
bubbleToParent finds no parent suspension and logs a warning: the parent flow never continues.
⇒ For a nested run the operator exit re-arms the leaf and loses the tree. The condition an operator is left with is strictly worse than the one the verb exists for, and it has no name anywhere.
What a fix has to decide
Related
#13909 (deliverable 2, the operator exit — this is its nested-run gap) · #13937 (shape-4 ruling; services half in flight) · #14379 (the delegated child's retryable refusal, a neighbouring seam on the same frame)
Found while delivering the services half of #13937 (branch
claude/issue-13937-stranded-run-operator-verb). ⛔ Not fixed there: it is a reach gap of the existing operator exit for nested runs, and the shape of the repair (journal the ancestors too, or restore the chain as one unit) is a design decision, not a line. Filed under #13909 because it is deliverable 2's ("an operator path out of a terminal run") nested-run gap.The reading, on
origin/main50d6c92resumeInternal's catch arm journals the consumed suspension of THE RUN THAT THREW (journalConsumedSuspension) — the inputrestoreConsumedSuspensionputs back. For a nested run, the ancestors are then handled on both paths without any journal:skipBubble === false):failAncestorswalks$parentRunIdand callsfailSuspendedRunon each suspended ancestor.skipBubble === true): the parent frame sees!childRes.successwith no retryable code and callsfailSuspendedRun(run, ...)on itself.failSuspendedRunisforgetSuspendedRun(run, 'failed')plus afailedlog record — it journals NOTHING. So after a child strands:status: 'stranded'on its result;restoreConsumedSuspension(CHILD_RUN_ID)answersrestored: true);failedwith its pause consumed and no snapshot:restoreConsumedSuspension(PARENT_RUN_ID)answersNO_CONSUMED_SUSPENSION, and the parent's own resume result (delegation path) carries no status at all — it is neither stranded nor repairable, and must not be stamped stranded (nothing can re-arm it);bubbleToParentfinds no parent suspension and logs a warning: the parent flow never continues.⇒ For a nested run the operator exit re-arms the leaf and loses the tree. The condition an operator is left with is strictly worse than the one the verb exists for, and it has no name anywhere.
What a fix has to decide
Related
#13909 (deliverable 2, the operator exit — this is its nested-run gap) · #13937 (shape-4 ruling; services half in flight) · #14379 (the delegated child's retryable refusal, a neighbouring seam on the same frame)