Repository navigation
Give windows their own addresses, keep preferences and contain crashes (app review batch 5, getting around) - #31
Merged
Conversation
Each commune keeps its own currency, so the Settings choice changed nothing on any screen. The preference, its stored value and its state go; the Profile window no longer lists it among the settings. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A6P7aTcMBccooYYr4xYnVS
"Next due" took the earliest due date of any open bill, so a rent payment a month late still read as "4 Sept". It now reads "Overdue since 4 Sept" once the date has passed. Billing only said it was not connected, and Analytics was the activity list with four figures on top. Both leave the navigation, and their old addresses go to Home, until they do something. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A6P7aTcMBccooYYr4xYnVS
Preferences lived in the tab's session storage, so closing the tab lost the commune you were using, dark mode, photos and payment hints, and a new tab opened the newest commune instead. Device preferences (theme, sidebar, notices) and each account's own (last commune, photos, payment hints) now live in local storage, read and written through wrappers that never throw when the store is full, blocked or private. A tab that still holds the old session copy moves it across once. A new tab reopens the last commune while the account is still a member of it, and falls back to the newest otherwise. The dark mode switch becomes a Theme choice: Match this device (the default, following prefers-color-scheme), Light or Dark. A change in one tab shows in the others. Signing out still removes everything kept for the account and leaves only the device preferences. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A6P7aTcMBccooYYr4xYnVS
…sked for across sign-in Every window now has an address that continues its screen's (an expense is /expenses/<id>, a note's editor /notes/<id>/edit, the breakdown /settle/breakdown, a fund /funds/<id>), and a screen that shows one commune names it with ?commune=<id>. The address is the only record of what is open, so Back closes a window, Forward and a reload open it again and a link opens it for another member. Closing a window returns to the entry it was opened from when there is one; leaving a form replaces it, so Back never reopens a saved or cancelled form. Back over typed text asks first, as Close does. An address for a commune this account is not in says so instead of showing another commune, and an address Commune does not have shows a not-found page in the sign-in layout. Each page sets a short title, such as "Expenses · Flat 4 · Commune". A page opened while signed out (a reminder email's link to Settings, a shared expense, an invitation) opens after signing in or creating an account, including through Google. Only a path on this site is kept: never an absolute or protocol-relative URL, a backslash or a control character. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A6P7aTcMBccooYYr4xYnVS
…on is for
An invitation opened by an account with a different email address said only
"Invitation unavailable", with no way on. The page now says which address it
was sent to, masked ("e•••@g•••.com"), and which account is signed in, and
offers "Sign out and use another account", which comes back to the
invitation once signed in again, and "Continue to Commune". A signed-in
account whose invitation is unavailable for any other reason can also
continue to Commune.
The hint comes from the database (public.invite_address_hint, migration
0038) only to a signed-in account holding the invitation's token, only
while the invitation could still be accepted, and only when the address is
not the account's own. The page now reads its token through the router,
like every other page.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A6P7aTcMBccooYYr4xYnVS
React removes everything below a drawing error that nothing catches, so one error anywhere left a blank page. Error boundaries now surround the app, each screen and each window. A screen that fails shows a card in its place with the navigation still working; a window that fails shows the card inside the window, over the untouched screen; and if the app itself fails, a whole-page card in the connection card's style. Each says what happened in plain words and offers Try again and Go to Home. Nobody found out about failures either. The boundaries, and errors in event handlers and promises (not refused requests or dropped connections), are reported once per page load, and about one page load in ten reports its largest contentful paint, interaction to next paint and layout shift from the browser's own PerformanceObserver when it is first hidden. Reports go only for a signed-in person, through the local API (POST /api/client-reports) or the Data API, to public.report_client_event (migration 0038), which keeps them in commune_private.client_reports where no client can read them: kind, release (the commit Vercel built), the page as a pattern such as /expenses/:id, the browser family, and an error's message and first ten stack frames, with record ids, email addresses and queries taken out by the app and again by the database. An account may send 20 reports an hour and 100 a day; more are dropped rather than refused. The worker's scheduled run deletes reports after 30 days. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A6P7aTcMBccooYYr4xYnVS
…up to date Adding the app to a phone's home screen gave a screenshot for an icon and no name. A web app manifest now names it Commune (en-GB, standalone, on the navy theme colour, with the cream canvas behind its splash screen), with icons at 192 and 512 pixels, a maskable one that keeps the mark inside every launcher's mask, and a 180-pixel Apple touch icon. The icons were rendered from public/logo-mark.svg by scripts/render-icons.mjs with headless Chromium, which is kept for when the mark changes. The hosted policy already allows the manifest and icons (default-src and img-src 'self'). apple-mobile-web-app-title keeps the home-screen name Commune now that each page has its own title. The page language is en-GB and its description is in the app's own words, without "Hub OS". The calendar stylesheet is bundled with the app's styles, ahead of them as its link was, rather than loaded on its own before the first paint; the design reference links the same file from src. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A6P7aTcMBccooYYr4xYnVS
Remembering the commune a tab shows moved into an effect, which can run just after sign-out has removed the account's preferences, and so wrote them back. Saving now checks that the account is still the one signed in here, which also stops one account's preferences landing on another's after a switch in the same tab. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A6P7aTcMBccooYYr4xYnVS
… carry What stays in the browser now matches where preferences live: the last commune, payment usernames and photos for the account until it signs out there, and display settings for whoever uses the browser. A new Error reports section says what a report holds, how often speed figures go with it, why it is linked to the account, where it is kept and that it is deleted after 30 days. Both are part of the legal wording waiting for the owner's approval. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A6P7aTcMBccooYYr4xYnVS
- infra/neon/README.md: 0038 joins the local-only range and the release steps, with what it adds, the order to release it in, and the Vercel setting a report's release needs. - infra/local/README.md: 0038 in the local setup order. - DESIGN-LANGUAGE.md: the calendar stylesheet now lives in src/styles and is bundled. - HANDOFF.md: a Start here entry for addresses, preferences, error recovery and reports, the invitation hint, the hidden placeholders and the icons. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A6P7aTcMBccooYYr4xYnVS
The page sits in the sign-in layout, where the heading and text are centred, but its button used the app's row of buttons and sat to the left with underlined text. It now uses the same full-width button as "Back to sign in" on the password reset screens. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A6P7aTcMBccooYYr4xYnVS
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Owner
Author
|
The Vercel preview for Generated by Claude Code |
EmotiveImpact
changed the base branch from
claude/app-review-accessibility
to
main
October 12, 2026 02:01
EmotiveImpact
marked this pull request as ready for review
October 12, 2026 02:01
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
This branch had an error being deployed
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.
Before: anything opened on top of a screen (an expense, a note, the breakdown, a fund) had no address of its own, so Back left the screen instead of closing it, a reload closed it and a link to it could not be sent to anyone. Preferences lived in the tab's session storage, so closing the tab lost the commune you were using, dark mode, photos and payment usernames. A drawing error anywhere blanked the whole app, and nobody found out. An invitation opened by an account with a different email address said only "Invitation unavailable", with no way on. Billing and Analytics sat in the navigation without doing anything, the Currency preference changed nothing, and adding the app to a phone's home screen gave a screenshot for an icon and no name.
After: every window has its own address, such as
/expenses/<id>or/settle/breakdown, and commune screens name their commune with?commune=<id>. Back closes a window, Forward and a reload open it again, a link opens it for another member, and a page opened while signed out opens after signing in. Preferences stay in this browser, the theme can follow the device, and a new tab reopens the last commune. A crash stays inside the screen or window it happened in, with Try again and Go to Home, and is reported with personal details removed. The invitation page names the address it was sent to, masked, and offers to switch account. Billing, Analytics and Currency are gone until they do something, and the app has a home-screen name and icons.This is the second of three pull requests for batch 5 of the app review fixes. It is built on #30 (accessibility), so review that first; the diff here shows only this part.
What changed, by finding
apps/web/src/nav.ts): an expense at/expenses/<id>, a note's editor at/notes/<id>/edit, the breakdown at/settle/breakdown, a fund at/funds/<id>and Profile at/settings/profile, and commune screens carry?commune=<id>. Closing a window returns to the entry it was opened from; a saved or cancelled form is replaced, so Back never reopens it, and Back over typed text asks first. An address for a commune this account is not in says "This commune isn’t available to you." and never shows another commune's records; an address Commune does not have shows "This page isn’t here." Each page has a short title, such as "Expenses · 14 Park Street · Commune". A page opened while signed out, including through Google sign-in, opens after signing in; only a path on this site is kept, never a full or protocol-relative URL.report_client_event(migration 0038), which keeps them where no client can read them. Record ids, email addresses and queries are removed by the app and again by the database, and each account may send 20 an hour and 100 a day.invite_address_hint(0038) only to a signed-in account holding the invitation's token, only while the invitation could still be accepted, and only when the address is not the account's own.public/logo-mark.svgbyscripts/render-icons.mjs. The page language is en-GB and its description is in the app's own words, without "Hub OS". The calendar stylesheet is bundled with the app's styles instead of loading on its own before the first paint.The privacy page now says what stays in the browser (the last commune, payment usernames and photos until sign-out, and display settings for whoever uses the browser) and has a new "Error reports" section: what a report holds, why it is linked to the account, where it is kept and that it is deleted after 30 days.
Releasing
Nothing hosted was touched. Migration 0038 is local only and follows 0037. Apply it and refresh the Data API schema cache before deploying this client; against an older database the client still works but shows no address hint, and its reports are dropped. The worker's scheduled run deletes reports older than 30 days through
prune_delivery_records(), which 0038 replaces in place, so the worker needs no redeploy. A report names its release from Vercel's commit SHA at build time, so Vercel's "Automatically expose System Environment Variables" setting needs to be on; otherwise reports say "local". To read reports, use an owner connection:SELECT kind, release, route, browser, message, created_at FROM commune_private.client_reports ORDER BY created_at DESC.Needs the owner
How it was checked
On the final branch:
addresses(30),error-recovery(12),preferences(14),invitation-hint(6),home-screen(4) andplaceholder-screens(4). Every new test failed before its fix.run-local.sh, including the newclient_reports.sqlandinvite_address_hint.sql; 2 more need a Neon branch.client-reports.mjsandinvitation-hint.mjs, and the reminder worker's unit tests and 4 database suites.In Chromium, on a disposable database with three communes, on top of the Home and notices branch: a signed-out visit to Settings returns there after sign-in, and Back then leaves the app instead of showing the sign-in form; an expense opens at its own address, Back closes it, Forward and a reload open it again; Back over typed text asks before discarding and Keep editing keeps the text; Theme stays Dark after a reload; an unknown address and a commune the account is not in each say so;
/billinggoes to Home; and the manifest names Commune with 3 icons. No page errors.How
The open window, the record it shows and the active commune all come from the address, so nothing else records what is open. Opening a window adds a history entry that remembers where it opened from, and leaving it goes back to that entry when it is the one before, or replaces it otherwise. Preferences are written only while the account that owns them is still the one signed in, so a sign-out cannot write them back and one account's preferences cannot land on another's.
docs/HANDOFF.md,infra/neon/README.mdandinfra/local/README.mdrecord the addresses, preferences, reports and migration 0038.🤖 Generated with Claude Code
https://claude.ai/code/session_01A6P7aTcMBccooYYr4xYnVS
Generated by Claude Code