Files
lmxopcua/docs/plans/2026-07-24-driver-expansion-tracking.md
T
Joseph Doherty e27eb77187
v2-ci / build (pull_request) Successful in 3m45s
v2-ci / unit-tests (pull_request) Failing after 13m54s
docs(modbus-rtu): record Wave-1 RTU-over-TCP live /run gate result (PASSED)
Claude-Session: https://claude.ai/code/session_01GASWkNEi68FSCtvr6rLoEW
2026-07-24 15:50:10 -04:00

13 KiB
Raw Blame History

Driver-expansion — Waves 02 tracking

Living status tracker for the driver-expansion program (Waves 0, 1, 2). One row per deliverable, each pointing at its design doc, its implementation plan (once written), and its current status. The authoritative architecture index is the program design doc; this file is the authoritative progress index.

Program design (architecture / shared contract / build order): 2026-07-15-driver-expansion-program-design.md

Last updated: 2026-07-24.

Legend

Status Meaning
Done Merged to master, tests green.
🟡 Live gate open Code merged; a live /run or hardware-gated verification still outstanding.
📝 Plan ready Executable implementation plan (*-implementation.md + .tasks.json) written; not yet built.
📐 Design only Design doc exists; no implementation plan yet — writing-plans is the next step.
Not started No design, no plan.

Doc types (per the writing-plans skill): a design states architecture, decisions, and risks; an implementation plan is the bite-sized, TDD, file-path-level task list the subagent-driven executor runs off, with a co-located .tasks.json for resume. A deliverable is only buildable once it reaches 📝.

Summary

Wave Deliverable Design Impl. plan Status Effort Fixture / hardware
0 Universal Discover-backed browser design plan · tasks 🟡 Live gate open SM none (retrofits shipped drivers)
1 Modbus RTU (extend Modbus) design plan · tasks 🟢 Built — live gate PASSED (11 tasks, branch feat/modbus-rtu-driver, pending merge) S (lowest) pymodbus rtu_over_tcp — CI-simulatable, no new infra
1 SQL poll design plan · tasks 📝 Plan ready (22 tasks) SM existing central SQL Server 10.100.0.35,14330 + SQLite unit
2 MTConnect Agent design plan · tasks 📝 Plan ready (23 tasks) SM Dockerized mtconnect/cppagent — CI-simulatable
2 MQTT / Sparkplug B design plan · tasks 📝 Plan ready (27 tasks, P1+P2) ML Mosquitto/EMQX + C# Sparkplug sim — CI-simulatable

Waves 3+ (BACnet/IP, Omron) and the deferred MELSEC are tracked in the program design doc §6/§8, not here. Omron CIP is the program's sole real-hardware wire gate; BACnet's broadcast/BBMD leg is env-gated live. Both are out of this file's scope until they're pulled forward.


Executing a plan (git worktree + subagent-per-task)

Each 📝 plan is executed with the subagent-driven-development skill: it sets up an isolated git worktree first (via using-git-worktrees), then dispatches a fresh subagent per task, running the classification-driven review chain (trivial = implement only … high-risk = spec-review → code-review → integration review) between tasks. The .tasks.json next to each plan tracks progress and lets a later session resume.

Paste one of these into Claude Code to build a driver:

Deliverable Command
Modbus RTU (Wave 1) Use superpowers-extended-cc:subagent-driven-development to execute docs/plans/2026-07-24-modbus-rtu-driver.md in a new git worktree
SQL poll (Wave 1) Use superpowers-extended-cc:subagent-driven-development to execute docs/plans/2026-07-24-sql-poll-driver.md in a new git worktree
MTConnect (Wave 2) Use superpowers-extended-cc:subagent-driven-development to execute docs/plans/2026-07-24-mtconnect-driver.md in a new git worktree
MQTT/Sparkplug (Wave 2) Use superpowers-extended-cc:subagent-driven-development to execute docs/plans/2026-07-24-mqtt-sparkplug-driver.md in a new git worktree
  • Slash-command form (equivalent): /superpowers-extended-cc:subagent-driven-development <plan-path>.
  • Parallel-session / resume form (batch execution with checkpoints, no fresh-subagent-per-task): /superpowers-extended-cc:executing-plans <plan-path> — reads the same .tasks.json and continues from the first pending task.
  • Recommended order: Modbus RTU → SQL poll → MTConnect → MQTT/Sparkplug (lowest effort first; see each wave below for the gating notes). Run one plan per worktree; the four plans are independent, so separate worktrees may run concurrently.

Wave 0 — Universal Discover-backed browser 🟡

What it is. One generic DiscoveryDriverBrowser (+ CapturingAddressSpaceBuilder, CapturedTreeBrowseSession, BrowserSessionService fallback, and the ITagDiscovery.SupportsOnlineDiscovery gate) that turns any driver's ITagDiscovery.DiscoverAsync into an AdminUI browse tree. It is the Wave-0 gate: every browsable new driver depends on this seam, and it retrofits browse to the already-shipped AbCip / TwinCAT / FOCAS drivers for near-zero marginal cost.

  • Design: 2026-07-15-universal-discovery-browser-design.md
  • Implementation plan: 2026-07-15-universal-discovery-browser-implementation.md · .tasks.json
  • Status: 🟡 code-complete + merged, live gate open.
    • Merged to master — 056887d6 (Merge feat/universal-discovery-browser — Wave-0 universal Discover-backed browser), 2026-07-15.
    • Implementation plan: 19 / 19 tasks completed.
    • Lit up AbCip / TwinCAT / FOCAS pickers with zero per-driver browse code.
  • Outstanding: the full tree-render live /run gate is fixture-blocked — tracked as Gitea #468. Complete this before leaning on browse in Wave 2/3.

Wave 1 — low-effort / high-leverage pair 📝

Both are fully CI-simulatable with zero new hardware; Modbus RTU needs no new infra at all, and SQL poll reuses the always-on central SQL Server. This is the recommended next build.

Modbus RTU — 🟢 Built, live gate PASSED (branch feat/modbus-rtu-driver, pending merge)

  • Design: 2026-07-15-modbus-rtu-driver-design.md
  • Implementation plan: 2026-07-24-modbus-rtu-driver.md · .tasks.json11 tasks (1 trivial / 5 small / 2 standard / 3 high-risk), all complete via subagent-driven-development.
  • Scope: extend the existing Modbus driver with a Transport selector (RTU CRC-16 + FC-aware length, no TxId) + a rtu_over_tcp pymodbus docker profile + the AdminUI selector. Direct-serial transport is descoped (user, 2026-07-15) — RTU-over-TCP via a serial→Ethernet gateway is the only shipped mode, so there is no serial hardware gate.
  • Fixture: added the rtu_over_tcp profile (framer=rtu, host :5021, co-runs with standard) to the Modbus integration fixture. Unknown confirmed: pymodbus 3.13's simulator DOES honour framer=rtu on a TCP server (wire-probed a pure RTU FC03 response, no MBAP) — so the simple profile path was taken; no stdlib fallback server was needed.
  • Verification (all green): unit suite 344/344; full solution build 0 errors; the 2 RTU integration tests pass live against the real framer=rtu fixture (read HR5→5, write+readback HR200←4242). Per-task review chain (spec + code reviewers) + a final whole-branch review, all approved-to-merge.
  • Live /run gate — PASSED (2026-07-24, docker-dev rebuilt from this branch):
    • AdminUI /raw Modbus driver config modal renders the new Transport selector (with the operator hint) — set to RtuOverTcp, saved.
    • Device Test Connect → OK · 23 MS — the probe built a ModbusRtuOverTcpTransport via the factory and spoke FC03 over real RTU framing to 10.100.0.35:5021.
    • Authored raw tags HR5 (r/o) + HR200 (r/w) → deployment 06ec1632 Sealed (all 6 nodes acked).
    • Client.CLI on opc.tcp://localhost:4840 (multi-role/password): read ns=2;s=rtu-gate/Device1/HR55, Good; write ns=2;s=rtu-gate/Device1/HR200 = 4242 → readback 4242, Good.
  • Effort: S — the lowest on the roadmap. Delivered first, as recommended.

SQL poll — 📝 Plan ready

  • Design: 2026-07-15-sql-poll-driver-design.md
  • Implementation plan: 2026-07-24-sql-poll-driver.md · .tasks.json22 tasks. ISqlDialect seam in from day one; only the SQL Server dialect built in v1 (Postgres/ODBC deferred).
  • Scope: a bespoke schema-browser driver polling a SQL table into equipment tags (SQL Server P1; Postgres/ODBC land in P2/P3 behind ISqlDialect).
  • Fixture: SQLite unit fixture (primary) + an env-gated integration fixture against the existing central SQL Server (10.100.0.35,14330) with a seeded SqlPollFixture DB. The blackhole/timeout live-gate pauses a dedicated mssql container — never the shared central SQL Server (it hosts ConfigDb).
  • Effort: SM.

Wave 2 — strategic telemetry / UNS pair 📝

Both CI-simulatable on the shared docker host, no hardware.

MTConnect Agent — 📝 Plan ready

  • Design: 2026-07-15-mtconnect-driver-design.md
  • Implementation plan: 2026-07-24-mtconnect-driver.md · .tasks.json23 tasks. Task 0 is the TrakHound-vs-hand-rolled client decision; browse-picker live-verify is gated on Wave-0 #468.
  • Scope: P1 Agent MVP (IDriver+ITagDiscovery+IReadable+ISubscribable+probe+rediscover), browse free via the Wave-0 universal browser (SupportsOnlineDiscovery=true, no browser code), typed editor, UNAVAILABLE→BadNoCommunication mapping, ring-buffer re-baseline paging.
  • Fixture: canned XML unit fixtures (bulk of coverage) + a dockerized mtconnect/cppagent integration fixture (env-gated). Depends on Wave 0's browse seam being live-verified (#468).
  • Effort: SM (≈11.5 wk with TrakHound, ≈2.53 wk hand-rolled).

MQTT / Sparkplug B — 📝 Plan ready

  • Design: 2026-07-15-mqtt-sparkplug-driver-design.md
  • Implementation plan: 2026-07-24-mqtt-sparkplug-driver.md · .tasks.json27 tasks (P1 plain MQTT = Tasks 014, a complete shippable milestone; P2 Sparkplug B = Tasks 1526). Task 0 is the mandatory MQTTnet-5/net10 + central-pinning validation spike.
  • Scope: P1 plain MQTT (MQTTnet-5 connect/TLS/auth + hand-rolled reconnect, subscribe→ OnDataChange, retained last-value read, #-observation browser); P2 Sparkplug B ingest (vendored Tahu proto, birth/alias/seq-gap/rebirth state machine, death→STALE).
  • Fixture: Mosquitto/EMQX broker (TLS + real auth, not anonymous) + a project-owned C# Sparkplug edge-node simulator for the rebirth/seq-gap/death test matrix + env-gated live suite (MQTT_FIXTURE_ENDPOINT).
  • Effort: ML. Top risks: Sparkplug state-machine correctness; MQTTnet-5/net10 + the repo's fragile central pinning (mitigated by hand-rolling Tahu over one MQTTnet-5 client).

Next actions

  1. Close the Wave-0 live gate (Gitea #468) — unblocks browse verification for MTConnect/BACnet.
  2. Build Wave 1 — Modbus RTU first (lowest effort, no new infra), then SQL poll. Both plans are 📝 ready; run the command from the Executing a plan table (subagent-driven-development in a git worktree).
  3. Build Wave 2 (MTConnect, then MQTT/Sparkplug) — both plans 📝 ready. MTConnect's browse leg wants #468 closed first; MQTT's Task 0 pinning spike gates everything after it.

Update this file's Summary table and per-wave status whenever a deliverable changes state.