Skip to content

feat: in-app auto-update (X6) + v1.5.0 - #78

Merged
scotej merged 5 commits into
mainfrom
feat/auto-update
Jul 20, 2026
Merged

feat: in-app auto-update (X6) + v1.5.0#78
scotej merged 5 commits into
mainfrom
feat/auto-update

Conversation

@scotej

@scotej scotej commented Jul 20, 2026

Copy link
Copy Markdown
Owner

What

StudyVis now updates itself, via tauri-plugin-updater. It checks GitHub on launch and every 6h, downloads new releases in the background, and offers a Restart now banner once the new version is staged and signature-verified. Only the first install stays manual. This is the v1.5.0 release.

The premise correction

The repo's docs claimed auto-update was blocked on an Apple Developer ID / Windows cert. That was a conflation. Tauri's updater has its own integrity chain — artifacts are signed with a minisign keypair and verified in-app against plugins.updater.pubkey before unpacking, independent of OS code signing. So this ships on the existing ad-hoc-signed builds. PLAN §8, ARCHITECTURE, README, INSTALL, and CLAUDE.md are corrected rather than worked around.

Behavior

  • No check, download, or banner during a session — a WebRTC mesh has no bandwidth to spare, and nothing should offer to restart out of a live study session. The check→download boundary re-reads session state to close the race where a session starts mid-check.
  • Sidecar stopped before the bundle swap — Windows NSIS can't overwrite a running llama-server.exe; a macOS orphan would survive the relaunch.
  • Background failures are silent; only user-initiated checks surface copy.
  • Signature verified before install (confirmed against the plugin source) — the "ready" state genuinely means downloaded + verified.

Notable changes

  • Windows: NSIS -setup.exe, not .msi. MSI updates need msiexec elevation every time (a UAC prompt per release). NSIS installs per-user + passive. Friends on ≤1.4.0 uninstall the old MSI once first — documented in CHANGELOG / INSTALL / README.
  • Auto-update defaults ON, widening PLAN §3's outbound carve-out. Requests stay anonymous with no payload; the toggle still buys literal zero outbound. An explicit OFF on the old version_check_enabled key migrates to OFF.
  • Retired X4's hand-rolled system_fetch_latest_version command.
  • release.yml: signing secrets + preflight gate, includeUpdaterJson: true, NSIS bundles, max-parallel: 1 so the two jobs can't clobber each other's latest.json entry.

Verification

  • Local signed-artifact build verified: StudyVis.app.tar.gz + .sig, signature key ID cross-checked against the configured pubkey.
  • Adversarial multi-agent review run pre-cut (6 dimensions, per-finding verification); the 6 confirmed minor/doc findings are applied in this PR.
  • Gates green: build, lint, 761 tests (17 new for the updater store), tokens, strings, contrast, format, a11y (axe over the new story), cargo fmt.
  • Not yet exercised: the full check→download→install→relaunch round trip — that needs a published v1.5.0 and a prior build in the field.

Manual-test note

Not machine-walked (no updater end-to-end without a published release). The runtime relaunch + signature-verify semantics were confirmed against the plugin's own source rather than a live run.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added automatic in-app updates, enabled by default, with background downloads and signature verification.
    • Added update status controls in Settings → About, including manual checks and an opt-out option.
    • Added a “Restart now” banner to apply downloaded updates, with a “Later” option.
    • Updated Windows distribution to use the x64-setup.exe installer.
  • Documentation

    • Updated installation, release, and upgrade guidance for automatic updates and the new Windows installer.
    • Documented macOS permission re-prompts that may occur after updates.
  • Bug Fixes

    • Improved release publishing reliability and prevented conflicting update metadata.

scotej and others added 4 commits July 20, 2026 23:57
StudyVis now updates itself: it checks GitHub for new releases on launch
and every 6h, downloads them in the background, and offers a "Restart
now" banner once the new version is staged and signature-verified.

