Repository navigation
feat(cloud): say cloud.tun at hello when the link carries the tunnel - #1639
Merged
Merged
Conversation
A phone that knows the home id goes through FTW Cloud only to a box that said cloud.tun at its last hello, so an older box costs it no wait. The registry copy also gains the carrier state tunnel. Contract pair: srcfl/ftw-webapp claude/registry-cloud-tunnel. 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. |
This was referenced Oct 15, 2026
frahlg
added a commit
that referenced
this pull request
Oct 15, 2026
…m pairing (#1635) * feat(cloud): carry the phones' sessions through FTW Cloud, linked from pairing Step 1 of the one-door plan, the srcfl/ftw half. A phone reaches its box through FTW Cloud with the relay unreachable. - cloudwire: tun {sid, d} on /v1/app and tun {dev, sid, d} on /v1/box, unsigned and without a header; d is the ftw.session.v1 session byte for byte. The closed downlink grows to six. The roster gains a per-device tun bit and pending pairing hashes, and the grant gets an off and a withdrawing shape; purged gains what: copy. Vectors, allowlist, fuzz and docs/protocol-cloud.md ("Tunnel") follow. - cloudlink: the box links at its first QR code or tun-capable phone, independent of the readable grant, and ends the link when nothing needs it. Revoking the grant deletes the copy and keeps the link and home id. tun goes through the Tunnel port unread, with its own queue and a budget apart from the copy's 20 MB; hb and readings go only with the copy on. - appuplink: the tunnel table routes tun by device and session, checks the handshake's key against the device the service named, and admits as over the relay. Each device holds one session across relay and tunnel, in place of four anonymous places. - appenroll/cmd: the live QR code is listed by hash; spoken and watch codes never are. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com> * style: gofmt Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com> * feat(cloudwire): the box session rides in the app session's message 1 now.tun carries message 1 of the phone's session with its box, so the service forwards it as soon as it admits the phone and that session is up one round trip after TLS. Vector and protocol text follow; the protocol admission rule reads "with tun, or while the readable copy is on". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com> * docs(cloudwire): a phone draws a new sid for each box session A late end of an older session must never end a newer one under the same number. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com> * feat(appenroll): define the v3 QR that names the home, and keep showing v2 v3 is v2 with a sixth segment, the home id at FTW Cloud in base64url, so a new phone knows where to dial before any session with the box. Every shipped parser (ftw-app Enrollment.swift and Enrollment.kt, ftw-webapp enrollment.ts) takes exactly five v2 segments, so the box keeps showing v2 until one constant, appenroll.QRNamesHome, turns v3 on in step 2. A new phone learns the home id from hello_ok.cloud meanwhile, which the box sends from its first pairing. docs/protocol-cloud.md specifies v3 and the gate. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com> * feat(cloud): lane 0 ahead of paced bulk on the tunnel; handshakes per device Review of srcfl/ftw-cloud#15 (L) and #1635 (P): - The box's tun goes in two queues. A lane 0 frame (a command, its answer, a tick) goes first and is never held; bulk is paced to nine tenths of the service's limits, now shared as cloudwire.TunMsgBurst and friends, so the service never drops for a box that keeps to them. A command's answer never waits behind bulk. - The tunnel answers at most 12 handshakes a minute per device and 240 in all, so one phone or one pairing cannot starve the others. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com> * fix(cloud): review of #1635 — a session proves itself before it takes a place - A new session, through FTW Cloud or the relay, waits pending until its first transport message decrypts; only then does it commit the pairing or the reconnect stamp (appenroll.Check), take the device's slot and replace the live session. A replayed message 1 changes nothing. - The roster is built from the link as it is when due, so a revoke that lands mid-tick goes in that roster. - A dropped tun is counted and the session goes on; acceptCmd forgets an id whose ack could not leave. - An unused pairing code that runs out ends an idle link; ErrLinkEnding is 409; the slot's release is set without a race; cloud.key is adopted and never overwritten; each tunnel handshake runs on its session's goroutine. - The roster adapter moves to appuplink.CloudRoster for cmd/ftw and the end-to-end test; new tests for each point; protocol text for pending sessions, hello's fields and how a phone treats an end. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com> * feat(cloud): say cloud.tun at hello when the link carries the tunnel (#1639) A phone that knows the home id goes through FTW Cloud only to a box that said cloud.tun at its last hello, so an older box costs it no wait. The registry copy also gains the carrier state tunnel. Contract pair: srcfl/ftw-webapp claude/registry-cloud-tunnel. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> --------- Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.
Stacked on #1635 (base
feat/cloud-tunnel). It can as well be folded into #1635.What
cloud.tuninhello_ok.capswhen its FTW Cloud link carries the phones' own sessions: a build that names the service and has a tunnel table (Link.TakesTun).contract/registry.yamlgains the capabilitycloud.tunand the carrier statetunnel, copied byte for byte from registry: the tunnel carrier and the cloud.tun capability ftw-webapp#88.go generateaddsprotocol.CapCloudTun.docs/protocol-cloud.md: when a phone sends its box session through FTW Cloud, and the two new registry rows.Why
The iPhone sends its box session through FTW Cloud only to a box that said
cloud.tunat its last hello, or to one it has never reached when a v3 QR named the home. Without the bit, a phone that knows the home id would try a box that cannot taketun, and wait for its fallback: an older box lists the phone withouttun, and FTW Cloud then passes nothing on and says nothing.Paired PRs (one-door plan, step 2)
enrollment.tsreads QR v3.appenroll.QRNamesHomestays off.Contract-pair: srcfl/ftw-webapp@claude/registry-cloud-tunnel
Tests
TestAppSessionsHearOfTheTunnelOnlyWhenTheLinkTakesIt: no tunnel table, no service key, and both.go test ./cmd/ftw ./internal/cloudlink ./internal/appproto ./internal/apiauth, andgo test ./...ingo/protocol.ftwclouddfrom feat: carry each phone's session to its box, and survive a restart ftw-cloud#15 and the iPhone's FTWKit, with the relay unreachable. The phone paired from a v3 link through FTW Cloud, set the mode 50 times, and came back from the background five times through the tunnel because the box saidcloud.tun. The numbers are in iPhone: the box session goes through FTW Cloud, the relay as fallback (one door, step 2) ftw-app#67.test.ymlruns only for pull requests to master, so this stacked PR shows no CI until it is rebased onto master after feat(cloud): carry the phones' sessions through FTW Cloud, linked from pairing #1635.🤖 Generated with Claude Code