--- phase: 13-robustness-fixes plan: 01 type: summary status: complete completed: 2026-05-18 commit: 4cd7715 --- # Summary: Plan 13-01 — Robustness Fixes ## What Was Built Three targeted defensive fixes. No new files. No interface changes. ### Task 1 — MachineFingerprint null guard (ISS-001) **File:** `Licensing/MachineFingerprint.cs` Both WMI property reads now use null-safe operators: - `mo.Properties["processorID"]?.Value?.ToString() ?? string.Empty` - `obj["SerialNumber"]?.ToString() ?? string.Empty` Customers on hardware where WMI returns null for processorID or SerialNumber no longer get an unhandled NullReferenceException at license check startup. ### Task 2 — SHA256 provider disposed (ISS-005) **File:** `Licensing/LicenseValidator.cs` `SHA256CryptoServiceProvider` wrapped in `using` block inside `Validate()`. Disposed on every call — success or failure. RSACryptoServiceProvider pattern unchanged. Public key constant untouched. ### Task 3 — LSV2 connect timeout aborts socket (ISS-006) **File:** `Cnc/Heidenhain/Lsv2Client.cs` `Connect()` now calls `_tcp.Close()` when `ConnectAsync().Wait(timeout)` returns false. Closes the underlying socket, causing the pending task to complete with SocketException rather than holding a thread-pool slot indefinitely. No async/await introduced (Connect() stays synchronous by design). ## Acceptance Criteria Results | AC | Description | Result | |----|-------------|--------| | AC-1 | WMI null returns non-null string, no throw | PASS | | AC-2 | SHA256 provider disposed after every Validate() | PASS | | AC-3 | Timeout branch closes socket before returning false | PASS | ## Decisions Made - `?? string.Empty` used (not `?? "unknown"`) — fingerprint string concatenated; empty is correct fallback - `_tcp.Close()` in bare `try { } catch { }` — same pattern as existing Disconnect() in same file - No CancellationTokenSource pattern (ISS-006 fix note suggested it) — simpler Close() approach sufficient for .NET 4.7.2 synchronous design ## Deferred None — all three tasks completed as planned. ## Files Modified - `Licensing/MachineFingerprint.cs` — null guards on WMI reads - `Licensing/LicenseValidator.cs` — SHA256 using block - `Cnc/Heidenhain/Lsv2Client.cs` — socket close on timeout ## Issues Closed - ISS-001 — MachineFingerprint null dereference on unusual hardware ✓ - ISS-005 — SHA256 crypto provider not disposed ✓ - ISS-006 — LSV2 connect timeout doesn't abort hung task ✓ ## Commit `4cd7715` — fix(robustness): null guard WMI reads, dispose SHA256, abort LSV2 timeout (ISS-001, ISS-005, ISS-006)