Repository navigation
OTA and update UX: nightly installs, update now, banners, honest outcomes, clock trust, board report - #3
Merged
Conversation
… screen Release channel updates no longer install the moment they are downloaded. The channel check verifies the package, checks it would install, and hands it to a new update scheduler (internal/updates), which keeps it in /var/lib/musallahboard/updates and installs everything waiting as one batch in the board's install window: update_time (default 23:00, in the content's time zone) for four hours. A board with no app installs at once. Waiting updates survive restarts and are dropped if they stop applying. /api/local/status gains "updates" (what waits and when it installs) and the SSE stream an "updates" event, so the board app can put it on the ticker. Install now: `sudo musallahboard-agent update now` (a request file the daemon polls, like the inbox) and the update.install_now remote command both check the channels and install at once. `status` shows what waits. The update screen switch is now a dip to black: the agent fades the page on screen to black over CDP before each navigation, and the update screen fades in from black on load. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VUxfdFFUkL7SmAEUvUzspy
The remote command runs under its deadline, which the admin portal sets to 30 s for most commands. The channel check (the download) still honours it; the install that follows now always finishes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VUxfdFFUkL7SmAEUvUzspy
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
This was referenced Sep 25, 2026
Every batch now ends in one notice (internal/notice): a tone, a headline
and up to three plain lines ("Board app 2.1.0", "The board already has
newer content"), never a file name. Technical reasons move to a result's
new `detail`.
- The update screen goes up only when something is about to install.
Otherwise a person at the board sees a banner over the running board
(the new `notice` SSE event): "Checking updates" when a batch starts,
then "Already up to date", "Update not installed" and so on.
- Older content, app or agent is `outdated`, not `rejected`: an old stick
at a board that has synced since is not a failure.
- The USB helper tells the board what it is doing through notice files in
the inbox: "Reading USB stick", "Can't read this USB stick" (and why),
"No updates on this USB stick", "USB updates are turned off".
- Agent updates (internal/agentupdate): the new agent shows the batch's
outcome at startup; after a rollback the previous agent shows why; a
refusal by the root updater, which used to leave "Restarting" up for
good, is noticed and shown, and the inbox resumes. The updater now writes
its outcome before restarting the previous agent. Each outcome is shown
once, and a batch queued behind an agent update shares its screen.
- The update screen's done state takes a tone and wrapping lines, with a
drawn ring-and-mark for problems; the upload page, `import` and
`update now` use the same wording. /api/local/status gains
lastAgentUpdate, which `status` prints.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VUxfdFFUkL7SmAEUvUzspy
The clock floor stops the clock going backwards but cannot say it is right. The keeper now reports where the time comes from: NTP (timesyncd's synchronized flag), a fitted RTC, a laptop's time since this boot (a verified upload that set or confirmed it, keyed to the kernel boot id), the first three minutes after boot, or nothing. `clock` in /api/local/status carries it, the upload page and `status` show it, and the board app puts up a note when nothing has confirmed the time. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VUxfdFFUkL7SmAEUvUzspy
Heartbeats now carry `telemetry.board` (localserver.BoardReport): the board app version, the installed content and days left, software waiting for the install window, the last agent self-update outcome, clock trust and the last sync error. The backend keeps the latest per device for the admin portal. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VUxfdFFUkL7SmAEUvUzspy
The splash's footer said "MusallahBoard v2.0" in packaging/waiting.html and something else in setup.sh's inlined copy, which had already drifted. The agent now embeds packaging/waiting.html and installs it with `musallahboard-agent splash install`: setup.sh calls that instead of its heredoc, and the self-updater re-runs it after each successful update. The footer shows "MusallahBoard · agent <version>", pushed by the running agent with the address, so it is right after a self-update. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VUxfdFFUkL7SmAEUvUzspy
- The upload page no longer says "Update complete" when an agent update is only staged: the response says "Restarting to finish the update", lists what installs after the restart (queued results are no longer hidden), and the page follows the restart until the new agent answers, or reports a rollback, a refusal, or a board that does not come back. - Uploads take up to 16 packages, like a USB stick, and the page says so. - The USB helper unmounts the stick before handing its packages to the daemon, and every USB outcome carries a footer, "You can remove the USB stick", on the update screen and the banner. - updates.Info reports autoUpdate, lastCheckAt and lastCheckError, so "no update waiting" can be told apart from "cannot check". - `update now` no longer prints "up to date" after a failed check; it says nothing was installed and exits 1. - /api/local/status and the board report carry servicePort and usbImport, and the "waiting for the board app" page offers only the routes this board accepts. The board report's content carries its time zone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VUxfdFFUkL7SmAEUvUzspy
- Crash loops: the agent's unit never gives up restarting, backing off from 5 s to 2 minutes, and the kiosk opens a local "MusallahBoard is starting" page (starting.html, embedded and installed with the splash) that waits for the agent's new /_mb/alive.gif before moving to the board, so Chromium's "refused to connect" page no longer shows. - enroll: plain output instead of JSON logs, requires root, refuses to re-enroll an enrolled board without --force (the old device would be orphaned in the portal), and says what happens next. - status: what the screen is showing (asked over CDP), whether the board is connected to LensBridge (the WebSocket client now tracks it), which offline routes are on, update-check failures, and readable times. - The normal setup prepares the ethernet service port (left off), so `sudo musallahboard-agent service-port on` works without a local copy of setup.sh; the RTC still needs `curl ... | bash -s -- --service-port --rtc`, which the messages now give in full. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VUxfdFFUkL7SmAEUvUzspy
- Prompts read from /dev/tty, so `curl ... | bash` asks instead of silently taking defaults (MB_ASSUME_YES=1 or no terminal still takes them). - No personal default for the admin user: it must be given, and is checked to be a valid username; the SSH key is checked to look like one, and the messages say why it is needed. - README: run setup.sh as a user with sudo (it refuses root), the enroll command in the form the portal gives, the service port turned on with the agent CLI, the RTC re-run spelled out, and USB sticks removed when the screen says so rather than at "Update complete". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VUxfdFFUkL7SmAEUvUzspy
…ours - Update screen: the working caption, the outcome lines and the footer at 2.6vmin (about 28px at 1080p, up from 19px), and "Please keep MusallahBoard plugged in" at 1.8vmin: read from across a room. - The enrollment splash moves from its old green to the board's navy and gold (like the update screen and the starting page), sized in vmin, and once it knows its address says what to do next: SSH in and run the enroll command the admin portal gives. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VUxfdFFUkL7SmAEUvUzspy
TestRefreshTriggersDebouncedSync gave start-up sync, the refresh
WebSocket dial and the 50 ms debounce 400 ms in total, which a busy CI
runner under -race sometimes exceeds ("1 content syncs, want 2"). It now
waits up to 10 s for the second sync, then long enough for an unfolded
third to show, and still fails if the burst is not folded into one.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VUxfdFFUkL7SmAEUvUzspy
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Nightly OTA updates. Release channel updates wait in
/var/lib/musallahboard/updates/and install as one batch in the install window:update_time(default23:00, in the content's time zone) for 4 hours./api/local/statushasupdates(now includingautoUpdate,lastCheckAtandlastCheckError), and SSE sends anupdatesevent, which drives the ticker line.Install now.
sudo musallahboard-agent update nowand theupdate.install_nowremote command check the channels and install at once. The command's deadline covers only the download. After a failed check the command no longer says "up to date".Plain outcomes, screen or banner. Every batch ends in one notice (
internal/notice): a tone, a headline, up to three plain lines, and an optional footer. File names never appear; technical reasons go in a result's newdetail.noticeSSE event).outdated, notrejected.USB feedback.
Truthful agent updates (
internal/agentupdate):Upload page.
Clock trust, board report, fades.
clockin the status gives the time's source and whether it can be trusted.telemetry.board, including the offline routes and the update-check status.Pre-pilot audit fixes
starting.htmlthat waits for the agent (/_mb/alive.gif) before moving to the board, so Chromium's "refused to connect" page no longer shows. Checked in real Chromium.servicePortandusbImport).enroll: plain output, requires root, refuses to re-enroll without--force, and says what happens next.status: shows what the screen is showing, the LensBridge connection, the offline routes, update-check failures, and readable times.setup.sh:/dev/tty, socurl | bashasks its questions.service-port onworks without a local copy ofsetup.sh.musallahboard-agent splash install, refreshed after each self-update), in the board's navy and gold.Test plan
go test ./...,go test -raceon the new packages, andgo vet ./...all pass.updates,notice,agentupdate, the importer (banner vs screen,Summarize, USB notices and footer),usbimport(a notice per failure case),selfupdate(the outcome is written before the restart),clock(Info),localserver(BoardReport, no-app routes) andsplash(version push).systemd-analyze verifypasses on the new agent unit.setup.shprompt helper was tried both with and without a terminal.Companion PRs: LensBridge/MusallahBoard#3, LensBridge/LensBridgeBackend#20, LensBridge/LensBridgeFrontend#10.
Note:
curl | bashinstalls fetchsetup.shfrommain, so the setup fixes reach new boards oncedevelopis merged intomain.🤖 Generated with Claude Code
https://claude.ai/code/session_01VUxfdFFUkL7SmAEUvUzspy