FixoWizard reference

A single linear wizard that takes a fresh agent from "nothing configured" to "firmware running on the board." Owns the end-to-end Fixo authoring UX.


At a glance

Field Value
Activity name FixoWizard
Header "Set up Fixo"
Pages 4 (Introduction → Pick template → Configure → Build & inject)
Launchable via AgentUnboxingWizard.controller_config, agent main-menu Controller row, OPAL fixo.wizard.open
Owns Step list + page navigation, skip flag, running-hashes set
Does not own Build / flash subsystems (those live in libfirmware and ride on BuildInjectWidget)

Pages

Page 1 — Introduction

Inline activity (FixoWizardIntroductionPage). One sentence of concept, Continue to advance, Learn more to push HelpActivity with the Fixo overview doc. No inputs, no toggles — the wizard self-suppresses on isComplete() once dismissed.

Page 2 — Pick template

FixoWizardTemplatePickPage. Three regions stacked top-to-bottom:

  1. Filter bar — search input (~80 ms debounce) plus four badge toggles (Official / Vetted / Popular / Unbadged). Defaults: Official + Vetted on, Popular + Unbadged off.
  2. Template list — QTableView painted by PresetTemplateRowDelegate showing icon + title + badge chips + subtitle + actuator/sensor/lobe count chips.
  3. Manual setup (expert only) — bails out of the wizard into FixoStudioActivity, preserving whatever the user has typed.

Continue advances with the picked template id; back leaves the prior pick in place (per §FW-7.2).

Page 3 — Configure template

FixoWizardTemplateConfigurePage. Data-driven form built from the template's declared parameters. The form is reactive — every field edit re-runs PresetTemplate::instantiate() against the parameter map, re-resolves the stanza template, and refreshes the BuildInjectWidget band at the bottom. No Save buttons — the live preset is always the latest snapshot of what was typed. Continue lights up only when the live instantiate result is complete enough to build.

The form's widget registry:

Parameter type Widget
int, pin QSpinBox (constraints: min, max)
float QDoubleSpinBox (constraints: min, max, step)
bool QCheckBox
enum QComboBox (constraints: QStringList of allowed values)
board-type QComboBox populated from FixoBoardTypeBook
channel QLineEdit (will become a typed picker once the host wires the channel registry)
string and fallback QLineEdit

Page 4 — Build & inject

FixoWizardBuildInjectPage. Centred BuildInjectWidget with a thin chrome — the widget owns every action button. The page's only button is Done, which is enabled once the widget reaches BuildInjectMode::Running. Clicking Done pops with the preset's contentHash() so the wizard can record it in the running-hashes set.


Completion states (three-state)

State Indicator When
Green / Done green check The agent's active preset has reached Running on this agent — its contentHash() is in SETTINGS_KEY_FIXO_RUNNING_HASHES.
Amber / Acknowledged amber dot The skip flag (SETTINGS_KEY_FIXO_CONFIG_SKIPPED) is true. Set by the wizard's footer Skip button, the unboxing wizard's controller_config skip surface, or the OPAL fixo.wizard.skip task.
Grey / Not yet grey dot Neither of the above.

AgentUnboxingWizard.controller_config.isDone returns true for both Green and Amber, and its statusText differentiates ("Configured" / "Configuration incomplete"). Reaching Running clears the skip flag automatically.

Editing the preset changes its content hash and demotes the row to Grey until the new hash also reaches Running.


Skip semantics

The Skip button is reachable from every page past Introduction — either as the wizard's footer Cancel (re-labelled "Skip — set up Fixo later") or as the unboxing wizard's per-step skip surface. Pressing either:

  1. Sets SETTINGS_KEY_FIXO_CONFIG_SKIPPED → true.
  2. Pops the wizard back to its caller.
  3. controller_config re-evaluates and renders Amber.

There is no confirmation modal — the button label is the explicit acknowledgement.

Pressing Back inside FixoWizard does not set the skip flag (only the explicit Skip button does); the user is free to navigate up and down without committing to "I gave up." A later phase may revisit this if the pattern doesn't match real usage.


Re-entry

Every entry is a fresh decision point per §FW-7.2:


OPAL surface

Task Effect
fixo.wizard.open Push FixoWizard onto the activity stack.
fixo.wizard.pickTemplate(name) Push with a pre-selected template; skips Page 1.
fixo.wizard.configureTemplate(name, values) Push with template + JSON parameter values; lands on Page 3 with the form pre-filled.
fixo.wizard.build Trigger the BnI Build action on the active wizard. Fails when no wizard is active.
fixo.wizard.inject Trigger the BnI Inject action on the active wizard.
fixo.wizard.skip Set the Amber skip flag through the active wizard's host.

The build / inject / skip tasks all route through FixoWizardActions::instance() — a singleton mediator the wizard registers with on push and unregisters on dtor.