Uh oh!
There was an error while loading. Please reload this page.
test(service-automation): pin that a node failing mid-resume strands the run (#13807 step 1 measurement) - #13899
Merged
Conversation
…the run A measurement instrument, not a repair. The reported strand came from the approvals reject door, whose error prose is the only place the word "stranded" appears. This pins the same outcome through the GENERIC resume door with no approvals involvement: `resumeInternal` calls `forgetSuspendedRun(run, 'resumed')` before `traverseNext`, so a downstream node that throws throws with the pause already consumed. Characterization assertions: the suspension is gone, the run is recorded `failed`, a second resume answers RUN_NOT_FOUND, and cancelRun is a no-op. Two reverse controls keep those from being constants -- a resume refused before the consumption point (INVALID_SIGNAL) leaves the pause intact and resumable, and a clean resume also ends unsuspended, so the strand is the FAILED status rather than the missing pause. A repair should turn the first test red; that is why it is pinned now. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016ZC5rNQj3WEet5HAmmAkMs
Contributor
📓 Docs Drift CheckNothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs. What this run could not see
Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
os-steve
marked this pull request as ready for review
August 31, 2026 17:10
os-steve
enabled auto-merge
August 31, 2026 17:10
Uh oh!
There was an error while loading. Please reload this page.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #13807 — step 1 only (the measurement slice). No repair is included, deliberately.
The card's step 1 asks one question: does any workflow node failing mid-resume strand the run, or is
strandedspecific to the approval resume path? The card is explicit that the generalisation was a hypothesis, not its premise. This PR carries the instrument that answers it; the full written answer, with all four deliverables, is posted as a comment on #13807.Verdict: general to the workflow engine, not approval-path-specific
AutomationEngine.resumeInternalconsumes the suspension before it runs any downstream work:So a downstream node that throws throws with the pause already gone. The
catcharm records the runfailedand returns; nothing puts the suspension back. The word "stranded" never appears in the engine — it is prose in aplugin-approvalserror message wrapped around this engine outcome.What the new test measures
packages/services/service-automation/src/resume-node-failure-strands-run.test.tsreproduces the strand with zero approvals involvement: a plain pausing node declaringresumeAuthority: 'any'(the deliberate opposite of theapprovalnode'sresumeAuthority: 'service'), continued through the genericengine.resume()door — the same doorPOST /:name/runs/:runId/resumeserves — with a downstream node that throws the reporter's ownupdate_record ... not foundshape.Characterization assertions, all passing against
maintoday:hasSuspendedRunis false);failed;RUN_NOT_FOUND;cancelRunreturns false — a no-op, since it needs a suspended run to consume.Two reverse controls keep those from being constants. A resume refused before the consumption point (
INVALID_SIGNAL) leaves the pause intact and still resumable, so the same probes readtruewhere they readfalseabove. And a clean resume also ends unsuspended — so the strand is thefailedstatus, not merely the missing pause.These are characterization assertions, not desired behaviour. A repair for #13807 should turn the first test red. That is why it is pinned now: the repair then has to state which of these facts it changed.
Scope
/rejectstill returns 500. Making it green would hide the defect, which the card names explicitly.packages/objectql/src/engine.tswas read only, never edited (it is held by another open PR).skip-changeset.Gates
Re-derived from the actual diff with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack, both output sections read whole — 22 path-matched families plus the convention-triggered set for adding a test file.Union run at
69d9b14f8(the final commit): 23 families green, including every convention-triggered ratchet —check:engine-double-contract,check:where-matcher,check:cross-package-test-inputs,check:query-options-erasure,check:type-check-coverage,check:test-source-alias,check:published-files.check:type-check-debt— the ledger entry for@objectstack/service-automationreadserrors: 3;tsc --noEmiton the package at69d9b14f8measures exactly 3, all three the ledgeredTS2341s innested-region-parity.test.ts, and 0 from the new file.--listFilesconfirms the new test is in the tsc program (so this is a measurement, not an exclusion reading).Two gates returned exit 3 = NOT MEASURED, by their own printed verdict lines, neither a pass nor a red:
check-test-completeness.mjs(needs a savedturbo run testlog, which CI tees and a local run cannot produce) andcheck:dual-build-cjs-loads(PREREQUISITE NOT MET— needs a fullpnpm build; 49 packages have nodist/). Both are CI's to run.Vitest:
Test Files 1 passed (1) · Tests 3 passed (3).Generated by Claude Code
Generated by Claude Code