Skip to content

test(native-chat): cancel the journal import test's tick before teardown - #24071

Merged
brennanb2025 merged 1 commit into
mainfrom
brennanb2025/journal-import-test-closed-db-tick
Oct 1, 2026
Merged

brennanb2025 merged 1 commit into
mainfrom
brennanb2025/journal-import-test-closed-db-tick

Conversation

@brennanb2025

@brennanb2025 brennanb2025 commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 1 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​4 $\color{#cf222e}{\Huge{\mathbf{−}}}$​6 $\color{#cf222e}{\Huge{\mathbf{−}}}$​2
Prod 0 0 0 0

Fixes: a flaky unit test that can fail a CI shard even when every test passes. Scope: one test in src/main/native-chat/agent-session-journal/journal-per-session-import.test.ts. No app code changes and no user-facing change. The test came in with #23613.

ELI5

A test kept poking the database in a loop while a copy ran, and told the loop to stop with a "please stop" flag. One more poke was already queued when the flag went up. If the test's cleanup closed the database before that last poke ran, the poke hit a closed database and crashed. Now the test cancels the queued poke instead of asking it to stop.

What Changed

The test "commits copy batches unsynced, and every other commit synced" re-arms a setImmediate tick while the import copies, recording the database's sync level between batches. It used to stop with a copying = false flag, but a tick queued before the flag flipped still ran and read the database. When the afterEach teardown closed the database first, that read threw journal_closed as an unhandled error. Vitest counts that as a failure, so shard 2/5 of PR #23806's CI failed with all 19,428 tests green (run 36649661726, attempt 1).

Now the test keeps the handle of the queued tick and calls clearImmediate on it as soon as the import resolves, so nothing touches the database after the test's own assertions.

Why

Cancelling the queued callback removes the race; a flag can only stop the tick after it has already run once more. Other options were worse: waiting a turn before the assertions would still leave the ordering to the event loop, and closing the database later in teardown would change shared test support for one test.

Linked Issue

None (maintainer fix for a CI flake).

Visual Proof

N/A: test-only change with no UI or behavior change.

Testing

  • Reproduced the failure deterministically by adding a database close at the end of the test (standing in for teardown winning the race): the old test threw the exact CI error (journal_closed, unhandled); the fixed test passes with the same forced close. The probe was not committed.
  • journal-per-session-import.test.ts: 22/22 pass. Main-process typecheck, oxlint, oxfmt and the changed-code quality gate pass.
  • Automated tests updated (this is the test).

Notes

Test-only; no effect on security, platforms, SSH, mobile, compatibility or performance.

Checklist

  • This PR is small and focused
  • I explained what changed and why (ELI5, the user-facing before/after, the mechanism, and why over the alternatives)
  • Before/after screenshots or videos attached for UI changes, or N/A with reason
  • Self-reviewed for correctness, security, and performance
  • Cross-platform, SSH/remote, and path/shortcut impact considered (or N/A)
  • pnpm lint, pnpm typecheck, pnpm test, and pnpm build pass (or CI will cover; local preferred)

The test re-arms a setImmediate tick while the copy runs and stopped it with a
flag. A tick already queued when the import resolved still ran, and when the
afterEach teardown closed the database first it threw journal_closed as an
unhandled error, failing a CI shard with every test green. Clear the queued
tick instead.
@greptile-apps

greptile-apps Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

[Low risk] Fixes a test cleanup race condition.

The PR appears safe to merge.

Summary

The PR replaces a stop flag with cancellation of the queued setImmediate callback in one journal-import test, preventing that callback from reading the database after teardown.

  • No application code or user-facing behavior changes.

Reviews (1) · Last reviewed commit: "test(native-chat): cancel the journal im..."

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes

  • Cancel the queued journal-import tick instead of flagging it — the test now holds the setImmediate handle in pending and calls clearImmediate(pending) after importPerSessionJournal resolves, so no tick can read the database after teardown closes it. Replaces the copying = false flag, which could not stop an already-queued callback.

The mechanism is sound: tick re-arms into the same pending variable, so exactly one handle is ever live, and the await continuation runs after the current macrotask completes — clearImmediate therefore reliably cancels the last queued tick. between.length > 0 still relies on the import yielding at least one macrotask, but that reliance predates this change. Verified with a focused run: journal-per-session-import.test.ts 22/22 pass.

Pullfrog  | View workflow run | Using DeepSeek Flash (free via Pullfrog for OSS) | 𝕏

@coderabbitai

coderabbitai Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

📝 Walkthrough

Walkthrough

The commit-synchronization test now schedules recurring setImmediate ticks and stores the latest handle in pending. After the import completes, the test clears the pending callback.

Priority: ⬇️ Low

Merge Risk: ⚪ Minimal · up to 78b0e

A rejected import can still leave a test tick running into teardown, as before this change. The PR fixes cleanup after successful imports and introduces no new merge risk.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main change: cancelling the journal import test's queued tick before teardown. It is concise and specific.
Description check ✅ Passed The description is mostly complete. It explains the failure, the fix, the reason for the approach, testing, scope, visual proof, notes, and checklist status. The missing AI Disclosure and Agent skill …
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 1…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Advanced

Run ID: 6b5e60c8-8e06-4360-b840-475a4f9d7e8c

📥 Commits

Reviewing files that changed from the base of the PR and between f37a849 and 78b0e27.

📒 Files selected for processing (1)
  • src/main/native-chat/agent-session-journal/journal-per-session-import.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 2 remain after this review.

})
copying = false
// A flag would still let the queued tick read the database after teardown closes it.
clearImmediate(pending)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Cancel the tick when the import rejects.

If importPerSessionJournal rejects, execution skips clearImmediate(pending). The queued tick then reschedules itself and continues reading the database. Put the cancellation in a finally block so a failed import cannot leave the loop running during teardown.

Proposed fix
-    await importPerSessionJournal({
-      database,
-      identity: IDENTITY,
-      legacyDirectory: legacyDir(),
-      batchRows: 1
-    })
-    // A flag would still let the queued tick read the database after teardown closes it.
-    clearImmediate(pending)
+    try {
+      await importPerSessionJournal({
+        database,
+        identity: IDENTITY,
+        legacyDirectory: legacyDir(),
+        batchRows: 1
+      })
+    } finally {
+      clearImmediate(pending)
+    }

@brennanb2025
brennanb2025 merged commit a37e502 into main Oct 1, 2026
33 checks passed
@pullfrog pullfrog Bot mentioned this pull request Oct 1, 2026
7 of 9 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant