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>
153 lines
5.1 KiB
Markdown
153 lines
5.1 KiB
Markdown
---
|
|
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>
|