@@ -591,19 +591,16 @@ export async function processWake(
591591 let idleTimer : ReturnType < typeof setTimeout > | null = null
592592 let idleController : AbortController | null = null
593593 let runAbortController : AbortController | null = null
594- // Turn-end background compaction: a detached summarization started after a
595- // turn whose result (or failure) is applied as a checkpoint either at the
596- // *next* turn's start, or — if the summarize finishes while the entity is
597- // idle — immediately by waking the idle loop (so the "Compacting…" indicator
598- // never lingers past completion). The checkpoint write always stays inside a
599- // handler/idle drain. Persists across loop iterations.
594+ // Turn-end background compaction: a detached summarize, applied as a
595+ // checkpoint at the next turn's start — or immediately if it settles while
596+ // idle. Persists across loop iterations.
600597 let pendingBackgroundCompaction : {
601598 watermark : number
602599 status : `pending` | `ready` | `failed`
603600 summary : string
604601 } | null = null
605- // Set by the detached summarize when it settles while idle; signals the idle
606- // loop to apply the checkpoint without running the agent handler.
602+ // Set when the detached summarize settles while idle; tells the idle loop to
603+ // apply the checkpoint without running the handler.
607604 let backgroundApplyRequestedDuringIdle = false
608605 let activeSignalHandler :
609606 | ( (
@@ -2462,39 +2459,42 @@ export async function processWake(
24622459 break
24632460 }
24642461
2462+ // Idle until a fresh wake resumes us or we genuinely go idle — re-entering
2463+ // each time a detached background compaction settles while idle, so its
2464+ // checkpoint is written (without an agent run) and the indicator doesn't
2465+ // linger.
24652466 let resumedFromIdle = false
24662467 let idleReason = `handler returned`
2467- for ( ; ; ) {
2468+ let appliedBackgroundDuringIdle = false
2469+ do {
2470+ appliedBackgroundDuringIdle = false
24682471 const resumed = await awaitIdleForFreshWork (
24692472 `${ idleReason } , entering idle (${ idleTimeout / 1000 } s timeout)`
24702473 )
24712474 if ( resumed ) {
24722475 resumedFromIdle = true
24732476 break
24742477 }
2475- // Woke from idle because a detached background compaction settled with
2476- // no turn to apply it at. Write its checkpoint now (NO agent run) so the
2477- // indicator clears and the next turn starts compacted, then re-idle.
24782478 const settled = backgroundApplyRequestedDuringIdle
24792479 ? pendingBackgroundCompaction
24802480 : null
24812481 backgroundApplyRequestedDuringIdle = false
2482- if ( ! settled || settled . status === `pending` ) {
2483- break
2484- }
2485- if ( settled . status === `ready` ) {
2486- writeBackgroundCheckpoint ( settled . watermark , settled . summary )
2487- log . info ( `background compaction applied during idle` )
2488- } else {
2489- failBackgroundCheckpoint ( settled . watermark )
2490- log . info ( `background compaction failed; cleared during idle` )
2482+ if ( settled && settled . status !== `pending` ) {
2483+ if ( settled . status === `ready` ) {
2484+ writeBackgroundCheckpoint ( settled . watermark , settled . summary )
2485+ log . info ( `background compaction applied during idle` )
2486+ } else {
2487+ failBackgroundCheckpoint ( settled . watermark )
2488+ log . info ( `background compaction failed; cleared during idle` )
2489+ }
2490+ pendingBackgroundCompaction = null
2491+ await drainAllPendingWrites ( )
2492+ await wakeSession . commitManifestEntries ( )
2493+ await flushProducedWrites ( )
2494+ idleReason = `background compaction applied`
2495+ appliedBackgroundDuringIdle = true
24912496 }
2492- pendingBackgroundCompaction = null
2493- await drainAllPendingWrites ( )
2494- await wakeSession . commitManifestEntries ( )
2495- await flushProducedWrites ( )
2496- idleReason = `background compaction applied`
2497- }
2497+ } while ( appliedBackgroundDuringIdle )
24982498 if ( resumedFromIdle ) {
24992499 continue
25002500 }
0 commit comments