Skip to content

feat(cloud): the car class in FTW Cloud's copy, and a charger's level and goal read from its car - #1662

Open
frahlg wants to merge 2 commits into
masterfrom
claude/cloud-car
Open

frahlg wants to merge 2 commits into
masterfrom
claude/cloud-car

Conversation

@frahlg

@frahlg frahlg commented Oct 16, 2026 •

Copy link
Copy Markdown
Member

What

FTW Cloud's copy carries the cars, as docs/protocol-cloud.md defines since #1647. The service half is srcfl/ftw-cloud#23 and the phone half srcfl/ftw-app#77.

Built on #1650, now merged; this is one commit on master.

  • The car class. When the site keeps cars (cloudlink.CarSite, which cmd/ftw's cloudSite meets with the car runtime), the link sends car under ftw.live.read: each car's level and goal by the grant's opaque id, through feat(cars): the car apart from the charger, in Core #1650's ProjectCars, so no name, maker, VIN, identifier or source leaves the box. It goes at most once per lp's period, in full every 15 minutes and after a resync, and hello.caps names it. A site without cars sends none, so the test fakes in other packages are untouched.
  • The change test. It ignores socAgeS and counts energySinceWh at 100 Wh, as the document says, and the level at 10 ‰, as lp counts its level. Without that band an estimated level that rises with a charging car would send the class at nearly every reading. Whether the level is an estimate counts at once. The document now says so.
  • The join rule. A charger whose session has a known car takes its level and goal fields from that car's own view: socPermille as the car's; socSource vehicle (with its socAgeS), assumed, unknown or inferred; targetPermille and recurring from the goal; surplusOnly as the car's. readyByMs stays the box's next ready time for that goal. Before this, within the first kWh after someone set the level, the charger showed the reading plus the energy since, with an empty socSource, while the car class showed the reading. The agent reads (loadpoints.get) use the same view.
  • lp.carId was already filled by feat(cars): the car apart from the charger, in Core #1650 and cut per grant by ProjectLP.

Tests

  • cloudlink: the class goes by an opaque id and names no car; it needs ftw.live.read (and the link does not read the cars without it); a goal goes within lp's period while 60 Wh does not; a resync sends it again; the change test's bands.
  • cmd/ftw: TestTheChargerShowsItsCarAsTheCarClassDoes runs the real car runtime and loadpoint manager through a tapped session: no level, a level set with half a kWh since, and an estimate. Without the join the second step fails (charger 431 with no source, car 420 manual).
  • GOFLAGS=-p=2 make verify: clean (vet, tests, build).

Contract check

This PR changes neither contract/registry.yaml nor contract/push-catalogue.yaml. Master's registry lags srcfl/ftw-webapp#91 (cloud_transports, which #1653 copies here), so the drift check fails on master and on every PR. This one compares against the webapp commit before #91, which matches master's copies byte for byte. Drop the line once #1653 lands.

Contract-pair: srcfl/ftw-webapp@bd5565e

🤖 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:01:35.574923Z 9aa7315 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: 9aa7315707

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

// The session names the plug-in the tap answers. The cars go
// with the event to FTW Cloud once the uplink cuts their
// opaque ids (docs/cars.md).
go s.handleCatalogued(PushCarWhich, ev.LoadpointID, map[string]string{"session": ev.Session})

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 Carry the car choices into car.which notifications

When an ambiguous session has two to four eligible cars, this drops ev.CarIDs and forwards only the session. Neither notifications.Message nor cloudlink.EventIn later reconstructs them, so projectEvent always leaves cloudwire.Event.Cars empty and the phone cannot render the promised one-button-per-car choice. Preserve the IDs through the notification message and project them to opaque car IDs in the cloud event.

AGENTS.md reference: AGENTS.md:L24-L25

Useful? React with 👍 / 👎.

Comment thread go/cmd/ftw/cars_wiring.go
Comment on lines +94 to +98
if lp.VehicleCapacityWh != prev.VehicleCapacityWh && lp.VehicleCapacityWh > 0 {
c.CapacityWh = &lp.VehicleCapacityWh
}
if plugin, prevPlugin := pluginFraction(lp), pluginFraction(prev); plugin != prevPlugin && plugin > 0 {
c.PluginSoC = &plugin

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 Propagate clearing legacy loadpoint settings

When an operator removes vehicle_capacity_wh or plugin_soc from config (so the new value is zero), these > 0 guards suppress the reload change. The migrated car therefore retains the old persisted capacity or plug-in SoC and immediately reapplies it to the loadpoint, so hidden state continues steering charging despite the setting being cleared. Zero-valued transitions need to clear the corresponding car field rather than being ignored.

AGENTS.md reference: AGENTS.md:L20-L21

Useful? React with 👍 / 👎.

… and goal read from its car

The link sends the car class under ftw.live.read when a site keeps cars:
each car's level and goal by the grant's opaque id, with nothing that
names the car, at most once per lp's period, in full every 15 minutes and
after a resync. The change test counts energy and an estimated level with
lp's deadbands. A charger whose session has a known car takes its level,
source, goal, recurrence and surplus choice from the car's own view, so the
two classes agree where a phone joins carId to the car.

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