chore(integration): snapshot local main worktree
This commit is contained in:
@@ -690,6 +690,38 @@ describe('coding Conversation store', () => {
|
||||
await selection;
|
||||
});
|
||||
|
||||
it('refreshes an existing Conversation silently without surfacing a reconnect state', async () => {
|
||||
const refresh = deferred<ConversationSnapshot>();
|
||||
const store = createCodingConversationStore({
|
||||
getSnapshot: vi.fn(() => refresh.promise),
|
||||
openEvents: vi.fn(),
|
||||
submitPrompt: vi.fn(),
|
||||
createId: ids(),
|
||||
});
|
||||
store.getState().applySnapshotEvent(snapshotEvent(snapshot('conversation-a', 1)));
|
||||
|
||||
const flight = store.getState().loadSnapshot('conversation-a', 'silent');
|
||||
|
||||
expect(store.getState().entriesByConversationId['conversation-a']).toMatchObject({
|
||||
loadState: 'live',
|
||||
error: null,
|
||||
});
|
||||
const refreshed = snapshot('conversation-a', 1, 1);
|
||||
refreshed.conversation.model = {
|
||||
model: { accountId: 'account-a', modelId: 'model-b', thinkingLevel: 'low' },
|
||||
modelResolution: 'resolved',
|
||||
};
|
||||
refresh.resolve(refreshed);
|
||||
await flight;
|
||||
|
||||
expect(store.getState().entriesByConversationId['conversation-a']).toMatchObject({
|
||||
loadState: 'live',
|
||||
error: null,
|
||||
});
|
||||
expect(selectCodingConversationSnapshot('conversation-a')(store.getState())?.conversation.model)
|
||||
.toEqual(refreshed.conversation.model);
|
||||
});
|
||||
|
||||
it('surfaces a cold preparation deadline and recovers without losing selection or draft', async () => {
|
||||
const getSnapshot = vi.fn()
|
||||
.mockImplementationOnce(() => new Promise<ConversationSnapshot>(() => undefined))
|
||||
@@ -926,6 +958,51 @@ describe('coding Conversation store', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('ignores a snapshot-covered batch and applies only an overlapping unseen tail', () => {
|
||||
const getSnapshot = vi.fn(() => Promise.resolve(snapshot('conversation-a')));
|
||||
const store = createCodingConversationStore({
|
||||
getSnapshot,
|
||||
openEvents: vi.fn(),
|
||||
submitPrompt: vi.fn(),
|
||||
createId: ids(),
|
||||
});
|
||||
store.getState().applySnapshotEvent(snapshotEvent({
|
||||
...snapshot('conversation-a', 1, 3),
|
||||
run: { status: 'running', runId: 'run-a' },
|
||||
}));
|
||||
|
||||
store.getState().applyPatchBatchEvent(patchBatch('conversation-a', 2, [
|
||||
{ op: 'run.state', run: { status: 'running', runId: 'run-a' } },
|
||||
{
|
||||
op: 'context.replace',
|
||||
context: { usedTokens: 10, contextWindow: 100, compaction: 'idle' },
|
||||
},
|
||||
]));
|
||||
expect(getSnapshot).not.toHaveBeenCalled();
|
||||
expect(selectCodingConversationSnapshot('conversation-a')(store.getState()))
|
||||
.toMatchObject({ cursor: { seq: 3 }, context: { usedTokens: 0 } });
|
||||
|
||||
store.getState().applyPatchBatchEvent(patchBatch('conversation-a', 3, [
|
||||
{
|
||||
op: 'context.replace',
|
||||
context: { usedTokens: 10, contextWindow: 100, compaction: 'idle' },
|
||||
},
|
||||
{
|
||||
op: 'run.state',
|
||||
run: { status: 'idle', runId: 'run-a', terminalReason: 'completed' },
|
||||
},
|
||||
]));
|
||||
|
||||
expect(getSnapshot).not.toHaveBeenCalled();
|
||||
expect(selectCodingConversationSnapshot('conversation-a')(store.getState()))
|
||||
.toMatchObject({
|
||||
cursor: { workerGeneration: 1, seq: 4 },
|
||||
context: { usedTokens: 0 },
|
||||
run: { status: 'idle', runId: 'run-a', terminalReason: 'completed' },
|
||||
});
|
||||
expect(store.getState().entriesByConversationId['conversation-a'].loadState).toBe('live');
|
||||
});
|
||||
|
||||
it('refreshes a target Snapshot once more when the first recovery response is still behind', async () => {
|
||||
const firstRecovery = deferred<ConversationSnapshot>();
|
||||
const secondRecovery = deferred<ConversationSnapshot>();
|
||||
|
||||
Reference in New Issue
Block a user