nc_program_manager/.paul/phases/11-refactor/11-02-PLAN.md
dtrentin bd17ea46e5 feat(11-refactor): extract ArgParser, fix error handling, remove dead code
Phase 11 complete:
- ArgParser.cs: CLI parsing extracted from Program.cs (pure static method)
- Program.cs: no static state; Scarica/Invia take explicit InputArgs param
- Program.cs: try/finally with connected flag — fixes connection leak on exception
- Program.cs: PrintErrors helper surfaces CncResult.Errors on every failure
- AesCrypt.cs: deleted (dead code, zero references)
- NcProgramManager.csproj: AesCrypt.cs → ArgParser.cs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 00:01:32 +02:00

5.1 KiB

phase plan type wave depends_on files_modified autonomous
11-refactor 02 execute 2
11-01
Program.cs
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<CncError>) added
@.paul/PROJECT.md @Program.cs @.paul/phases/11-refactor/11-01-SUMMARY.md

<acceptance_criteria>

AC-1: Disconnect always runs after connect

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

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

Given any CncResult<T> 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

</acceptance_criteria>

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)

<success_criteria>

  • 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 </success_criteria>
After completion, create `.paul/phases/11-refactor/11-02-SUMMARY.md`