system: a what's-new sheet after an update #106

Merged
nalum merged 6 commits from feat/whats-new into main 2026-08-16 19:44:49 +00:00
Owner

Stacked on #104 (merge order #101 → #102 → #103 → #104 → this). Closes #105.

The gap. The server quietly becomes a new version under the web app, and a new APK just opens onto the same screens. The release notes exist — the pipeline publishes them on the forge — but nobody sees them unless an admin goes looking.

The server serves the notes. The web canon forbids external requests, and phones have no business talking to the forge either. SystemService/ReleaseNotes returns the running server version plus the release entry (title, body, url) for a requested tag — empty means the server's own. The per-tag endpoint is derived from the existing update feed (releases/latest → releases/tags/<tag>), with CheckForUpdate's timeout, body cap and URL sanitising, and entries are cached in memory per tag: releases are immutable, so a hit never expires, while a miss is not cached and retries. Every signed-in role may ask (matrix entry: Admin, Member, Child) — release notes are household news, not admin business. A tag with no published entry answers found: false honestly, which is what a dev build's own version gets.

Web. After sign-in, the shell compares the server version against a per-profile seen-mark in device localStorage (deliberately not the synced prefs — "seen" is a fact about this screen, and it stays clear of the ADR-0029 whole-message write). Different → a Sheet ("shown-once content opens in a Sheet") with the notes, pre-wrapped, plus a link to the release page. A brand-new profile records the version silently — a first visit is not an update — and the seen-mark is written only after the sheet actually shows, so an unreachable feed retries next open instead of losing the notes.

Android. The same dance against BuildConfig.VERSION_NAME and a device preference, fetching the notes for the APK's own version through the new RPC, shown as a bottom sheet from the signed-in shell.

Verified against the live deploy: a member (not admin) fetched the real published v1.5.0 notes through the proxy — title and the pipeline's markdown body came back intact — and the dev build's own version answered found: false, so debug builds greet nobody. Unit specs cover the fetch, the cache surviving a dead feed, the not-found answer and the not-a-version refusal. make check and the Android unit tests are green; on-device sheet verification pending with the rest of the stack.

