fix(codex): ignore empty goal clear snapshots

This commit is contained in:
Merge Sim
2026-09-10 21:01:04 -07:00
parent bb190b67fe
commit a480896890
2 changed files with 31 additions and 2 deletions
@@ -96,6 +96,28 @@ function texts(rows: readonly AgentJournalItemBody[]): string[] {
}
describe('codex goal lifecycle resume', () => {
it('does not append a cleared snapshot when the journal has no prior goal occurrence', async () => {
const journal = goalJournal()
journal.unbind()
const resumed = new CodexJournalGoals(journal.sink)
expect(
resumed.handle({
threadId: THREAD,
method: 'thread/goal/cleared',
params: { threadId: THREAD, turnId: null, clearedAt: 1789068999 }
})
).toEqual({ accepted: true })
expect(journal.writes).toHaveLength(0)
journal.rebind()
await journal.drained()
expect(journal.writes).toHaveLength(0)
expect(journal.publishes()).toBe(0)
resumed.dispose()
})
it('does not scan durable history for accounting-only updates', async () => {
const journal = goalJournal()
const goals = new CodexJournalGoals(journal.sink)
@@ -57,7 +57,8 @@ function goalStateFromItem(itemId: string, thread: string): GoalThreadState | nu
function persistedGoalIdentity(
journal: Pick<AgentSessionJournal, 'latestItemIdMatching'>,
thread: string,
signature: string
signature: string,
requirePrevious: boolean
): AgentJournalItemIdentity | null {
const previousItemId = journal.latestItemIdMatching(
(itemId) => goalStateFromItem(itemId, thread) !== null
@@ -66,6 +67,11 @@ function persistedGoalIdentity(
if (previous?.signature === signature) {
return null
}
// Codex sends a cleared snapshot while resuming threads that never had a goal.
// A clear is only a lifecycle occurrence when durable history proves one existed.
if (previous === null && requirePrevious) {
return null
}
const occurrence = previous
? digest(JSON.stringify([previous.occurrence, signature]))
: digest(JSON.stringify([thread, signature]))
@@ -116,7 +122,8 @@ export class CodexJournalGoals {
this.sink,
goalIdentity(thread, signatureKey, occurrence),
translated.body,
(journal) => persistedGoalIdentity(journal, thread, signatureKey)
(journal) =>
persistedGoalIdentity(journal, thread, signatureKey, event.method === 'thread/goal/cleared')
)
if (!admission.accepted) {
return admission