fix(todo-continuation-enforcer): make compaction guard epoch-aware

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
YeonGyu-Kim
2026-03-24 20:36:22 +09:00
parent 733676f1a9
commit 8e239e134c
2 changed files with 97 additions and 1 deletions

View File

@@ -0,0 +1,67 @@
import { describe, expect, it as test } from "bun:test"
import { COMPACTION_GUARD_MS } from "./constants"
import {
acknowledgeCompactionGuard,
armCompactionGuard,
isCompactionGuardActive,
} from "./compaction-guard"
import type { SessionState } from "./types"
function createSessionState(): SessionState {
return {
stagnationCount: 0,
consecutiveFailures: 0,
}
}
describe("compaction guard regressions", () => {
describe("#given a compaction epoch was already acknowledged", () => {
describe("#when a newer compaction epoch is armed", () => {
test("#then the guard re-arms for the newer epoch", () => {
const state = createSessionState()
const firstEpoch = armCompactionGuard(state, 1_000)
expect(acknowledgeCompactionGuard(state, firstEpoch)).toBe(true)
expect(isCompactionGuardActive(state, 1_001)).toBe(false)
const secondEpoch = armCompactionGuard(state, 2_000)
expect(secondEpoch).toBe(firstEpoch + 1)
expect(state.recentCompactionEpoch).toBe(secondEpoch)
expect(isCompactionGuardActive(state, 2_001)).toBe(true)
})
})
})
describe("#given a newer compaction epoch is armed before an older idle check finishes", () => {
describe("#when the older epoch tries to acknowledge the guard", () => {
test("#then it does not clear the newer epoch", () => {
const state = createSessionState()
const firstEpoch = armCompactionGuard(state, 1_000)
const secondEpoch = armCompactionGuard(state, 2_000)
expect(acknowledgeCompactionGuard(state, firstEpoch)).toBe(false)
expect(state.acknowledgedCompactionEpoch).toBeUndefined()
expect(state.recentCompactionEpoch).toBe(secondEpoch)
expect(isCompactionGuardActive(state, 2_001)).toBe(true)
})
})
})
describe("#given the current compaction epoch is still inside the guard window", () => {
describe("#when that same epoch is acknowledged", () => {
test("#then continuation can proceed again without waiting for the window to expire", () => {
const state = createSessionState()
const currentEpoch = armCompactionGuard(state, 1_000)
expect(isCompactionGuardActive(state, 1_000 + COMPACTION_GUARD_MS - 1)).toBe(true)
expect(acknowledgeCompactionGuard(state, currentEpoch)).toBe(true)
expect(isCompactionGuardActive(state, 1_001)).toBe(false)
expect(isCompactionGuardActive(state, 1_000 + COMPACTION_GUARD_MS - 1)).toBe(false)
})
})
})
})

View File

@@ -1,8 +1,37 @@
import { COMPACTION_GUARD_MS } from "./constants"
import type { SessionState } from "./types"
export function armCompactionGuard(state: SessionState, now: number): number {
const nextEpoch = (state.recentCompactionEpoch ?? 0) + 1
state.recentCompactionAt = now
state.recentCompactionEpoch = nextEpoch
return nextEpoch
}
export function acknowledgeCompactionGuard(
state: SessionState,
compactionEpoch: number | undefined
): boolean {
if (compactionEpoch === undefined) {
return false
}
if (state.recentCompactionEpoch !== compactionEpoch) {
return false
}
state.acknowledgedCompactionEpoch = compactionEpoch
return true
}
export function isCompactionGuardActive(state: SessionState, now: number): boolean {
if (!state.recentCompactionAt) {
if (state.recentCompactionAt === undefined || state.recentCompactionEpoch === undefined) {
return false
}
if (state.acknowledgedCompactionEpoch === state.recentCompactionEpoch) {
return false
}