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.
| 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) |
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.
FixoWizardTemplatePickPage. Three regions stacked top-to-bottom:
QTableView painted by
PresetTemplateRowDelegate showing icon + title + badge chips +
subtitle + actuator/sensor/lobe count chips.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).
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 |
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.
| 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.
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:
SETTINGS_KEY_FIXO_CONFIG_SKIPPED → true.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.
Every entry is a fresh decision point per §FW-7.2:
| 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.