---
phase: 11-refactor
plan: 02
type: execute
wave: 2
depends_on: ["11-01"]
files_modified:
  - Program.cs
autonomous: true
---

<objective>
## 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
</objective>

<context>
@.paul/PROJECT.md
@Program.cs
@.paul/phases/11-refactor/11-01-SUMMARY.md
</context>

<acceptance_criteria>

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

<tasks>

<task type="auto">
  <name>Task 1: Add PrintErrors helper + refactor Scarica</name>
  <files>Program.cs</files>
  <action>
    Add private static helper at bottom of Program class:
    ```
    static void PrintErrors(System.Collections.Generic.IReadOnlyList<CncError> 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).
  </action>
  <verify>
    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
  </verify>
  <done>AC-1, AC-2, AC-3 satisfied for Scarica</done>
</task>

<task type="auto">
  <name>Task 2: Refactor Invia with same pattern</name>
  <files>Program.cs</files>
  <action>
    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.
  </action>
  <verify>
    Read Program.cs Invia method:
    - Same structure as Scarica post-refactor
    - Zero `DisconnectAsync` calls inside try
    - `PrintErrors` called on all failed CncResult checks
  </verify>
  <done>AC-1, AC-2, AC-3 satisfied for Invia</done>
</task>

</tasks>

<boundaries>

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

</boundaries>

<verification>
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)
</verification>

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

<output>
After completion, create `.paul/phases/11-refactor/11-02-SUMMARY.md`
</output>
