diff --git a/.paul/codebase/ARCHITECTURE.md b/.paul/codebase/ARCHITECTURE.md new file mode 100644 index 0000000..7efde8a --- /dev/null +++ b/.paul/codebase/ARCHITECTURE.md @@ -0,0 +1,156 @@ +# Architecture + +**Analysis Date:** 2026-05-18 + +## Pattern Overview + +**Overall:** Layered CLI console application with abstract machine interface, factory dispatch, and offline license gate. + +**Key Characteristics:** +- Single Windows EXE (all dependencies embedded via Costura.Fody) +- Polymorphic multi-vendor CNC support via `ICncMachine` interface +- Factory pattern for manufacturer selection at runtime +- Async/await throughout (Task-based), but blocked at CLI boundary via `.GetAwaiter().GetResult()` +- Result-wrapper pattern (`CncResult`) instead of exceptions for CNC operations +- RSA license validation gate on every startup + +## Layers + +**CLI Entry Layer:** +- Purpose: Parse args, validate license, dispatch to action (Scarica/Invia) +- Contains: `Program.cs` (main orchestration), `ArgParser.cs` (regex arg parsing), `InputArgs.cs` (config object) +- Depends on: Licensing layer, CNC abstraction layer +- Error output: Negative exit codes (-100 to -208) mapped to Italian user messages + +**Licensing Layer:** +- Purpose: Prevent execution on unlicensed machines +- Contains: `Licensing/LicenseValidator.cs`, `Licensing/MachineFingerprint.cs`, `Licensing/LicenseFile.cs` +- Depends on: WMI (System.Management), RSA crypto +- Used by: CLI entry layer (startup check only) + +**CNC Abstraction Layer:** +- Purpose: Uniform interface over 4 different CNC protocols +- Contains: `Cnc/ICncMachine.cs`, `Cnc/IFanucMachine.cs`, `Cnc/CncMachineFactory.cs`, `Cnc/Models/` +- Key types: `CncResult`, `CncError`, `CncManufacturer`, `ConnectionState`, `CncProgram` +- Used by: CLI entry layer + +**Manufacturer Implementations:** +- Purpose: Protocol-specific CNC communication +- Contains: `Cnc/Fanuc/`, `Cnc/Heidenhain/`, `Cnc/Siemens/`, `Cnc/Mitsubishi/` +- Each implements `ICncMachine` (Fanuc also implements `IFanucMachine`) +- Depends on: Protocol libraries (FOCAS DLL, TCP socket, FtpWebRequest) + +**Validation Layer:** +- Purpose: Pre-upload NC program syntax checking +- Contains: `Cnc/INcProgramValidator.cs`, `Cnc/NcProgramValidator.cs` +- Injected into machine implementations; upload blocked on Error severity +- Depends on: Nothing external + +**NC Program Parsing:** +- Purpose: Parse/format Fanuc composite NC file format +- Contains: `FanucProgram.cs` (program + tooloffset + workzero sections) +- Used by: CLI entry layer post-download + +## Data Flow + +**Scarica (Download from CNC):** +``` +CLI args + → ArgParser.Parse() → InputArgs + → LicenseValidator.Validate() [exit -1xx on failure] + → CncMachineFactory.Create(InputArgs) → ICncMachine + → machine.ConnectAsync() → CncResult + → machine.ReadProgramAsync(path) → CncResult + → [IFanucMachine cast] ReadToolDataAsync / ReadWorkZeroDataAsync + → FanucProgram.Format() → composite file string + → File.WriteAllText(localPath) +``` + +**Invia (Upload to CNC):** +``` +CLI args + → ArgParser.Parse() → InputArgs + → LicenseValidator.Validate() [exit -1xx on failure] + → CncMachineFactory.Create(InputArgs) → ICncMachine + → File.ReadAllText(localPath) + → NcProgramValidator.Validate() [exit on Error severity] + → machine.ConnectAsync() + → machine.WriteProgramAsync(path, content) → CncResult +``` + +**State Management:** +- No persistent in-memory state between invocations (each run is independent) +- Machine state tracked per-instance: `ConnectionState` enum + `StateChanged` event +- Thread safety: `SemaphoreSlim` gate per machine instance + +## Key Abstractions + +**ICncMachine:** +- Purpose: Uniform contract for all CNC machines +- Location: `Cnc/ICncMachine.cs` +- Methods: `ConnectAsync`, `DisconnectAsync`, `ReadProgramAsync`, `WriteProgramAsync`, `ReadAsync`, `DeleteProgramAsync`, `ReadActiveProgramAsync`, `SelectMainProgramAsync` +- Pattern: Interface + factory dispatch + +**IFanucMachine:** +- Purpose: Fanuc-specific extensions (tool offsets, work zero) +- Location: `Cnc/IFanucMachine.cs` +- Extends: `ICncMachine` +- Pattern: Interface specialization + +**CncResult:** +- Purpose: Typed result wrapper replaces exception-based control flow +- Location: `Cnc/Models/CncResult.cs` +- Factories: `Ok()`, `Fail()`, `Cancelled()`, `OkWithWarnings()` +- Properties: `Success`, `Errors`, `WasCancelled`, `Value` + +**IFocasDialect:** +- Purpose: Abstract FOCAS version differences (Legacy vs Modern API) +- Location: `Cnc/Fanuc/IFocasDialect.cs` +- Implementations: `LegacyFocasDialect.cs`, `ModernFocasDialect.cs` +- Detection: `FanucDialectDetector.cs` at connect time + +**CncMachineFactory:** +- Purpose: Create correct ICncMachine from InputArgs +- Location: `Cnc/CncMachineFactory.cs` +- Dispatches on: `CncManufacturer` enum (Fanuc, Heidenhain, Siemens, Mitsubishi) + +## Entry Points + +**CLI Entry:** +- Location: `Program.cs` (Main method) +- Triggers: Process execution from command line or calling application +- Responsibilities: Arg parsing → license check → machine factory → action dispatch → exit code + +**Argument Parser:** +- Location: `ArgParser.cs` (static `Parse(string[])`) +- Returns: `InputArgs` with all 16 CLI parameters normalized + +## Error Handling + +**Strategy:** Result wrapper at CNC layer, exit codes at CLI boundary, ArgumentNullException for null guards + +**Patterns:** +- `CncResult.Fail(errors)` for CNC operation failures +- `ArgumentNullException` for constructor null guards (`Cnc/Fanuc/FanucMachine.cs`) +- Exit codes -100 to -208 in `Program.cs` for user-facing errors +- `try/finally` with `connected` flag for connection leak prevention (`Program.cs`) +- `catch { }` (silent) on disconnect cleanup paths — known weakness (see CONCERNS.md) + +## Cross-Cutting Concerns + +**Logging:** +- `Console.WriteLine` only — no structured logging framework +- Debug mode (`-debug=` arg): keeps terminal open after operation + +**Validation:** +- `NcProgramValidator` injected into machine constructors +- Runs before upload; blocked on `ValidationSeverity.Error` + +**Cancellation:** +- `CancellationToken` passed through all async methods +- CLI does not currently expose cancellation to user + +--- + +*Architecture analysis: 2026-05-18* +*Update when major patterns change* diff --git a/.paul/codebase/CONCERNS.md b/.paul/codebase/CONCERNS.md new file mode 100644 index 0000000..555b531 --- /dev/null +++ b/.paul/codebase/CONCERNS.md @@ -0,0 +1,152 @@ +# Codebase Concerns + +**Analysis Date:** 2026-05-18 + +## Tech Debt + +**Blocking async calls at CLI boundary:** +- Issue: 56+ `.GetAwaiter().GetResult()` calls block async operations synchronously +- Files: `Program.cs` (lines 90, 101, 122, 142, 166, 200, 221, 240, 262), machine classes +- Why: Main() was not async when initially written; .NET 4.7.2 supports async Main via C# 7.1 +- Impact: Thread pool starvation risk, deadlock risk in certain SynchronizationContext scenarios, harder debugging +- Fix: Refactor `Program.Main` to `static async Task Main(string[] args)`, propagate `await` throughout + +**Silent exception handlers (catch without logging):** +- Issue: `try { ... } catch { }` swallows exceptions with no trace +- Files: `Cnc/Fanuc/FanucMachine.cs` (disconnect cleanup), `Cnc/Siemens/SiemensMachine.cs`, `Cnc/Heidenhain/HeidenhainMachine.cs`, `Cnc/Heidenhain/Lsv2Client.cs` +- Why: Cleanup paths (disconnect, logout) should not propagate to caller; silence was intentional +- Impact: Resource leaks masked, production issues undiagnosable, disconnect failures invisible +- Fix: Log at minimum to debug/trace: `catch (Exception ex) { /* log ex */ }`. Add logging framework. + +**No structured logging framework:** +- Issue: Entire codebase uses `Console.WriteLine` (98+ calls in `Program.cs` alone) +- Files: `Program.cs`, all machine implementations +- Why: MVP simplicity; tool was always a CLI +- Impact: No log levels, no timestamps, no file logging, production issues undiagnosable +- Fix: Add Serilog or NLog. Replace Console.WriteLine with `_logger.Information()`. Add request/response tracing to FOCAS calls. + +**Large monolithic FanucMachine:** +- Issue: `Cnc/Fanuc/FanucMachine.cs` is ~740 lines with complex state management +- Files: `Cnc/Fanuc/FanucMachine.cs` +- Why: FOCAS protocol has many edge cases; chunked transfer and offset handling grew organically +- Impact: Hard to test individual branches; buffer handling edge cases unclear +- Fix: Extract `IFocasTransferHandler` for chunk upload/download logic; separate offset data reader + +**`string.Format()` over `$""` interpolation:** +- Issue: Old string formatting style throughout validator and some machine code +- Files: `Cnc/NcProgramValidator.cs`, `Program.cs` +- Why: Legacy code predates C# 6 adoption on this project +- Impact: Cosmetic; harder to read format strings +- Fix: Opportunistic migration to `$""` during edits + +## Known Issues / Incomplete Implementations + +**Heidenhain ReadActiveProgramAsync / SelectMainProgram not implemented:** +- Symptoms: Returns `CncResult.Fail("Not supported via basic LSV2")` +- Files: `Cnc/Heidenhain/HeidenhainMachine.cs` +- Root cause: LSV2 protocol complexity; feature not required for initial release +- Workaround: Users specify program path explicitly + +**Siemens ReadActiveProgramAsync / SelectMainProgram not implemented:** +- Symptoms: Returns stub failure +- Files: `Cnc/Siemens/SiemensMachine.cs` +- Root cause: FTP protocol doesn't expose active program info +- Workaround: Users specify program path explicitly + +**MachineSnapshot returns stub data for Heidenhain/Siemens/Mitsubishi:** +- Files: `Cnc/Heidenhain/HeidenhainMachine.cs`, `Cnc/Siemens/SiemensMachine.cs`, `Cnc/Mitsubishi/MitsubishiMachine.cs` +- Issue: All snapshot fields return Unknown/empty; no real machine state read +- Impact: No diagnostic info available for non-Fanuc machines + +## Security Considerations + +**RSA public key hardcoded in binary:** +- Risk: Key embedded as const string in binary; cannot be rotated without recompile and redeploy +- Files: `Licensing/LicenseValidator.cs` +- Current mitigation: Asymmetric RSA — private key is vendor-only; hardcoded public key is acceptable for this use case +- Recommendation: Document key rotation procedure; consider adding license version/expiration metadata for future revocation + +**MachineFingerprint null dereference on unusual hardware:** +- Risk: `mo.Properties["processorID"].Value.ToString()` throws NullReferenceException if WMI property missing +- Files: `Licensing/MachineFingerprint.cs` +- Current mitigation: None +- Fix: `mo.Properties["processorID"]?.Value?.ToString() ?? "unknown"` + +**Obsolete crypto APIs:** +- Risk: `RSACryptoServiceProvider` and `SHA256CryptoServiceProvider` are obsolete in .NET 6+ +- Files: `Licensing/LicenseValidator.cs` +- Current mitigation: .NET 4.7.2 target — obsolete warning only, not broken +- Fix when upgrading: Use `RSA.Create()` + `VerifyData(data, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)` + +**SHA256 provider not explicitly disposed:** +- Risk: Minor resource leak in license validation path +- Files: `Licensing/LicenseValidator.cs` +- Fix: Wrap in `using (var sha = new SHA256CryptoServiceProvider()) { ... }` + +## Platform Constraints + +**Windows-only (hard constraint):** +- FOCAS1 DLL (`Fwlib32.dll`) is 32-bit Windows native — no Linux/macOS support +- WMI (`System.Management`) Windows-only — licensing system non-functional on Linux +- Files: `Cnc/Fanuc/libs/`, `Licensing/MachineFingerprint.cs`, `fwlib32.cs` +- Impact: Cannot run on Linux/macOS; CI on Linux can only test non-FOCAS paths +- Action if cross-platform needed: Abstract fingerprinting behind `IMachineFingerprint`; already done — add Linux implementation using `/proc/cpuinfo` or `dmidecode` + +**FOCAS DLL version sensitivity:** +- Risk: FOCAS API changes between Fanuc control versions; `FanucDialectDetector` auto-detects but may fail on unknown versions +- Files: `Cnc/Fanuc/FanucDialectDetector.cs`, `Cnc/Fanuc/FanucMachine.cs` +- Mitigation: Dialect abstraction layer (`IFocasDialect`) isolates version differences + +## Performance Bottlenecks + +**In-memory accumulation for large NC programs:** +- Issue: `UploadProgramByIdentifier` appends to `StringBuilder` for entire program before writing +- Files: `Cnc/Fanuc/FanucMachine.cs` +- Impact: For programs >10MB, high memory allocation; streaming to file would be more efficient +- Fix: Write chunks directly to `FileStream` instead of accumulating in memory + +**Polling with 100ms busy-wait during transfer:** +- Issue: `ct.WaitHandle.WaitOne(100)` loops during buffer waits +- Files: `Cnc/Fanuc/FanucMachine.cs` +- Impact: Wastes thread-pool slot; CPU cycles during transfer +- Fix: Use `await Task.Delay(100, ct)` instead of blocking WaitOne + +**Network connection timeout via `.Wait()` with boolean return:** +- Issue: `_tcp.ConnectAsync().Wait(timeout)` — if task never completes, does not abort it +- Files: `Cnc/Heidenhain/Lsv2Client.cs` +- Fix: `await Task.WhenAny(connectTask, Task.Delay(timeout, ct))` + cancellation + +## Fragile Areas + +**FOCAS dialect detection (`FanucDialectDetector`):** +- Files: `Cnc/Fanuc/FanucDialectDetector.cs` +- Why fragile: Relies on probing specific FOCAS API calls to detect version; untested against full range of Fanuc control generations +- Safe modification: Always test against physical hardware after changes; log detected dialect version + +**License validation (no recovery path):** +- Files: `Licensing/LicenseValidator.cs`, `Licensing/MachineFingerprint.cs` +- Why fragile: Any WMI failure or file read error produces a hard exit with no diagnostic for user +- Safe modification: Add exception handling with user-facing error message; distinguish "no license file" from "invalid license" from "fingerprint failure" + +**Integration tests with hardcoded IPs:** +- Files: `NcProgramManager.Tests/Integration/SiemensMachineIntegrationTests.cs`, `HeidenhainMachineIntegrationTests.cs`, `MitsubishiMachineIntegrationTests.cs` +- Why fragile: Tests will fail in CI without physical hardware at specific IPs +- Fix: Make IPs configurable via environment variables; skip integration tests in CI by default + +## Missing / Not Covered + +- No CLI-level tests (no test for `Program.cs` orchestration or exit code behavior) +- No tests for `MachineFingerprint` (WMI, no mock tests) +- No tests for `LicenseFile` parsing edge cases (corrupt Base64, empty file) +- No structured logging or diagnostics framework +- No error code documentation in code (only in `README.md`) +- No architecture documentation (FOCAS dialect selection logic undocumented in code) + +--- + +**Overall Assessment:** Architecture is solid — clean machine abstraction, well-structured interfaces, good error propagation via `CncResult`. Main concerns are operational (logging, blocking async, empty catch blocks) rather than structural. Platform constraints (Windows, FOCAS DLL) are intentional for the target environment. + +--- + +*Concerns analysis: 2026-05-18* +*Update as issues are resolved or discovered* diff --git a/.paul/codebase/CONVENTIONS.md b/.paul/codebase/CONVENTIONS.md new file mode 100644 index 0000000..7f068fd --- /dev/null +++ b/.paul/codebase/CONVENTIONS.md @@ -0,0 +1,122 @@ +# Coding Conventions + +**Analysis Date:** 2026-05-18 + +## Naming Patterns + +**Files:** +- PascalCase for all `.cs` files: `FanucMachine.cs`, `CncResult.cs` +- Interfaces: I-prefix PascalCase: `ICncMachine.cs`, `IFocasDialect.cs` +- Tests: `{Subject}Tests.cs` or `{Subject}IntegrationTests.cs` +- Config classes: `{Manufacturer}ConnectionConfig.cs` + +**Classes:** +- PascalCase for all classes +- Sealed preferred for implementations (not open to inheritance) + - Examples: `NcProgramValidator.cs`, `CncResult.cs` +- Manufacturer-prefixed where relevant: `FanucMachine`, `HeidenhainMachine`, `SiemensMachine` + +**Interfaces:** +- I-prefix strictly followed: `ICncMachine`, `IFanucMachine`, `ILicenseValidator`, `IFocasDialect` + +**Fields:** +- Private: `_camelCase` with underscore prefix + - Example: `_config`, `_validator`, `_state`, `_hndl` in `Cnc/Fanuc/FanucMachine.cs` +- Constants (public): PascalCase — `AlarmSlots`, `TransferChunkSize` in `Cnc/Fanuc/FanucMachine.cs` +- Constants (private): can be UPPER_CASE or PascalCase +- Static readonly: `_camelCase` with underscore + +**Properties:** +- PascalCase, read-only preferred + - Example: `Name`, `Comment`, `Content`, `Path` in `Cnc/Models/CncProgram.cs` + +**Methods:** +- PascalCase for all public methods: `ConnectAsync()`, `ReadProgramAsync()` +- `Async` suffix on all methods returning `Task` or `Task` +- Private helpers: `PascalCase` (same as public, no underscore) + - Example: `NcProgramValidator.cs` + +**Enums:** +- PascalCase for type name, PascalCase for values + - Examples: `CncManufacturer.Fanuc`, `ConnectionState.Connected`, `FanucTransport.Ethernet` + +## Code Style + +**Formatting:** +- 4-space indentation +- Allman brace style (opening brace on new line for classes and methods) + - Example: `Cnc/Fanuc/FanucMachine.cs` +- Single-line property getters: inline `{ get { return _x; } }` +- No `.editorconfig` or StyleCop — conventions enforced by practice + +**String Formatting:** +- `string.Format()` for parameterized messages (not `$""` interpolation) + - Example: `Cnc/NcProgramValidator.cs` lines with format strings +- `+` concatenation for console output in `Program.cs` + +**Async:** +- `default` parameter for `CancellationToken` on async methods +- `ConfigureAwait(false)` on library-level code +- `Task.Run()` for blocking FOCAS calls in async context (RunGuardedAsync pattern) + +## Import Organization + +**Order:** +1. System namespaces +2. External packages +3. Internal project namespaces + +No path aliases (not applicable to .NET Framework / no source generators). + +## Error Handling + +**Patterns:** +- Null guards at constructor: `if (config == null) throw new ArgumentNullException("config")` + - Example: `Cnc/Fanuc/FanucMachine.cs` +- Null-coalescing for optional deps: `_validator = validator ?? new NcProgramValidator(...)` +- `CncResult` wrapper for all CNC operations (not exceptions) +- Exit codes at CLI boundary: -100 to -208 in `Program.cs` +- `try/finally` with `connected` flag for connection cleanup in `Program.cs` + +**Result Wrapper Factories:** +- `CncResult.Ok(value)` — success +- `CncResult.Fail(errors)` — failure with error list +- `CncResult.Cancelled()` — cancellation +- `CncResult.OkWithWarnings(value, errors)` — partial success + +## Logging + +**Framework:** None — `Console.WriteLine` only + +**Patterns:** +- User-facing output: `Console.WriteLine()` in `Program.cs` +- Error output: same Console (no stderr separation) +- No log levels, no timestamps, no structured logging +- Debug mode via `-debug=` arg keeps terminal open post-operation + +## Comments + +**When to Comment:** +- Document intent/constraints, not obvious code + - Example: `NcProgramValidator.cs` — "Name-format check (uses just the bare filename without path)" +- Separator line style for section breaks: `// ── private helpers ─────────────────` + - Example: `NcProgramValidator.cs` + +**XML Doc Comments:** +- Sparse; only on public classes and key methods +- Format: `/// Brief description.` + - Examples: `NcProgramValidator.cs`, `CncResult.cs`, `ValidationResult.cs` + +**No TODO/FIXME comments found in codebase** — known deferred work tracked in STATE.md. + +## Function Design + +- Private async methods wrap blocking/mixed code with semaphore locking (RunGuardedAsync pattern) + - Example: `Cnc/Fanuc/FanucMachine.cs` RunGuardedAsync +- Large transfer methods split into chunked helpers (`TransferChunked`, `UploadProgramByIdentifier`) +- Interface/implementation pairs for all protocol clients (I-prefix interface + concrete) + +--- + +*Conventions analysis: 2026-05-18* +*Update when style decisions change* diff --git a/.paul/codebase/INTEGRATIONS.md b/.paul/codebase/INTEGRATIONS.md new file mode 100644 index 0000000..b0bbdfd --- /dev/null +++ b/.paul/codebase/INTEGRATIONS.md @@ -0,0 +1,87 @@ +# External Integrations + +**Analysis Date:** 2026-05-18 + +## CNC Machine Protocols + +**Fanuc FOCAS1/FOCAS2 (proprietary):** +- Used for: Program upload/download, tool data, work zero offset, machine state +- SDK/Client: `fwlib32.cs` (11,569 lines, P/Invoke wrapper, Fanuc copyright 2002-2014) +- Native DLLs: `Cnc/Fanuc/libs/Fwlib32.dll`, `fwlibe1.dll`, `fwlibNCG.dll` +- Transport: Ethernet TCP (port 8193 default) or HSSB (legacy serial bus) +- Main implementation: `Cnc/Fanuc/FanucMachine.cs` +- Dialect abstraction: `Cnc/Fanuc/IFocasDialect.cs` → `LegacyFocasDialect.cs` / `ModernFocasDialect.cs` +- Auto-detection: `Cnc/Fanuc/FanucDialectDetector.cs` (detects FOCAS version at connect time) +- Config: `Cnc/Fanuc/FanucConnectionConfig.cs` (IP, port, HSSB node, transport type) +- Platform: Windows only (DLL is 32-bit native) + +**Heidenhain LSV2 (proprietary TCP protocol):** +- Used for: Program transfer to/from Heidenhain iTNC/TNC controllers +- Client: Custom TCP implementation `Cnc/Heidenhain/Lsv2Client.cs` +- Default port: 19000 +- Auth: Username + password required +- Framing: STX, SIZE, CMD, data, CRC-16/CCITT +- Commands implemented: T_LS_SELECT, T_LS_LOG_IN, T_LS_LOG_OUT, T_R_FL (read file), T_S_FL (send file), T_FD +- Main implementation: `Cnc/Heidenhain/HeidenhainMachine.cs` +- Config: `Cnc/Heidenhain/HeidenhainConnectionConfig.cs` +- Note: ReadActiveProgramAsync / SelectMainProgram not implemented (LSV2 limitation) + +**Siemens Sinumerik FTP:** +- Used for: Program transfer to/from Siemens Sinumerik controllers +- Protocol: Standard FTP (RFC 959) via `System.Net.FtpWebRequest` +- Default port: 21 +- Default program dir: `/_N_MPF_DIR/` +- Auth: Username + password +- Client: `Cnc/Siemens/SiemensFtpClient.cs` +- Main implementation: `Cnc/Siemens/SiemensMachine.cs` +- Config: `Cnc/Siemens/SiemensConnectionConfig.cs` +- Requirement: Sinumerik FTP option must be enabled on machine + +**Mitsubishi M-Series FTP:** +- Used for: Program transfer to/from Mitsubishi M-series controllers +- Protocol: Standard FTP (RFC 959) via `System.Net.FtpWebRequest` +- Default port: 21 +- Default program dir: `/PRG/` +- Auth: Username + password +- Client: `Cnc/Mitsubishi/MitsubishiFtpClient.cs` +- Main implementation: `Cnc/Mitsubishi/MitsubishiMachine.cs` +- Config: `Cnc/Mitsubishi/MitsubishiConnectionConfig.cs` + +## Licensing System + +**RSA Offline License Validation:** +- Used for: Binding license to specific machine hardware +- Mechanism: RSA-SHA256 signature verification +- Public key: Embedded as const string in `Licensing/LicenseValidator.cs` +- Private key: Vendor-only, stored at `~/Documents/mine/c#/LicenseGenerator/private.key.xml` (gitignored) +- Machine fingerprint: WMI queries (CPU ID + motherboard serial) via `Licensing/MachineFingerprint.cs` +- License file: `license.lic` (Base64-encoded RSA signature) next to EXE +- Crypto: `RSACryptoServiceProvider` + `SHA256CryptoServiceProvider` (.NET 4.7.2 compatible) +- Generator tool: Separate repo `ssh://git@3nt-git.duckdns.org:222/davide.trentin/license-generator.git` + +## Hardware Access + +**WMI (Windows Management Instrumentation):** +- Used for: Machine fingerprinting in licensing +- Queries: `Win32_Processor` (processorID), `Win32_BaseBoard` (SerialNumber) +- Package: `System.Management 7.0.1` +- Files: `Licensing/MachineFingerprint.cs` +- Platform: Windows only + +## Data Storage + +**File System (local):** +- NC program files written/read from local path specified via `-pathprogramma=` CLI arg +- License file read from `AppDomain.CurrentDomain.BaseDirectory` +- No database, no cloud storage + +## Monitoring & Observability + +- No error tracking service (Sentry, etc.) +- No analytics +- Logging: `Console.WriteLine` only (no structured logging framework) + +--- + +*Integrations analysis: 2026-05-18* +*Update when new protocols or services are added* diff --git a/.paul/codebase/STACK.md b/.paul/codebase/STACK.md new file mode 100644 index 0000000..da945d0 --- /dev/null +++ b/.paul/codebase/STACK.md @@ -0,0 +1,83 @@ +# Technology Stack + +**Analysis Date:** 2026-05-18 + +## Languages + +**Primary:** +- C# (.NET Framework 4.7.2) - All application code + +**Secondary:** +- XML - Project files, App.config, binding redirects + +## Runtime + +**Environment:** +- .NET Framework 4.7.2 — Windows only (FOCAS1 DLL + WMI) +- No cross-platform support; Windows desktop/server target + +**Package Manager:** +- NuGet (packages.config format, not PackageReference) +- Lockfile: `packages.config` present in root and test project + +## Frameworks + +**Core:** +- None (vanilla .NET console application) + +**Testing:** +- NUnit 3.13.3 — Unit and integration tests (`NcProgramManager.Tests/packages.config`) +- NUnit3TestAdapter 4.2.1 — VS / dotnet test runner +- Moq 4.18.4 — Interface mocking + +**Build/IL Weaving:** +- Fody 6.6.4 — IL code weaver (`NcProgramManager.csproj`) +- Costura.Fody 5.7.0 — Embeds NuGet assemblies + native DLLs into output EXE + +## Key Dependencies + +**Critical:** +- `System.Management 7.0.1` — WMI queries for machine fingerprinting (`Licensing/MachineFingerprint.cs`) +- `Microsoft.Bcl.AsyncInterfaces 7.0.0` — Async backport for .NET 4.7.2 (`packages.config`) +- `System.Memory 4.5.5` — Span and Memory compatibility (`packages.config`) +- `System.Runtime.CompilerServices.Unsafe 6.0.0` — Low-level ops (`packages.config`) +- `System.Net.Sockets 4.3.0` — TCP networking for LSV2/FTP (`packages.config`) + +**Infrastructure:** +- `NETStandard.Library 2.0.3` — .NET Standard facade (`packages.config`) +- `System.Net.Http 4.3.4` — HTTP base infrastructure (`packages.config`) +- `Castle.Core 5.1.1` — Moq dependency (`NcProgramManager.Tests/packages.config`) + +**Native (embedded via Costura.Fody):** +- `Cnc/Fanuc/libs/Fwlib32.dll` — Fanuc FOCAS1 library (32-bit, ~629KB) +- `Cnc/Fanuc/libs/fwlibe1.dll` — Extended FOCAS (~1MB) +- `Cnc/Fanuc/libs/fwlibNCG.dll` — FOCAS NCG support (~2MB) + +## Configuration + +**Environment:** +- No environment variables +- All runtime config passed via CLI arguments (parsed by `ArgParser.cs`) +- License file: `license.lic` next to EXE (no CLI override) + +**Build:** +- `NcProgramManager.csproj` — MSBuild 15.0, OutputType=Exe +- `App.config` — Runtime binding redirects only (no business settings) +- `FodyWeavers.xml` — Costura assembly embedding config + +## Platform Requirements + +**Development:** +- Windows (FOCAS1 DLL requires 32-bit Windows; WMI for licensing) +- Visual Studio 2017+ or MSBuild 15+ +- Fanuc FOCAS DLL unavailable on Linux (test suite ignores FOCAS tests) + +**Production:** +- Windows (desktop or server) +- `license.lic` placed alongside EXE +- 32-bit process or AnyCPU with 32-bit preferred (FOCAS1 DLL constraint) + +--- + +*Stack analysis: 2026-05-18* +*Update after major dependency changes* diff --git a/.paul/codebase/STRUCTURE.md b/.paul/codebase/STRUCTURE.md new file mode 100644 index 0000000..76d3998 --- /dev/null +++ b/.paul/codebase/STRUCTURE.md @@ -0,0 +1,160 @@ +# Codebase Structure + +**Analysis Date:** 2026-05-18 + +## Directory Layout + +``` +nc_program_manager/ +├── NcProgramManager/ # Main application +│ ├── Program.cs # CLI entry point, action dispatch +│ ├── ArgParser.cs # CLI argument parser +│ ├── InputArgs.cs # Parsed args config object +│ ├── FanucProgram.cs # Fanuc composite NC file parser +│ ├── fwlib32.cs # Fanuc FOCAS1 P/Invoke wrapper (auto-gen, 11K lines) +│ ├── NcProgramManager.csproj # Project file (.NET 4.7.2, Console) +│ ├── App.config # Runtime binding redirects +│ ├── packages.config # NuGet dependencies +│ ├── Licensing/ # License validation subsystem +│ ├── Cnc/ # CNC abstraction + implementations +│ │ ├── ICncMachine.cs +│ │ ├── IFanucMachine.cs +│ │ ├── INcProgramValidator.cs +│ │ ├── NcProgramValidator.cs +│ │ ├── CncMachineFactory.cs +│ │ ├── Models/ # DTOs and value objects +│ │ ├── Fanuc/ # FOCAS protocol +│ │ │ └── libs/ # Native DLLs (embedded) +│ │ ├── Heidenhain/ # LSV2 protocol +│ │ ├── Siemens/ # FTP protocol +│ │ └── Mitsubishi/ # FTP protocol +│ └── Properties/ +│ └── AssemblyInfo.cs +├── NcProgramManager.Tests/ # Test suite +│ ├── Unit/ # Isolated unit tests +│ ├── Integration/ # Protocol integration tests +│ │ └── Stubs/ # In-process server stubs +│ ├── NcProgramManager.Tests.csproj +│ ├── packages.config +│ └── nunit.runsettings +├── NcProgramManager.sln # Solution file +├── Dockerfile.test # Containerized test runner +└── README.md # Italian operator docs +``` + +## Directory Purposes + +**`Licensing/`:** +- Purpose: RSA-based offline license validation +- Key files: `LicenseValidator.cs`, `MachineFingerprint.cs`, `LicenseFile.cs`, `ILicenseValidator.cs`, `IMachineFingerprint.cs` + +**`Cnc/Models/`:** +- Purpose: Shared DTOs and value objects for CNC layer +- Key files: `CncResult.cs`, `CncError.cs`, `CncManufacturer.cs`, `CncProgram.cs`, `ConnectionState.cs`, `ValidationError.cs`, `ValidationResult.cs`, `ValidationSeverity.cs`, `MachineSnapshot.cs`, `MachineMode.cs`, `MotionState.cs`, `RunState.cs` + +**`Cnc/Fanuc/`:** +- Purpose: Fanuc FOCAS protocol implementation +- Key files: `FanucMachine.cs` (main), `FanucConnectionConfig.cs`, `IFocasDialect.cs`, `LegacyFocasDialect.cs`, `ModernFocasDialect.cs`, `FocasDialectFactory.cs`, `FanucDialectDetector.cs`, `FanucErrorTranslator.cs`, `IsoProgramFormatter.cs`, `FanucCapabilities.cs`, `FanucTransport.cs` + +**`Cnc/Heidenhain/`:** +- Purpose: Heidenhain LSV2 protocol implementation +- Key files: `HeidenhainMachine.cs`, `Lsv2Client.cs`, `ILsv2Client.cs`, `HeidenhainConnectionConfig.cs` + +**`Cnc/Siemens/`:** +- Purpose: Siemens FTP protocol implementation +- Key files: `SiemensMachine.cs`, `SiemensFtpClient.cs`, `ISiemensFtpClient.cs`, `SiemensConnectionConfig.cs` + +**`Cnc/Mitsubishi/`:** +- Purpose: Mitsubishi FTP protocol implementation +- Key files: `MitsubishiMachine.cs`, `MitsubishiFtpClient.cs`, `IMitsubishiFtpClient.cs`, `MitsubishiConnectionConfig.cs` + +**`NcProgramManager.Tests/Unit/`:** +- Purpose: Isolated unit tests with mocks +- Key files: `NcProgramValidatorTests.cs`, `FanucMachineTests.cs`, `FanucProgramParsingTests.cs`, `IsoProgramFormatterTests.cs`, `CncMachineFactoryTests.cs`, `LicenseValidatorTests.cs`, `SiemensMachineTests.cs`, `MitsubishiMachineTests.cs`, `HeidenhainMachineTests.cs` + +**`NcProgramManager.Tests/Integration/`:** +- Purpose: Protocol-level tests using in-process stubs +- Key files: `HeidenhainMachineIntegrationTests.cs`, `SiemensMachineIntegrationTests.cs`, `MitsubishiMachineIntegrationTests.cs` + +**`NcProgramManager.Tests/Integration/Stubs/`:** +- Purpose: In-process server stubs for protocol testing +- Key files: `FtpServerStub.cs` (FTP server with in-memory file store), `Lsv2ServerStub.cs` (LSV2 TCP server) + +## Key File Locations + +**Entry Points:** +- `Program.cs` — Main(), CLI orchestration, exit codes +- `ArgParser.cs` — static `Parse(string[]) → InputArgs` + +**Configuration:** +- `NcProgramManager.csproj` — Project metadata, NuGet refs, build config +- `App.config` — Binding redirects only +- `packages.config` — NuGet dependency list + +**Core Logic:** +- `Cnc/ICncMachine.cs` — Primary abstraction interface +- `Cnc/CncMachineFactory.cs` — Manufacturer dispatch +- `Cnc/Models/CncResult.cs` — Result wrapper pattern +- `Cnc/Fanuc/FanucMachine.cs` — Largest impl (~740 lines) +- `Licensing/LicenseValidator.cs` — License check entry + +**Testing:** +- `NcProgramManager.Tests/Unit/NcProgramValidatorTests.cs` — Most comprehensive unit tests +- `NcProgramManager.Tests/Integration/Stubs/FtpServerStub.cs` — Reusable FTP stub + +**Documentation:** +- `README.md` — Italian operator-facing docs (CLI args, license setup, error codes) + +## Naming Conventions + +**Files:** +- PascalCase for all `.cs` files: `FanucMachine.cs`, `CncResult.cs` +- Interfaces prefixed with I: `ICncMachine.cs`, `IFocasDialect.cs` +- Config classes: `{Manufacturer}ConnectionConfig.cs` +- Test files: `{Subject}Tests.cs` or `{Subject}IntegrationTests.cs` + +**Directories:** +- PascalCase for manufacturer dirs: `Fanuc/`, `Heidenhain/`, `Siemens/`, `Mitsubishi/` +- Lowercase for support: `libs/` + +## Where to Add New Code + +**New CNC manufacturer:** +- Implementation: `Cnc/{Manufacturer}/{Manufacturer}Machine.cs` (implement `ICncMachine`) +- Config: `Cnc/{Manufacturer}/{Manufacturer}ConnectionConfig.cs` +- Client: `Cnc/{Manufacturer}/I{Manufacturer}FtpClient.cs` + `{Manufacturer}FtpClient.cs` (if FTP) +- Wire: Add case to `Cnc/CncMachineFactory.cs` +- Enum: Add value to `Cnc/Models/CncManufacturer.cs` +- Args: Update `ArgParser.cs` if new transport args needed + +**New Fanuc FOCAS feature:** +- Add to `Cnc/Fanuc/IFocasDialect.cs`, implement in `LegacyFocasDialect.cs` + `ModernFocasDialect.cs` +- Surface in `Cnc/Fanuc/FanucMachine.cs` +- If Fanuc-specific CLI exposure: update `IFanucMachine.cs`, `Program.cs` + +**New validation rule:** +- Add to `Cnc/NcProgramValidator.cs` +- Add test to `NcProgramManager.Tests/Unit/NcProgramValidatorTests.cs` + +**New CLI arg:** +- Add to `ArgParser.cs` regex parsing +- Add field to `InputArgs.cs` +- Update `README.md` params table + +## Special Directories + +**`Cnc/Fanuc/libs/`:** +- Purpose: Native Fanuc FOCAS DLLs +- Source: Fanuc-provided proprietary binaries +- Committed: Yes (required for build) +- Embedded: Via Costura.Fody into output EXE + +**`.paul/`:** +- Purpose: PAUL project planning state +- Source: Generated/maintained by PAUL workflow +- Committed: Yes + +--- + +*Structure analysis: 2026-05-18* +*Update when directory structure changes* diff --git a/.paul/codebase/TESTING.md b/.paul/codebase/TESTING.md new file mode 100644 index 0000000..225ea9f --- /dev/null +++ b/.paul/codebase/TESTING.md @@ -0,0 +1,153 @@ +# Testing Patterns + +**Analysis Date:** 2026-05-18 + +## Test Framework + +**Runner:** +- NUnit 3.13.3 — `NcProgramManager.Tests/packages.config` +- NUnit3TestAdapter 4.2.1 — VS/dotnet test runner integration +- Config: `NcProgramManager.Tests/nunit.runsettings` + +**Assertion Library:** +- NUnit fluent API: `Assert.That(actual, Is.True)`, `Is.EqualTo()`, `Is.InstanceOf()` + +**Mocking:** +- Moq 4.18.4 for interface mocking +- Castle.Core 5.1.1 (Moq dependency) +- Custom delegates for `ref` parameter workaround (Moq limitation with P/Invoke refs) + - Example: `NcProgramManager.Tests/Unit/FanucMachineTests.cs` + +**Run Commands:** +```bash +# Standard NUnit runner or VS Test Explorer +dotnet test NcProgramManager.Tests/NcProgramManager.Tests.csproj +# Or via Dockerfile: +docker build -f Dockerfile.test . +``` + +## Test File Organization + +**Location:** +- All tests in `NcProgramManager.Tests/` (separate project) +- Unit tests: `NcProgramManager.Tests/Unit/` +- Integration tests: `NcProgramManager.Tests/Integration/` +- Stubs: `NcProgramManager.Tests/Integration/Stubs/` + +**Naming:** +- Unit: `{Subject}Tests.cs` — `NcProgramValidatorTests.cs`, `FanucMachineTests.cs` +- Integration: `{Subject}IntegrationTests.cs` — `HeidenhainMachineIntegrationTests.cs` +- Stubs: `{Protocol}ServerStub.cs` — `FtpServerStub.cs`, `Lsv2ServerStub.cs` + +## Test Structure + +**Fixture Pattern:** +```csharp +[TestFixture] +public class NcProgramValidatorTests +{ + [SetUp] + public void SetUp() { ... } + + [Test] + public void MethodName_Condition_ExpectedResult() + { + // arrange + // act + // assert (NUnit fluent) + } +} +``` + +**Parameterized Tests:** +```csharp +[TestCase(CncManufacturer.Fanuc)] +[TestCase(CncManufacturer.Siemens)] +[TestCase(CncManufacturer.Heidenhain)] +[TestCase(CncManufacturer.Mitsubishi)] +public void Validate_TabCharacter_ReturnsWarning(CncManufacturer m) { ... } +``` +Example: `NcProgramManager.Tests/Unit/NcProgramValidatorTests.cs` + +**Async Tests:** +- No `async Task` test methods — use `.GetAwaiter().GetResult()` to block + - Example: `NcProgramManager.Tests/Integration/HeidenhainMachineIntegrationTests.cs` + +**Test Categories:** +```csharp +[Category("Integration")] // marks integration tests +``` + +## Mocking + +**Interface mocking via Moq:** +```csharp +var mockDialect = new Mock(); +mockDialect.Setup(d => d.Connect(...)).Returns(...); +var machine = new FanucMachine(config, mockDialect.Object); +``` +Example: `NcProgramManager.Tests/Unit/FanucMachineTests.cs` + +**Reflection-based state injection (for bypassing protected fields):** +```csharp +// Set internal connection state without real hardware +typeof(FanucMachine) + .GetField("_state", BindingFlags.NonPublic | BindingFlags.Instance) + .SetValue(machine, ConnectionState.Connected); +``` +Example: `NcProgramManager.Tests/Unit/FanucMachineTests.cs` + +**What to mock:** +- Protocol interfaces: `IFocasDialect`, `ILsv2Client`, `ISiemensFtpClient`, `IMitsubishiFtpClient` +- Licensing: `IMachineFingerprint`, `ILicenseValidator` + +## In-Process Protocol Stubs + +**FtpServerStub** (`NcProgramManager.Tests/Integration/Stubs/FtpServerStub.cs`): +- Minimal FTP server for Siemens/Mitsubishi integration testing +- In-memory file store: `Dictionary Files` +- Supported commands: USER, PASS, CWD, TYPE, PASV, LIST, NLST, RETR, STOR, DELE +- Usage: Start before test, inject port into machine config + +**Lsv2ServerStub** (`NcProgramManager.Tests/Integration/Stubs/Lsv2ServerStub.cs`): +- Minimal LSV2 TCP server for Heidenhain integration testing +- Implements LSV2 framing (STX, SIZE, CMD, data, CRC) +- Thread-per-client architecture + +## Ignored Tests + +**FOCAS DLL-dependent tests marked `[Ignore]`:** +- All tests requiring actual `Fwlib32.dll` calls are ignored +- Reason: Cannot mock static P/Invoke calls; DLL requires real Fanuc hardware on Windows +- Example: `NcProgramManager.Tests/Unit/FanucMachineTests.cs` + +**Pattern for skipping:** +```csharp +[Test] +[Ignore("Requires Fanuc FOCAS DLL and real hardware")] +public void ConnectAsync_ValidConfig_Connects() { ... } +``` + +## Coverage Approach + +**Well-covered:** +- `NcProgramValidator` — universal rules + all 4 manufacturers, 30+ test cases + - `NcProgramManager.Tests/Unit/NcProgramValidatorTests.cs` +- `FanucProgram` parsing — `FanucProgramParsingTests.cs` +- `IsoProgramFormatter` — `IsoProgramFormatterTests.cs` +- `CncMachineFactory` dispatch — `CncMachineFactoryTests.cs` +- `LicenseValidator` — 6 unit tests via internal ctor injection — `LicenseValidatorTests.cs` + +**Partially covered (blocked by hardware):** +- `FanucMachine` connect/read/write — FOCAS tests `[Ignore]`d +- Heidenhain/Siemens/Mitsubishi machines — integration tests use stubs + +**Not covered:** +- `MachineFingerprint` (WMI, Windows-only, no mocked tests) +- `LicenseFile` parsing edge cases +- `Program.cs` CLI orchestration (no CLI-level tests) + +--- + +*Testing analysis: 2026-05-18* +*Update when test framework or patterns change*