Repository navigation
docs: the watch exchange, an Apple Watch that works without the phone - #83
Conversation
watchOS allows HTTPS and no WebSocket, so the relay gains a request and answer route that hands opaque Noise messages to a second socket from the box. The relay reads only the id it writes. The doc covers the wire, the Noise use, the receipt line, adding and removing a watch, what the relay still knows, limits, latency, client changes and the tests. Proposed only. Paired with srcfl/ftw ADR 0009. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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. |
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
ftw-webapp | cffa2fe | Commit Preview URL Branch Preview URL |
Oct 14 2026, 07:43 AM |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3902d7147a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| **Role `watch`.** Scopes `ftw.live.read` and `ftw.dispatch.write`: Charge | ||
| now, Pause, Back to the plan and the car's level. Not `ftw.mode.write`, no | ||
| members scopes, no passthrough, no history. Each check takes the role's scopes |
There was a problem hiding this comment.
Restrict the watch role to the commands listed
Granting ftw.dispatch.write authorizes every operation mapped to that scope, not just Charge now, Pause, Back to the plan, and car-level updates. In the current registry, this also includes battery.hold, loadpoint.boost, and loadpoint.surplus_only.set (contract/registry.yaml lines 139–143), and the box deliberately authorizes named operations by scope. Consequently, a modified watch client could control the house battery or enable battery boost even if the watch UI never exposes those actions; define a narrower scope or an explicit server-side operation allow-list for the watch role.
Useful? React with 👍 / 👎.
Fredrik said yes to the design on 14 October 2026 and asked that the watch work fully on its own. The doc now splits two doors: commands through the relay's exchange, reads through FTW Cloud's one-shot read (ADR 0009). The exchange gains `now` for homes with FTW Cloud off, at the same lengths as a command, and `hello_ok` carries what the watch needs to read FTW Cloud. The watch role gains the plan and alert scopes, and one identity covers both doors. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Accepted design, no code. Paired with srcfl/ftw#1621 (ADR 0009), which holds Core's and FTW Cloud's side, the decisions and the order of work; neither works without the other.
Decision
Fredrik answered "ja på alla" on 14 October 2026 and asked that the watch work fully on its own, for example on LTE with the phone away.
docs/watch-exchange.mdis now marked accepted.watchOS allows HTTPS and no WebSocket (TN3135). So a watch on its own uses two doors:
/r/<epoch>/<handle>/exchange; the watch posts one Noise message to/x/<epoch>/<handle>; the relay draws a random id, hands the body to that socket and returns the reply. It reads only the id it wrote. Exchanges never take a stream place.nowon the exchange answers in one lane 0 frame.What the doc covers
cmd.ackandcmd.result; the watch showsobserved; a retry with the samecmdIdacts once.watchwithftw.live.read,ftw.plan.read,ftw.events.readandftw.dispatch.write, never more than its phone; the key underkSecAttrAccessibleWhenPasscodeSetThisDeviceOnly; one identity removed in one place, the box./x/.Order of work in this repository
ADR 0009's milestones hold the full order. Here: the registry (role
watch, capabilitycmd.exchange, copied to ftw and ftw-app in a pair) is step 2, and the relay exchange with its tests is step 4. Both can start now.What I checked
Read against
relay/src/server.ts,relay/src/limits.ts,relay/deploy/Caddyfile,docs/protocol.md, Core's session, handler, command and transport code, FTW Cloud's protocol and app session, and the W1 plan. Nothing was run; this is a document.🤖 Generated with Claude Code