The blocker recorded in PLAN §8 / ARCHITECTURE §2 — "auto-update can't
be verified without signed artifacts" — was a conflation. Tauri's
updater carries its own integrity chain: artifacts are signed with a
minisign keypair and verified in-app against `plugins.updater.pubkey`
before unpacking. That is independent of Apple/Windows code signing, so
this ships on the existing ad-hoc-signed builds. The docs are corrected
rather than quietly worked around, and the macOS TCC caveat that comes
with staying unsigned is written down where someone will find it.

Behavior:
- No check, no download, no banner during a session — a WebRTC mesh has
  no bandwidth to spare for an installer, and nothing should offer to
  restart out of a live study session.
- The sidecar is stopped before the bundle swap: Windows NSIS cannot
  overwrite a running llama-server.exe, and a macOS orphan would
  survive the relaunch holding its port and model file.
- Background failures are silent; only user-initiated checks surface
  copy.

Notable changes:
- Windows ships NSIS `-setup.exe` instead of `.msi`. Applying an MSI
  update needs msiexec elevation every time, i.e. a UAC prompt per
  release. NSIS installs per-user and supports passive install mode.
- Auto-update defaults ON, widening PLAN §3's outbound carve-out from
  X4's opt-in tag check. Requests stay anonymous with no payload, and
  the toggle still buys literal zero outbound. An explicit OFF on the
  old `version_check_enabled` key migrates to OFF.
- X4's hand-rolled `system_fetch_latest_version` command is retired —
  the updater subsumes it, and two overlapping mechanisms would be
  worse than one.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Both matrix jobs append their platform's entry to the same latest.json
on the release, and tauri-action does it as a read-merge-write with no
locking. Run in parallel and the slower job can overwrite the faster
one's entry — which fails silently: the release looks fine, and an
entire platform never sees the update.

max-parallel: 1 costs one build's wall-clock on a workflow that runs a
few times a year.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
An adversarial multi-agent review of the auto-update change surfaced six
minor issues before the v1.5.0 cut; all applied:

- updaterStore: close the check→download race. UpdaterBoot only gates
  *scheduling*, so a session starting during the network-bound check
  could still let the installer download onto a live WebRTC mesh. The
  check→download boundary now re-reads session state (new isSessionActive
  dep) and defers to the next post-session check. The residual — a
  download already in flight — is documented as unfixable in this plugin
  version (no AbortSignal).
- AboutCategory: a downloaded, verified "ready" update now always shows
  its restart row, even with auto-update toggled off, so Settings agrees
  with the Home banner instead of going silent while the banner prompts.
- README / ARCHITECTURE §12 / CLAUDE.md: corrected stale "download the
  .msi" / "no auto-update" / "V1 ships an unsigned .msi" claims the
  feature commit missed. README versioning section advanced to v1.5.0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bumps the five tracked version files in lockstep and retitles the
CHANGELOG's Unreleased section to 1.5.0 (auto-update). Tagging v1.5.0
dispatches release.yml to build the per-OS installers as a draft.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 20, 2026 21:41

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@scotej, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 52 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c961b1d6-bd04-42ad-9f27-a35580555fbe

📥 Commits

Reviewing files that changed from the base of the PR and between e771053 and 6bc3433.

📒 Files selected for processing (7)
  • CHANGELOG.md
  • src-tauri/capabilities/default.json
  • src-tauri/src/lib.rs
  • src/App.tsx
  • src/features/settings/categories/AboutCategory.tsx
  • src/stores/settingsStore.ts
  • src/strings.ts
📝 Walkthrough

Walkthrough

StudyVis 1.5.0 adds signed Tauri auto-updates with scheduled background checks, staged installation, restart controls, migrated settings, NSIS packaging, serialized publishing, updater tests, and updated release and installation documentation.

Changes

Automatic update release

Layer / File(s) Summary
Updater configuration and release publishing
.github/workflows/release.yml, package.json, src-tauri/...
Registers the updater, configures signed updater artifacts and NSIS packaging, removes the legacy version command, and updates release publishing.
Updater state machine and settings migration
src/features/updater/updaterStore.ts, src/stores/settingsStore.ts, tests/unit/updater-store.test.ts
Adds update lifecycle state, persistence migration, download/install actions, session gating, and unit coverage.
Runtime scheduling and update controls
src/App.tsx, src/features/updater/..., src/components/UpdateReadyBanner.tsx, src/features/settings/categories/AboutCategory.tsx, src/routes/Home.tsx, src/strings.ts, src/stories/...
Schedules checks, replaces manual version checks, and adds status controls and restart UI.
Release and installation documentation
ARCHITECTURE.md, CHANGELOG.md, INSTALL.md, PLAN.md, README.md, CLAUDE.md
Documents automatic updates, signature verification, NSIS installation, migration guidance, and known macOS permission behavior.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant App
  participant UpdaterBoot
  participant UpdaterStore
  participant TauriUpdater
  participant UpdateReadyBanner

  App->>UpdaterBoot: mount updater scheduler
  UpdaterBoot->>UpdaterStore: checkNow after delay or interval
  UpdaterStore->>TauriUpdater: check and download
  TauriUpdater-->>UpdaterStore: staged update
  UpdaterStore-->>UpdateReadyBanner: ready status
  UpdateReadyBanner->>UpdaterStore: installAndRestart
  UpdaterStore->>TauriUpdater: install and relaunch
Loading

Possibly related PRs

Suggested reviewers: copilot, claude

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: in-app auto-update for X6 and the v1.5.0 release bump.
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
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch feat/auto-update

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.

# Conflicts:
#	CHANGELOG.md
#	src-tauri/capabilities/default.json
#	src/App.tsx

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
src/features/updater/updaterStore.ts (1)

145-148: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove the unused release-notes state and copy. notes is stored in updater state, but neither UpdateReadyBanner nor AboutCategory reads it, and strings.updater.banner.notesCta is unused too. If release notes aren’t going to be surfaced, drop both; otherwise wire them into the update UI.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/updater/updaterStore.ts` around lines 145 - 148, Remove the
unused release-notes state by deleting the notes assignment from the updater
store’s downloading update state, and remove the unused
strings.updater.banner.notesCta copy. Do not add UI wiring; keep the existing
update flow and other state fields unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@PLAN.md`:
- Around line 27-28: Revise the updater privacy wording to distinguish
application data from unavoidable HTTP transport metadata such as source IP,
User-Agent, and request timing. Update PLAN.md lines 27-28 as the canonical
statement, and apply the same narrower claim in INSTALL.md lines 42-46,
README.md lines 46-51, and CHANGELOG.md lines 46-50; avoid claiming that nothing
about the user is sent.

In `@README.md`:
- Around line 78-81: Update the Linux platform note in the README to remove the
stale “not in 1.0” reference and use a current version-neutral statement, such
as indicating that Linux is not currently in the release matrix. Preserve the
existing explanation about WebKitGTK validation and the development build
command.

In `@src/features/settings/categories/AboutCategory.tsx`:
- Around line 113-120: Update the help-text selection around the updater status
logic so updaterCopy.upToDateHelp(__APP_VERSION__) is returned only after a
confirmed up-to-date state, not for idle or error states with a null errorKind.
Add a neutral fallback for unchecked and silently failed states while preserving
the existing checking and attributed check/download error messages.

---

Nitpick comments:
In `@src/features/updater/updaterStore.ts`:
- Around line 145-148: Remove the unused release-notes state by deleting the
notes assignment from the updater store’s downloading update state, and remove
the unused strings.updater.banner.notesCta copy. Do not add UI wiring; keep the
existing update flow and other state fields unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6e63158f-d8d8-4782-afd5-701d94314094

📥 Commits

Reviewing files that changed from the base of the PR and between c2bbc38 and e771053.

⛔ Files ignored due to path filters (2)
  • package-lock.json is excluded by !**/package-lock.json
  • src-tauri/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (24)
  • .github/workflows/release.yml
  • ARCHITECTURE.md
  • CHANGELOG.md
  • CLAUDE.md
  • INSTALL.md
  • PLAN.md
  • README.md
  • package.json
  • src-tauri/Cargo.toml
  • src-tauri/capabilities/default.json
  • src-tauri/src/commands/system.rs
  • src-tauri/src/lib.rs
  • src-tauri/tauri.conf.json
  • src/App.tsx
  • src/components/UpdateReadyBanner.tsx
  • src/features/settings/categories/AboutCategory.tsx
  • src/features/updater/UpdaterBoot.tsx
  • src/features/updater/index.ts
  • src/features/updater/updaterStore.ts
  • src/routes/Home.tsx
  • src/stores/settingsStore.ts
  • src/stories/UpdateReadyBanner.stories.tsx
  • src/strings.ts
  • tests/unit/updater-store.test.ts
📜 Review details
🧰 Additional context used
📓 Path-based instructions (9)
src/**/*.{ts,tsx,css}

📄 CodeRabbit inference engine (CLAUDE.md)

src/**/*.{ts,tsx,css}: All design tokens—including colors, spacing, fonts, radii, shadows, motion, and z-index values—must come from src/design/tokens.ts; do not use raw hex values, arbitrary pixel values, or inline cubic-bezier values outside that file.
Meet WCAG AA contrast requirements for text/background pairings in both themes, never convey information by color alone, and implement reduced motion as a global kill switch with new motion gated by default.

Files:

  • src/App.tsx
  • src/stories/UpdateReadyBanner.stories.tsx
  • src/routes/Home.tsx
  • src/features/updater/UpdaterBoot.tsx
  • src/features/updater/index.ts
  • src/components/UpdateReadyBanner.tsx
  • src/features/settings/categories/AboutCategory.tsx
  • src/strings.ts
  • src/features/updater/updaterStore.ts
  • src/stores/settingsStore.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

src/**/*.{ts,tsx}: Keep toast and notification copy in src/strings.ts; prefer centralized strings for other user-facing text, including JSX text and aria labels, and follow the voice in DESIGN-SYSTEM.md §14.
Treat peer wire formats and identity derivation as cross-version contracts; coordinate changes so older peers continue to work and existing identity/data are not stranded.
The application is local-only: never add telemetry, and never instruct users to paste model files or BIP39 mnemonics into an AI service.
Use Context7 to verify current external library, API, framework, version, CLI, and platform behavior before relying on it; do not assume facts from memory when they are load-bearing.

Files:

  • src/App.tsx
  • src/stories/UpdateReadyBanner.stories.tsx
  • src/routes/Home.tsx
  • src/features/updater/UpdaterBoot.tsx
  • src/features/updater/index.ts
  • src/components/UpdateReadyBanner.tsx
  • src/features/settings/categories/AboutCategory.tsx
  • src/strings.ts
  • src/features/updater/updaterStore.ts
  • src/stores/settingsStore.ts
src/**/*.tsx

📄 CodeRabbit inference engine (CLAUDE.md)

Only import Radix or shadcn primitives from src/components/ui/; application components under src/components/ must compose from ui/, src/design/, and shared utilities, with no reverse imports.

Files:

  • src/App.tsx
  • src/stories/UpdateReadyBanner.stories.tsx
  • src/routes/Home.tsx
  • src/features/updater/UpdaterBoot.tsx
  • src/components/UpdateReadyBanner.tsx
  • src/features/settings/categories/AboutCategory.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: TypeScript must remain strict and pass the repository TypeScript/build checks.
Run the frontend quality gates before committing or opening a PR: build, lint, tests, token checking, string checking, contrast checking, and Storybook accessibility checking (building Storybook first when required).

