Files
HC_APTBS/docs/gap-test-running-controls.md
LucianoDev 0280a2fad1 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>
2026-04-18 13:11:34 +02:00

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.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.