refactor(lifecycle): dissolve alarm memory-limit policy into the jobs domain (#2190)
* refactor(lifecycle): dissolve alarm memory-limit policy into the jobs domain
Recovery-loop membership becomes a property of the job row (schedule
option recoveryLoop / LifecycleJobPushOptions.recoveryLoop): the breaker
backs flagged rows off on a strike and purges them at seal, so a new
recovery schedule can no longer silently escape it. Capabilities get an
optional onMemoryLimit hook (dispatched best-effort, before the host's
onAlarmMemoryLimit, without gating on startup — a strike can land while
startup is the doomed work), and the strike budget moves from the
setLifecycleAlarmMemoryLimitStrikes WeakMap side channel into
Lifecycle.install(host, { maxAlarmMemoryLimitStrikes }).
Agent's onAlarmMemoryLimit relay and the _cf_recoveryAlarmCallbacks /
_cf_sealMemoryLimitedRecovery template methods are deleted, along with
Scheduler.applyMemoryLimitPolicy. AIChatAgent and Think flag their
recovery schedules via chatRecoverySchedulePolicy and seal in-flight
incidents from their own protected onAlarmMemoryLimit hooks (the
pattern: Lifecycle dispatches host hooks structurally, so framework
hosts keep internal machinery in private _cf_-prefixed methods behind a
protected hook).
Claude-Session: https://claude.ai/code/session_011QZUJztM1rMTsHEC7mbcbz
* test: teach the jobs-table DDL copies about recovery_loop
The schema snapshot and the seedTaskRun helper's lazy CREATE TABLE both
carry the cf_agents_jobs DDL verbatim; the helper's stale copy made the
real queue's flagged push fail with 'no column named recovery_loop'.
Claude-Session: https://claude.ai/code/session_011QZUJztM1rMTsHEC7mbcbz
* fix(schedules): keep breaker membership across the legacy migration
Rows migrated from cf_agents_schedules predate the recovery_loop flag;
migrate _chatRecoveryContinue/_chatRecoveryRetry rows flagged (the
migration already knows legacy names — it drops _cf_keepAliveHeartbeat),
and let an idempotent dedup hit restore membership on an unflagged row
by re-pushing the same durable intent in place. Covers migrated rows
through an unsealed strike and sealing.
Claude-Session: https://claude.ai/code/session_011QZUJztM1rMTsHEC7mbcbz
* refactor(schedules): keep recoveryLoop out of the public schedule vocabulary
Schedules only shape future work: ScheduleOptions loses the flag, and
chat recovery reaches the job row's breaker membership through an
explicitly internal RecoveryLoopScheduleOptions scaffolding type that
documents its own removal when recovery migrates onto the Tasks
capability. The four manual post-handoff re-defers route through a new
chatRecoveryRedeferPolicy helper instead of writing the flag by hand.
Also widens the breaker tests' flagged-schedule delays so a loaded run
cannot fire them before the strike (caught by a full-suite run).
Claude-Session: https://claude.ai/code/session_011QZUJztM1rMTsHEC7mbcbz
* fix(deps): require agents >= 0.23.0 from the chat packages
ai-chat and think consume new agents/chat runtime exports
(chatRecoveryRedeferPolicy) and no longer implement the old
template-method breaker hooks, so older agents releases inside the
previous peer ranges would crash at module init or silently lose
breaker protection. Bump both peer lower bounds to the release this
train produces, and give ai-chat the same workspace:* agents
devDependency think already has so the unpublished bound resolves
locally.
Claude-Session: https://claude.ai/code/session_011QZUJztM1rMTsHEC7mbcbz
* fix(lifecycle): seal routed recovery owners on memory limit
Carry a pre-purge snapshot of recovery-loop jobs through the memory-limit
context. Scheduler uses the owner addresses from that snapshot to deliver a
sealed strike to each affected dynamic agent, where the existing chat host
hook terminalizes its durable incident.
This is an internal compatibility bridge for root-owned routed schedules and
is explicitly removed by the chat-recovery-on-Tasks migration. Regression
coverage uses two AIChatAgent children under a plain Agent root: the executing
OOM recovery and a pending sibling whose row is purged by the same seal.
* fix(agents): preserve legacy chat OOM sealing
Already-published AI Chat and Think releases accept agents 0.23 but expose
only the former _cf_sealMemoryLimitedRecovery hook. Keep a sealed-only Agent
fallback that invokes that terminalization method when a newer host hook does
not override it. Job-row recovery membership remains authoritative.
Add a mixed-generation host regression at the real alarm breaker boundary. M
Matt committed
58c586aa179690f78a4327288fe27ee9875e8624
Parent: b40bc5b
Committed by GitHub <noreply@github.com>
on 9/1/2026, 2:44:17 PM