Skip to content

Loop and loop_group executors read as resume, setup and one call per iteration (1140 R2–R3) - #4571

Merged
Wirasm merged 3 commits into
devfrom
build/4566-1140-r2-r3-r2-loop-r3-loop-group-cfc1ede2
Oct 18, 2026
Merged

Wirasm merged 3 commits into
devfrom
build/4566-1140-r2-r3-r2-loop-r3-loop-group-cfc1ede2

Conversation

@Wirasm

@Wirasm Wirasm commented Oct 18, 2026 •

Copy link
Copy Markdown
Collaborator

Problem and outcome

executeLoopNode and executeLoopGroupBody were single functions of about 1,500 and 1,000 lines (cognitive complexity 539 and 259). Their resume prelude and per-iteration body could not be read, tested or changed without holding the whole function in your head. This is steps R2 and R3 of lane R in #1140.

  • Outcome: both executors read as resume detection, setup, and one call per iteration. Every extracted function scores 15 or lower on the A complexity ratchet whose baseline the change cannot edit #3020 scorer. executeLoopNode goes 539 to 39, executeLoopGroupBody 259 to 9.
  • Invariant: no behavior change. Every value, event, log key and message is the same, and the public entries stay where they are.
  • Scope boundary: helpers stay inside dag/nodes/loop/ and dag/nodes/loop-group/. No new field on RunLayersContext, no new dependency, no test changes.

Known failing check, not from this change: bun run test src/dag/ has one failure, executeDagWorkflow -- durable wait node > persists a future wait and returns without invoking a provider. It fails the same way at the starting commit, and src/dag/nodes/wait/ alone passes 18/18. The wait node is untouched.

Review guidance

  • Feedback requested: value identity. Closure variables became fields on shared state objects, so check that each one is read and written at the same moment as before.
  • Start here: packages/workflows/src/dag/nodes/loop/loop-state.ts — LoopRun (fixed for the node) and LoopState (what iterations used to share through closures) define the seam for R2. For R3 it is loop-group/loop-group-state.ts.
  • Review order: commit 1 (loop), then commit 2 (loop_group). In each, the state file, then loop.ts / loop-group.ts, then iteration*.ts and resume.ts. Diff with --color-moved=dimmed-zebra --color-moved-ws=allow-indentation-change to dim the moved lines.
  • Lower-attention areas: the bodies of the iteration*.ts functions are the original code moved, with ctx. / state. prefixes.
  • Known risk or uncertainty: the loop's attempt loops now take the iteration's resume session as a value computed once at the iteration start. The original read the same value before the first attempt and never re-derived it, so attempts after a transient retry still resume the pre-iteration session, not one a failed attempt reported.

Solution

R2, loop. loop.ts keeps executeLoopNode, readLoopResume and finalizeOnBareApprove. The iteration moves into iteration.ts (stop check, events, completion channels, until_bash, completion record, interactive gate), iteration-stream.ts (retry and reask attempt loops, result chunks, usage folding) and iteration-outcome.ts (judging an attempt: cancelled, empty, unsettled, transient retry, structured-output gate).

R3, loop_group. resume.ts holds resume-shape detection, owner session cursor restore, the bare-approve finalize, the terminal wait resume, the $LOOP_PREV snapshot restore and the escalated completion check. iteration.ts holds the per-iteration body. The two until_bash sites share one subprocess and rejection path in until-bash.ts, each keeping its own order of path resolution, artifact listing and substitution.

Finalize-on-approve is not unified. The plan said to unify only if byte-identical. They are not: the loop records a completed execution through finalizeLoopFromSignal with the gate's usage and session, while the group returns its output and lets executeLoopGroupNode record it. dag/loop-completion.ts is untouched. A group comment that pointed at a finalizeLoopFromSignal call the group never makes was corrected.

Dropped as dead: the per-iteration AbortController, provider event handler and cancel-check clock that the original created and then overwrote at the start of every attempt.

Validation

  • bun run type-check in packages/workflows and bun run lint at the root (cleanup-drift, persistence and SDK drift checks included) — pass.
  • bun run scripts/check-ratchet.ts against origin/dev after each commit — pass, no Ratchet-Allow trailer needed.
  • bun run test src/dag/nodes/loop/ src/dag/nodes/loop-group/ — 189 pass, 0 fail. The same command at the starting commit gives 189 pass, so the moved suites keep their count. No tests were deleted.
  • dag-executor, executor, run-resume, fixture-runner, packaged-workflow and dry-run test files, each run alone — all pass (12, 185, 12, 57, 3, 115).
  • bun run test src/dag/ — 1066 pass, 1 fail: executeDagWorkflow -- durable wait node > persists a future wait and returns without invoking a provider. It fails the same way at the starting commit, and src/dag/nodes/wait/ alone passes 18/18. The wait node is untouched.
  • Not verified: passing several top-level test files to one bun run test call gives mass mock-pollution failures. That combination is not a valid check, so each file was run separately.

Links

