Skip to content

Keep a way back to the plan after Self (manual) - #57

Open
frahlg wants to merge 2 commits into
mainfrom
cursor/restore-optimal-plan-mode-8480
Open

Keep a way back to the plan after Self (manual)#57
frahlg wants to merge 2 commits into
mainfrom
cursor/restore-optimal-plan-mode-8480

Conversation

@frahlg

@frahlg frahlg commented Aug 31, 2026

Copy link
Copy Markdown
Member

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:

  • an In use mark on the selected card (and Sending… while the command is in flight)
  • a Use the plan button that restores the first primary mode (planner_passive_arbitrage)
  • the extra fallbacks folded after the tap, so Use the plan stays on screen instead of sitting above Idle / Peak / Charge
  • the selected fallback still shown when the drawer is closed, so a house already on Self (manual) does not need "More ways" to see what is running

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.svelte for 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

  • The app still only sends a mode command; the box decides.
  • "Use the plan" maps to plan.primaryModes[0], not a new mode.
  • Viewers see the copy, not the button.
  • A later setMode is not overwritten by a stale in-flight command.
  • Buttons stay enabled while sending so a mis-tap can be corrected.

Verification

  • npx vitest run src/views/Plan.svelte.test.ts src/lib/state/plan.test.ts — 35 passed.
  • Browser, simulated home: More ways → Self (manual) folds the extras and keeps Use the plan on screen → Use the plan restores Passive arbitrage.

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.

Open in Web Open in Cursor 

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>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 31, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

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>
@frahlg
frahlg marked this pull request as ready for review August 31, 2026 04:56
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 31, 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-08-31T04:58:03.918027Z 771ebcc Draft marked ready
ℹ️ 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: 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".

Comment thread src/views/Plan.svelte
aria-pressed={plan.shownMode === info.key}
disabled={!plan.canControl || plan.command.kind === 'sending'}
aria-pressed={pressed}
disabled={!plan.canControl}

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 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 👍 / 👎.

@cursor cursor 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.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

❌ 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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 771ebcc. Configure here.

@cursor cursor 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.

Not approved: Cursor Bugbot was present but skipped, so the required automated-review signal did not complete successfully. Reviewers were assigned for human review.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

@cursor
cursor Bot requested review from Leitet and davmoz August 31, 2026 05:01
frahlg added a commit to srcfl/ftw that referenced this pull request Aug 31, 2026
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
frahlg added a commit to srcfl/ftw that referenced this pull request Aug 31, 2026
* 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 miravoss26 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.

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 #cmdGen sequence-number guard is the right fix for the race — each setMode call is tagged, and a stale call's callback bails if a newer one has since started. Test does not let an earlier mode change paint over a later one exercises this directly with a held promise + mocked site.command, which is a solid way to prove the ordering. inManual/planHome derive from shownMode rather than actualMode, 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 viewer test).
  • 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.

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.

3 participants