Skip to content

Correct the remote specs; one mouse-override rule; drop the duplicate direct-path bounds - #712

Draft
nedtwigg wants to merge 5 commits into
specs-host-auditfrom
specs-remote-audit
Draft

nedtwigg wants to merge 5 commits into
specs-host-auditfrom
specs-remote-audit

Conversation

@nedtwigg

@nedtwigg nedtwigg commented Sep 20, 2026

Copy link
Copy Markdown
Member

Spec audit, group 4 (remote-security-model / remote-api / relay / pocket-app / mobile-terminal-ui). Stacked on #711 (the spec-audit PRs merge in order #708#715); independent of the alert series. One minimal wording change in security-remote.md line 239 because the symbols it named are deleted below; pnpm lint:e2e is green.

Commit 1 — docs and comments. Corrections: DIRECT_HANDOFF_TIMEOUT_MS is 15 000 (= DIRECT_SETUP_TIMEOUT_MS), not 5 000; the Guardrails rule now says "every keyed store" and names the two challenge issuers as the accepted exception; a stale Future item the scope owner already calls done; { token, expiresAt }; the runtime-file location is an installer fact, not a Relay check; the install notice deliberately omits push; two scanner error lines, not one; the live VAPID rule (only a missing subject withholds the sender); seven smaller precision fixes. Condensed: Settings-dialog QR mechanics, the Pocket DB probe ladder, the diagnostics harness (now its own heading), duplicate direct-path rules across the two remote specs.

Commit 2 — code.

  • MobileTerminalUi loses the activeSection/defaultSection/onSectionChange trio (Storybook-only).
  • One paneMouseOverride(touchMode, reporting) replaces the rule implemented twice in PocketWall and the website's Pocket experience; tests added.
  • MAX_DIRECT_OUTBOUND_* were literal aliases of MAX_DIRECT_PENDING_*; deleted.

Budgets: remote-security-model 4800→4750, relay 10200→10100.

For the owner (deferred, needs a security-model decision first): re-pairing appends an ACL record forever (BurrowAcl.approve pushes unconditionally), and the Burrow seals one push envelope per active record, so every re-pair adds a permanently failing push recipient. pairing.mdx §9 already documents the visible half. Also deferred: whether to keep DORMOUSE_REQUIRE_USER_VERIFICATION.

🤖 Generated with Claude Code

nedtwigg and others added 2 commits September 20, 2026 00:52
…anism to it

Ten inaccuracies the audit found in the remote group, and eight sections whose
mechanism belongs at the module that carries it.

Corrections: the direct handoff deadline is the setup deadline (15 s), not five
seconds; the Relay's challenge issuers are the one unkeyed transient store, so
Guardrails states the exception rather than a universal claim; the setup-token
mint answers `{ token, expiresAt }`, meaning no origin and no URL rather than
"the token alone"; the runtime file's placement outside the state dir is the
installers' convention, not a Relay check; push is switched off by a missing
VAPID subject alone, since the key is always minted; the install notice
deliberately omits push; the scanner has two camera lines, not one; the
Burrows-view install notice is gated on push not being disabled; ImageAddon
loads only where `inlineImages` is on; the pairing prologue puts `burrowId`
ahead of the version the QR leads with; the push upsert response is
VAPID-current; a passkey label's control characters become spaces before the
bidi set is dropped; `DORMOUSE_ORIGIN` must be http(s); the root-build pin named
a test that pins only the assertion's own fixtures. Pocket's phone-side
selfhost-onboarding item is done, so it leaves `## Future`, and only
`getUserMedia` in a Home Screen web app is still unverified on a device.

`paneRef` is marked reserved — it equals `surfaceId` and no Client reads it —
alongside `focused` and `exitCode`, which have no Client reader either.

The QR panel, the Burrow status store, the connect-src build guards, the Pocket
storage probe and the capability harness keep their bolded rules and their
`Source of truth:` pointers; their mechanism now lives in comments at the code,
and the harness gets its own heading, since it is not serving. Two code comments
cited scopes that no longer exist.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…d the direct-path queue bound

