Skip to content

fix(dag): mark wake reported at admit time - #326

Merged
LeXwDeX merged 2 commits into
devfrom
fix/wake-durability
Aug 17, 2026
Merged

fix(dag): mark wake reported at admit time#326
LeXwDeX merged 2 commits into
devfrom
fix/wake-durability

Conversation

@LeXwDeX

Copy link
Copy Markdown
Owner

Closes#321.

Incident chain (from #321)

After the terminal wake of dag_fe5ff13ada6fUONA2rH3Pypdf4 was injected at 17:25:29, the parent turn ran ~10 min when the process restarted at 17:35:22. Because wake_reported was persisted only AFTER yield* delivered.value (the whole wake-driven turn completes) — while the transcript part is written at admit time — the mark never landed. The new process's startup sweep re-injected the byte-identical 4391-char wake (diff-verified): the in-memory dedup map deliveredWakeSummaries does not survive restarts. This is the hole the old GOAL-FP-01-14 rationale in loop.ts admitted.

Semantic change

Admit success = delivered.markWakeBatchReported (and the terminal-workflow automation.unregister calls) now run immediately after admitIfIdle admits the part, BEFORE awaiting the wake turn — dropping the "turn failure triggers redelivery" semantics. The synthetic part is durable in transcript history either way; redelivery added duplicates, never information. The restart window shrinks from minutes (turn duration) to microseconds (admit→mark).

Mark failures (leases lost / generation raced / store write dying) degrade to retry-later instead of propagating: rows stay unreported, a later trigger re-marks, and the admitted turn still runs (its end-of-turn idle re-arms the retry). The in-memory dedup map is kept only for that narrow same-process mark-retry path. automation-lease.ts unregister stays safe moved earlier: it gates its goal re-trigger on session status and relies on the turn re-emitting idle when it ends.

What flipped in tests

  • dag-wake-integration — the two failure-redelivery tests flipped to the new contract: the batch is reported at admit even when the turn then fails, and no duplicate prompt is injected on a re-trigger. Added regression tests for both plus a simulated restart (fresh loop over the same store after an admitted-but-unfinished turn delivers nothing).
  • dag-timeout-escalation — the two Q2-gate tests held their wake via an in-flight turn to keep wake_reported=false. That window no longer exists (the mark lands at admit), so they now hold the wake via a busy parent session (the idle-gate never admits it), preserving the escalationPending ∧ ¬wakeReported ⇒ skip re-time contract. This coupling was not anticipated by fix(dag): mark wake reported at admit time (restart-safe wake delivery) #321 but is sanctioned by the mark-at-admit semantics; full test/dag/ acceptance requires them green.

Acceptance

  • Wake admitted → turn fails/interrupted → wake_reported=1, no re-injection on next trigger.
  • Simulated restart (fresh loop over same store) does not re-deliver.
  • bun test test/dag/ full suite green (551 pass, 0 fail).
  • bun typecheck clean; repo lint under the --max-warnings ratchet.

wake_reported landed only after the whole wake-driven turn completed, so a
restart or mid-turn interruption left the synthetic part durable but the mark
absent, and the startup sweep re-injected a byte-identical wake. Mark the batch
(and unregister terminal workflows) immediately after admitIfIdle, before
awaiting the turn; drop the turn-failure-redelivery semantics. Mark failures
degrade to retry-later while the admitted turn still runs.
Flips the two dag-wake-integration failure-redelivery assertions and reworks
the two timeout-escalation Q2-gate tests (their "held turn => wakeReported=false"
window no longer exists; they now hold the wake via a busy parent session).
Adds regression tests for failed-turn no-redelivery and a simulated restart.
Sign up for freeto 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.

1 participant

@LeXwDeX