Skip to content

ftwcloudd: hold a signed copy of each home in memory (FTW Cloud C2) - #1

Merged
frahlg merged 1 commit into
mainfrom
claude/c2-first-version
Oct 13, 2026
Merged

frahlg merged 1 commit into
mainfrom
claude/c2-first-version

Conversation

@frahlg

@frahlg frahlg commented Oct 13, 2026

Copy link
Copy Markdown
Member

What this is

The first version of FTW Cloud's service, ftwcloudd. It is milestone C2 in ADR 0008 (srcfl/ftw#1589).

A box whose owner turned FTW Cloud on dials out over one WebSocket and streams a box-signed, readable copy of its state. The service verifies every signature and the box's device roster, and keeps each home in memory behind store.For(principal). It reads and never controls: the downlink is a closed set of messages, covered by a fuzz test, and an import check keeps control code out of the binary.

Paired PRs

Evidence

Run end to end on a laptop: a Core built from #1595 with simulated drivers, against a local ftwcloudd.

  • What the service holds is byte for byte what the box's /api/cloud/preview shows.
  • A snapshot replayed an hour later turns down.
  • A revoked grant answers "off" with a receipt after 0.07 s, and the home is gone from the service.
  • A frozen service does not affect the box.
  • Traffic is 4.57 MB/day in frames and 5.18 MB/day at the TLS layer, against the design's estimate of about 5 MB.

Tests, the race detector, fuzzing, the import check and the Docker build all pass. Dev-only inspection code builds only with -tags ftwclouddev; the Dockerfile builds without tags.

Deliberate differences from the design

  • No Caddy in front. The handshake is bound to the TLS session, and a proxy that terminates TLS breaks that binding. ftwcloudd terminates TLS itself, so deploy/ has one container.
  • App socket and APNs are later milestones (C3 and C4). The places for them are marked in the code.

AGPL-3.0-only. The commits have no DCO sign-off; Fredrik signs off his own work.

🤖 Generated with Claude Code

The first version of FTW Cloud (srcfl/ftw ADR 0008, step C2):

- /v1/box takes one uplink per home. The service checks that the box
  signed hello over this TLS session's exporter value, answers with a
  hello_ok signed by the service key, and accepts only messages signed
  by that box's key. The home id is a hash of the key.
- store.For(principal) is the only way to a home. Each home's newest
  message of each class is kept in memory as the exact bytes the box
  sent; readings go an hour after the box does and never reach disk.
- The registry (SQLite, secure_delete) holds the home id, the box key,
  the signed roster and tombstones. bye with purge deletes the home and
  returns a signed receipt, again if the first one was lost.
- The downlink is a closed set of five types; what a box can sign is
  fuzzed. /source serves the running source. A test checks that no
  route reads a home.
- /v1/app (C3) and /v1/now (C5) are marked and answer 501.

The wire format comes from github.com/srcfl/ftw/go/protocol, pinned
to a commit; CI checks that nothing else from srcfl/ftw is imported.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@frahlg
frahlg merged commit d8d3275 into main Oct 13, 2026
1 check passed
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