Skip to content

fix(act): arm drain flag on reset so settled apps replay#609

Merged
Rotorsoft merged 4 commits intomasterfrom
fix/act-reset-needs-drain
Apr 26, 2026
Merged

fix(act): arm drain flag on reset so settled apps replay#609
Rotorsoft merged 4 commits intomasterfrom
fix/act-reset-needs-drain

Conversation

@Rotorsoft
Copy link
Copy Markdown
Owner

@Rotorsoft Rotorsoft commented Apr 26, 2026

Summary

Two related fixes for the reset/replay flow on the orchestrator:

  1. Act.reset(streams) — wraps store().reset(...) and arms the orchestrator's internal _needs_drain flag. Calling store().reset(...) directly leaves the flag untouched, so a settled app short-circuits in drain()/settle() and silently skips the replay.
  2. settle() drains to completion by defaultmaxPasses default changed from 1Infinity, and the loop now exits on "no progress" (no new subscriptions AND no acks AND no blocks). The previous early-exit bailed out before draining paginated work whenever correlate returned 0 subs on iteration > 0. maxPasses remains as a kill-switch for runaway reaction chains.

Together: a single await app.reset([...]) followed by app.settle() (or one drain() for small streams) fully catches up paginated streams of any length, with no caller-side loop.

Reproducer

Two new tests in libs/act/test/rebuild.spec.ts exercise the full settle-then-reset path. Both fail on master and pass with this fix:

  • should replay events when drain runs after reset on a settled app
  • should replay events when settle runs after reset on a settled app

The pre-existing act.spec.ts test "should break early when correlate returns no subscriptions on second pass" was asserting the old buggy paginated-drain behavior — replaced with a regression test that proves settle keeps draining as long as drain is still acking.

Docs / pattern

Updated to consistently recommend app.reset(...) + settle():

  • CLAUDE.md § Projection Rebuild
  • README.md § Projections Are Disposable
  • libs/act/README.md § Settle (debounce + completion semantics)
  • libs/act/PERFORMANCE.md (reflects new maxPasses default)
  • Store.reset JSDoc points at Act.reset as the high-level API
  • .claude/skills/scaffold-act-app/act-api.md — new § 15 plus updated settle docs
  • .claude/skills/scaffold-act-app/server.md — drops manual maxPasses: 10

Test plan

  • New reproducer tests fail on master, pass on this branch
  • All 786 existing tests still pass (npx vitest run)
  • pnpm typecheck clean
  • pnpm build clean

🤖 Generated with Claude Code

rotorsoft and others added 4 commits April 26, 2026 09:01
Add Act.reset(streams) that wraps store().reset() and sets _needs_drain
when the orchestrator has reactive events. Calling store().reset()
directly leaves the flag untouched, so a settled app short-circuits in
drain()/settle() and silently skips the replay.

Updates docs, scaffold-act-app skill, and the calculator rebuild demo
to recommend app.reset(...) over store().reset(...).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two related fixes for the reset/replay flow:

1. settle() default maxPasses changed from 1 → Infinity.
2. settle() exit condition rewritten: stop when a pass makes no progress
   (no new subscriptions AND no acks AND no blocks), rather than the
   previous "exit when correlate finds no new subs on i>0" — which
   bailed out before draining paginated work.

Together this means a single app.settle() after app.reset(...) fully
catches up streams of any length, with no caller-side loop. maxPasses
remains as a kill-switch for runaway reaction chains.

Updates docs (CLAUDE.md, README, libs/act/README, PERFORMANCE.md) and
the scaffold-act-app skill to drop manual drain loops in favor of the
single-call pattern. The previous "should break early when correlate
returns no subscriptions on second pass" test asserted the old buggy
behavior — replaced with a regression test that fixes paginated drain.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Rotorsoft Rotorsoft merged commit 8927c10 into master Apr 26, 2026
6 checks passed
@github-actions
Copy link
Copy Markdown

🎉 This PR is included in version @rotorsoft/act-v0.30.1 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant