fix(daemon): port upstream's handoff grace window without regressing the consecutive circuit breaker - #46
Open
asachs01 wants to merge 1 commit into
Open
fix(daemon): port upstream's handoff grace window without regressing the consecutive circuit breaker#46asachs01 wants to merge 1 commit into
asachs01 wants to merge 1 commit into
Conversation
…egressing the consecutive circuit breaker
Reconciliation task from analyst's diagnosis (deliverables/2026-07-28-daemon-
circuit-breaker-upstream-reconciliation.md, task_1785200519438), deferred from
the 2026-07-21 upstream-divergence brief.
Ports upstream's (grandamenium/cortextos) fresh-session grace window
additively on top of wyre's Tier-3 circuit breaker, per the diagnosis's
explicit hard constraint: do NOT adopt upstream's window-based
`ctxCircuitRestarts: number[]` structure for the context circuit breaker —
that is literally the pre-PR#27 code and the bug class PR#27 fixed (a slow,
spaced-out crash loop that never accumulated in a 15min window and never
tripped).
What's ported: `handoffGraceMs(runtime)` + `ctxSessionStartedAt` anchor,
suppressing Tier 1 (warning) and Tier 2 (handoff) — the soft, cooperative
actions — for a runtime-aware grace period after a fresh session starts.
Explicitly NOT applied to Tier 3 (deadline-exceeded force-restart) or the
hard API-overflow banner check, both safety backstops that must act
regardless of session age. Also independent of the separate hang-detector
subsystem (wyre-only, untouched) and the consecutive circuit breaker itself
(grace only gates whether Tier 1/2 fire, never the breaker's counters).
Also adds a defensive log (not a silent default) in loadCtxCircuit() if
`.ctx-circuit.json` is ever found in upstream's `{ restarts: number[] }`
shape instead of wyre's `{ consecutiveWithoutRecovery, handoffFires,
brokenAt }` — belt-and-suspenders per the diagnosis, no evidence this has
happened.
12 new tests cover: handoffGraceMs per-runtime values, grace suppressing
Tier 1/2, grace expiring and re-enabling them, runtime-aware window
differences, Tier 3 and the overflow banner staying ungated by grace,
non-interaction with the Tier-3 breaker's own counter, and the
loadCtxCircuit shape-detection log (both trip and non-trip cases).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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
Implements the reconciliation task from analyst's diagnosis (
deliverables/2026-07-28-daemon-circuit-breaker-upstream-reconciliation.md, task_1785200519438), deferred from the 2026-07-21 upstream-divergence brief (task_1783984438986).Ports upstream's (grandamenium/cortextos) fresh-session handoff grace window additively on top of wyre's Tier-3 context circuit breaker, per the diagnosis's hard constraint: do not adopt upstream's window-based
ctxCircuitRestarts: number[]structure for the context breaker — that is literally the pre-PR#27 code, the exact bug class PR#27 fixed (a slow, spaced-out crash loop that never accumulated in a 15min window and never tripped, causing a 7-hour incident).What's ported
handoffGraceMs(runtime)— exported pure function, 10min grace forcodex-app-server/opencoderuntimes (they can emit a spurious prompt-cache-token spike several minutes after boot), 2min for everything else.ctxSessionStartedAtfield — anchored the moment a newsession_idis observed.withinHandoffGracegate applied to Tier 1 (warning) and Tier 2 (handoff) only — the soft, cooperative actions that a transient fresh-boot spike could otherwise mis-trigger into a handoff → restart → fresh-session loop.What's explicitly NOT touched
consecutiveCtxRestartsWithoutRecovery) — grace only gates whether Tier 1/2 fire in the first place; it does not touch the breaker's counters or reset logic.agent-manager.ts/CrashLoopPauser— confirmed textually identical to upstream in the diagnosis, no changes needed.Defensive addition
loadCtxCircuit()now logs (does not silently default) if.ctx-circuit.jsonis ever found in upstream's{ restarts: number[] }shape instead of wyre's{ consecutiveWithoutRecovery, handoffFires, brokenAt }. Belt-and-suspenders per the diagnosis — no evidence this has happened, cheap to guard against a silent-default failure mode.Test plan
12 new tests in
tests/unit/daemon/context-handoff-grace-window.test.ts:handoffGraceMsper-runtime values (codex-app-server, opencode, claude-code, hermes, undefined)loadCtxCircuitshape-detection log fires on upstream-shaped state, does not false-positive on wyre-shaped stateRan
npx tsc --noEmitclean, and the fulltests/unit/daemon/+ related integration suite (458 tests, all passing). Also ran the fullnpm testsuite — 11 pre-existing failing files (dashboard tests,bus-crons.test.ts,hooks.test.ts, the known-flakyfast-checker.test.tsheartbeat-watchdog tests already tracked in task_1785176939193) confirmed identical with this diff stashed out, so unrelated to this change.🤖 Generated with Claude Code