Skip to content

emrg: upgrade banner — in-memory run version vs live installed_version, dedicated upgrade event (rant 2026-08-21T14:38:27) - #917

Merged
argszero merged 1 commit into
masterfrom
feature/upgrade-banner-run-vs-installed
Aug 21, 2026
Merged

emrg: upgrade banner — in-memory run version vs live installed_version, dedicated upgrade event (rant 2026-08-21T14:38:27)#917
argszero merged 1 commit into
masterfrom
feature/upgrade-banner-run-vs-installed

Conversation

@argszero

Copy link
Copy Markdown
Owner

Upgrade banner — in-memory run version vs live installed_version + dedicated upgrade event

Rant 2026-08-21T14:38:27: the banner judgment model had two logic flaws:

  1. previous-version.txt residue — the daemon's pong current_version
    read version.txt live and previous_version read previous-version.txt.
    The file stays at the pre-upgrade version forever (e.g. 0.2.61), so every
    launch judged "version changed" and re-showed the banner even with no new
    release.
  2. Live read hides "pending restart"current_version reading the file
    in real time meant that after a daemon restart the GUI saw the new version
    and could not distinguish "already applied" from "needs restart".

New model

  • daemon.py: version.txt read once at startup into self._run_version
    (the code version this daemon process actually runs, fixed for its
    lifetime). Pong now returns:
    • current_version = in-memory _run_version (actually running)
    • installed_version = live disk read (upgrade agent may have updated it)
    • previous_version removed — previous-version.txt is no longer part of
      the judgment (the file may still be written by the upgrade agent).
  • main.js: init still passes current_version to the renderer as the
    lastKnownVersion baseline; the 15s heartbeat (from emrg: GUI daemon heartbeat — periodic liveness probe + active reconnect (rant 2026-08-21T12:44:34) #912) compares
    pong.installed_version !== pong.current_version (and installed non-empty)
    and emits a dedicated upgrade event (not reusing status, avoiding
    handleStatus side-effect spam) with {current_version, installed_version}.
  • renderer app.js: handleEvent gains case "upgrade"
    maybeShowUpgradeBanner(installed_version, current_version) — text
    "upgraded from {current} to {installed} — restart to apply" with the
    existing lastKnownVersion dedup (same installed version shown once).

Self-consistency: no upgrade (run==installed) → no banner; upgrade installed
but not restarted (run 0.2.61 vs disk 0.2.62) → banner; after restart-to-apply
(new daemon, run==installed) → no banner; dismiss + relaunch GUI without
restarting the daemon → banner again (correct: not yet applied); further
upgrade 0.2.63 → banner again. No cross-session persistence needed.

Tests / verification

  • tests/test_daemon.py: test_pong_includes_current_version asserts both
    current_version and installed_version; new
    test_pong_run_vs_installed_version verifies _run_version is fixed at
    startup while _current_installed_version() reflects a later disk write,
    and that pong no longer carries previous_version.
  • renderer.smoke.test.js: banner test rewritten for the upgrade event —
    positive (installed≠run → from→to shown), negative (already shown version →
    hidden), and a new negative asserting status no longer triggers the
    banner; source-level asserts case "upgrade" and the heartbeat's
    sendToRenderer("upgrade") / pong.installed_version.
  • Local: Python pytest 994 passed + 1 skipped (995 collected), GUI npm test
    257 (249 pass + 8 skipped), node --check main.js + app.js OK, import +
    CLI OK. Test counts unchanged (Agent.md stays valid).

…n, dedicated upgrade event (rant 2026-08-21T14:38:27)

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

✅ LGTM — cycle

Fresh review of the upgrade-banner judgment refactor (rant 2026-08-21T14:38:27):

  • Root causes addressed: (1) previous-version.txt residue previously made every launch re-show the banner; (2) live current_version read hid the "pending restart" state.
  • daemon: self._run_version captured once at startup; pong returns current_version (in-memory run) + installed_version (live disk); _previous_installed_version() and pong previous_version removed.
  • main.js: init baseline unchanged; heartbeat compares installed_version !== current_version → dedicated upgrade event (no status reuse, no handleStatus spam).
  • app.js: case "upgrade"maybeShowUpgradeBanner(installed, run) with from→to text + lastKnownVersion dedup; banner logic removed from handleStatus.
  • Tests cover all three states (show on installed≠run, hide on already-shown, status no longer triggers) + daemon run-vs-installed fixed/live semantics; no previous_version leakage anywhere.
  • Verified locally: pytest 994 passed + 1 skipped (995 collected), GUI 257 (249+8), node --check main.js + app.js OK, import + CLI OK.

1/3.

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

✅ LGTM — cycle

2nd review (head ca93102, MERGEABLE/CLEAN, CI test + test-windows PASS):

  • Fresh local verification on this branch: pytest 994 passed + 1 skipped (995 collected), GUI npm test 257 (249 pass / 0 fail / 8 skipped), import + CLI OK.
  • daemon.py: _run_version captured once at startup (fixed for process lifetime); pong now returns current_version = in-memory run version + installed_version = live disk read; previous_version removed from the judgment (previous-version.txt no longer part of the model — addresses the residue flaw).
  • main.js: init passes current_version as lastKnownVersion baseline; 15s heartbeat compares installed_version ≠ current_version → dedicated 'upgrade' event (not reusing 'status', avoiding handleStatus side-effect spam).
  • renderer: handleEvent case 'upgrade' → maybeShowUpgradeBanner(installed, current) with lastKnownVersion dedup.
  • Self-consistency matrix is correct: run==installed → no banner; installed≠run → banner; after restart-to-apply run==installed → gone; dismiss+relaunch without daemon restart → banner again (correct).

2/3.

@argszero argszero left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

✅ LGTM — cycle

3rd review (head ca93102, CI test + test-windows PASS on run 32457292037):

  • Fresh local verification: Python pytest 994 passed + 1 skipped (995 collected), GUI npm test 257 (249 pass + 8 skipped), node --check main.js + app.js OK, import OK.
  • Model verified sound: self._run_version fixed at daemon startup; pong current_version = run version, installed_version = live disk; heartbeat emits dedicated upgrade event on mismatch; renderer case "upgrade" shows from→to with lastKnownVersion dedup; previous_version fully removed from judgment path.
  • New daemon test proves _run_version stays fixed while the disk read reflects a later upgrade, and pong carries no previous_version.

3/3 — merging.

@argszero
argszero merged commit 65c6b16 into master Aug 21, 2026
2 checks passed
@argszero
argszero deleted the feature/upgrade-banner-run-vs-installed branch August 21, 2026 07:17
argszero added a commit that referenced this pull request Aug 21, 2026
Co-authored-by: EMRG Evolution <emrg@argszero.dev>
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