Comments described the *history* of how the code arrived (phase numbers,
wave IDs, review IDs, dated TODOs) instead of what it does today. That
scaffolding rotted as the codebase evolved. Cleaned 60 source files +
.gitignore; behaviour unchanged (387/387 tests still pass).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes the 5 "easily addable" W3 test gaps left after the prior W3 commit;
the 5 race-hard gaps remain documented as known omissions per the plan.
Tests: 382 pass / 0 fail (baseline 378 + 4 net new methods — the supervisor
runtime-fault test replaces the existing placeholder).
#11 BcdCodecTests.Encode16_IntMinValue_Throws_OutOfRange_NoArithmeticSurprise
Locks the (uint)value > Max16 boundary check against int.MinValue. The
cast becomes 0x80000000 which is well above 9999, so the throw fires
cleanly. Prevents regression to a two-sided int comparison that would
underflow.
#15 BcdPduPipelineTests.FC03_Request_QtyAbove128_AtNonBcdAddress_PassesThroughUnchanged
DL205/DL260 caps FC03/FC04 at qty=128 (DL260/dl205.md). The proxy must
NOT truncate the qty field — passing through unchanged lets the PLC's
own validator return exception 03 to the client (transparent contract
for FCs/addresses the rewriter doesn't own).
#4 SupervisorTests.Supervisor_RuntimeFault_OnRunningListener_RecoversAndRebinds
Replaces the previous placeholder. Genuinely faults the running listener
mid-life by stopping its underlying TcpListener via reflection (the
single externally-observable hook to force the accept loop's
AcceptAsync to throw ObjectDisposedException). Asserts the supervisor
transitions to Recovering, re-binds via the Polly pipeline, and bumps
RecoveryAttempts.
#10 HotReloadE2ETests.E2E_ReadCoalescingEnabled_FlipAtRuntime_PropagatesToOptionsMonitor
Validates that flipping Mbproxy.Resilience.ReadCoalescing.Enabled at
runtime via hot-reload propagates through the live IOptionsMonitor.
The W2.1 fix wires the accessor through to add/restart supervisors;
the multiplexer reads it per-PDU (unit-tested separately). Proving
IOptionsMonitor sees the new value is sufficient for the contract.
#16 ConfigReconcilerTests.Apply_ManyConcurrentReloads_With_PlcChurn_NoCorruption
Stress-tests the W2.3 ConcurrentDictionary fix. 16 concurrent applies
cycle through 8 distinct PLC rosters, driving Add+Remove churn against
the live supervisor dict. Without W2.3 the inner Task.WhenAll
continuations would corrupt Dictionary<,> and crash with
KeyNotFoundException / ArgumentException. Asserts every apply succeeds,
no orphan supervisors remain, and the reload counter equals 16.
The 5 deterministically-race-hard gaps (#5 TxId saturation propagation, #6
coalescing factory leak under saturation, #7 backend-reader head-of-line
block, #8 watchdog↔response race, #9 cascade↔new-accept race) remain open
by design — reproducing those races deterministically requires test seams in
production code or stress-style tests that flake on slow CI. The Wave-1
fixes are still verified at the unit-contract level
(UpstreamPipeTests.TrySendResponse_WhenChannelFull, etc.).
This closes everything actionable in codereviews/2026-05-14/RemediationPlan.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds the mbproxy service end-to-end. Phases 00-08 implement the
production-ready single-listener / 1:1-backend transparent Modbus TCP
proxy with bidirectional BCD rewriting for the ~54-PLC DL205/DL260
fleet. Phase 9 replaces the connection layer with a single backend
socket per PLC plus MBAP TxId rewriting, lifting the H2-ECOM100's
4-concurrent-client cap as an operational ceiling.
Phase 9 additions of note:
- PlcMultiplexer + UpstreamPipe + TxIdAllocator + CorrelationMap
- InFlightRequest with IReadOnlyList<InterestedParty> (load-bearing
for Phase 10 read coalescing — do not collapse to a single field)
- Per-request watchdog: surfaces Modbus exception 0x0B to upstream
on BackendRequestTimeoutMs, defending against lost responses,
dead-PLC paths, and pymodbus 3.13.0's concurrent-multiplexed-
request bug (its ServerRequestHandler.last_pdu state race)
- Status DTO + HTML gain inFlight / maxInFlight / txIdWraps /
disconnectCascades / queueDepth (Tier 1.6 in docs/kpi.md)
Tests: 263 unit + 38 E2E. Multiplexer correctness under truly
concurrent backend traffic is proved against a stub backend in
PlcMultiplexerTests; MultiplexerE2ETests paces requests so pymodbus
3.13's single-PDU framer stays in known-good mode.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>