Stacked on #104 (merge order #101 → #102 → #103 → #104 → this). Closes #105. **The gap.** The server quietly becomes a new version under the web app, and a new APK just opens onto the same screens. The release notes exist — the pipeline publishes them on the forge — but nobody sees them unless an admin goes looking. **The server serves the notes.** The web canon forbids external requests, and phones have no business talking to the forge either. `SystemService/ReleaseNotes` returns the running server version plus the release entry (title, body, url) for a requested tag — empty means the server's own. The per-tag endpoint is derived from the existing update feed (`releases/latest` → `releases/tags/<tag>`), with `CheckForUpdate`'s timeout, body cap and URL sanitising, and entries are cached in memory per tag: releases are immutable, so a hit never expires, while a miss is not cached and retries. Every signed-in role may ask (matrix entry: Admin, Member, Child) — release notes are household news, not admin business. A tag with no published entry answers `found: false` honestly, which is what a dev build's own version gets. **Web.** After sign-in, the shell compares the server version against a per-profile seen-mark in device localStorage (deliberately not the synced prefs — "seen" is a fact about this screen, and it stays clear of the ADR-0029 whole-message write). Different → a Sheet ("shown-once content opens in a Sheet") with the notes, pre-wrapped, plus a link to the release page. A brand-new profile records the version silently — a first visit is not an update — and the seen-mark is written only after the sheet actually shows, so an unreachable feed retries next open instead of losing the notes. **Android.** The same dance against `BuildConfig.VERSION_NAME` and a device preference, fetching the notes for the APK's own version through the new RPC, shown as a bottom sheet from the signed-in shell. Verified against the live deploy: a member (not admin) fetched the real published v1.5.0 notes through the proxy — title and the pipeline's markdown body came back intact — and the dev build's own version answered `found: false`, so debug builds greet nobody. Unit specs cover the fetch, the cache surviving a dead feed, the not-found answer and the not-a-version refusal. `make check` and the Android unit tests are green; on-device sheet verification pending with the rest of the stack.
The release notes exist on the forge, but the web canon forbids
external requests and phones should not talk to the forge either —
the server is the household's one door. ReleaseNotes returns the
running version plus the release entry for a requested tag (empty =
the server's own), derived from the existing update feed with the
same timeout, body cap and URL sanitising as CheckForUpdate, cached
per tag in memory: releases are immutable. Every signed-in role may
ask — release notes are household news, not admin business.
Issue #105.
The server quietly becomes a new version under the app; now the first
open after a deploy greets each member once with that version's
release notes, served through the new ReleaseNotes RPC. The seen-mark
lives in the namespaced device prefs and is written only after the
sheet actually shows, so an unreachable feed retries next open. A
brand-new profile records the version silently — a first visit is
not an update. Issue #105.
feat(android): what's-new sheet after an app update
Some checks failed
android / build (pull_request) Has been cancelled
android / report (pull_request) Has been cancelled
check / commits (pull_request) Has been cancelled
check / go (pull_request) Has been cancelled
check / report (pull_request) Has been cancelled
check / web (pull_request) Has been cancelled
8d5d0dbde5
The first open after installing a new APK greets the member once with
that version's release notes, fetched for the app's own version
through ReleaseNotes — the phone never talks to the forge. The
seen-mark is a device preference, written only after the sheet shows.
Issue #105.
feat(web): show the release notes from the admin version check
Some checks failed
android / report (pull_request) Has been cancelled
check / commits (pull_request) Has been cancelled
check / go (pull_request) Has been cancelled
check / report (pull_request) Has been cancelled
check / web (pull_request) Has been cancelled
android / build (pull_request) Has been cancelled
6c73a2da23
When the version check finds a newer release, the admin card now
opens the same release-notes sheet the what's-new popup uses —
fetched through ReleaseNotes for the latest tag — instead of only
linking out to the forge. The sheet itself still carries the link.
Issue #105 follow-up.
Author
Owner

Grew by one commit: the admin version check now opens the same release-notes sheet. When the check finds a newer release, the card offers Show the release — it fetches the latest tag through ReleaseNotes and opens the shared ReleaseNotesSheet (extracted from the what's-new popup), which still carries the forge link. A failed fetch says so and falls back to the plain link. Verified live: the dev cluster (a pre-release of v1.5.0) reports v1.5.0 available and fetches its notes — the exact path the button drives.

Grew by one commit: the admin version check now opens the same release-notes sheet. When the check finds a newer release, the card offers **Show the release** — it fetches the latest tag through `ReleaseNotes` and opens the shared `ReleaseNotesSheet` (extracted from the what's-new popup), which still carries the forge link. A failed fetch says so and falls back to the plain link. Verified live: the dev cluster (a pre-release of v1.5.0) reports v1.5.0 available and fetches its notes — the exact path the button drives.
fix(web): format the version card and render the notes' markdown
Some checks failed
check / commits (pull_request) Successful in 7s
android / report (pull_request) Has been cancelled
check / report (pull_request) Has been cancelled
check / web (pull_request) Has been cancelled
android / build (pull_request) Has been cancelled
check / go (pull_request) Has been cancelled
320c3cdd1c
The two buttons stack awkwardly; they now share one actions row. The
release notes rendered as raw markdown text — a small hand-rolled
renderer (headings, bullets, bold, inline code; text nodes only, no
raw HTML) formats them in the sheet, within the no-new-dependencies
canon. Android's sheet gets the same line-based treatment.
fix(web): clickable changelog links in the release notes
Some checks failed
check / commits (pull_request) Successful in 10s
android / report (pull_request) Has been cancelled
check / report (pull_request) Has been cancelled
check / web (pull_request) Has been cancelled
android / build (pull_request) Has been cancelled
check / go (pull_request) Has been cancelled
c43b0c195d
The notes' closing 'Full changelog' URL rendered as dead text. Both
renderers now make [text](url) and bare http(s) URLs links — anchors
on the web (text nodes only, http(s) schemes only), tappable
LinkAnnotation spans in the accent colour on Android.
nalum force-pushed feat/whats-new from c43b0c195d
Some checks failed
check / commits (pull_request) Successful in 10s
android / report (pull_request) Has been cancelled
check / report (pull_request) Has been cancelled
check / web (pull_request) Has been cancelled
android / build (pull_request) Has been cancelled
check / go (pull_request) Has been cancelled
to d003d037fc
All checks were successful
check / commits (pull_request) Successful in 8s
check / go (pull_request) Successful in 6m45s
check / report (pull_request) Successful in 3s
check / web (pull_request) Successful in 10m59s
android / build (pull_request) Successful in 25m5s
android / report (pull_request) Successful in 5s
check / commits (push) Successful in 6s
check / go (push) Successful in 5m18s
check / report (push) Has been skipped
check / web (push) Successful in 9m25s
android / build (push) Successful in 19m10s
android / report (push) Has been skipped
tag / tag (push) Successful in 17m47s
release / binaries (push) Successful in 10m32s
release / docs (push) Successful in 15m0s
release / android (push) Successful in 18m48s
release / image (push) Successful in 15m55s
release / manifests (push) Successful in 6m54s
release / module (push) Successful in 7m46s
release / release (push) Successful in 14s
2026-08-16 16:29:44 +00:00
Compare

Test report

Suite Tests Result Skipped
Unit 1363 ✅ pass 1
Integration 83 ✅ pass —

Coverage: 28.2%

Updated by the check workflow · commit d003d037fc

<!-- ci-test-report --> ## Test report | Suite | Tests | Result | Skipped | | --- | --: | --- | --: | | Unit | 1363 | ✅ pass | 1 | | Integration | 83 | ✅ pass | — | **Coverage:** 28.2% <sub>Updated by the check workflow · commit d003d037fc0f13b43c70c47ad72001a152edd5ab</sub>

Android test report

Suite Tests Result Skipped
Unit (debug) 31 ✅ pass 0

Coverage: 2.4% of lines

Updated by the android workflow · commit d003d037fc

<!-- android-test-report --> ## Android test report | Suite | Tests | Result | Skipped | | --- | --: | --- | --: | | Unit (debug) | 31 | ✅ pass | 0 | **Coverage:** 2.4% of lines <sub>Updated by the android workflow · commit d003d037fc0f13b43c70c47ad72001a152edd5ab</sub>
nalum changed target branch from feat/repeat-rule-editing to main 2026-08-16 19:44:43 +00:00
nalum merged commit d003d037fc into main 2026-08-16 19:44:49 +00:00
nalum deleted branch feat/whats-new 2026-08-16 19:44:49 +00:00
Sign in to join this conversation.
No reviewers
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
eagraiclainne/app!106
No description provided.