From 08d95b9979686bb1d7b70d9a6d3d72ea735913fd Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Mon, 31 Aug 2026 13:22:20 -0700 Subject: [PATCH] test(native-chat): remove initial-snapshot recovery race in watch-error test (#17722) Root cause: the test cleared the injected tail-reader failure *before* writing the recovered transcript line. The capped rotation retry loop is still firing at that point, so a retry drain could succeed against the still-empty file, consume the pending initial drain, and emit an empty initial snapshot (`[], false, 0, undefined, undefined`). The later manual watch callback then took the append path, and `u-recovered` never reached onInitialSnapshot -- producing the CI failure `expected [ false, +0, ...(5) ] to deeply equal ArrayContaining{...}`. That empty-snapshot-then-append sequence is correct product behavior, so this is a test bug: write the content first, then clear the failure, so no drain can ever observe a readable-but-empty transcript. The assertion now checks the exact recovered snapshot instead of a flattened arrayContaining, so an empty recovery snapshot fails loudly. --- .../native-chat/transcript-watch-error.test.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/native-chat/transcript-watch-error.test.ts b/src/main/native-chat/transcript-watch-error.test.ts index 655d53c1cbe..cd8243590da 100644 --- a/src/main/native-chat/transcript-watch-error.test.ts +++ b/src/main/native-chat/transcript-watch-error.test.ts @@ -164,14 +164,16 @@ describe('native chat transcript watcher errors', () => { // initialDrain stays true after the error, so a recovered read delivers the // real snapshot instead of stranding the client on the error frame. - tailReaderState.failure = null + // The content must land before reads recover: the capped rotation retry is + // still firing, and any drain that succeeds against a still-empty file + // legitimately consumes the pending initial drain with an empty snapshot. await writeFile(filePath, claudeLine('u-recovered', 'user', 'back')) + tailReaderState.failure = null watchCallbacks[0]!('change', 'transcript.jsonl') - await vi.waitFor(() => - expect(onInitialSnapshot.mock.calls.flat(2)).toEqual( - expect.arrayContaining([expect.objectContaining({ id: 'u-recovered' })]) - ) - ) + await vi.waitFor(() => expect(onInitialSnapshot).toHaveBeenCalledTimes(2)) + expect(onInitialSnapshot.mock.calls[1]![0]).toEqual([ + expect.objectContaining({ id: 'u-recovered' }) + ]) subscription.unsubscribe() })