docs: map existing codebase

- STACK.md - Technologies and dependencies (.NET 4.7.2, NuGet, Costura.Fody)
- ARCHITECTURE.md - Layered CLI with ICncMachine factory pattern
- STRUCTURE.md - Directory layout and where to add new code
- CONVENTIONS.md - C# style, naming, result wrapper pattern
- TESTING.md - NUnit 3 + Moq, stubs, ignored FOCAS tests
- INTEGRATIONS.md - FOCAS, LSV2, FTP, RSA licensing
- CONCERNS.md - Blocking async, silent catch, no logging, Windows-only

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
dtrentin 2026-05-18 22:48:20 +02:00
parent f55d0b313b
commit dabcf989d9
7 changed files with 913 additions and 0 deletions

View file

@ -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<T>`) 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<T>`, `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<bool>
→ machine.ReadProgramAsync(path) → CncResult<string>
→ [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<bool>
```
**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<T>:**
- 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<T>.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*

152
.paul/codebase/CONCERNS.md Normal file
View file

@ -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<int> 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<T>`. 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*

View file

@ -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<T>` 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<T>` 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<T>.Ok(value)` — success
- `CncResult<T>.Fail(errors)` — failure with error list
- `CncResult<T>.Cancelled()` — cancellation
- `CncResult<T>.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: `/// <summary>Brief description.</summary>`
- 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*

View file

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

83
.paul/codebase/STACK.md Normal file
View file

@ -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<T> and Memory<T> 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*

160
.paul/codebase/STRUCTURE.md Normal file
View file

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

153
.paul/codebase/TESTING.md Normal file
View file

@ -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<T>()`
**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<IFocasDialect>();
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<string, string> 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*