From this PR's own validation gap: 111 unit tests plus five code-review rounds
all passed, yet a cross-host behavioral eval immediately found agents emitting a
wrong CLI flag from the continuation prose. Documents the practice (eval skill
prose behavior cross-host, not just the script) and the authoring rule (name CLI
flags, not just recorded variables).
Claude-Session: https://claude.ai/code/session_01WpxSdCDogx9GM2wdypEpiy
Behavioral eval (skill-creator-style, cross-host): given a managed-stack layer
transition, 3 of 4 fresh agents (both Codex, one Claude) emitted
--invocation-started-at, which pr-snapshot rejects as an unrecognized argument.
The continuation prose named the recorded variable (RUN_STARTED_AT) but never
the flag (--session-started-at), so agents guessed. Name the actual flags in
both SKILL.md and watch-loop.md continuation sections (and call out that the
anchor flag is --session-started-at, not --invocation-started-at). Re-eval after
the fix: agents now emit --session-started-at. Not catchable by bun test.
Claude-Session: https://claude.ai/code/session_01WpxSdCDogx9GM2wdypEpiy
PR review (Codex P2): _run_snapshot captured 'now' before the blocking
_fetch_snapshot, so a suspend during the fetch was not credited as dead time by
that poll's _advance_activity; the next top-of-loop budget check could then fire
max-runtime on a gap it had not yet excluded. Re-capture _now() after the fetch
(generalizing the prior start-only re-capture) so the just-elapsed fetch/suspend
is credited before the cap is evaluated. Conservative direction either way.
Claude-Session: https://claude.ai/code/session_01WpxSdCDogx9GM2wdypEpiy
PR review (Codex P2): the SKILL.md continuation protocol was updated to pass
--continue-dead-time-seconds, but the parallel Managed-stack continuation section
in references/watch-loop.md (which Step 1 sends the agent to read for the
mechanics) still said to init the next layer with only --continue-invocation +
id/start/budget. An agent following that reference would omit the carry and
reintroduce the excluded-suspend-counted-as-active bug. Reconcile both.
Claude-Session: https://claude.ai/code/session_01WpxSdCDogx9GM2wdypEpiy
PR review (Cursor Bugbot): --continue-dead-time-seconds was applied only on the
adopt branch, so a carry passed on a later same-id re-continue (early-return
path) was ignored. Honor it there too as a monotonic floor: raise dead_time to
the carried value without clobbering time the dir already accumulated. Test
covers the raise and the no-clobber-on-lower-carry cases.
Claude-Session: https://claude.ai/code/session_01WpxSdCDogx9GM2wdypEpiy
PR review (Codex P2): active-time dead_time is per-state-dir, but a managed
stack shares one non-rolling active-time budget across layers. A layer
continuation via --continue-invocation gave the next layer a fresh state dir
with dead_time reset to 0, so the prior layer's excluded-suspend time was
re-counted as active and the stack could hit max-runtime early. Add
--continue-dead-time-seconds so the continuation threads the prior layer's
accumulated dead time through; an ordinary adopt (no arg) still resets to 0,
keeping the unrelated-invocation reset Bugbot flagged. SKILL.md continuation
protocol updated to pass it; test covers both carry and reset.
Claude-Session: https://claude.ai/code/session_01WpxSdCDogx9GM2wdypEpiy
PR review (Cursor Bugbot High + Codex P2): on legacy-state migration and
invocation adoption, last_activity_at was seeded to the old started_at, so the
first watch poll charged the whole historical span as one supra-threshold gap
and refunded it as dead time — a 9h-old 8h invocation read as ~15 min active and
never hit max-runtime. Seed the heartbeat to now (load time) instead, so the
first poll sees a ~0 gap and elapsed stays on real wall-clock. Adds a regression
test asserting an expired legacy invocation still max-runtimes with dead_time 0.
Claude-Session: https://claude.ai/code/session_01WpxSdCDogx9GM2wdypEpiy
Code review follow-up. The --continue-invocation branch that adopts a new
invocation id into an existing state dir now resets last_activity_at and
dead_time_seconds (like --start), so it never inherits a prior invocation's
accumulated dead time. Adds tests for checkpoint-mode wall-clock retention, the
mark heartbeat bump, clock-backward safety, and the adoption reset; softens an
over-strong docstring claim to match the deferred coarse-discriminator limit.
Claude-Session: https://claude.ai/code/session_01WpxSdCDogx9GM2wdypEpiy
The 8h invocation budget was pure wall-clock (now - started_at), so time the
machine spent suspended (laptop asleep) drained the cap even though the watch
was doing nothing. Measure active watch-capability time instead: a coarse
activity heartbeat accumulates any span where neither the detector polled nor
the agent worked, and elapsed excludes it. A separate 3-calendar-day wall-clock
backstop bounds the zombie-watch risk. Human-blocked waits and active agent
work keep counting; checkpoint/durable modes retain wall-clock.
Claude-Session: https://claude.ai/code/session_01WpxSdCDogx9GM2wdypEpiy