Config system fixes: - Implement SavePump() — full XML serialization with insert/update by pump ID - Add CanBusParameter.ToPumpXml() for legacy P1-P6 pump param format - Fix LastRotationDirection never loaded in LoadSettings() - Add SaveAlarms() to ConfigurationService and IConfigurationService - Remove dead fields AppSettings.Clients and AppSettings.PumpIds PDF report redesign: - Professional layout with charts, verdict badges, and tolerance bands - Add ReportChartRenderer (SVG) and ReportTheme styling constants - Embed default_logo.png as fallback report logo Documentation: - Add gap analysis docs (config validation, ford unlock, missing features) - Update CLAUDE.md architecture, known gaps, and debt tracking Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
6.2 KiB
Gap: Missing Features
1. Localization System (HIGH)
Problem
The old app supported runtime Spanish/English switching via R.LoadLanguage() which swapped WPF ResourceDictionary files (StringResources.xaml for Spanish, StringResourcesEN.xaml for English). The new app has AppSettings.Language ("ESP"/"ENG") persisted but NOT used — all UI strings are hardcoded in English.
Implementation approach
- Create
Resources/StringResources.xaml(Spanish) andResources/StringResources.en.xaml(English) with keyedsys:Stringentries - Reference strings in XAML via
{DynamicResource key}(notStaticResource— dynamic allows runtime swap) - Add
LanguageServiceor extension method that merges the correct dictionary intoApplication.Current.Resources - Wire language toggle to
AppSettings.Languagechange - Default resource dictionary should be Spanish (the primary user base)
Scope
All user-facing text: labels, button text, dialog messages, status messages, report text, error messages. Roughly 200-300 strings.
2. User Credential Encryption (HIGH)
Problem
Users stored as plaintext user:password pairs in config.xml. Default is admin:admin. Old system used AES-256 (Rijndael CBC, PBKDF2 1000 iterations) via Encrypter.cs.
Recommended approach
Don't re-implement the old Rijndael scheme (it used obsolete primitives and weak iteration count). Instead:
- Hash passwords with
Rfc2898DeriveBytesusing HMAC-SHA256, 600,000 iterations, random 16-byte salt - Store as
user:salt:hashin config.xml ValidateUser()computes hash of input password with stored salt and compares- Migration: on first load of old-format
user:passwordentries, hash them and rewrite
This is more secure than the old encrypted-but-reversible approach. Passwords become irreversible.
Files to modify
Models/BenchConfiguration.cs— changeUsersproperty formatServices/Impl/ConfigurationService.cs—ValidateUser(),GetUsers(),UpdateUsers(),SaveSettings()
3. KlineIDs Auto-Mapping (MEDIUM)
Problem
Old system remembered K-Line ID → pump ID associations via Settings.Default.KlineIDs (comma-separated klineID:pumpID string). When a pump was connected and identified via K-Line, the system could auto-select it next time. New system has no equivalent.
Implementation
- Add
Dictionary<string, string> KlineIdMaptoAppSettings - Persist as
<KlineIDs>kline1:pump1,kline2:pump2</KlineIDs>in config.xml - In
KwpServiceorPumpIdentificationViewModel: after successful K-Line read, save the mapping - On pump connection: look up K-Line ID in map, auto-select pump if found
4. Test Phase Timer/Countdown Display (MEDIUM)
Problem
During test execution, conditioning and measurement phases have timed durations (e.g., 10 sec conditioning, 30 sec measurement). The old system showed a visual countdown. The new system fires VerboseMessage events with text like "Conditioning: 8s remaining" but there's no dedicated countdown UI.
Implementation
- Add countdown properties to
TestDisplayViewModel:RemainingSeconds,PhaseProgress(0-1),PhaseName - Fire
PhaseTimerTickevent fromBenchServicewith remaining seconds - Display as a circular progress indicator or large countdown text in
TestDisplayView
5. QOver Zero-Flow Safety Check (HIGH — Safety)
Problem
The old system had a safety check: if QOver == 0 while RPM > 300 and oil pump is on, trigger emergency stop (leak/blockage detection). This is completely absent from the new codebase.
Implementation
Add to BenchService or the ViewModel's bench monitoring loop:
if (qOverValue == 0 && benchRpm > 300 && IsRelayOn(RelayNames.OilPump))
{
EmergencyStop();
_log.Error(LogId, "QOver zero-flow safety triggered: oil flow blocked while motor running");
}
Debounce for 2-3 seconds to avoid false positives during startup transients.
6. Alarm Bit Recording During Tests (HIGH)
Problem
PhaseDefinition has ErrorBits list and RecordErrorBit(int bit) method, but no code in BenchService ever calls it. The old system tracked which alarm bits fired during each test phase for inclusion in the report.
Implementation
In BenchService.MeasurePhaseAsync(), subscribe to alarm parameter changes. When an alarm bit transitions to active during a measurement phase, call phase.RecordErrorBit(bit). The error bits are already rendered in the PDF report (PdfService checks phase.ErrorBits).
7. Per-Sample Real-Time UI Callback (MEDIUM)
Problem
Old system fired ITestParameterListener.OnValueUpdate for every measurement sample, enabling live chart updates during test execution. New system silently collects samples with no per-sample event.
Implementation
Add an event to IBenchService:
event Action<string, double, double>? MeasurementSampled; // paramName, value, timestamp
Fire in MeasurePhaseAsync after each sample. ViewModel subscribes to update live charts.
8. Pump Parameter Zeroing Between Phases (MEDIUM)
Problem
Old system called StopPump() between phases, which zeroed ME/FBKW/PreIn values. New system calls SetRpm(0) but does NOT zero pump injection parameters. This means the pump may continue injecting fuel between phases at the previous phase's setpoint.
Implementation
Add a StopPumpParameters() method to BenchService that sets ME, FBKW, and PreIn to 0 and sends the CAN frame. Call it at the end of each phase (currently line 776 in BenchService.cs — after SetRpm(0)).
9. PDF Report Observations Section (LOW)
Problem
Old report had an "Observaciones" free-text section at the bottom. New IPdfService.GenerateReport() has no observations parameter and no observations rendering.
Implementation
- Add
string? observationsparameter toIPdfService.GenerateReport() - Add a text section at the bottom of the PDF body in
PdfService - Add an observations text box to
ReportDialog/ReportViewModel
10. PDF Auto-Open After Generation (LOW)
Problem
Old code called Process.Start(filePath) to open the generated PDF. New code returns the path but doesn't open it.
Implementation
After GenerateReport() returns the path, call Process.Start(new ProcessStartInfo(path) { UseShellExecute = true }) in the ViewModel.