Keep a way back to the plan after Self (manual) - #57
Conversation
Choosing a fallback hid the next step: the planner cards stayed on the page but nothing said they were the way out, and the tap itself only dimmed. A house already on Self (manual) now gets an In use mark, Sending while the command is in flight, and a Use the plan button that restores the first primary mode. Signed-off-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Fredrik Ahlgren <fredrik@sourceful-labs.com> Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
ftw-webapp | 771ebcc | Commit Preview URL Branch Preview URL |
Aug 31 2026, 04:51 AM |
Choosing Self (manual) used to leave the extras open, so the way back scrolled off under Idle, Peak and Charge. The selected fallback already renders when the drawer is closed; fold the extras on the tap. Signed-off-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Fredrik Ahlgren <fredrik@sourceful-labs.com> Signed-off-by: Cursor Agent <cursoragent@cursor.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: 771ebccb72
ℹ️ 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".
| aria-pressed={plan.shownMode === info.key} | ||
| disabled={!plan.canControl || plan.command.kind === 'sending'} | ||
| aria-pressed={pressed} | ||
| disabled={!plan.canControl} |
There was a problem hiding this comment.
Queue correction taps until the control revision advances
When a user taps a second mode before the first command's round trip completes, both Session.command() calls are created with the same controlRev. The box accepts the first command, increments that revision, and then rejects the second with E_CONFLICT, so the initially mis-tapped mode remains active even though these newly enabled buttons suggest it can be corrected immediately. Keep the controls disabled during the in-flight request, or queue the later selection until the updated revision arrives.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default 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 771ebcc. Configure here.
|
|
||
| try { | ||
| const result: CmdResult = await this.#site.command(OP_SET_MODE, { mode }) | ||
| if (mine !== this.#cmdGen) return |
There was a problem hiding this comment.
In-flight correction hits a conflict
Medium Severity
#cmdGen only stops a stale result from painting. A second setMode is still sent immediately with the same controlRev as the in-flight one, so the box applies the earlier tap and refuses the correction as E_CONFLICT. The house stays on the mis-tap and the UI reports that something else changed the setting.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 771ebcc. Configure here.
Master replaced the Passive/Active strategy pair with the household prefs on the Plan card -- the trust slider and the battery-sale permission -- and renderModeCatalog now skips every planner_ key, so the primary row renders empty and hides itself. That left no control anywhere in the dashboard that starts planning again: once a house sat in a manual mode it stayed there, while the card told it to "select a planning strategy" that no longer exists. Only HA, the phone app or the API could get it out. The phone app already shipped the answer (srcfl/ftw-webapp#57); the dashboard never got it. "Use the plan" appears on the card whenever a manual mode drives, and hands the house to the planner mode its own preference implies. The server owns that mapping -- GET /api/planner/prefs returns mapped_mode -- so the button never decides whether this battery may sell. A prefs read that fails or answers with anything else falls back to the passive mode: permission to sell is a deliberate household answer, never a default. The button routes through setMode, so the optimistic paint and the pending-mode hold behave as they do for any tap, and it is disabled with the planner's own reason when MPC cannot run, matching Replan. Both manual sentences now name the button that exists. Verified in a browser against a local box with the planner enabled: export allowed -> planner_arbitrage; export not allowed -> planner_passive_arbitrage (real mouse click); prefs read rejected -> passive even though permission was on file; the button hides itself as soon as the planner drives, and is dimmed with "not-allowed" when the planner is off. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01C1d4uknzs7QUv7nE9rW4fi
* fix: keep Manual… visible after leaving the planner Simple view hid the fallback buttons behind .advanced-only, so a house already on Self (manual) had no selected strategy and no way back. The toggle and the button row stay on the Plan card, open when the live mode is a fallback, and mark the tap before the POST. Signed-off-by: Cursor Agent <cursoragent@cursor.com> * fix(web): auto-open the manual drawer only on a mode change The status poll runs every couple of seconds and carried the same mode each time, so revealManualModes forced the drawer back open a second after someone pressed Hide manual. Reveal now returns early when the mode has not changed since the last reveal, which leaves an explicit collapse alone while a move to a different manual mode still puts that button on screen. The tracker is recorded only once the mode catalog has painted: before that a missing button means "not rendered yet", and recording it would make the catalog's own call a no-op and leave a manual house with a closed drawer -- the bug this branch set out to fix. A tap also holds its optimistic paint for up to four seconds, so a status read already in flight with the previous mode can no longer flash the old button back. The hold clears on server confirmation, on expiry, or when the write fails. Verified in a browser against a local box: a manual live mode opens the drawer on load, Hide manual survives four polls, an external mode change reopens it, and a tapped strategy stays marked from the tap onwards. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01C1d4uknzs7QUv7nE9rW4fi * feat(web): give a manually-driven house a way back to the plan Master replaced the Passive/Active strategy pair with the household prefs on the Plan card -- the trust slider and the battery-sale permission -- and renderModeCatalog now skips every planner_ key, so the primary row renders empty and hides itself. That left no control anywhere in the dashboard that starts planning again: once a house sat in a manual mode it stayed there, while the card told it to "select a planning strategy" that no longer exists. Only HA, the phone app or the API could get it out. The phone app already shipped the answer (srcfl/ftw-webapp#57); the dashboard never got it. "Use the plan" appears on the card whenever a manual mode drives, and hands the house to the planner mode its own preference implies. The server owns that mapping -- GET /api/planner/prefs returns mapped_mode -- so the button never decides whether this battery may sell. A prefs read that fails or answers with anything else falls back to the passive mode: permission to sell is a deliberate household answer, never a default. The button routes through setMode, so the optimistic paint and the pending-mode hold behave as they do for any tap, and it is disabled with the planner's own reason when MPC cannot run, matching Replan. Both manual sentences now name the button that exists. Verified in a browser against a local box with the planner enabled: export allowed -> planner_arbitrage; export not allowed -> planner_passive_arbitrage (real mouse click); prefs read rejected -> passive even though permission was on file; the button hides itself as soon as the planner drives, and is dimmed with "not-allowed" when the planner is off. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01C1d4uknzs7QUv7nE9rW4fi * style(web): keep the Plan card's controls to a readable column The card is as wide as the chart below it. A slider and four buttons stretched across that width read as a banner rather than as something to touch, and the help text under them ran to a line nobody wants to follow. Slider, export row, manual drawer and the rules between them now share a 560px column, prose caps at 70ch, and "Use the plan" takes the accent and only the width its label needs -- so the card has one obvious action instead of a full-width bar. Moves that button's accent rule from style.css to app.css, beside the Plan card's other prefs styling and modelled on #plan-export-allow; the disabled state is left to the mode buttons' existing opacity rule. The strategy hint is hidden while empty, so the planner no longer leaves a bordered blank strip where a manual mode's description goes. Checked in a browser at both themes, in a manual mode and under the planner. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01C1d4uknzs7QUv7nE9rW4fi --------- Signed-off-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
miravoss26
left a comment
There was a problem hiding this comment.
Adds a way back from a manual mode (Self, Idle, Peak, Charge) to the plan in the Plan view, plus fixes a real race: PlanStore.setMode could let an earlier in-flight command's result paint over a later one's UI state.
- Correctness: the
#cmdGensequence-number guard is the right fix for the race — eachsetModecall is tagged, and a stale call's callback bails if a newer one has since started. Testdoes not let an earlier mode change paint over a later oneexercises this directly with a held promise + mockedsite.command, which is a solid way to prove the ordering.inManual/planHomederive fromshownModerather thanactualMode, matching the stated intent (optimistic UI, "hides the manual banner at once, rather than waiting for the box to confirm"). - UI: viewer role is correctly excluded from the "Use the plan" button and the mode buttons stay disabled (covered by the
does not offer Use the plan to a viewertest). - Security: no secrets, no new dependencies, no new network destinations — pure client-side state/UI change.
- CI: green (one skipped Bugbot check, rest pass).
Safe to merge from my read.




What changed
On the Plan screen, choosing Self (manual) (or any other fallback) left the planner cards on the page without saying they were the way out, and the tap itself only dimmed the row. A house already on a fallback now gets:
planner_passive_arbitrage)Catalogue labels stay the box's wording. Nothing is renamed to "Optimal".
Why
Björn could not get back from Self (manual) to the planner. The cards were still there; they just looked like jargon, and tapping one of the fallbacks gave almost no feedback. Fredrik confirmed the buttons looked missing.
Open PR #55 touches
Plan.sveltefor a small CSS pass. This PR only adds the way-back banner, selected-state copy, and folding the extras after a manual tap.Boundaries and safety
plan.primaryModes[0], not a new mode.setModeis not overwritten by a stale in-flight command.Verification
npx vitest run src/views/Plan.svelte.test.ts src/lib/state/plan.test.ts— 35 passed.Self (manual) in use, Use the plan on screen, extras folded
Passive arbitrage restored after Use the plan
plan_self_manual_folds_use_the_plan.mp4
To show artifacts inline, enable in settings.