Summary by CodeRabbit

  • New Features
    • Added support for resuming paused loops and loop groups, restoring prior outputs and session context.
    • Loops and loop groups can now finish based on configured completion signals, including Bash checks, or pause for interactive approval.
    • Added structured-output validation and re-asks, transient retries, and clearer handling of cancelled or failed iterations.
    • Iteration results and usage are tracked across runs and included when reporting completion or failure.

…40 R2)

The resume-state prelude becomes readLoopResume and finalizeOnBareApprove
in loop.ts. The per-iteration body moves into the loop folder: iteration.ts
runs one iteration (stop check, completion channels, until_bash, completion
record and the interactive gate), iteration-stream.ts streams its attempts
and folds their usage, and iteration-outcome.ts judges an attempt (cancelled,
empty, unsettled, transient retry, structured-output gate). The values the
iterations shared through closures now live on one LoopState, and the
values fixed for the node on one LoopRun; failLoopNode reads both.

Every value, event and message is unchanged. Each attempt of an iteration
still resumes the session the previous iteration ended in, never one a
failed attempt reported. executeLoopNode drops from cognitive complexity
539 to 39; no extracted function scores above 15.

Part of #1140 (step R2, #4566).
…n (1140 R3)

The resume-state prelude moves to resume.ts: reading the resume shape and
restoring named owner session cursors, the bare-approve finalize, the
terminal wait resume, the $LOOP_PREV snapshot restore, the escalated
completion check and the state the first iteration starts from. The
per-iteration body moves to iteration.ts: the stop checks, the body's run
context, usage, body failure and suspension, completion and the
interactive gate. Both until_bash call sites share one subprocess and
rejection path in until-bash.ts, each keeping its own order of path
resolution, artifact listing and substitution.

Every value, event and message is unchanged. executeLoopGroupBody drops
from cognitive complexity 259 to 9; no extracted function scores above 15.

The two finalize-on-approve branches are not unified: the loop node
records a completed execution with the gate's usage and session through
finalizeLoopFromSignal, while the group returns its output and lets
executeLoopGroupNode record it. A gate comment that pointed at a
finalizeLoopFromSignal call the group never makes now says what the
group's finalize writes.

Part of #1140 (step R3, #4566).
@coderabbitai

coderabbitai Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 6b5b9308-6444-4b4b-8f27-ff9598d3e7e0
📥 Commits

Reviewing files that changed from the base of the PR and between 743ca8a and aa88e42.

📒 Files selected for processing: 2
  • packages/workflows/src/dag/nodes/loop/iteration-outcome.ts
  • packages/workflows/src/dag/nodes/loop/loop.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 5 remain after this review.

📝 Walkthrough

The pull request separates loop and loop-group execution into dedicated iteration, state, resume, and outcome modules. It adds handling for streamed attempts, retries, structured output, completion conditions, usage, and interactive pauses.

Changes: Loop-group execution

Layer / File(s) Summary
Resume and state restoration
packages/workflows/src/dag/nodes/loop-group/loop-group-state.ts, packages/workflows/src/dag/nodes/loop-group/resume.ts, packages/workflows/src/dag/nodes/loop-group/loop-group.ts
Adds loop-group execution state and helpers to restore resume metadata, body outputs, and session cursors. The executor delegates resume setup to these helpers.
Body iteration, completion, and suspension
packages/workflows/src/dag/nodes/loop-group/iteration.ts, packages/workflows/src/dag/nodes/loop-group/until-bash.ts
Adds per-iteration body execution, usage aggregation, completion checks, Bash-condition handling, failure results, and approval or wait suspension handling.

Loop-node execution

Layer / File(s) Summary
Run state and resume setup
packages/workflows/src/dag/nodes/loop/loop-state.ts, packages/workflows/src/dag/nodes/loop/loop.ts
Adds shared loop state and resume handling. The executor builds the run context, handles bare approval, and delegates iteration execution.
Streaming attempts and failure handling
packages/workflows/src/dag/nodes/loop/iteration-stream.ts, packages/workflows/src/dag/nodes/loop/iteration-outcome.ts
Adds provider streaming, session and usage tracking, structured-output validation, transient retries, and iteration failure handling.
Iteration completion and interactive gates
packages/workflows/src/dag/nodes/loop/iteration.ts, packages/workflows/src/dag/nodes/loop/loop.ts
Adds reply handling, completion checks, optional Bash conditions, iteration events, and interactive-gate handling. The executor delegates iterations and reports max-iteration failures.

Priority: ➖ Normal

Estimated code review effort: 4 (Complex) | ~60 minutes

Change: Refactor

Merge Risk: ⚪ Minimal · up to aa88e

This change reorganizes loop and loop-group execution into smaller helpers without intending any behavior change. Retry limits for transient, rate-limited, and overloaded failures match the previous behavior. No concrete regression was found, and the change appears ready to merge after normal CI.

Pre-merge checks: Passed 3 · Failed 1 · Inconclusive 1

