Make the EV flow match Core with immediate and honest feedback - #63
Conversation
Press feedback on every control, direction-aware tab transitions and a haptic tick on tab switch. The shell keeps a phone shape on wide screens; the theme follows the OS live; the Android keyboard shrinks the layout so bottom sheets stay usable. Two failure paths now leave on their own: a stalled passkey ceremony gets a Cancel, and an open that outlives a beat says what it is doing. Manifest gains id and long-press shortcuts; update checks run at launch. Polish: scrim, z-index and pill tokens replace literals in the sheets and the canvas zero-line; micro-text sits at 10px or above; range pickers meet the 44px target floor.
The hero's box-page snapshot and the charger ask land in chunks after mount, inside the window this test judged. Let them settle first, so the assertion measures what the tap alone adds — which is the thing it was written to prove.
The box's own EV modal lets a person correct the car's charge level and switch charging to solar surplus only. The remote client drew neither, although both ops have existed since #61. - A "Car is at" slider above the charging controls, 0-100 in whole percent, prefilled from `current_soc` (a fraction since srcfl/ftw#962; `current_soc_pct` still read for older boxes) with its source in words from `soc_source`. It writes `loadpoint.soc.set` on release, says "Replanning from N %..." while out and "Plan updated from N %." when the box has read the level back, and rereads the charger. A draft holds the thumb until that reread lands, so the minute's ask cannot snap it. The unplugged refusal (`E_UNAVAILABLE`, `reason: "unplugged"`) gets its own sentence. Hidden when no car is on the cable. - A "Charge from solar surplus only" switch bound to `surplus_only`, writing `loadpoint.surplus_only.set` on toggle, with the same outcome sentences and reread. The boost offer already reads the flag and now follows it live. - The store resolves a command only after the charger has been reread, so the panel knows when the box's value is on screen. - The simulator serves `current_soc` and `soc_source` for a plugged car, answers both ops as the box does (refusing a level for an empty bay, reading a flag back as 1/0), refuses a boost while PV only is on and withdraws a running one with `surplus_only`. Closes #62 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
ftw-webapp | 8ead63a | Commit Preview URL Branch Preview URL |
Sep 06 2026, 02:40 PM |
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a6e694d41c
ℹ️ 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".
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit c470462. Configure here.



EV controls now follow Core's charging state and actions. Connecting a car brings its status onto Home; one tap opens the battery level, current command and ready-time goal. Opening a section does not change charging mode.
Battery level, goal and battery size save on release with pending, failure and readback feedback. Owners can set battery size before plugging in, as in Core; live car controls still require a connected car. A saved goal is confirmed while its plan is still being calculated. Failed planning does not become a false write failure, and old charge windows stay hidden. Pause waits for a fresh zero-power report. Charge now and Resume plan are separate actions. Viewer devices cannot change settings.
A failed first read shows waiting or error feedback; setup help appears only after a successful empty response. Tapping the car while reconnecting opens the panel immediately, keeps that intent and fills the same panel when the box answers. A connected box without charging API support gets an explanation. Home reads only the seven savings days that it displays. Current Core supplies charge windows in the same loadpoint response, so the EV poll does not wait for a full-plan read. Accepted SoC and solar choices remain visible if the following read fails. A confirmed goal deletion clears the old goal immediately and shows its own result even if status readback fails. External replanning uses neutral status text.
The command queue retries only explicit busy refusals. It never replays a write after a timeout or another uncertain outcome. Battery and charger messages distinguish missing evidence, failed persistence and actual charging without inventing a full battery or a successful write.
This branch includes the existing work in #55, with the LivePanel width corrected for desktop. Merge #55 first to leave the EV diff for review. Paired Core: srcfl/ftw#1074. Both commits carry the same push catalogue.
Validation: npm run verify passes 1017 tests with 1 skip on Node 24.20.0; Svelte reports 0 errors and 0 warnings. Build and test checks pass on this exact head. Browser scenarios cover late arrival at 12%, autosave, cloud delay, failed writes, pending and failed planning, retry, pause, reload and viewer permissions.
A mobile owner/passkey walkthrough passed on Core 6843ddd0 and Webapp 8ead63a against the real box. The goal slider saved 85% by 07:00 in 1.46 seconds while planning continued, then reached a current plan. Both clients retained the goal after reload; an early car tap during reconnect opened the panel. Remove showed Goal removed and cleared the target and deadline. Both clients saved battery size 60→61→60 kWh without Save while unplugged. The App retained each value after a full reload; Core retained the restored value after reload. No browser errors occurred. The temporary identity was revoked and the original four identities remain.
The car is unplugged during this final walkthrough. Physical current reduction, current battery level and push delivery to a closed phone app remain unverified on the final candidate. Battery-size changes also passed through the real owner connection while unplugged. No public Webapp deployment has been made.
Contract-pair: srcfl/ftw@6843ddd