Skip to content

fix(ai): cancel the deferred startup model sync when the plugin unloads - #1823

Merged
chhoumann merged 1 commit into
masterfrom
fix/cancel-startup-model-sync-on-unload
Sep 26, 2026
Merged

chhoumann merged 1 commit into
masterfrom
fix/cancel-startup-model-sync-on-unload

Conversation

@chhoumann

@chhoumann chhoumann commented Sep 26, 2026 •

Copy link
Copy Markdown
Owner

Summary

QuickAdd schedules its background AI model sync 5 s after layout-ready with a bare window.setTimeout. onunload never cancelled that timer. So if the plugin was disabled, reloaded or updated within those 5 s, the unloaded instance still ran a full model sync against the network, including a ~5 MB models.dev download. That happened even when the user had just turned QuickAdd off.

Changes

  • New src/ai/startupModelSync.ts: scheduleStartupModelSync(host, sync) keeps the same behaviour (5 s after layout-ready). It registers a cleanup through Obsidian's Component.register, so unloading the plugin cancels a pending run. If the plugin unloads before layout-ready, nothing is scheduled at all.
  • src/main.ts calls it instead of the inline onLayoutReady + setTimeout.

Testing / validation

  • Reproduced first on unmodified master. I used a temporary build that tagged each plugin instance and logged whether it was still the loaded one when its timer fired. After plugin:reload and then plugin:disable 1 s later, the console showed fired; loaded=false followed by a models.dev request, 4–5 s after QuickAdd was disabled (app.plugins.plugins.quickadd was false).
  • Before/after in real Obsidian 1.13.7 (isolated throwaway e2e vault). Requests to models.dev were counted at Obsidian's request-url IPC boundary. Each plugin sync pass makes exactly one request, and the sync throttle was cleared before each step. The runs used the raw obsidian CLI, because the obsidian:e2e wrapper reloads the plugin before every command, which would add instances of its own.
Sequence (within the 5 s delay) master this PR
one plugin:reload 1 1
two plugin:reloads 1 s apart 2 1
plugin:reload, then plugin:disable 1 s later 1 while disabled 0

The first row shows the live instance still syncs as before.

  • src/ai/startupModelSync.test.ts (4 tests, fake timers) covers: exactly one sync at 5 s after layout-ready (none before layout-ready, none at 4,999 ms), no sync when unloaded during the delay, no scheduling when unloaded before layout-ready, and only the live instance syncing after a reload. Mutation check: removing either the clearTimeout or the unloaded guard fails 3 of the 4 tests.
  • pnpm run test: 455 files passed, 5887 tests passed. pnpm run build-with-lint: clean.

Checklist

Note

Cancel the deferred startup model sync on plugin unload

  • Replaces the direct layout-ready listener and timer in QuickAdd.onload with scheduleStartupModelSync, which registers unload cleanup that cancels the pending sync.
  • The sync still runs 5 seconds after layout-ready (STARTUP_MODEL_SYNC_DELAY_MS = 5000), and the delay is injectable for tests. See startupModelSync.ts and main.ts.
  • Adds tests in startupModelSync.test.ts covering unload during the delay, unload before layout-ready, and plugin reload scenarios.

Macroscope summarized e8923bc.

Summary by CodeRabbit

  • Improvements
    • Startup model synchronization now runs five seconds after the app layout is ready, helping avoid running it during initial loading.
    • If the plugin unloads before synchronization begins, the pending sync is canceled.

The 5 s post-layout-ready auto-sync timer was never cleared, so disabling,
reloading or updating QuickAdd within that window still ran a full model
sync (including the models.dev download) from the unloaded instance.
Register a cleanup that cancels it, and skip scheduling if the plugin
unloads before layout-ready.

Co-authored-by: Christian Bager Bach Houmann <christian@bagerbach.com>
@coderabbitai

coderabbitai Bot commented Sep 26, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

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

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 9d961945-e8ab-43da-9701-fa7f4e7319a0

📥 Commits

Reviewing files that changed from the base of the PR and between 594b952 and e8923bc.

📒 Files selected for processing (3)
  • src/ai/startupModelSync.test.ts
  • src/ai/startupModelSync.ts
  • src/main.ts

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


📝 Walkthrough

Walkthrough

The startup model sync now uses a scheduler that waits for layout readiness and then delays the sync by 5,000 ms. The scheduler clears a pending timer when the plugin unloads. Tests cover layout readiness, unload, and reload behavior.

Changes

Startup model-sync scheduling

Layer / File(s) Summary
Schedule and cancel startup sync
src/ai/startupModelSync.ts, src/main.ts, src/ai/startupModelSync.test.ts
The scheduler waits for layout readiness, then runs the sync after a 5,000 ms delay. It cancels a pending timer on unload. QuickAdd.onload delegates scheduling to the new function. Tests cover the delay, unload before and during the delay, and reload behavior.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Merge Risk: ⚪ Minimal · up to e8923

The pending startup sync is canceled on unload, with no supported issue remaining that would prevent merging after normal checks.

Security Architecture Review

Security architecture risk: 🔵 Low · up to e8923

The change reduces model-sync requests after the plugin is disabled or reloaded. It does not appear to add a new way to trigger synchronization, but work already running when the plugin unloads can still finish.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The affected work is this plugin instance’s scheduled provider-model sync, which may make network requests and merge results into shared settings. Canceling a pending run reduces post-unload activity without expanding the sync service’s authority.

Trust Boundaries and Controls

  • observed — The startup call passes no throttle override. Online-feature disablement, provider opt-in, and throttling remain enforced inside the existing sync service.

Resilience and Maintainability Implications

  • observed — The sync service merges results against current providers, preserving removals and other edits made while requests are in flight, but it has no unload-generation check before updating the store.

Hardening Proposals

  • proposed — If post-unload state changes must also be prohibited, invalidate in-flight sync results before committing them and test completion across reload; timer cleanup alone cannot provide that guarantee.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: cancelling the deferred startup model sync when the plugin unloads.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 3 files.
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
🧪 Generate unit tests (beta)
  • 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

A rabbit checks the layout light
Then waits five seconds, calm and bright
If unload comes, the timer clears
A fresh start syncs when it appears
Hop, the model sync runs just right!

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

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-26T23:04:42.908393Z e8923bc PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chhoumann
chhoumann merged commit c1fdc58 into master Sep 26, 2026
14 of 15 checks passed
@chhoumann
chhoumann deleted the fix/cancel-startup-model-sync-on-unload branch September 26, 2026 23:07
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.

2 participants