Skip to content

fix(workflow-engine): mark completed inner-loop iterations visited on resume#5324

Open
abcxff wants to merge 1 commit into
mainfrom
stack/slop-claude-opus-4-8-high-fix-workflow-engine-mark-completed-inner-loop-iterations-visited-on-resume-wrxknkmx
Open

fix(workflow-engine): mark completed inner-loop iterations visited on resume#5324
abcxff wants to merge 1 commit into
mainfrom
stack/slop-claude-opus-4-8-high-fix-workflow-engine-mark-completed-inner-loop-iterations-visited-on-resume-wrxknkmx

Conversation

@abcxff

@abcxff abcxff commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

No description provided.

@abcxff

abcxff commented Jun 24, 2026

Copy link
Copy Markdown
Contributor Author

Stack for rivet-dev/rivet

Get stack: forklift get 5324
Push local edits: forklift submit
Merge when ready: forklift merge 5324

@claude

claude Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

PR Review: Mark completed inner-loop iterations visited on resume

This PR fixes a real HistoryDivergedError crash in the workflow engine: when a nested loop resumes from a saved iteration, its already-completed prior iterations were never marked visited, causing the enclosing scope's validateComplete() to reject them as history divergences. The fix (markCompletedLoopIterationsVisited) and its test are conceptually correct for the stated scenario.

However, the same root cause exists in two adjacent code paths that the fix does not reach.


1. Early-return paths for already-completed loops still have the same gap (confirmed bug)

context.ts lines 1231-1237

When a loop has already completed (status === completed or output !== undefined), it returns before line 1244 without calling markCompletedLoopIterationsVisited:

if (metadata.status === 'completed') {
    return loopData.output as T;   // no markCompletedLoopIterationsVisited
}
if (loopData.output !== undefined) {
    return loopData.output as T;   // no markCompletedLoopIterationsVisited
}

Failure scenario: outer loop at saved iteration K; within outer iteration K, inner loop A completed in a previous run (ran one step, broke) and inner loop B suspended (the case this PR fixes). On resume, outer iteration K replays: inner loop A hits line 1232 or 1237, marks only its own root key visited (line 1197), then returns. Inner loop B is correctly resumed (line 1244 fires). But inner loop A's iteration sub-entries -- e.g. outerK/innerA/~0/step1 -- are still in storage.history.entries and were never added to visitedKeys. branchCtx.validateComplete() at line 1323 then throws HistoryDivergedError.

Pruning does not reliably prevent this: collectLoopPruning only fires when currentIteration > historySize (default 20), so any inner loop that completed in fewer than 20 iterations retains all its iteration entries in storage.

Suggested fix: call markCompletedLoopIterationsVisited before each early return, using loopData.iteration + 1 so all completed iterations 0..iteration are marked. The same applies to the rollback early-return at lines 1223-1224.


2. iterationSegment.loop !== loopSegment is always false (cleanup)

context.ts line 538

Both loopSegment (loopLocation[last]) and iterationSegment.loop resolve to registerName(storage, config.name) -- the same idempotent registry call. When isLocationPrefix(loopLocation, entry.location) passes, this condition can never be true. It mirrors the identical unreachable guard in collectLoopPruning at line 1432. Worth removing or annotating if intentionally defensive.


3. Multi-paragraph docstring violates CLAUDE.md (conventions)

context.ts lines 499-513

The new method has an 11-line JSDoc block. CLAUDE.md states: 'Never write multi-paragraph docstrings or multi-line comment blocks -- one short line max.' The why is non-obvious and warrants a comment, but it should be condensed to one line.

@abcxff abcxff force-pushed the stack/slop-claude-opus-4-8-high-fix-workflow-engine-mark-completed-inner-loop-iterations-visited-on-resume-wrxknkmx branch from 035dd0d to e010972 Compare June 24, 2026 15:43

@abcxff abcxff left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@railway-app

railway-app Bot commented Jun 24, 2026

Copy link
Copy Markdown

🚅 Deployed to the rivet-pr-5324 environment in rivet-frontend

Service Status Web Updated (UTC)
kitchen-sink 😴 Sleeping (View Logs) Web Jun 24, 2026 at 3:57 pm
frontend-cloud 😴 Sleeping (View Logs) Web Jun 24, 2026 at 3:54 pm
frontend-inspector 😴 Sleeping (View Logs) Web Jun 24, 2026 at 3:54 pm
website 😴 Sleeping (View Logs) Web Jun 24, 2026 at 3:35 pm
ladle ✅ Success (View Logs) Web Jun 24, 2026 at 3:30 pm
mcp-hub ✅ Success (View Logs) Web Jun 24, 2026 at 3:27 pm

@NathanFlurry NathanFlurry changed the title [SLOP(claude-opus-4-8-high)] fix(workflow-engine): mark completed inner-loop iterations visited on resume fix(workflow-engine): mark completed inner-loop iterations visited on resume Jun 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant