Lands the design-contract pivot ahead of any cache implementation code so reviewers can evaluate the change to the "purely transparent proxy" stance independently of the Phase-11 code that depends on it. - docs/design.md: rewrite "What this is" / Read-coalescing / Failure-modes sections to acknowledge the opt-in cache; add new "Response cache (Phase 11)" section covering lookup order (cache -> coalesce -> backend), multi- tag range TTL = min, post-rewriter storage, address-range-overlap write invalidation, hot-reload PLC-wide flush, no-persistence, AllowLongTtl gate, and LRU-bounded capacity. Extend log event table with mbproxy.cache.* events. Extend per-PLC status field table with cacheHitCount / cacheMissCount / cacheInvalidations / cacheEntryCount / cacheBytes. Extend hot-reload propagation table with CacheTtlMs / Cache.* rows. - docs/kpi.md: graduate Tier 1.8 (response cache) from "requires Phase 11" to "shipped in Phase 11" and add Tier 2.4a cache-memory section. - CLAUDE.md (mbproxy): update Purpose paragraph and the Architecture headline bullets to reflect the transparent-by-default + opt-in-cache contract; flip "Implementation complete through Phase 10" to "through Phase 11". - install/mbproxy.config.template.json: add a fully-commented Mbproxy.Cache block and a CacheTtlMs example on a BcdTags.Global entry, with prominent staleness commentary documenting the design contract. No code changes in this commit - implementation lands in a follow-up. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
mbproxy
A .NET 10 Windows Service that sits inline as a Modbus TCP proxy in front of a fleet of AutomationDirect DirectLOGIC DL205/DL260 controllers, rewriting BCD-encoded registers bidirectionally so upstream clients can read and write them as plain integers.
Hard constraints / prerequisites
- Windows 10 / Server 2019 or later, 64-bit. No Linux or Docker support — the service uses
Microsoft.Extensions.Hosting.WindowsServicesand the Windows Event Log. - Modbus TCP backends reachable from the proxy host on port 502 (or the port configured per PLC). The H2-ECOM100 module caps simultaneous connections at 4 per PLC — a fifth upstream client will fail to connect.
- Admin rights to install the service (
install.ps1requires elevation). - No COM dependency — this is a pure .NET 10 socket-level proxy (unlike the
.NET Framework 4.8 / x86siblings in this repo). - Python 3.10+ on the test machine to run the pymodbus-backed E2E simulator (not needed to run the service in production).
Layout
src/Mbproxy/ Main C# project (net10.0, Microsoft.NET.Sdk.Worker)
tests/Mbproxy.Tests/ xUnit v3 test project (282 unit + 43 E2E tests)
install/ PowerShell install/uninstall scripts and config template
docs/ Design document, phase plans, and operations runbook
DL260/ DL205/DL260 reference material and pymodbus simulator profile
Resource index
| Task | Go to |
|---|---|
| Full architecture, schema, log events, status counters, test strategy | docs/design.md |
| Phase-by-phase implementation plan | docs/plan/README.md |
| Install, upgrade, config, logs, troubleshooting | docs/operations.md |
| DL205/DL260 Modbus quirks (BCD, CDAB, octal V-memory, FC limits) | DL260/dl205.md |
| pymodbus simulator profile (register seeds for E2E tests) | DL260/dl205.json |
| Agent-oriented coding guide (architecture bullets, device quirks, phase context) | CLAUDE.md |
Build and run
Build (Debug, multi-file — fast for iteration):
dotnet build Mbproxy.slnx -c Debug
Publish (Release, single-file self-contained, win-x64):
dotnet publish src/Mbproxy/Mbproxy.csproj -c Release -r win-x64 --self-contained true -o C:\build\mbproxy-publish
The published output is a single Mbproxy.exe (~100 MB). The self-contained publish bundles the full .NET 10 + ASP.NET Core runtime. No .NET installation is required on the target machine.
Run tests:
dotnet test Mbproxy.slnx -c Debug # all tests
dotnet test Mbproxy.slnx -c Debug --filter Category=Unit # unit tests only (no Python required)
dotnet test Mbproxy.slnx -c Debug --filter Category=E2E # E2E tests (require Python + pymodbus)
Run interactively (without installing as a service):
cd src/Mbproxy
dotnet run --configuration Debug
Edit src/Mbproxy/appsettings.json to configure PLCs before running. The admin status page will be at http://localhost:8080/ by default.
Install
Full detail is in docs/operations.md. Quick path:
# 1. Publish
dotnet publish src/Mbproxy/Mbproxy.csproj -c Release -r win-x64 --self-contained true -o C:\build\mbproxy-publish
# 2. Install (elevated PowerShell)
.\install\install.ps1 -PublishOutput C:\build\mbproxy-publish -Start
# 3. Edit the config that was placed at %ProgramData%\mbproxy\appsettings.json
# 4. Verify
Invoke-WebRequest http://localhost:8080/ -UseBasicParsing
Maintenance
Documentation doctrine for this repo: ../DOCS-GUIDE.md.
- This README routes to deep docs — it does not duplicate them.
- Design decisions:
docs/design.mdis the source of truth. - When the service's public surface or task→tool mapping changes, update this README and the root
../CLAUDE.mdindex row.