Files:

  • src/App.tsx
  • src/stories/UpdateReadyBanner.stories.tsx
  • src/routes/Home.tsx
  • src/features/updater/UpdaterBoot.tsx
  • src/features/updater/index.ts
  • src/components/UpdateReadyBanner.tsx
  • tests/unit/updater-store.test.ts
  • src/features/settings/categories/AboutCategory.tsx
  • src/strings.ts
  • src/features/updater/updaterStore.ts
  • src/stores/settingsStore.ts
**/*.{ts,tsx,rs}

📄 CodeRabbit inference engine (CLAUDE.md)

When fixing behavior traceable to an existing issue or improvement, preserve the repository's compact comment tags such as I9, F6, or PR-27 and retain the surrounding rationale needed for safe editing.

Files:

  • src/App.tsx
  • src/stories/UpdateReadyBanner.stories.tsx
  • src/routes/Home.tsx
  • src/features/updater/UpdaterBoot.tsx
  • src/features/updater/index.ts
  • src/components/UpdateReadyBanner.tsx
  • tests/unit/updater-store.test.ts
  • src/features/settings/categories/AboutCategory.tsx
  • src/strings.ts
  • src-tauri/src/commands/system.rs
  • src/features/updater/updaterStore.ts
  • src-tauri/src/lib.rs
  • src/stores/settingsStore.ts
{package.json,package-lock.json,src-tauri/Cargo.toml,src-tauri/Cargo.lock,src-tauri/tauri.conf.json}

📄 CodeRabbit inference engine (CLAUDE.md)

Release version bumps must update all five tracked version locations in lockstep, and CHANGELOG.md must be updated as part of the release.

Files:

  • src-tauri/Cargo.toml
  • package.json
  • src-tauri/tauri.conf.json
src/**/*.stories.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Every primitive and feature component must have a Storybook story, and every Storybook story must pass the axe-core accessibility gate.

Files:

  • src/stories/UpdateReadyBanner.stories.tsx
**/*.test.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Vitest tests run in a Node environment without RTL/jsdom; do not add component tests in *.test.tsx without a deliberate, flagged scope expansion. Component behavior is covered by Storybook and axe-core.

Files:

  • tests/unit/updater-store.test.ts
src-tauri/**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

src-tauri/**/*.rs: Treat Tauri/Rust changes affecting peer wire formats, identity derivation, or persisted data as cross-version compatibility changes; do not break older peers or stored data.
For Rust changes, run cargo test, cargo fmt --check, and cargo clippy before committing or opening a PR.

Files:

  • src-tauri/src/commands/system.rs
  • src-tauri/src/lib.rs
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: scotej/studyvis

Timestamp: 2026-07-20T21:42:37.356Z
Learning: Read the canonical documents relevant to a task—PLAN.md, ARCHITECTURE.md, and DESIGN-SYSTEM.md are the sources of truth; surface conflicts rather than silently deviating.
Learnt from: CR
Repo: scotej/studyvis

Timestamp: 2026-07-20T21:42:37.356Z
Learning: Do not create new documentation files unless explicitly requested; update canonical documentation, CHANGELOG.md, or ISSUES.md only when justified.
Learnt from: CR
Repo: scotej/studyvis

Timestamp: 2026-07-20T21:42:37.356Z
Learning: Add comments only when the reason is non-obvious; identifiers should carry meaning and code should read top-to-bottom.
Learnt from: CR
Repo: scotej/studyvis

Timestamp: 2026-07-20T21:42:37.356Z
Learning: Maintain scope discipline: do not refactor adjacent code while implementing a feature, add abstractions for hypothetical future needs, or expand a bug fix beyond the bug.
Learnt from: CR
Repo: scotej/studyvis

Timestamp: 2026-07-20T21:42:37.356Z
Learning: Use one focused change per commit, with a Conventional Commit subject such as `feat:`, `fix:`, `chore:`, `docs:`, or `ci:`; pull requests are squash-merged.
Learnt from: CR
Repo: scotej/studyvis

