Skip to content

docs(cloud): take in what C2 and C3 built - #1604

Merged
frahlg merged 4 commits into
masterfrom
claude/cloud-doc-c2-c3
Oct 13, 2026
Merged

frahlg merged 4 commits into
masterfrom
claude/cloud-doc-c2-c3

Conversation

@frahlg

@frahlg frahlg commented Oct 13, 2026

Copy link
Copy Markdown
Member

docs/protocol-cloud.md was written before the code. #1595 (C2) and #1603 (C3) each list where the code had to differ. This moves those differences into the text, so the document stays normative. It builds on #1589 and merges into its branch.

The sources were the two lists and the code on claude/cloud-c3-core (c6301a0b): cloudwire/app.go, view.go, messages.go, testdata/cloud-app-vectors.json, cloudlink, and the service (srcfl/ftw-cloud#5) and app (srcfl/ftw-app#19) where the doc describes their side.

What changes

From C2 (#1595)

  • fieldSources travels only with sources.
  • A roster goes at every connect. Each one renews ttlS.
  • lp compares measured values with a deadband: power past max(100 W, 5 %), sessionWh by 100 Wh, socPermille by 10.
  • An empty list or map is [] or {}, and an unknown number is null.
  • session is the plug-in count since the box started. socAgeS is set only when the car reported the level.
  • manual.reason is the hold's limit reason. manual.commandedW is null at zero.
  • hello.caps lists the classes the box sends.
  • prices runs from the start of today, and the box looks at it once a minute.
  • The service signs hello_ok and purged over the box's home id.
  • No route asks for a step-up.
  • A restore never brings cloud.key back. A restored box has FTW Cloud off until an owner turns it on again, under a new home id.

From C3 (#1603)

  • The app session URL is /v1/app?home=<id>, and the prologue binds the home.
  • Message 2 is an unsigned snapshot envelope, {envelopes, lastSeenMs, online, more}. Envelopes that do not fit follow as frames.
  • A phone's watch holds until it changes. While a phone looks, the service renews the box's watch every 50 s and again when the box connects.
  • Close codes 4400, 4403, 4408, 4409 and 4429, plus 1013 for a phone that falls behind. A table says what the phone does for each one, including the slow retry after 4403: 7.5 s at first, at most 5 min.
  • The session limits are written down and added to "Numbers in one place".
  • A new "Session information" section covers hello_ok.cloud {pk, home, boot, sources, loadpoints} (K11) and cloud.link.
  • The statistics consent routes, their gates and the 409 case. A scope or statistics change sends no push. The grant record gains the statistics policy.
  • Freshness: a dropped message changes nothing; an unknown state ranks as never; a source missing from the table counts as stale. Case 12 now shows no sources, not stale ones.
  • Role names are not generated in go/protocol.

ADR 0008

  • Turning FTW Cloud on or off notifies owners. Other changes do not.
  • The protocol has sixteen cases, not eight.

Code that looks wrong, not the doc

  1. DELETE /api/cloud/stats drops the statsId at once (cloudlink.StopStats). The doc says the box keeps it until purged {what: "stats"}, so stats.withdraw can name it. This does no harm while no stats leaves the box, but C7 must fix it before it sends any.
  2. Feedback.ageMs and Manual.sinceAgeMs are wall-clock differences (cmd/ftw/cloud_link.go). The doc counts ageMs in box uptime. A clock step, such as the first NTP sync, moves them.
  3. A restore while a revoke waits for its receipt loses the key. The box can then never send bye or accept purged for that home, so the service keeps it until the 90-day rule. A restore flow that refuses, or warns, while a purge is pending would close this.

Outside C2 and C3: on claude/cloud-c4-core, event has a ts field with no row in this document, so TestFieldsMatchTheProtocolDocument fails there against this text. C4's doc change should add that row.

Checks

  • TestFieldsMatchTheProtocolDocument and TestEveryFieldHasARow pass against this text on claude/cloud-c3-core (c6301a0b), and the test does not skip.
  • Only docs/ changes, so no changeset is needed. Release files, chore(release): version packages #1584 and the version are untouched.

🤖 Generated with Claude Code

frahlg and others added 3 commits October 12, 2026 18:37
ADR 0008, status proposed, records Fredrik's decisions of 12 October
2026: a readable, read-only copy of what a home's owner turns on, served
to the iPhone app, its widgets and APNs from ftwcloudd in srcfl/ftw-cloud
on AWS eu-north-1. The box signs every message; the service never
controls and never chooses actions; the relay, escrow and lane 0 do not
change. It states the statistics rules now, because consent comes at
first use, orders the work core first (uplink, cache, first screen),
and records the turn away from #1323 and ADR 0006's single remote path.

docs/protocol-cloud.md is the normative wire format: unpadded lane 1
frames, one signing rule, a handshake bound to the TLS session, a field
table per class and scope, cadence, the closed set the service may send
the box, roster, extension token, push, freshness with eight vectors
described in text, and the new registry names.

VISION.md and AGENTS.md gain the matching paragraph and invariants;
architecture.md and ADR 0006 point to the ADR.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An independent review found ways stale data could still show as live.

- hb now names the newest live and lp it covers (liveSeq, lpSeq) and
  carries each source's reading age, so the phone grades a reading by
  the box's own ladder instead of keeping it live for another S.
- The box sends no hb while a changed live or lp waits, nor past the
  byte budget, so an hb never vouches for values the box has not sent.
- The phone keys its table by boot, tracks seq per class, takes the
  earlier of wallMs and arrival under rule N, adds a drift margin and a
  24 h lifetime under rule U, and shows old alerts without buttons.
- hello now carries the box's TLS exporter value too, so a proxy that
  ends TLS cannot hold a socket for the home; the label starts with
  EXPERIMENTAL as RFC 5705 asks.
- Restores, roster expiry, purge receipts, tiles for phones, Live
  Activity tokens and what Apple sees are now stated; timers agree
  between the ADR and the protocol. Eight new vectors cover the cases.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The protocol was written before the code. #1595 (C2) and
#1603 (C3) each list where the code had to differ. This moves
those differences into the text so it stays normative.

From C2: fieldSources travels only with sources; a roster at every
connect; a deadband on lp's measured values; [] and null on the wire;
session as a plug-in count; manual.reason as the limit reason;
hello.caps as the classes sent; prices from the start of today; the
service signs over the box's home id; no step-up on the grant; a
restore never brings cloud.key back.

From C3: /v1/app?home=<id>; message 2 as an unsigned snapshot
envelope with spill-over frames; a phone's watch holds until it
changes, and the service renews the box's every 50 s; close codes
4400, 4403, 4408, 4409, 4429 and 1013, with the phone's retries;
session limits; hello_ok.cloud (K11); the statistics consent routes,
which push nothing; case 12 shows no sources rather than stale ones;
role names are not generated in go/protocol.

ADR 0008: turning FTW Cloud on or off notifies owners, not every
change; the protocol has sixteen cases, not eight.

TestFieldsMatchTheProtocolDocument passes against this text on the
C3 branch (c6301a0).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@frahlg
frahlg changed the base branch from claude/cloud-c1b-adr-128531 to master October 13, 2026 08:27
@frahlg
frahlg marked this pull request as ready for review October 13, 2026 08:31
@frahlg
frahlg merged commit f592ab9 into master Oct 13, 2026
13 checks passed
@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 added a commit that referenced this pull request Oct 13, 2026
#1607 added ts to the event body and its allowlist. #1604 then brought
in docs/protocol-cloud.md without that row, so the test that compares the
allowlist with the document failed on master. CI did not see it because
#1604 changed only docs.

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