feat(vibe): reconcile mutable session previews in playback

This commit is contained in:
kami
2026-08-01 23:47:02 +04:00
parent 51ef7c84db
commit 57df1cfe9f
20 changed files with 1311 additions and 312 deletions
@@ -47,6 +47,7 @@ function setup() {
endVibeSessionWithEvent: vi.fn().mockResolvedValue({ session: session('ended'), ended: true }),
resumeVibeSession: vi.fn().mockResolvedValue({ session: session(), resumed: true }),
serveNextVibePlanItem: vi.fn().mockResolvedValue({ item: plan().items[0], stale: false }),
advancePastUnplayableVibePlanItem: vi.fn().mockResolvedValue({ item: plan().items[0], stale: false }),
persistNextVibePlan: vi.fn().mockResolvedValue({ ...plan(), version: 2, reason: 'feedback:completed' }),
getVibePlanForFeedbackEvent: vi.fn().mockResolvedValue(null),
} as unknown as DbService;
@@ -179,6 +180,25 @@ describe('VibeSessionCoordinator', () => {
expect(result).toMatchObject({ planVersion: 1, now: { track_id: TRACK_ID } });
});
it('advances past an unplayable served item using a distinct idempotent event protocol', async () => {
const { db, coordinator } = setup();
const planVersionId = '44444444-4444-4444-8444-444444444444';
const eventId = '55555555-5555-4555-8555-555555555555';
const result = await coordinator.advancePastUnplayable('user-1', SESSION_ID, {
expectedPlanVersion: 1,
planVersionId,
ordinal: 0,
trackId: TRACK_ID,
eventId,
});
expect(db.advancePastUnplayableVibePlanItem).toHaveBeenCalledWith(SESSION_ID, 'user-1', {
expectedPlanVersion: 1, planVersionId, ordinal: 0, trackId: TRACK_ID, eventId,
});
expect(result.now).toMatchObject({ track_id: TRACK_ID });
});
it('ends an active session once and preserves its latest persisted plan', async () => {
const { db, coordinator } = setup();
const response = await coordinator.end('user-1', SESSION_ID);