Timestamp: 2026-07-20T21:42:37.356Z
Learning: Before committing multi-file or subagent work, run repository-wide formatting; keep the pre-commit gates functioning and run `npm run prepare` if Husky hooks are not firing.
Learnt from: CR
Repo: scotej/studyvis

Timestamp: 2026-07-20T21:42:37.356Z
Learning: Use desktop-control tooling when live-app observation benefits a task; confirm before destructive on-screen actions and state which manual checks were machine-walked versus user-walked.
🔇 Additional comments (25)
.github/workflows/release.yml (1)

51-64: LGTM!

Also applies to: 79-82, 96-102, 115-124, 162-168, 179-183

src-tauri/Cargo.toml (1)

3-3: LGTM!

Also applies to: 41-41

src-tauri/capabilities/default.json (1)

4-12: LGTM!

src-tauri/src/commands/system.rs (1)

7-10: LGTM!

Also applies to: 363-364, 516-524

src-tauri/src/lib.rs (1)

57-61: LGTM!

Also applies to: 85-97, 150-150

src-tauri/tauri.conf.json (1)

4-4: LGTM!

Also applies to: 35-49, 63-67

package.json (1)

4-38: 📐 Maintainability & Code Quality

No change needed.

ARCHITECTURE.md (1)

78-90: LGTM!

Also applies to: 630-630

CHANGELOG.md (2)

31-42: LGTM!

Also applies to: 53-65


21-29: 📐 Maintainability & Code Quality

No release-state mismatch here. v1.5.0 is already treated as the current release across the changelog, README, and version files.

			> Likely an incorrect or invalid review comment.
CLAUDE.md (1)

5-5: LGTM!

INSTALL.md (1)

5-5: LGTM!

Also applies to: 19-24, 30-40, 48-56

PLAN.md (1)

66-66: LGTM!

Also applies to: 164-166

README.md (1)

69-76: LGTM!

Also applies to: 83-86, 220-228

src/stores/settingsStore.ts (1)

75-80: LGTM!

Also applies to: 151-155, 182-186, 227-227, 586-586, 654-663, 873-876

tests/unit/updater-store.test.ts (1)

1-289: LGTM!

src/App.tsx (1)

14-14: LGTM!

Also applies to: 54-54

src/features/updater/UpdaterBoot.tsx (1)

30-62: LGTM!

src/features/updater/index.ts (1)

1-9: LGTM!

src/features/settings/categories/AboutCategory.tsx (1)

27-44: LGTM!

Also applies to: 79-111, 153-170

src/components/UpdateReadyBanner.tsx (1)

1-109: LGTM!

src/routes/Home.tsx (1)

22-22: LGTM!

Also applies to: 455-458

src/strings.ts (1)

1248-1258: LGTM!

Also applies to: 1577-1617

src/stories/UpdateReadyBanner.stories.tsx (1)

1-30: LGTM!

src/features/updater/updaterStore.ts (1)

55-60: 🩺 Stability & Availability

No missing updater wiringsidecar_stop and system_relaunch_app are registered in src-tauri/src/lib.rs, and src-tauri/capabilities/default.json grants updater:default to the main window, so the restart flow has the needed IPC access.

			> Likely an incorrect or invalid review comment.

Comment thread PLAN.md
Comment on lines +27 to +28
- **Outbound data beyond P2P + Nostr signaling**: zero, with one explicit carve-out — **auto-update** (X6, ON by default, Settings → About). While it is on, the app fetches `latest.json` from the public GitHub Releases page on launch and every 6 hours, and downloads the installer when a newer version exists. Every request is unauthenticated and carries no identifiers, no query parameters, and no payload; nothing about the user, their friends, or their sessions is transmitted, and background failures are silent. Turning the toggle off restores literal zero outbound — no check is scheduled and none is made. No telemetry, no crash auto-uploads. Crash logs stay local with a manual "Share Log" button.
- *This widened in v1.5.0.* Before it, the carve-out was an opt-in, OFF-by-default tag comparison the user had to visit Settings to trigger. The exchange is deliberate: friends installing by hand meant security fixes landed only when someone remembered to check. The privacy properties that mattered — no identifiers, no payload, user-disableable — are unchanged.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use precise privacy wording for updater requests.

The app can avoid sending application identifiers, friend/session data, and payloads, but GitHub still receives ordinary HTTP metadata such as source IP, User-Agent, and timing.

  • PLAN.md#L27-L28: make the canonical outbound-data statement distinguish app data from transport metadata.
  • INSTALL.md#L42-L46: replace “Nothing about you is sent” with the narrower claim.
  • README.md#L46-L51: apply the same precise wording.
  • CHANGELOG.md#L46-L50: keep the release note consistent with the canonical privacy statement.
📍 Affects 4 files
  • PLAN.md#L27-L28 (this comment)
  • INSTALL.md#L42-L46
  • README.md#L46-L51
  • CHANGELOG.md#L46-L50
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@PLAN.md` around lines 27 - 28, Revise the updater privacy wording to
distinguish application data from unavoidable HTTP transport metadata such as
source IP, User-Agent, and request timing. Update PLAN.md lines 27-28 as the
canonical statement, and apply the same narrower claim in INSTALL.md lines
42-46, README.md lines 46-51, and CHANGELOG.md lines 46-50; avoid claiming that
nothing about the user is sent.

Source: Learnings

Comment thread README.md
Comment on lines 78 to 81
**Linux** — not in 1.0. WebKitGTK's `getDisplayMedia` support was not
validated; Linux returns when the V0 sanity pass is re-run on it. If
you want to try the dev build today, clone the repo and run
`npm run tauri dev`.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Update the stale Linux version reference.

This says Linux is “not in 1.0,” but the document now describes v1.5.0 as the current release. Say Linux is not currently in the release matrix or otherwise use a current version-neutral statement.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` around lines 78 - 81, Update the Linux platform note in the README
to remove the stale “not in 1.0” reference and use a current version-neutral
statement, such as indicating that Linux is not currently in the release matrix.
Preserve the existing explanation about WebKitGTK validation and the development
build command.

Comment on lines +113 to +120
const help =
status === 'checking'
? updaterCopy.checkingHelp
: errorKind === 'check'
? strings.updater.errors.checkFailed
: errorKind === 'download'
? strings.updater.errors.downloadFailed
: updaterCopy.upToDateHelp(__APP_VERSION__)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

"Up to date" copy is shown for un-checked and silently-failed states.

The final else returns upToDateHelp(__APP_VERSION__) whenever status isn't checking/downloading/ready and there's no attributed errorKind. That also covers status === 'idle' (before the first scheduled check runs) and status === 'error' with errorKind === null (a silent background check/download failure), so the row asserts the user is on the latest version without ever confirming it.

Gate the up-to-date message on the actual state:

🐛 Proposed fix
     const help =
       status === 'checking'
         ? updaterCopy.checkingHelp
         : errorKind === 'check'
           ? strings.updater.errors.checkFailed
           : errorKind === 'download'
             ? strings.updater.errors.downloadFailed
-            : updaterCopy.upToDateHelp(__APP_VERSION__)
+            : status === 'upToDate'
+              ? updaterCopy.upToDateHelp(__APP_VERSION__)
+              : copy.version.help

idle/silent-error then falls back to neutral copy while the "Check now" button still invites an explicit check. Adjust the neutral string as fits the voice.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/settings/categories/AboutCategory.tsx` around lines 113 - 120,
Update the help-text selection around the updater status logic so
updaterCopy.upToDateHelp(__APP_VERSION__) is returned only after a confirmed
up-to-date state, not for idle or error states with a null errorKind. Add a
neutral fallback for unchecked and silently failed states while preserving the
existing checking and attributed check/download error messages.

@scotej
scotej merged commit 4bffa90 into main Jul 20, 2026
3 of 4 checks passed
@scotej
scotej deleted the feat/auto-update branch July 20, 2026 21:52
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