fix(transcript): collapse rolling segment echoes
All checks were successful
Build & Push Docker Image / test (push) Successful in 12s
Build & Push Docker Image / build-and-push (push) Successful in 45s

Normalize incremental backend hypothesis chains before persistence and ignore stale or replayed webhook callbacks so duplicate transcript text does not survive ingest.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-05-11 22:46:38 +02:00
parent 35a2d86dbb
commit 672b161cda
7 changed files with 246 additions and 33 deletions

View File

@@ -132,6 +132,43 @@ describe('POST /api/webhook/[jobId] — locally cancelled job', () => {
});
});
// ── Duplicate / stale callback guards ──────────────────────────────────────────
describe('POST /api/webhook/[jobId] — duplicate and stale callbacks', () => {
it('ignores replayed success callbacks after the transcript is already done', async () => {
mockGetJob.mockReturnValue({
...makeJob('job-done'),
status: 'done',
segmentsJson: JSON.stringify([makeSeg(0, 'Already saved.')]),
whisperJobId: 'whisper-id'
});
const res = await POST(makeEvent('job-done', makeWhisperJob()) as any);
expect(res.status).toBe(200);
expect(await res.json()).toEqual({ ok: true, ignored: 'duplicate_webhook' });
expect(mockSetJobStatus).not.toHaveBeenCalled();
expect(mockUpdateJob).not.toHaveBeenCalled();
expect(mockWriteOutputs).not.toHaveBeenCalled();
});
it('ignores stale callbacks from an older whisper job after retry', async () => {
mockGetJob.mockReturnValue({
...makeJob('job-stale'),
status: 'transcribing',
whisperJobId: 'current-whisper-job'
});
const res = await POST(
makeEvent('job-stale', makeWhisperJob({ id: 'old-whisper-job', segments: [makeSeg(0, 'stale')] })) as any
);
expect(res.status).toBe(200);
expect(await res.json()).toEqual({ ok: true, ignored: 'stale_whisper_job' });
expect(mockSetJobStatus).not.toHaveBeenCalled();
expect(mockUpdateJob).not.toHaveBeenCalled();
expect(mockWriteOutputs).not.toHaveBeenCalled();
});
});
// ── Whisper job failed / cancelled ───────────────────────────────────────────
describe('POST /api/webhook/[jobId] — whisper failure', () => {