Skip to content

Keep Manual… visible after leaving the planner - #1032

Merged
frahlg merged 4 commits into
masterfrom
cursor/restore-optimal-plan-mode-8480
Aug 31, 2026
Merged

Keep Manual… visible after leaving the planner#1032
frahlg merged 4 commits into
masterfrom
cursor/restore-optimal-plan-mode-8480

Conversation

@frahlg

@frahlg frahlg commented Aug 31, 2026

Copy link
Copy Markdown
Member

Accepted text proposal

Issue or Discussion: Discord #general, 31 Aug 2026 — Björn could not get back from Self (manual) to the planner; Fredrik confirmed the buttons looked missing.

Maintainer comment that accepted this scope: Fredrik ("Will get right to it") on the same thread.

What changed

Simple view hid the fallback buttons behind .advanced-only, so a house already on Self (manual) had no selected strategy and no labelled way back. The Manual… toggle and the button row now stay on the Plan card in simple view, open when the live mode is a fallback, and mark the tap before the POST.

Catalogue labels are unchanged.

Pairs with srcfl/ftw-webapp#57 (phone app: Use the plan + In use).

Why

The on-box LAN dashboard is the same trap as the phone app: once you leave the planner, the way back is CSS-hidden.

Boundaries and safety

  • Mode commands are still POST /api/mode; the box still validates.
  • Simple view still hides other advanced-only surfaces. Only this picker is excepted, because a live fallback has to stay reachable.
  • Optimistic paint is visual only; a failed POST is overwritten by the next status poll.

Verification

  • node --test web/mode-picker.test.mjs — 3 passed. The strategy block no longer carries advanced-only on the toggle or the button row; setMode paints active and opens the drawer before the POST.

The on-box UI was not driven in a browser in this environment (make dev needs the Ferroamp/Sungrow simulators). Phone-app behaviour is on srcfl/ftw-webapp#57.

Checklist

  • The diff implements one accepted scope and does not add follow-on work.
  • I checked open pull requests that touch the same files.
  • Tests cover the changed behaviour and its failure path.
  • A human reviewed every changed web/UI view in a browser, or no UI changed.
  • A Changeset is included, or the change is exempt.
  • Every commit has a DCO sign-off.
Open in Web Open in Cursor 

@frahlg
frahlg marked this pull request as ready for review August 31, 2026 05:02
@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-31T05:04:34.667660Z 1c10ac6 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: 1c10ac6914

ℹ️ 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 web/index.html
Comment on lines +553 to +556
<div class="mode-advanced-toggle">
<button class="btn-link" id="mode-advanced-btn" title="Show manual modes">Manual…</button>
</div>
<div class="mode-buttons mode-buttons-advanced advanced-only" id="mode-buttons" style="display:none"></div>
<div class="mode-buttons mode-buttons-advanced" id="mode-buttons" style="display:none"></div>

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 Complete the required browser inspection

This changes rendered strategy controls, yet the commit's own verification says the dashboard was not driven in a browser and leaves the human browser-review checkbox unchecked. A human needs to inspect the Plan card in simple mode with both planner and manual live states before landing, because repository policy does not allow source inspection and tests alone to validate UI changes.

AGENTS.md reference: AGENTS.md:L90-L91

Useful? React with 👍 / 👎.

Comment thread web/app.js Outdated
if (btn.dataset.mode === data.mode) btn.classList.add("active");
else btn.classList.remove("active");
});
revealManualModes(data.mode);

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 Preserve a user's collapsed manual drawer

When the live mode remains manual, the dashboard's two-second status polling reaches this call after every successful /api/status response and forces the panel back to display: flex. Consequently, clicking the newly visible “Hide manual” control collapses the drawer only until the next poll, when it reopens and the label flips back; auto-reveal should happen on initial load or a mode transition, while respecting an explicit collapse.

Useful? React with 👍 / 👎.

Comment thread web/app.js
Comment thread web/app.js

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

Stale comment

Not approved: Cursor Bugbot finished with unresolved findings that need human review (including a medium-severity poll/drawer issue). Reviewers were assigned.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

@cursor
cursor Bot requested a review from erikarenhill August 31, 2026 05:06
cursoragent and others added 2 commits August 31, 2026 07:32
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>
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
@frahlg
frahlg force-pushed the cursor/restore-optimal-plan-mode-8480 branch from 368f3d7 to b129511 Compare August 31, 2026 05:35
@frahlg

frahlg commented Aug 31, 2026

Copy link
Copy Markdown
Member Author

Both review findings are fixed in b129511, and the branch is rebased on master.

Poll reopens hidden manual drawer (Codex P2 / Cursor Medium) — correct, and it was the interesting one. revealManualModes now returns early when the mode has not changed since the last reveal, so the 2 s status poll no longer fights an explicit collapse. A move to a different manual mode still opens the drawer, because that button has to be on screen.

One extra guard turned out to be load-bearing. Recording the mode unconditionally breaks the initial load: render runs before the catalog has painted — it triggers renderModeCatalog() on the same tick — so the button lookup finds nothing, and the tracker would already be set. The catalog's own revealManualModes(currentMode) would then read as a repeat and leave a manual-mode house with a closed drawer, which is the exact bug this branch set out to fix. The tracker is therefore recorded only once modeCatalogRendered is true.

Optimistic mode mark lost to poll (Cursor Low) — fixed too. A tap holds its paint for up to 4 s; render prefers the pending mode and clears it on server confirmation, on expiry, or when the write fails.

Browser inspection (Codex P1) — done, against a local box with the simulators, and it drove the states rather than reading the source:

  • live mode self_consumption on load → drawer opens by itself, Hide manual label, Self (manual) marked active;
  • press Hide manual → still closed 9 s later, four status polls in (this was the bug);
  • external POST /api/mode {idle}, as the phone app or HA would → drawer reopens, Stop batteries marked;
  • tap Active arbitrage → marked from the tap onward, and it stays marked once the server confirms.

npm test is green (465 tests) and make verify passed in pre-commit. Screenshot of the Plan card with the drawer open is in the PR thread on the maintainer side.

One note for the human reviewer: after leaving a manual mode for a planner strategy the drawer stays open until you collapse it. That looked right in the browser — the buttons you just used do not vanish under your cursor — but it is a judgement call worth a second opinion.

Comment thread web/app.js
fetchStatus();
})
.catch(function () {
pendingMode = null; // the write failed — show server truth again

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Failed tap clears newer pending mode

Low Severity

The setMode failure handler always sets pendingMode to null, even when a later tap has already stored a different mode there. An in-flight status poll can then paint the old live mode over the newer optimistic selection until that second POST settles.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit b129511. 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.

Stale comment

Not approved: Cursor Bugbot skipped on this head and left one unresolved finding that needs human review. Reviewers were assigned.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

@cursor
cursor Bot requested a review from Leitet August 31, 2026 05:40
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

frahlg commented Aug 31, 2026

Copy link
Copy Markdown
Member Author

Scope correction, pushed as 91940d6. The maintainer pointed out that Passive/Active arbitrage is no longer how a household picks a strategy, and the branch was written against a master 64 commits old, where it still was. After the rebase the diagnosis changes.

What master actually does now: renderModeCatalog skips every planner_ key, so #mode-buttons-primary renders empty and sets itself hidden. The strategy pair was replaced by the household prefs on the Plan card — the forecast-trust slider and "Allow the battery to sell to the grid" — and the server maps those to a planner mode (mapped_mode).

So the reported bug is worse than this branch assumed. The manual buttons were not merely hidden behind .advanced-only; the way back was removed on purpose and its replacement shipped only in the phone app (srcfl/ftw-webapp#57). Driven in a browser on this rebased tree, with the live mode self_consumption: #mode-buttons-primary empty and hidden, no planner control anywhere on the page, and the card printing "Planner off — Select a planning strategy to enable it" with no strategy to select. applyPlannerPrefs (go/internal/api/api_planner_prefs.go:109) only calls ApplyMode when the controller is already in a planner mode, so the checkbox cannot rescue it either. A house that lands in a manual mode stays there unless someone reaches for HA, the app or the API.

What the branch does now, on top of the manual-drawer fix already reviewed:

  • a "Use the plan" button on the Plan card, shown only while a manual mode drives;
  • the planner mode comes from GET /api/planner/prefsmapped_mode, so this button never decides whether the battery may sell;
  • a failed or unusable prefs read falls back to planner_passive_arbitrage — permission to sell is a household answer, never a default;
  • it routes through setMode, inheriting the optimistic paint and the pending-mode hold from this PR's earlier commit;
  • it is disabled with the planner's own unavailable reason when MPC cannot run, the way plan-replan already is;
  • both manual sentences now name the button that exists ("Use the plan to create a schedule" / "…to enable it").

Browser evidence, planner enabled, real mouse clicks:

Driven Result
manual mode, export allowed button visible and accented; click → planner_arbitrage; button hides itself
manual mode, export not_allowed click → planner_passive_arbitrage
prefs read forced to fail, export allowed on file planner_passive_arbitrage; the fallback refuses the exporting mode
planner unavailable button dimmed, cursor: not-allowed, tooltip carries the planner's reason
manual drawer still auto-opens on a manual mode; "Hide manual" still survives repeated polls

npm test 469 pass, make verify green in pre-commit.

Two notes for the human reviewer. After returning to the planner the manual drawer stays open until collapsed — deliberate, but worth an opinion. And the button is a single primary action rather than a choice, which is the whole point of the simplification: the choice is the checkbox above it.

Comment thread web/plan-brief.js
Comment thread web/app.js

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

Stale comment

Not approved: Cursor Bugbot was present on this head but completed as skipped, so the required automated-review signal did not finish successfully. Reviewers were already assigned; none added.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

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

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

There are 2 total unresolved issues (including 1 from previous review).

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 4754273. Configure here.

Comment thread web/app.css
background: var(--accent-e);
color: var(--on-accent);
opacity: 0.9;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Disabled plan button lights up on hover

Low Severity

The #plan-use-btn:hover rule sets opacity to 0.9 with an ID, so it wins over the shared button:disabled fade and button:disabled:hover grey-out. When the planner cannot run, hovering Use the plan makes the disabled control look tappable.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 4754273. 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 on this head but completed as skipped, so the required automated-review signal did not finish successfully. Reviewers were already assigned; none added.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

@frahlg
frahlg merged commit aa8bf39 into master Aug 31, 2026
17 checks passed
@frahlg
frahlg deleted the cursor/restore-optimal-plan-mode-8480 branch August 31, 2026 08:25
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.

2 participants