Skip to content

iPhone: security notices from FTW Cloud, and the car class in CloudView - #77

Merged
frahlg merged 2 commits into
mainfrom
claude/cloud-notices-car
Oct 16, 2026
Merged

frahlg merged 2 commits into
mainfrom
claude/cloud-notices-car

Conversation

@frahlg

@frahlg frahlg commented Oct 16, 2026 •

Copy link
Copy Markdown
Member

What

The phone half of two things FTW Cloud now carries. The box halves are srcfl/ftw#1661 (notices) and srcfl/ftw#1662 (the car class); the service half is srcfl/ftw-cloud#23.

Security notices

A box tells every owner when someone gains access, asks for a change, is about to lose access, can now approve access, or pairs as an owner. FTW Cloud sends the box's signed notice in an alert to the owners' phones, with the readable copy on or off.

  • PushAlert reads a signed notice in the alert's event member as an event of its kind, for a day, as Go's ReadAlert does. It refuses a notice with any field beyond the header, a boot that is not 16 bytes, a kind outside the five, or a client's name on another kind or longer than the consent page's 64 characters and "…" or with a control or format character. A notice kind in an event envelope still reads as generic, as push: copy the agents' kinds from srcfl/ftw's catalogue #78 made it.
  • PushText: the kinds, the catalogue and the Swedish came with push: copy the agents' kinds from srcfl/ftw's catalogue #78. agent.added names the client when the box sent a name that will do: "Claude was given access to your box. See who has access in the app." / "Claude har fått åtkomst till din box. Se vem som har åtkomst i appen." The box sends it only while the readable copy carries events. Otherwise the catalogue's sentence shows. That named sentence is the phone's own, so the catalogue test does not hold it. Notices get no buttons and the usual interruption level.
  • PushSeen keeps the numbers it showed per home and boot, the newest 64 above a floor, so a notice that arrives after a later event is shown once, not quieted as a repeat. A file from before keeps its highest number as the floor.
  • SiteModel.takesAlerts: an owner's phone registers for FTW Cloud's alerts whenever the box is linked, not only with the copy on. Without that, no owner hears a notice with the copy off. A viewer still registers only with the copy. Two lines; it sits outside the Carrier and push files on purpose.

The car class

  • CloudWire.Cars, Car, CarGoal and carID; a charger's carId, carIdentifiedBy, carCorrected, carCorrectedFrom and choose; car is a phone class.
  • CloudView holds cars and joined(_:): a charger's level and goal read from its session's car, the car winning where the two disagree, as the protocol says. socReadAtMs dates the level from the car class's own send time, so an old class cannot say "read a minute ago". takeCloudCars uses both and runs on car too.
  • No screen reads cars yet; that belongs to the car view.

Copies from srcfl/ftw

push-vectors.json (srcfl/ftw#1661's, ten notice cases) and cloud-vectors.json (master's, with the car messages and ids). The catalogue came with #78; agent.added now reads "An assistant or Sourceful was given access to your box. See who has access in the app." from srcfl/ftw-webapp#94 (review S6), and the Swedish says the same.

Tests

  • PushAlertTests replays all 28 push vectors and 27 cloud messages.
  • PushTextTests.aNoticeNamesTheClientWhenItCan; the catalogue tests now cover the five kinds.
  • CloudWireTests decodes the car class and the asking and tapped chargers, and cuts car ids as Go does.
  • CloudViewCarTests.aChargerReadsItsCarAndTheCarWins, with the read time from the car class's send.
  • PushStoreTests.anEventIsShownOnce (a late, lower number is shown once) and theNumbersKeptAreBounded (the floor, and a file from before).
  • swift test in appleApp/FTWKit: 461 + 257 tests pass.

Not done: a look at the notification in the simulator. The words come from PushText, which the tests above hold.

Not here: a tap on a notice opening the Access screen. It follows once #76 lands.

Deploy order

Cloud first (srcfl/ftw-cloud#23), then boxes (srcfl/ftw#1661, #1662), then phones (this).

Keeps clear of FTW/Access/* and FTW/Car/*. #74 and #76 touch CloudView, CloudWire and SiteModel, in other hunks.

🤖 Generated with Claude Code

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 16, 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-16T08:09:43.444312Z 4aaed24 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.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4aaed2491d

ℹ️ 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".

cloudView = view
switch env.t {
case CloudWire.msgLP: takeCloudCars(at)
case CloudWire.msgLP, CloudWire.msgCar: takeCloudCars(at)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Use the car timestamp for car-triggered updates

When a car envelope arrives after the current lp, this calls takeCloudCars, but that function stamps the joined result using view.sentMs(lp.header, ...). LoadpointsModel.takeCloud rejects a non-cache result whose asOfMs is no newer than the displayed stamp, so after the LP has been consumed, a car-only SoC or goal update receives the same old LP timestamp and is discarded. Stamp car-triggered projections with the car header, or the newest relevant class send time.

Useful? React with 👍 / 👎.

/// whenever the box is linked, since security notices go to every owner
/// with the readable copy on or off; another phone only while the copy
/// carries its events.
private var takesAlerts: Bool { cloudOn || canConfigure }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Wait for confirmed ownership before prompting

Before the box answers hello, SessionState.role defaults to owner, so takesAlerts is true and startCloud installs the push sink even for a viewer, removed phone, or other unconfirmed connection. PushTokens.install immediately requests notification authorization; a later hello can uninstall the sink but cannot retract that one-time system prompt, and the asynchronous install can race with the uninstall. Require heardFromBox for the owner-only branch while retaining cloudOn for a known readable copy.

Useful? React with 👍 / 👎.

The notification extension reads a box-signed notice in an alert as an
event of its kind, for a day, since a notice states a lasting fact. It
checks the notice as Go's ReadNotice does: a 16-byte boot, and on
agent.added a client's name of at most the consent page's 64 characters
and its "…", with no control or format character. A notice kind sent as
an event still reads as generic (#78). agent.added names the client when
the box sent one: "Claude was given access to your box". An owner's phone
registers for FTW Cloud's alerts whenever the box is linked, so notices
reach it with the readable copy off.

PushSeen keeps the numbers it showed per boot, the newest 64 above a
floor, so a notice that arrives after a later event is shown, not
quieted as a repeat. A file from before keeps its highest as the floor.

CloudView holds the car class and joins a charger to its session's car
by carId, the car winning where the two disagree. socReadAtMs dates the
level from the car class's own send. The push vectors and the cloud
vectors are srcfl/ftw's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The catalogue from srcfl/ftw-webapp#94, and the same in Swedish. The
named line stays the phone's own, from the notice's client.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@frahlg
frahlg merged commit f90bf88 into main Oct 16, 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