feat: page-based navigation shell + Tests page wizard
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>
This commit is contained in:
167
docs/gap-test-running-controls.md
Normal file
167
docs/gap-test-running-controls.md
Normal file
@@ -0,0 +1,167 @@
|
||||
# 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
|
||||
|
||||
```csharp
|
||||
/// <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.Samples`
|
||||
for that phase is cleared.
|
||||
- `PhaseChanged` event fires with the same phase name again so the UI re-highlights the card.
|
||||
|
||||
### Skip
|
||||
- Pump outputs: zeroed.
|
||||
- Phase disposition: `TestResult` row is inserted with `Status = Skipped` (new enum value
|
||||
on `TestResult.Status` or existing `Pass/Fail` with a separate `IsSkipped` flag).
|
||||
- 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.Pause`
|
||||
- `Test.Running.Resume`
|
||||
- `Test.Running.Retry`
|
||||
- `Test.Running.Skip`
|
||||
- `Test.Running.ComingSoon` (tooltip while buttons remain disabled)
|
||||
- `Test.Running.Abort`
|
||||
|
||||
To add when Skip confirmation lands:
|
||||
- `Test.Skip.ConfirmTitle`
|
||||
- `Test.Skip.ConfirmMessage`
|
||||
- `Test.Skip.Confirm`
|
||||
- `Test.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
|
||||
|
||||
1. 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.
|
||||
2. Click **Resume** — RPM ramps back to the phase target, countdown unfreezes from
|
||||
the exact value, label returns to "Pause".
|
||||
3. During a measurement phase with partial samples, click **Retry** — pump outputs
|
||||
zero, phase restarts at conditioning, card highlight refreshes, previous samples
|
||||
cleared from `TestResult`.
|
||||
4. 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.
|
||||
5. Skip the final enabled phase — test completes, transitions to Done step.
|
||||
6. Trigger a critical alarm mid-Pause — test aborts via the existing critical-alarm
|
||||
path, Done step shows "Failed — safety stop".
|
||||
7. Toggle language mid-Pause — button text updates to localized "Resume" / "Pause".
|
||||
8. 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.
|
||||
Reference in New Issue
Block a user