Skip to content

feat(cloud): say cloud.tun at hello when the link carries the tunnel - #1639

Merged
frahlg merged 1 commit into
feat/cloud-tunnelfrom
claude/cloud-tun-cap
Oct 15, 2026
Merged

frahlg merged 1 commit into
feat/cloud-tunnelfrom
claude/cloud-tun-cap

Conversation

@frahlg

@frahlg frahlg commented Oct 15, 2026 •

Copy link
Copy Markdown
Member

Stacked on #1635 (base feat/cloud-tunnel). It can as well be folded into #1635.

What

  • The box lists cloud.tun in hello_ok.caps when its FTW Cloud link carries the phones' own sessions: a build that names the service and has a tunnel table (Link.TakesTun).
  • contract/registry.yaml gains the capability cloud.tun and the carrier state tunnel, copied byte for byte from registry: the tunnel carrier and the cloud.tun capability ftw-webapp#88. go generate adds protocol.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.tun at 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 take tun, and wait for its fallback: an older box lists the phone without tun, and FTW Cloud then passes nothing on and says nothing.

Paired PRs (one-door plan, step 2)

appenroll.QRNamesHome stays off.

Contract-pair: srcfl/ftw-webapp@claude/registry-cloud-tunnel

Tests

🤖 Generated with Claude Code

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>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-15T15:47:09.047296Z 3c502bf PR opened
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@frahlg
frahlg merged commit 1b60844 into feat/cloud-tunnel 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>
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.

1 participant