Failed Failed checks: 1 warning · 1 inconclusive

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 54.05% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 74 functions across 10 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Linked Issues check Inconclusive The implementation satisfies the stated extraction scope for [#4566]: loop and loop-group resume logic and per-iteration bodies moved into helpers under their own folders; public entry points remain; … Provide the CI result for this head, or establish the project-approved disposition of the reported pre-existing executeDagWorkflow -- durable wait node failure.
Passed Passed checks: 3 passed
Check name Status Explanation
Title check Passed The title clearly describes the main change: extracting loop and loop-group executor logic into resume, setup, and per-iteration helpers. It is specific and related to the PR objective.
Description check Passed The description includes the required Problem and outcome, Review guidance, Solution, and Validation sections. It states the refactor scope, invariants, review focus, test results, known failure, and …
Out of Scope Changes check Passed The reported changes are confined to loop and loop-group execution helpers and their state types. The changes support the [#4566] extraction and complexity objectives. No unrelated dependency, context…
Full details: Description check

Explanation

The description includes the required Problem and outcome, Review guidance, Solution, and Validation sections. It states the refactor scope, invariants, review focus, test results, known failure, and unverified validation. Conditional sections are omitted appropriately for a behavior-preserving refactor.

Full details: Out of Scope Changes check

Explanation

The reported changes are confined to loop and loop-group execution helpers and their state types. The changes support the [#4566] extraction and complexity objectives. No unrelated dependency, context-field, public-entry-point, or test-suite change is reported.

Full details: Linked Issues check

Explanation

The implementation satisfies the stated extraction scope for [#4566]: loop and loop-group resume logic and per-iteration bodies moved into helpers under their own folders; public entry points remain; no dependency or RunLayersContext field was added; finalize-on-approve logic remained separate because the implementations differ. The reported moved-suite counts, type-check, lint, and ratchet checks pass, with no test deletions reported. The full src/dag test command still has one failure, and no independent evidence establishes that CI is green as required by [#4566].

Resolution

Provide the CI result for this head, or establish the project-approved disposition of the reported pre-existing executeDagWorkflow -- durable wait node failure.

  • Fix all pre-merge checks with AI
✨ Finishing Touches: 💡 1
📝 Generate docstrings: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@Wirasm

Wirasm commented Oct 18, 2026 •

Copy link
Copy Markdown
Collaborator Author

Reviewed commit: aa88e42a104478853f6c2f79621ae7b5703222c1
Verdict: ready

Review report

Verdict

Ready. Action: none. The delta since 743ca8a only resolves a merge of origin/dev; no code from dev's side was lost and nothing else changed.

Accepted contract

Required outcome: R2 (loop) and R3 (loop_group) of lane R in #1140 (issue #4566), one PR, one commit per step: extract the resume prelude and per-iteration body into helpers inside each node's folder. Acceptance: moved suites keep pass counts; type-check, lint and CI pass. Invariants: no behavior change; deleted tests named; #3020 ratchet holds; no new dependency; folder-only helpers, no field added to RunLayersContext. Steering: finalize-on-approve moved only if byte-identical, otherwise recorded as a discovery; re-read code first; one commit per step. No part assignment.

Reviewed head SHA

aa88e42

Contract coverage

Item Verdict Evidence
Required outcome (R2 then R3, one commit each) met Prior report; the head's loop/ and loop-group/ code equals the cursor's apart from two comments (git diff 743ca8aff aa88e42a1 over both folders: 3+/3- in iteration-outcome.ts)
Acc 1: pass counts equal met code.md: loop 91 pass, loop-group 98 pass at head; same as cursor; no test files changed
Acc 2: type-check, lint, CI green deferred tsc clean per code.md; CI is a later step of this delivery
Inv 1: no behavior change met dev's only change to loop/ (dba41b0..92a675a) is two comments; both ported to iteration-outcome.ts
Inv 2: deleted tests named met no tests deleted
Inv 3: complexity ratchet met unchanged since prior round; delta adds no code
Inv 4: no new dependency met no manifest touched
Inv 5: folder-only, RunLayersContext untouched met delta touches two files in loop/
Steering 1-4 met prior report; delta does not affect them

Findings

None blocking, no notes. Rejected findings: none.

Prior findings

The prior report had no findings. Nothing to carry forward.

Discoveries

No new discoveries. The prior round's discovery (finalizeLoopFromSignal keeps loop_group generality with no caller) is already preserved in an earlier run's discoveries.md; this round adds none. See /Users/rasmus/.archon/workspaces/coleam00/Archon/artifacts/runs/080d56fb-ab92-4d78-b426-abd9559beada/discoveries.md. Unrelated discoveries do not affect readiness.

Review coverage

Continuation round. The route selected seams, code and errors; all three reports exist with completed review-lens artifacts. Each found nothing. I verified the prior report against them and checked directly: no conflict markers in loop/ or loop-group/, and dev's side of the conflict was comment-only. Tests and docs lenses were off; the delta adds no user-facing surface, so no gate was re-evaluated.

@Wirasm
Wirasm marked this pull request as ready for review October 18, 2026 19:39
# Conflicts:
#	packages/workflows/src/dag/nodes/loop/loop.ts
@Wirasm
Wirasm merged commit a7acc54 into dev Oct 18, 2026
16 checks passed
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.

1140 R2–R3: R2 loop; R3 loop_group

1 participant

Sponsor
SponsoredKunjungi sekarang
Promo