Repository navigation
Run loops over items, with bounded work per event, recovery and replay - #45
Merged
Merged
Conversation
added 22 commits
October 13, 2026 12:47
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 free
to 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.
Summary
Loops run. A Loop over items (
forEach) step runs its body once per element,concurrencyat a time, inside the same run, and its output lists one result per element in element order, whatever order the iterations finish in.iruns in its own frame with/item,/indexand/loops/<id>/…; its steps, tasks, human tasks, waits and incidents use instance keys such assend[2], so iterations never share state. Finished iterations are removed from the run state together with every block their body created; sibling loops keep theirs.itemsvalue that is not a list, more elements thanmaxItems, or collected results over 1 MiB openWV-RUNTIME-LOOP-ITEMS,WV-RUNTIME-LOOP-LIMITorWV-RUNTIME-LOOP-OUTPUTand roll back the event. A task incident in one iteration suspends the run; the other iterations' results wait and are applied after the decision;retry_saferetries only that iteration under the same idempotency key. Afailstep fails the run and cancels the other iterations; canceling or timing out a run ends its loops, including runs too large to load.<loop>~<n>, and the deadline scanner continues it about one poll later. A 10,000-element loop whose body only returns its item finishes in five events. Capabilities report the budget asoperations.runtime.loop_units_per_turn.flow.forEachandforEach; publishing, importing, activating (activation readiness now derives its node kinds from the IR and the listed features) and debug sessions accept loops. Platforms without this change still refuse them withWV-IR-UNSUPPORTED.wait_elapsedevents; exported history of loop runs replays asconsistent. New countersweave.loop_iterations(status: okper collected result,cancelledper iteration a run's end stopped) andweave.loop_yields.tests/fixtures/golden/loops.json); the existing corpus is unchanged byte for byte.Verification
make check(every stage: source, docs, docs site, lint, format, types, 6,752 unit and contract tests, both workers, packaging and the installed wheel), the golden corpus check (existing corpus unchanged), the loop golden corpus check, the language fixture check, and Studio's type check, format check, 1,964 vitest tests and production build. Studio only gains the generated language manifest fixture; no screens changed, so there is no browser tour.fail, cancellation on the normal and the oversized path, restart, counters) and the full integration suite with-n 4 --dist loadfile. Every module that runs without external services passes; the timing-sensitive capacity tests that failed under parallel load pass when rerun alone, on this branch and onmain. Kafka, Keycloak, provider-inbox and connector-database modules need services the local run does not start.tests/benchmarks/test_loop_scaling.py(processor time, fastest of three, 1,000 vs 2,000 elements) was measured on a heavily loaded host, where ratios scattered between 1.3 and 4.0 on this branch and on the commit that introduced the linear path alike; 2,000 elements took 8–14 s against 31 s before the change. The 2.2× bound still needs a rerun on a quiet machine. The benchmark is not part of CI.offline,studio,buildandAcceptance, andcross-platformon macOS 15 and Windows 2022 (golden corpora, capability contract, compiler and debug-session tests). Kernel unit tests run on Linux in CI and on macOS locally. CI runs no PostgreSQL job.Upgrade
Upgrade the CLI and SDK together with the server: alpha15 and earlier clients reject the new
operations.runtime.loop_units_per_turncapability field (WV-WIREonweave remote capabilitiesand the SDK'scapabilities()), and human tasks inside loops now carryinstance_keyanditeration. Before rolling back to alpha15, let runs that use loops finish, or cancel them. No migration.Decisions
flow.forEachas soon as its runtime ships, so publishing, importing, activating and debugging workflows with loops work immediately. Studio's loop editor is not there yet; loops are authored in source or the CLI until it ships.status.weave.loop_iterationskeeps the three bounded metric attributes:operation: loop,status: okper collected result, and the new statuscancelledper iteration still running when its run ends (the one holding a failing step included; the failure is counted once, as the run's outcome).wait_elapsedevent are its history.Follow-ups
each~1) must stay out of step facts.