Skip to content
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
5d8481a
feat(core): checkpoint long-running Goal evidence
qqqys Aug 3, 2026
6a0fd28
Merge branch 'main' into codex/goal-evidence-checkpoint
wenshao Aug 3, 2026
1ab71ab
fix(core): reject blocked Goals on evidence exhaustion
qqqys Aug 4, 2026
f1cf71f
Merge branch 'main' into codex/goal-evidence-checkpoint
wenshao Aug 4, 2026
9a9fb0a
test(core): pin Goal checkpoint recovery contracts
qqqys Aug 4, 2026
e2d3122
Merge branch 'main' into codex/goal-evidence-checkpoint
qwen-code-dev-bot Aug 5, 2026
921971a
fix: retain Goal rejection feedback and dedupe checkpoint records (#8…
qqqys Aug 5, 2026
97d906b
Merge branch 'main' into codex/goal-evidence-checkpoint
qwen-code-dev-bot Aug 5, 2026
e39071b
Merge branch 'main' into codex/goal-evidence-checkpoint
qwen-code-dev-bot Aug 5, 2026
1a72372
fix: make Goal replay suppression and checkpoint recovery cause-aware…
qwen-code-dev-bot Aug 5, 2026
891adca
fix: persist goalCause in transcript replay state across page handoff…
qwen-code-dev-bot Aug 6, 2026
2cced78
fix(core): harden Goal evidence checkpoint gates and wire parsing (#8…
qwen-code-dev-bot Aug 6, 2026
482db7f
Merge branch 'main' into codex/goal-evidence-checkpoint
qwen-code-dev-bot Aug 7, 2026
7e470f8
fix: settle post-commit Goal checkpoint failures and tighten evidence…
qwen-code-dev-bot Aug 7, 2026
c4a2147
fix(core): resolve goal checkpoint review findings (#8465)
qwen-code-dev-bot Aug 7, 2026
529dde2
fix(core): align goal checkpoint byte budget with enforcement (#8465)
qwen-code-dev-bot Aug 7, 2026
ecefc20
test(core): pin unknown-source checkpoint rejection message (#8465)
qwen-code-dev-bot Aug 7, 2026
d143f20
fix(core): bound goal checkpoint windows and soften verifier failures…
qwen-code-dev-bot Aug 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
226 changes: 226 additions & 0 deletions packages/acp-bridge/src/transcript-replay.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,205 @@ describe('createTranscriptReplayMachine', () => {
});
});

it('skips checkpoint bookkeeping goal_state records during replay', () => {
const machine = createTranscriptReplayMachine();

expect(
updates(machine, goalStateRecord('goal-create', 'create', GOAL)),
).toHaveLength(1);

const turned: GoalRecord = {
...GOAL,
turnCount: GOAL.turnCount + 1,
activeTimeMs: 2100,
updatedAt: 300,
};
expect(
updates(machine, goalStateRecord('goal-turn', 'turn_finished', turned)),
).toHaveLength(1);

const checkpointed: GoalRecord = {
...turned,
evidenceCursor: { recordId: 'checkpoint-1' },
evidenceCheckpoint: {
checkpointId: 'checkpoint-1',
createdAt: 350,
claims: [
{
id: 'checkpoint-1:1',
proofKind: 'delivered_output',
claim: 'The result was delivered.',
sourceRefs: ['assistant-1'],
},
],
},
activeTimeMs: 2500,
updatedAt: 400,
};
expect(
updates(
machine,
goalStateRecord('goal-checkpoint', 'checkpoint', checkpointed),
),
).toEqual([]);

const rejected: GoalRecord = {
...checkpointed,
lastReason: 'More work remains',
};
expect(
updates(
machine,
goalStateRecord('goal-reject', 'verifier_reject', rejected),
),
).toHaveLength(1);

const recommitted: GoalRecord = {
...rejected,
activeTimeMs: 2900,
updatedAt: 500,
};
expect(
updates(
machine,
goalStateRecord(
'goal-reject-checkpoint',
'verifier_reject',
recommitted,
),
),
).toEqual([]);

expect(machine.snapshot().goalState?.goal).toEqual(recommitted);
});

it('persists goalCause so bookkeeping suppression survives a page boundary', () => {
const first = createTranscriptReplayMachine();
updates(first, goalStateRecord('goal-create', 'create', GOAL));
const turned: GoalRecord = {
...GOAL,
turnCount: GOAL.turnCount + 1,
activeTimeMs: 2100,
updatedAt: 300,
};
updates(first, goalStateRecord('goal-turn', 'turn_finished', turned));
const rejected: GoalRecord = {
...turned,
lastReason: 'More work remains',
activeTimeMs: 2200,
updatedAt: 310,
};
expect(
updates(
first,
goalStateRecord('goal-reject', 'verifier_reject', rejected),
),
).toHaveLength(1);

const state = first.snapshot();
expect(state.goalCause).toBe('verifier_reject');

// A page boundary falls between the genuine rejection and the
// shape-equal bookkeeping re-commit; the second machine must still
// recognize the re-commit as bookkeeping.
const second = createTranscriptReplayMachine({ initialState: state });
const recommitted: GoalRecord = {
...rejected,
activeTimeMs: 2300,
updatedAt: 320,
};
expect(
updates(
second,
goalStateRecord(
'goal-reject-checkpoint',
'verifier_reject',
recommitted,
),
),
).toEqual([]);
expect(second.snapshot().goalState?.goal).toEqual(recommitted);
});

it('emits a repeated verifier rejection that follows an empty turn', () => {
const machine = createTranscriptReplayMachine();

expect(
updates(machine, goalStateRecord('goal-create', 'create', GOAL)),
).toHaveLength(1);

const turnedOnce: GoalRecord = {
...GOAL,
turnCount: GOAL.turnCount + 1,
activeTimeMs: 2100,
updatedAt: 300,
};
expect(
updates(
machine,
goalStateRecord('goal-turn-1', 'turn_finished', turnedOnce),
),
).toHaveLength(1);

const rejectedOnce: GoalRecord = {
...turnedOnce,
lastReason: 'More work remains',
activeTimeMs: 2200,
updatedAt: 310,
};
expect(
updates(
machine,
goalStateRecord('goal-reject-1', 'verifier_reject', rejectedOnce),
),
).toHaveLength(1);

const turnedTwice: GoalRecord = {
...rejectedOnce,
turnCount: GOAL.turnCount + 2,
activeTimeMs: 2300,
updatedAt: 320,
};
expect(
updates(
machine,
goalStateRecord('goal-turn-2', 'turn_finished', turnedTwice),
),
).toHaveLength(1);

// Shape-equal to the preceding turn_finished record, but its cause is a
// genuine rejection, not checkpoint bookkeeping — it must stay visible.
const rejectedTwice: GoalRecord = {
...turnedTwice,
activeTimeMs: 2400,
updatedAt: 330,
};
expect(
updates(
machine,
goalStateRecord('goal-reject-2', 'verifier_reject', rejectedTwice),
),
).toHaveLength(1);

const recommitted: GoalRecord = {
...rejectedTwice,
activeTimeMs: 2500,
updatedAt: 340,
};
expect(
updates(
machine,
goalStateRecord(
'goal-reject-2-checkpoint',
'verifier_reject',
recommitted,
),
),
).toEqual([]);

expect(machine.snapshot().goalState?.goal).toEqual(recommitted);
});

it('reports and skips a malformed goal_state record', () => {
const onDiagnostic = vi.fn();
const machine = createTranscriptReplayMachine({ onDiagnostic });
Expand Down Expand Up @@ -538,6 +737,33 @@ describe('createTranscriptReplayMachine', () => {
expect(machine.snapshot().goalState).toBeUndefined();
});

it('drops a malformed goalCause from initialState and reports it', () => {
const onDiagnostic = vi.fn();
const machine = createTranscriptReplayMachine({
onDiagnostic,
initialState: {
v: 1,
pendingToolCalls: [],
cumulativeUsage: {
promptTokens: 0,
cachedTokens: 0,
candidateTokens: 0,
apiTimeMs: 0,
},
goalCause: 'bogus',
} as unknown as TranscriptReplayStateV1,
});

expect(onDiagnostic).toHaveBeenCalledWith(
expect.objectContaining({
code: 'invalid_replay_state',
message: 'Dropped a malformed Goal cause from replay state.',
affectsCompleteness: true,
}),
);
expect(machine.snapshot().goalCause).toBeUndefined();
});

it('emits gaps, todo plans, and cumulative usage deterministically', () => {
const machine = createTranscriptReplayMachine({
gaps: [{ childUuid: 'assistant-1', missingParentUuid: 'missing' }],
Expand Down
27 changes: 27 additions & 0 deletions packages/acp-bridge/src/transcript-replay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,14 @@ import type {
TranscriptReplayGapInput,
} from '@qwen-code/qwen-code-core/transcriptRecords';
import {
isGoalCheckpointBookkeepingCause,
isGoalCheckpointBookkeepingTransition,
parseGoalSnapshotV2,
parseGoalStateCause,
parseGoalStateRecordPayloadV2,
projectGoalStateToLegacy,
type GoalSnapshotV2,
type GoalStateCause,
} from '@qwen-code/qwen-code-core/goalWire';
// Narrow path — the helper is Node-free. Importing the core package barrel
// here would pull the whole Node-bound core graph into the browser
Expand Down Expand Up @@ -56,6 +60,7 @@ export interface TranscriptReplayStateV1 {
readonly pendingToolCalls: readonly PendingTranscriptToolCall[];
readonly cumulativeUsage: TranscriptReplayUsageState;
readonly goalState?: GoalSnapshotV2;
readonly goalCause?: GoalStateCause;
}

export interface TranscriptReplayToolMetadata {
Expand Down Expand Up @@ -389,6 +394,7 @@ class DefaultTranscriptReplayMachine implements TranscriptReplayMachine {
};
private finalized = false;
private goalState: GoalSnapshotV2 | undefined;
private goalCause: GoalStateCause | undefined;

constructor(private readonly options: TranscriptReplayMachineOptions) {
const initialState = parseInitialState(
Expand All @@ -397,6 +403,7 @@ class DefaultTranscriptReplayMachine implements TranscriptReplayMachine {
);
this.usage = { ...initialState.cumulativeUsage };
this.goalState = initialState.goalState;
this.goalCause = initialState.goalCause;
for (const pending of initialState.pendingToolCalls) {
this.pendingToolCalls.set(pending.callId, pending);
this.usedToolCallIds.add(pending.callId);
Expand Down Expand Up @@ -505,6 +512,7 @@ class DefaultTranscriptReplayMachine implements TranscriptReplayMachine {
})),
cumulativeUsage: { ...this.usage },
...(this.goalState ? { goalState: this.goalState } : {}),
...(this.goalCause ? { goalCause: this.goalCause } : {}),
};
}

Expand Down Expand Up @@ -873,11 +881,18 @@ class DefaultTranscriptReplayMachine implements TranscriptReplayMachine {
);
return;
}
const bookkeepingOnly =
isGoalCheckpointBookkeepingTransition(
this.goalState,
payload.snapshot,
) && isGoalCheckpointBookkeepingCause(payload.cause, this.goalCause);
const projection = projectGoalStateToLegacy(
payload,
this.goalState?.goal ?? null,
);
this.goalState = payload.snapshot;
this.goalCause = payload.cause;
if (bookkeepingOnly) return;
const { type: _type, ...goalStatus } = projection.goalStatus;
yield emit(
createTranscriptMessageUpdate({
Expand Down Expand Up @@ -1185,6 +1200,17 @@ function parseInitialState(
affectsCompleteness: true,
});
}
const rawGoalCause = value['goalCause'];
const goalCause =
rawGoalCause === undefined ? undefined : parseGoalStateCause(rawGoalCause);
if (rawGoalCause !== undefined && !goalCause) {
onDiagnostic?.({
code: 'invalid_replay_state',
severity: 'warning',
message: 'Dropped a malformed Goal cause from replay state.',
affectsCompleteness: true,
});
}
return {
v: 1,
pendingToolCalls,
Expand All @@ -1197,6 +1223,7 @@ function parseInitialState(
}
: emptyUsage(),
...(goalState ? { goalState } : {}),
...(goalCause ? { goalCause } : {}),
};
}

Expand Down
Loading
Loading