--- phase: 11-refactor plan: 02 type: execute wave: 2 depends_on: ["11-01"] files_modified: - Program.cs autonomous: true --- ## Goal Fix `Scarica` and `Invia` in Program.cs: use `try/finally` for guaranteed disconnect and print `CncResult.Errors` on every failure. ## Purpose Current code manually calls `DisconnectAsync` before each error return — but the `catch` block has no disconnect, so any unhandled exception after connect leaks the connection. Also, `CncResult.Errors` is never printed; operators get a numeric code with no machine-level detail. ## Output - `Program.cs` — both methods refactored: single `try/catch/finally` with `connected` flag; all `CncResult` failures print errors before returning - Private helper `PrintErrors(IReadOnlyList)` added @.paul/PROJECT.md @Program.cs @.paul/phases/11-refactor/11-01-SUMMARY.md ## AC-1: Disconnect always runs after connect ```gherkin Given Scarica or Invia successfully calls ConnectAsync When any exception is thrown during the operation Then DisconnectAsync is called exactly once (via finally block) ``` ## AC-2: No manual disconnect before early returns ```gherkin Given Scarica or Invia When read Then no call to DisconnectAsync exists inside the try block — only in the finally ``` ## AC-3: CncResult errors printed on failure ```gherkin Given any CncResult with Success == false and non-empty Errors list When the result is checked and found failed Then each error is printed via CncError.ToString() before VediErrore is called ``` Task 1: Add PrintErrors helper + refactor Scarica Program.cs Add private static helper at bottom of Program class: ``` static void PrintErrors(System.Collections.Generic.IReadOnlyList errors) { if (errors == null) return; foreach (var e in errors) Console.WriteLine(" " + e.ToString()); } ``` Refactor Scarica: 1. Declare `bool connected = false;` before try. 2. Wrap ALL operation logic in a single `try { } catch (Exception ex) { } finally { }`. 3. After `ConnectAsync` succeeds, set `connected = true`. 4. Remove ALL `macchina.DisconnectAsync().GetAwaiter().GetResult()` calls from inside the try block. 5. In `finally`: `if (connected) macchina.DisconnectAsync().GetAwaiter().GetResult();` 6. After every `!result.Success` check, call `PrintErrors(result.Errors)` before `VediErrore`. Early-return on `!connResult.Success` does NOT set connected=true, so finally skips disconnect — correct. Avoid: catching and swallowing the disconnect exception in finally (let it propagate naturally). Read Program.cs Scarica method: - `connected` flag declared - `finally { if (connected) macchina.DisconnectAsync()... }` present - Zero `DisconnectAsync` calls inside try block - `PrintErrors` called before each `VediErrore(-2XX)` that follows a CncResult check AC-1, AC-2, AC-3 satisfied for Scarica Task 2: Refactor Invia with same pattern Program.cs Apply identical refactor to Invia: 1. Declare `bool connected = false;` before try. 2. Single `try/catch/finally` — set `connected = true` after `ConnectAsync` succeeds. 3. Remove ALL `macchina.DisconnectAsync()` calls from inside try. 4. `finally { if (connected) macchina.DisconnectAsync().GetAwaiter().GetResult(); }` 5. Call `PrintErrors(result.Errors)` before each `VediErrore` that follows a failed CncResult. Note: `File.ReadAllText` in Invia can throw IOException — the finally will still run and disconnect safely. Read Program.cs Invia method: - Same structure as Scarica post-refactor - Zero `DisconnectAsync` calls inside try - `PrintErrors` called on all failed CncResult checks AC-1, AC-2, AC-3 satisfied for Invia ## DO NOT CHANGE - ArgParser.cs - InputArgs.cs - Cnc/* — all machine implementation files - Licensing/* - VediErrore content or error codes - MostraAiuto - NcProgramManager.Tests/* ## SCOPE LIMITS - Only Program.cs touched - Do not change method signatures - Do not add new error codes - Do not change the connection/operation logic — only the cleanup and error display Before declaring plan complete: - [ ] grep "DisconnectAsync" Program.cs — all results inside `finally` blocks only - [ ] grep "PrintErrors" Program.cs — called before every VediErrore that follows a CncResult check - [ ] `connected` flag declared in both Scarica and Invia - [ ] Project compiles (no new errors) - Both Scarica and Invia use try/catch/finally with connected flag - DisconnectAsync called only in finally - PrintErrors called on every CncResult failure - Zero compilation errors After completion, create `.paul/phases/11-refactor/11-02-SUMMARY.md`