Replace the monolithic MainWindow with a SelectedPage-driven shell (Dashboard / Pump / Bench / Tests / Results / Settings). The Tests page gets the Plan -> Preconditions -> Running -> Done wizard from ui-structure.md \u00a74, backed by a 7-item precondition gate and shared sub-views (PhaseCardView / TestSectionView / GraphicIndicatorView) extracted from the now-deleted monolithic TestPanelView. New VMs / views: - Tests wizard: TestPreconditions, PhaseCard, GraphicIndicator, TestSection, TestPlan, TestRunning, TestDone - Dashboard panels: DashboardConnection, DashboardReadings, DashboardAlarms, InterlockBanner, ResultHistory - Pump / bench panels: PumpIdentificationPanel, PumpLiveData, UnlockPanel, BenchDriveControl, BenchReadings, RelayBank, TemperatureControl, DtcList, AuthGate - Dialogs: generic ConfirmDialog, UserManageDialog, UserPromptDialog Supporting changes: - IsOilPumpOn exposed on MainViewModel for precondition evaluation - RequiresAuth added to TestDefinition (XML round-trip) - BipStatusDefinition + CompletedTestRun models - ~35 new Test.* localization keys (en + es) - Settings moved from modal dialog to full page - Pause / Retry / Skip stubs in TestRunningView; full spec in docs/gap-test-running-controls.md for follow-up implementation - docs/ui-structure.md captures the wizard design Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
7.8 KiB
Gap: Tests page — Pause / Retry-phase / Skip-phase controls
Context
The Tests wizard (Plan → Preconditions → Running → Done) introduces three controls
in the Running step's bottom bar:
| Control | Purpose |
|---|---|
| Pause | Temporarily halts phase progression — bench coasts to a safe-RPM hold, keep-alive and CAN traffic continue, timers freeze. |
| Retry current phase | Aborts the current phase (without failing it), zeroes pump outputs, restarts the same phase from conditioning. |
| Skip current phase | Marks the current phase as "skipped" (neither passed nor failed) and advances to the next enabled phase. |
At the time of writing these three buttons exist in Views/UserControls/TestRunningView.xaml
rendered IsEnabled="False" with a Test.Running.ComingSoon tooltip. This document
captures the full requirements for a follow-up task that wires them to IBenchService.
Required IBenchService API additions
/// <summary>
/// Pauses the currently running test. The bench holds at idle RPM, oil pump stays on,
/// keep-alive continues. Phase timers are frozen. No-op if not running.
/// </summary>
Task PauseAsync(CancellationToken ct = default);
/// <summary>
/// Resumes a paused test. Re-arms phase timers from where they were frozen.
/// Throws <see cref="InvalidOperationException"/> if not paused.
/// </summary>
Task ResumeAsync(CancellationToken ct = default);
/// <summary>
/// Aborts the current phase (without marking it failed), zeros pump outputs
/// (ME/FBKW/PreIn → 0), and restarts the same phase from the beginning of
/// its conditioning sub-section. No-op if not running.
/// </summary>
Task RetryCurrentPhaseAsync(CancellationToken ct = default);
/// <summary>
/// Marks the current phase as "skipped" and advances to the next enabled phase.
/// Pump outputs are zeroed between phases. No-op if at the last enabled phase
/// (in that case the test completes normally).
/// </summary>
Task SkipPhaseAsync(CancellationToken ct = default);
All four methods must be callable from a UI thread and must not block — they
queue a transition request onto the existing BenchService worker loop and await
completion via a TaskCompletionSource.
Safe-state expectations per operation
Pause
- RPM: ramp to idle hold (configurable, default 600 rpm) using the existing ramp logic.
- Oil pump relay: stays on.
- Pump outputs: unchanged (paused at current values).
- Counter / encoder relays: unchanged.
- Keep-alive loop: continues.
- Phase countdown: frozen in place. Timer resumes on
ResumeAsync. - Measurement buffer: continues accumulating samples while paused? Decision needed — current recommendation is to discard samples received while paused, so tolerance evaluation uses only "active" measurement time.
Resume
- RPM: ramp from idle-hold back to the current phase's target RPM before un-freezing timers.
- Un-freeze phase timers only after RPM is within ±5% of target for ≥500 ms (same condition the initial conditioning ramp uses).
Retry
- Pump outputs: zeroed immediately (ME=0, FBKW=0, PreIn=0). This addresses the HIGH-priority gap in CLAUDE.md ("Pump parameters (ME/FBKW/PreIn) not zeroed between test phases") for the retry path specifically.
- Phase: same phase re-entered at start of conditioning.
- Results: any partial samples for the retried phase are discarded.
TestResult.Samplesfor that phase is cleared. PhaseChangedevent fires with the same phase name again so the UI re-highlights the card.
Skip
- Pump outputs: zeroed.
- Phase disposition:
TestResultrow is inserted withStatus = Skipped(new enum value onTestResult.Statusor existingPass/Failwith a separateIsSkippedflag). - Progress: next enabled phase in the same test, or next enabled test if this was the last
phase. If no enabled phase follows, the test completes as normal (
IsTestRunning = false).
UI state transitions
| Button | Enabled when | Label change |
|---|---|---|
| Pause | IsTestRunning && !IsPaused |
becomes "Resume" (Test.Running.Resume) while paused |
| Retry | IsTestRunning && !IsPaused |
static — no relabel |
| Skip | IsTestRunning && !IsPaused |
static |
| Abort | always while running (paused or not) | static |
When paused, the Retry and Skip buttons are disabled to simplify the state machine (operator must Resume first, then Retry/Skip). This keeps the BenchService state space small (Running ↔ Paused; Retry/Skip only transition inside Running).
The Abort confirm dialog already used for Abort should be reused for Skip
but with different title/message (Test.Skip.ConfirmTitle, Test.Skip.ConfirmMessage).
Retry does not require confirmation — it's a non-destructive restart of the current
phase only.
Interaction with PID temperature control
PID loop (BenchService.TemperatureLoopAsync) should continue during all four
operations — temperature is an environmental condition, not a test output. The oil-pump
interlock (IsOilPumpOn) must stay satisfied throughout; a Pause that loses the oil
pump (e.g. operator toggles the relay via the Bench page) must abort the test
through the existing safety path, not silently resume with oil off.
Interaction with the oil-pump safety interlock
The "no critical alarms" precondition is evaluated at Preconditions-step entry only.
Once Running, the existing DashboardAlarmsViewModel.HasCritical observer is the
authoritative safety check. Pause/Retry/Skip do not bypass it — any of the four
operations should fail (throw) if a critical alarm is latched when invoked, surfacing
the same warning banner the existing Running state already shows.
Localization keys
Already added to Resources/Strings.en.xaml and Resources/Strings.es.xaml:
Test.Running.PauseTest.Running.ResumeTest.Running.RetryTest.Running.SkipTest.Running.ComingSoon(tooltip while buttons remain disabled)Test.Running.Abort
To add when Skip confirmation lands:
Test.Skip.ConfirmTitleTest.Skip.ConfirmMessageTest.Skip.ConfirmTest.Skip.Cancel
Relation to existing HIGH-priority gap
CLAUDE.md ("Pump parameters (ME/FBKW/PreIn) not zeroed between test phases") is the
broader gap. This document's Retry path implements the zero-between-phases behaviour
for the retry transition specifically. The general phase-to-phase zeroing in
BenchService.RunPhaseAsync must also be fixed — tracked separately.
Manual verification checklist
- Start a multi-phase test. During a measurement phase click Pause — RPM drops to idle, countdown freezes, button relabels to "Resume". Flow charts stop advancing, oil pump stays on, no critical alarm.
- Click Resume — RPM ramps back to the phase target, countdown unfreezes from the exact value, label returns to "Pause".
- During a measurement phase with partial samples, click Retry — pump outputs
zero, phase restarts at conditioning, card highlight refreshes, previous samples
cleared from
TestResult. - Click Skip on the second of three enabled phases — confirm dialog opens
(
Test.Skip.ConfirmMessage). Cancel: test continues. Confirm: phase disposition set to Skipped, pump outputs zeroed, next enabled phase starts conditioning. - Skip the final enabled phase — test completes, transitions to Done step.
- Trigger a critical alarm mid-Pause — test aborts via the existing critical-alarm path, Done step shows "Failed — safety stop".
- Toggle language mid-Pause — button text updates to localized "Resume" / "Pause".
- Unplug CAN during Pause — CAN-liveness watchdog aborts the test.
Out of scope (acknowledged)
- Skipping / retrying a phase while paused (requires Resume first).
- A Skip-all-remaining-phases shortcut.
- A "Retry this test" that restarts from the first phase of the current test.