Three duplications the audit found, each of one fact expressed twice.

`MobileTerminalUi` carried `activeSection` / `defaultSection` / `onSectionChange`
beside `activeKeyboardMode` / `defaultKeyboardMode` / `onKeyboardModeChange` for
one piece of state, resolved through `??` ladders. The `*Section` trio had no
production consumer, only Storybook; it is gone, and the stories drive the
keyboard-mode props directly.

The per-pane mouse override — Select mode plus a pane that reports mouse events
means `permanent`, everything else `off` — was written out in Pocket's wall and
again in the website playground. `lib` now exports `paneMouseOverride`, both
compositions loop over their panes calling it, and `mobile-terminal-ui.md` gains
a real `Source of truth:` for a rule it previously stated only in prose.

`MAX_DIRECT_OUTBOUND_BYTES` / `_FRAMES` were literal aliases of
`MAX_DIRECT_PENDING_BYTES` / `_FRAMES`, feeding the same `DirectFrameQueue`
class, and the Burrow-bounds table spent two rows saying so. One pair of
constants now bounds both directions, documented where they are declared.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 20, 2026

Copy link
Copy Markdown

Deploying mouseterm with  Cloudflare Pages  Cloudflare Pages

Latest commit: 8d0be4d
Status: ✅  Deploy successful!
Preview URL: https://d6ee5372.mouseterm.pages.dev
Branch Preview URL: https://specs-remote-audit.mouseterm.pages.dev

View logs

@nedtwigg
nedtwigg changed the base branch from main to specs-host-audit September 20, 2026 08:17

@dormouse-bot dormouse-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feedback on work in progress, not a merge verdict — mark the PR ready when you want the full review. The corrections I spot-checked against code all hold: DIRECT_HANDOFF_TIMEOUT_MS = DIRECT_SETUP_TIMEOUT_MS, { token, expiresAt }, the two camera lines, the VAPID-subject-only switch, the needs-install push-disabled gate, the prologue field order against pairingInvitationFields, paneRef === surfaceId with no Client reader for focused/exitCode, and the facts dropped from pocket-app.md -> "What Pocket stores" (nonextractable keys, probe-database deletion) are each still owned elsewhere and pinned by pocket-key-storage.test.ts. Two of the condensations say something the code doesn't, both inline.

One pointer outside the diff went stale in the same edit: SELF_HOST.md (in "Storage compatibility failures", the line reading "The diagnostic contract is docs/specs/pocket-app.md -> "Serving the built bundle"") now names the parent section rather than the new ### The capability harness that owns the contract — the same heading the new capabilities.js comment cites. Happy to push that one-line fix if you want it.

Budget note: the two inline rewords take docs/specs/relay.md to ~10,111 words, past the 10,100 this PR sets, so they need node scripts/spec-lint.mjs --ratchet docs/specs/relay.md (10,150) in the same edit — or a compensating cut in that section.

Comment thread docs/specs/relay.md Outdated
Comment thread docs/specs/relay.md Outdated
nedtwigg and others added 2 commits September 20, 2026 01:56
…he gate each challenge map sits behind

The keyed EnrolledView is what drops a setup code belonging to the Relay we
just left; the QR's own error boundary is what keeps a refused encode off the
app-wide ErrorBoundary. `/api/setup/begin` runs `readSetupGated` before
`setupChallenges.issue()`, so only sign-in's challenge map is reachable with
no gate at all. SELF_HOST.md now points at the pocket-app heading that owns
the diagnostic contract rather than its parent section.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@dormouse-bot

Copy link
Copy Markdown
Collaborator

Re-checked 19e1637 at 8d0be4d — all three land. Each QR-panel guard now carries its own consequence, the challenge-map exception matches what readSetupGated actually does with sign-in named as the ungated one, and the SELF_HOST.md pointer resolves to ### The capability harness, the heading that owns the diagnostic contract. relay.md sits inside the ratcheted 10,150 and the spec lint is clean, so nothing from the draft review is outstanding.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants