Skip to content

fix(hud): let a Settings banner carry its own next step - #494

Draft
michelhonold wants to merge 3 commits into
mainfrom
fix/hud-settings-banner-next-step
Draft

michelhonold wants to merge 3 commits into
mainfrom
fix/hud-settings-banner-next-step

Conversation

@michelhonold

@michelhonold michelhonold commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Plan

  • enter_settings_menu takes an action= beside banner=, stored, cleared on exit, carried into OverlayState
  • The Settings ERROR box draws a banner's own step on its second line; the video failure's step only under the video failure
  • Callers that put an observation and a step in one banner pass them separately, words unchanged
  • The auto-opened video banner passes the failure's own step
  • Tests, status-language doc
  • Split the pinned-interface warning into observation and step on both the Settings box and the web UI's PSN section (the user's decision)

Summary

Fixes #371.

The Operator Screen's Settings error box drew a banner as one line and put the video failure's next step under any banner, whether or not it belonged to it. A banner that needed its own step had to fold it into its sentence, which docs/STATUS_LANGUAGE.md rules out for a box, and could show an unrelated video step beneath it.

  • enter_settings_menu(banner=, action=): the action is the banner's one next step, drawn under it in the box's lighter second-line style. The box draws the video failure's step only when it shows the video failure (no banner).
  • Moved to the two-line form, with their words unchanged (only the split at the sentence boundary):
    • a source switch or value that could not be applied ("Couldn't switch to … / Couldn't apply …" + "Configure … in the web UI, then try again." / "Try a different value, or edit in the web UI.")
    • a change that is live but could not be saved ("… is live but could not be saved. The settings file …" + "…, then switch again.")
  • The startup video auto-open passes the failure's own step, so what it shows is unchanged.
  • The pinned-interface warning, by the user's decision, is split the same way on both surfaces it shares: "Pinned network interface '…' is not available. No usable interface." with "Pick one to continue." under it, on the Operator Screen's Settings box and in the web UI's PSN section box (as its muted .notice-sub line). It is still worded in one place, _refresh_psn_source_advisory, which sets the banner and its step; the web advisory carries the step as step. The fallback form ("… Using auto-detected .") has no step.

Test plan

  • Renderer: a banner's step is drawn muted and lighter under it, and the video's step is not drawn under a banner, with or without a step of its own
  • Every caller's banner and step asserted word for word; enter / exit store and clear the step; the app wrapper forwards it
  • The auto-opened video banner carries the failure's step for the source kind, refreshed while the menu stays open
  • Pinned-interface warning: the startup Settings menu opens with the banner and its step word for word; the advisory sets and clears the step with the banner; the web provider passes it; the PSN section renders it as the box's second line (and none for the fallback form); the Settings box draws it muted under the bold observation
  • Every new or changed test mutation-checked
  • Targeted tests, ruff, mypy
  • make ci-remote
  • On the Operator Screen: a Settings banner with a next step (for example a source switch that fails) shows the step on its own lighter line, and no video step under it
  • Pin the station to an interface that is absent at startup on a station with two or more other interfaces and no usable address: the Settings box and the web UI's PSN section both show "Pick one to continue." on its own muted line

🤖 Generated with Claude Code

michelhonold and others added 3 commits October 21, 2026 00:27
The Settings error box drew a banner as one line and put the video
failure's next step under any banner, whether or not it belonged to it.
A banner that needed its own step had to fold it into its sentence,
which the status language rules out for a box, and could show an
unrelated video step beneath it.

enter_settings_menu now takes an action beside the banner, drawn on the
box's second line; the video failure's step is drawn only under the
video failure. The callers that joined an observation and a step in one
banner (a switch or value that could not be applied, a change that is
live but could not be saved) pass them separately with unchanged words,
and the auto-opened video banner passes the failure's own step.

Fixes #371

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Also names the no-step renderer test after what it asserts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The startup warning for a station interface that cannot be honoured
folded its next step into the sentence after an en-dash ("No usable
interface – pick one to continue."), on the Operator Screen's Settings
box and in the web UI's PSN section alike. Both surfaces now show what
was observed on the main line and the step on a muted second line, as
docs/STATUS_LANGUAGE.md asks of a box.

The pair is still worded in one place: _refresh_psn_source_advisory
sets the banner and its step on the app, the Settings menu opens with
them as banner= and action=, and the web provider passes the step to
the PSN partial, which renders it as the box's .notice-sub.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@michelhonold michelhonold added the bug Something isn't working label Oct 21, 2026
@michelhonold

Copy link
Copy Markdown
Contributor Author

Review rounds

Three rounds over the full git diff origin/main HEAD.

Round 1

  • Minor: the status-language bullet split an inline code span across two lines; reworded. Fixed in e37f180.
  • Minor: a renderer test was named "draws no second line" but asserted only that the video's step is absent; renamed after what it asserts. Fixed in e37f180.
  • Found during build, before the rounds: a VideoFailure.NONE guard in the video banner's step lookup was an equivalent mutant (failure_action already returns "" for it); removed in 20ef5e3.

Round 2 - nothing beyond cosmetic. Checked: every opener of the Settings menu (11 call sites), the manual-open fallback (video sentence or element wording) still draws the video step, the auto-open banner's step is refreshed with its text each frame while the menu is open, the Settings menu is not a cached picture so the new state field needs no cache key, the render thread only reads the new OverlayState field.

Round 3 - nothing new.

Left as is

  • The pinned-interface banner at startup ("Pinned network interface '…' is not available. No usable interface – pick one to continue.") still carries its step after an en-dash. The same string is the PSN section's warning in the web UI, and splitting it changes punctuation and casing on both surfaces, so it was left for a decision. The user chose to split it on both surfaces; done in 402101d (below).
  • The Network screen's save-failure status row still reads "Could not save - the interface is unchanged. ." in one row; it is a status row, not the Settings box.
  • Cosmetic: a few pre-existing test fixtures use 10.0.0.x addresses rather than RFC 5737 ones; untouched.

Mutation results (each broke a test): renderer back to video_failure_action; enter_settings_menu not storing the step; exit not clearing it; marker-visuals not copying it; the video step lookup returning ""; ignoring the source kind; the refresh path not updating it; each caller dropping its action=; the app wrapper not forwarding it.

Pinned-interface warning split (the user's decision)

The pinned-interface warning moved to the two-line form on both surfaces in 402101d: main line "Pinned network interface '' is not available. No usable interface.", step "Pick one to continue.". The web UI's PSN section draws the step as the caution box's .notice-sub; the Operator Screen's Settings box draws it as the banner's muted second line. One source: _refresh_psn_source_advisory sets both on the app, read by the Settings menu (action=) and the web provider (step).

Round 4 (full git diff origin/main HEAD)

  • Rare: the refresh resets the step at the top and sets the banner at the end, so a web render on another thread between the two writes could pair the old banner with an empty step for one render. Left as is: the next render is right, and the refresh runs only on a station-interface change.
  • Cosmetic: the multi-NIC startup test's expected banner carries the fixture's existing 10.0.0.1 address rather than an RFC 5737 one; the new tests use RFC 5737 addresses.
  • Cosmetic: the web test asserts no notice-sub anywhere in the PSN section for the fallback form, which a future second box in that section would trip.

Round 5 - nothing beyond cosmetic. Checked: every consumer of the advisory (PSN partial, the services provider, the server's empty default, the live-apply refreshes in configuration.py), the Simple-mode PSN render with an advisory that has no step key, the step is cleared on a honoured pin, on an unpinned station and on a fallback to an auto-detected address, the help drawer and docs quote no warning text (the network guide now names the one place it is worded).

Mutation results (each broke a test): the startup menu opened without the step; the step never set; the step not reset (a stale step outliving its banner); the banner keeping the step in its sentence; the web provider dropping step; the server's empty default dropping it; the PSN partial not rendering the step, rendering it outside the box, rendering an empty second line for the fallback form, rendering it without .notice-sub; the Settings box drawing the video's step under the banner.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(hud): a Settings banner can't carry its own next step

1 participant