Repository navigation
Conversation
The account page will re-read an approval's result at the Burrow's poll pace, and its import graph may reach only policy-constants, never relay-api. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every account-page mutation now goes through one helper, mutate(), which shows the account as the server has it afterwards instead of patching local state. An approval returns a Pending: the desktop's next poll redeems it, so the page says it is waiting and re-reads at the poll pace until Natural Voice turns on or a new computer is listed, for up to a minute, then says the computer has not finished and leaves the rest to the focus refresh. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Deploying mouseterm with
|
| Latest commit: |
42cff4a
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://76741923.mouseterm.pages.dev |
| Branch Preview URL: | https://account-mutation-refresh.mouseterm.pages.dev |
dormouse-bot
left a comment
Collaborator
There was a problem hiding this comment.
Remove computer, remove passkey, and turn off Natural Voice now report a failed post-mutation refresh as if the mutation failed. Inline below.
nedtwigg
requested a deployment
to
hosted-preview
October 21, 2026 05:39 — with
GitHub Actions
Waiting
mutate() re-read the account with a bare refresh(), so a failed reload surfaced through act() as the mutation's own failure: a removed computer stayed listed under "Could not connect", and Turn off Natural Voice showed its "is off" notice beside an error. The re-read now goes through reread(), which reports the failure itself: the page says the change is saved but could not reload, and offers Retry. An approval still waits on its computer through follow(). The page also refreshes when the tab becomes visible, since mobile Safari fires no focus returning from another app. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dormouse-bot
left a comment
Collaborator
There was a problem hiding this comment.
The new "saved but could not reload" message outlives a reload that later succeeds. Details inline.
nedtwigg
marked this pull request as ready for review
October 21, 2026 06:52
dormouse-bot
left a comment
Collaborator
There was a problem hiding this comment.
The "late" approval notice stays on screen after a later refresh shows the change, so it contradicts the page beneath it. Details inline.
Draft
8 of 12 tasks
Two messages outlived the reads that contradicted them. The "change is
saved, but this page could not reload" alert stayed up after a focus,
visibilitychange, or approval re-read succeeded; and an approval's late
notice ("has not turned on Natural Voice yet") stayed after a later
refresh showed it on.
Errors now carry whether a failed read caused them: refresh() throws
ReadFailed, and a successful refresh clears only such an error, so an
action's own failure stays until the next action. A late approval stays
outstanding after its timeout; the first refresh whose account shows it
replaces the late notice with the done one.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dormouse-bot
approved these changes
Oct 21, 2026
comingSoon was `!session && !error`, so "no error on screen" stood in for "the account lookup succeeded". When a lookup failed (a 429 from the auth limiter under repeated reads, an outage), session stayed null and any later step that cleared the error (a new /enroll link's hashchange, Don't approve, Change email) turned a signed-in page into "Coming soon" and redirected it to nedshed.dev. main has the same path. The page now records what the latest lookup found (pending, failed, signed in, signed out), and preLaunchNotice() shows the notice only after a lookup that succeeded and found no login. The steps that read nothing keep a failed read's error (keepRead) instead of clearing it, so the page keeps saying it could not connect until a read succeeds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
dormouse-bot
approved these changes
Oct 21, 2026
This branch is waiting to be 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.
After approving a Natural Voice or remote-control request, the account page no longer shows the old state. It says it is waiting for Dormouse on the computer, re-reads every 5 s (the desktop's poll interval), and switches to "Natural Voice is on." or "Your computer is enrolled." once the desktop's poll redeems the approval. If nothing redeems it within a minute, it says the computer has not finished yet and that the page updates when you come back to it. It never shows "on" before the desktop holds its token.
Audit
onstays false until the desktop's next poll mints the token, after the page's one refreshon, or a "not finished yet" notice after 60 sMechanism
mutate()inhosted/src/App.tsxwraps every account mutation: it runs the action, then refetches the account through the existingrefresh()instead of hand-patching local state. If that refetch fails, the mutation is still reported as a success:reread()handles the failure, and the page shows "Your change is saved, but this page could not reload to show it." with Retry.Pending(what shows its completion, plus the waiting, done, and late copy). Only approvals return one.mutate()then re-reads in the background usingsettle()(hosted/src/settle.ts). The page stays usable while it waits. Any later action or unmount cancels the wait.ReadFailed), and the next successfulrefresh()clears only those; an action's own failure stays until the next action. After the 60 s timeout an approval stays outstanding, and the first later refresh that shows it replaces the late notice with the done notice.preLaunchNotice). Before, it was keyed on "no error on screen": a failed lookup whose error a new/enrolllink, Don't approve, or Change email then cleared sent a signed-in page to nedshed.dev.mainhas the same bug. Those steps now keep a failed read's error (keepRead).approvalShows()(hosted/src/settle.ts) turns the pre-approval state into the predicate: voice turned on, or aburrowIdnot listed before.ENROLLMENT_POLL_INTERVAL_Smoved fromrelay-api.tstopolicy-constants.ts, since the frontend's import graph may reach only that module.Rejected: counting an approved but unredeemed voice approval as
onon the server. That is dishonest when the desktop never redeems, and it does nothing for remote enrollment. Also rejected: a new approval-status route. Re-reading the existing routes is enough, and no wire contract changes, sodocs/specs/hosted.mdis unchanged.Test plan
hosted/server/tests/settle.test.ts: the approval predicates, the bounded re-read loop,reread, the read-error rules, andpreLaunchNotice. Each guarded line was mutation-checked: 29 mutations, all red.ENROLLMENT_POLL_INTERVAL_Sassertion inrelay.test.ts.pnpm exec tsc --noEmitandpnpm run testinhosted: 13 files, 197 tests.pnpm run lint:specs,pnpm run lint:mdpnpm dev:hosteddriven with agent-browser, with redemption simulated by inserting the token or Burrow row:get-sessionaborted, removing a computer shows the saved-but-could-not-reload message, not a failure. Retry then shows the list without it.visibilitychangeevent alone refreshes the page and shows a computer added in the database.visibilitychangeevent switch the notice to "Natural Voice is on."get-sessionfailing, changing the/enrolllink keeps the page on the sign-in prompt with its connection error, never "Coming soon". It recovers on the next good read.🤖 Generated with Claude Code