Show a lobby notice when a newer release is out

Merged
LJ
16h ago
+1480-107

The macOS release binary can now tell the candidate when the rolling latest release is a newer build, in the scope agreed on #543.

How it is enabled: CODETRIAL_UPDATE_CHECK=true in config/codetrial.env.local. It is off by default, and documented in docs/install.md, the README configuration table and config/codetrial.env.example.

What it does: the server asks GitHub (GET /repos/sysprog21/codetrial/releases/tags/latest) which commit latest names, caches the answer for ten minutes (kept even when the lobby that asked goes away mid-request), and answers /api/update with whether that differs from the build. The lobby asks when it loads, which covers both starting the binary and coming back from an interview, since leaving an interview navigates to /, and on every hour it stays open. An interview replaces the lobby page, so nothing is checked during one. A newer release shows a card in the lobby's corner with both commits and a link to the release page; its message is a status line, written a frame after the card shows so it is announced without taking focus. A later answer that no longer names a newer release, or a release dismissed in another tab, takes the card down. Dismissing it stores that release's commit and hides the card until a different one is named. The page's connect-src is unchanged.

When nothing is compared: the setting is off, the build is not macOS, CODETRIAL_BUILD_COMMIT did not come from GITHUB_SHA, or the server was started with --no-update-check, which the desktop app passes because it is published as desktop-latest and latest never names its server. build.rs now records the last as CODETRIAL_RELEASE_COMMIT, empty for a local build. The server then answers enabled: false, asks GitHub nothing, and the lobby stops asking. Every GitHub failure (no network, an error status or rate limit, the 404 while latest is republished, a body without a full commit) answers "no update" and shows nothing, and the lobby keeps checking on the hour; a lobby that cannot reach its own server stops until the next load.

/api/update answers without a session, like /api/session: both commits are public, and the cache means a caller cannot make the server ask GitHub more often.

Tests: tests/unit/web/update.rs runs the lookup against a stub GitHub for the matching-commit, differing-commit and failed-check cases (500, 403, 429, 404, a missing, short or non-hex target_commitish, a closed port), for the cache, and for a lookup whose caller went away mid-request; tests/web/update.rs goes through the router and shows a server with the check off makes no request to the stub; tests/config.rs pins the opt-in, platform and CI-commit rule, and checks that a CI build records its GITHUB_SHA as the release commit, which fails with build.rs recording nothing; tests/unit/bin.rs and desktop/tests/unit/server.rs cover --no-update-check and the launcher passing it; tests/browser/update-notice.test.js covers what the lobby shows, when its message is written, following a later release, taking it down without moving focus that was elsewhere, dismissing, the hourly schedule staying single across a restored page, and the stops, plus one Chromium run of the real lobby by keyboard. Each new assertion was checked to fail with its change reverted. The route allowlists in tests/web/routes.rs and tests/web/accounts.rs list the new route.

Validation, on the single commit rebased onto 38d53a7: ./scripts/test.sh rust, ./scripts/test.sh portable and the three browser shards pass locally, cargo clippy --all-targets -- -D warnings is clean, and cargo test in desktop/ passes. cargo-mutants was not available here, so the four mutants the gate missed, and the new flag's comparison and override, were applied by hand: each fails a test. The same was done for every new branch in web/update-notice.js, which the mutation gate does not cover.

Manual check on an Apple Silicon Mac, against the real GitHub API, with builds from this branch:

  1. Older build, check on: built with GITHUB_SHA set to an older commit of main and CODETRIAL_UPDATE_CHECK=true. The notice shows both commits, and its link opens the release page.

VIDEO 1 HERE <<<

https://github.com/user-attachments/assets/258fe309-232e-4f3d-9b33-513e5a5f720a

  1. Dismissed: after Dismiss and a reload, the notice stays hidden.

VIDEO 2 HERE <<<

https://github.com/user-attachments/assets/c8f6073a-45a2-4c5e-8f08-8fe85828b1d2

  1. Current build: no notice shows when the build is the one latest names.
    • Read the commit latest names: git ls-remote https://github.com/sysprog21/codetrial refs/tags/latest.
    • With CODETRIAL_UPDATE_CHECK=true still set, start the server built from that commit: GITHUB_SHA=<that commit> make web.
    • Remove codetrial:updateDismissed from the page's local storage, so the dismissal from step 2 does not hide the result, and reload the lobby.
    • No notice shows, and curl -s http://127.0.0.1:3000/api/update answers {"available":false,"enabled":true}.

VIDEO 3 HERE <<<

https://github.com/user-attachments/assets/ef631446-8660-4057-8ed4-3ad4d120730d

  1. Check off: nothing is compared, even for an older build, when the setting is absent.
    • Remove CODETRIAL_UPDATE_CHECK=true from config/codetrial.env.local.
    • Start the server built from the older commit of step 1: GITHUB_SHA=<older commit> make web.
    • Reload the lobby: no notice shows, and curl -s http://127.0.0.1:3000/api/update answers {"enabled":false}.

VIDEO 4 HERE <<<

https://github.com/user-attachments/assets/43245dbf-fa50-4f37-a864-16cb8e7b3ee9

Close #543


Summary by cubic

The macOS release binary now shows a lobby notice when the rolling latest release names a newer build, behind CODETRIAL_UPDATE_CHECK=true (off by default). Closes #543.

How it works

  • The server asks GitHub which commit latest names, caches the answer for ten minutes, and answers /api/update; the lobby checks on load and hourly.
  • A newer release shows a card in the lobby corner with both commits and a link to the release page; dismissing it hides it until a different release is named.
  • The status line is written a frame after the card shows so screen readers announce it, and a later check that names no newer release takes the card down.
  • Every GitHub failure answers "no update" and shows nothing, and the page's connect-src is unchanged.

When nothing is compared

  • The check runs only in a macOS build CI made: build.rs records the GITHUB_SHA commit as CODETRIAL_RELEASE_COMMIT, and other builds answer enabled: false and ask GitHub nothing.
  • The desktop app always passes --no-update-check, overriding its config file, because it is published as desktop-latest.

Manual check on an Apple Silicon Mac, against the real GitHub API, with builds from this branch:

  1. Older build, check on: the notice shows both commits, and its link opens the release page.
  2. Dismissed: after Dismiss and a reload, the notice stays hidden.
  3. Current build: no notice shows when the build is the one latest names.
  4. Check off: nothing is compared, even for an older build, when the setting is absent.