You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix(terraphim_orchestrator): gate compound-review fires against per-occurrence cursor
Adds `last_compound_review_fired_at: Option<DateTime<Utc>>` to
`AgentOrchestrator` and rewrites the compound-review branch of
`check_cron_schedules` so the cursor is recorded **before** the
`.await` on `handle_schedule_event`. Mirrors the per-agent
`last_cron_fire` pattern at the start of the same function.
Why: `reconcile_tick` is wrapped in a 90 s `tokio::time::timeout`
safety net. When the future is cancelled mid-await, `last_tick_time`
is never updated, so the previous `should_fire` check kept returning
true on every subsequent tick, spawning a fresh review worktree every
30 s (the bigbox storm). Recording the cursor synchronously before the
await makes cancellation safe: the next iteration sees the cursor and
short-circuits via `already_fired = fire_time <= prev`.
Verified via new regression test
`test_compound_review_cursor_advances_on_cancellation`: plants a
`last_tick_time` 2 h in the past, runs `check_cron_schedules` twice
without advancing wall-clock, and asserts the cursor is `Some(_)` after
the first call and unchanged after the second.
Note on design drift: the design doc (docs/design/adf-worktree-lifecycle-design.md
section 4.1) used `take_while(|t| *t <= now)` plus an explicit
`already_fired` gate. I initially collapsed both into
`compound_sched.after(&cursor).next()` for brevity but reverted to the
documented shape after the regression test exposed the catch-up vs
gating semantic difference -- the design's `last_tick_time`-anchored
`next_fire` plus separate cursor gate is the correct read of "same
occurrence, do not re-fire". Line numbers in the design (`:241`,
`:817`, `:7137-7161`, `:7712`) all matched current source unchanged.
Layer 0 of the ADF worktree lifecycle epic (Gitea #1567). Out of scope:
the per-agent cron path at lib.rs:7484, the WorktreeGuard refactor
(Layer 1, Gitea #1569), startup sweep (Layer 2, #1570), and the
adf-cleanup.sh hardening (Layer 3, #1571).
Refs #1562 (Gitea)
0 commit comments