From 8af5742406ddcd43a27333a54a9347132e6cd8c8 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Wed, 5 Aug 2026 04:32:38 -0400 Subject: [PATCH] docs(raw): live /run gate PASSED for the raw-modal picker live config; records Gitea #539 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All three legs pass against the patched AbCip fixture: the edit modal and the manual-entry grid both browse the live nine-tag symbol table, and an unreachable device degrades to the graceful error chip while the modal still saves. The gate also found a defect unrelated to this change and filed it as #539: the AbCip discovery path (LibplctagTagEnumerator, LibplctagTemplateReader) passes libplctag the bare host, so an authored non-default EtherNet/IP port is dropped and the browse reaches whatever answers on 44818 — #534's defect surviving in the discovery half. Discovered because the first negative-leg endpoint differed from the fixture only by port, which never reached the wire. --- ...versal-discovery-browser-implementation.md | 6 ++- .../2026-07-24-driver-expansion-tracking.md | 7 ++- ...-05-raw-modal-picker-live-config-design.md | 45 +++++++++++++++++-- 3 files changed, 52 insertions(+), 6 deletions(-) diff --git a/docs/plans/2026-07-15-universal-discovery-browser-implementation.md b/docs/plans/2026-07-15-universal-discovery-browser-implementation.md index 4d970582..71f80de8 100644 --- a/docs/plans/2026-07-15-universal-discovery-browser-implementation.md +++ b/docs/plans/2026-07-15-universal-discovery-browser-implementation.md @@ -1160,8 +1160,10 @@ neither agreed with a controller. Fixed, with the layout now pinned by a capture passing a `"{}"` stub as `GetDriverConfigJson`). Fixed by resolving the merged Driver+Device config (`IRawTreeService.LoadMergedProbeConfigAsync` — the same blob Test-connect and `RawBrowseModal` dial) once per open and forwarding a live accessor; fail-soft on resolve - failure. See `2026-08-05-raw-modal-picker-live-config-design.md` for the design and outcome - (including the stale-open race the review found and closed). + failure. **Live-gated 2026-08-05, all three legs PASSED** against the same patched AbCip fixture + this plan's second gate used. See `2026-08-05-raw-modal-picker-live-config-design.md` for the + design and outcome (including the stale-open race the review found and closed, and Gitea **#539** + — the AbCip discovery path dropping the authored EtherNet/IP port — which that gate uncovered). ## Out of scope (explicitly) diff --git a/docs/plans/2026-07-24-driver-expansion-tracking.md b/docs/plans/2026-07-24-driver-expansion-tracking.md index 0d06c642..f9df628f 100644 --- a/docs/plans/2026-07-24-driver-expansion-tracking.md +++ b/docs/plans/2026-07-24-driver-expansion-tracking.md @@ -113,7 +113,12 @@ marginal cost. fix surfaced and closed a further stale-open race (a superseded open could install another device's config); `RawBrowseModal` shares that pre-existing race shape and is recorded in `deferment.md` §0.1, not fixed here. Pinned by `RawTagModalMergedConfigTests` + - `RawManualTagEntryModalMergedConfigTests`. + `RawManualTagEntryModalMergedConfigTests`, and **live-gated 2026-08-05** — all three legs PASSED + against the patched AbCip fixture (edit modal + manual entry both browse the nine-tag tree; an + unreachable device degrades to the error chip and still saves). The gate also found **Gitea #539**: + the AbCip *discovery* path drops the authored EtherNet/IP port, so a device on a non-default port + browses whatever answers on 44818 — #534's defect surviving in `LibplctagTagEnumerator` + + `LibplctagTemplateReader`. --- diff --git a/docs/plans/2026-08-05-raw-modal-picker-live-config-design.md b/docs/plans/2026-08-05-raw-modal-picker-live-config-design.md index fbe224b9..473fee14 100644 --- a/docs/plans/2026-08-05-raw-modal-picker-live-config-design.md +++ b/docs/plans/2026-08-05-raw-modal-picker-live-config-design.md @@ -1,8 +1,9 @@ # Raw-modal address pickers: pass live merged config to browse — design -**Status:** IMPLEMENTED 2026-08-05 (unit suite green, AdminUI 1064/1064; live `/run` gate §4.2 -pending). Closes the last dangling follow-up from the #468 universal-browser live gate -("driver-page address pickers pass no live config"). Outcome notes in §6. +**Status:** DONE 2026-08-05 — unit suite green (AdminUI 1064/1064) and the live `/run` gate §4.2 +**PASSED** (all three legs; see §7). Closes the last dangling follow-up from the #468 +universal-browser live gate ("driver-page address pickers pass no live config"). Outcome notes in +§6; gate evidence + the defect it uncovered (Gitea **#539**) in §7. ## 1. Problem @@ -122,3 +123,41 @@ through a spec review + code review. Things the reviews changed or decided: - The liveness of the forwarded `Func` is load-bearing (the pickers call it at click time, after the async resolve) and is pinned in both files by retained-delegate facts, each falsified against a deliberate capture-by-value implementation before being trusted. + +## 7. Live `/run` gate — PASSED (2026-08-05) + +Run by the main session against the local docker-dev rig (`http://localhost:9200`, login disabled) +with **both** central containers rebuilt from master `d88e42b8` and verified on the same image +(`sha256:6b1ddb47…`) — the previously-running image predated the merge by three minutes, and `:9200` +round-robins central-1/central-2, so per-container image parity is the precondition for reading +anything into the result. Backend: the #468 patched `ab_server` (`otopcua-ab-server-controllogix`, +`10.100.0.35:44818`), authored as `docker-dev / abcip-browse / Device1`. + +| Leg | Result | +|---|---| +| **Edit modal** — `Device1/Motor_Run` → Tag config → Build → Browse controller | ✅ `BROWSER OPEN`, tree `AbCip → Device1 → Discovered` with **all nine** fixture tags (`Motor_Run`, `Line1_Count`, `Pump_1_Speed`, `TestArray`, `TestString`, `TestSINT`, `TestBOOL`, `TestREAL`, `TestDINT`). Selecting `TestREAL` landed it in the Tag-path field. | +| **Manual entry** — device → Add tags (manual) → row Configure → Build → Browse controller | ✅ Same nine-tag tree, same `Discovered` shape. | +| **Negative** — a device whose endpoint is unreachable | ✅ Button still renders; the click yields the graceful `ERRORTIMEOUT` chip, the grid stays usable, and the row **still saved** (a tag was created after the failed browse). | + +The tree's second level is labelled with the **device's own name** (`Device1`, and `DeadDevice` for +the throwaway negative-leg device) — direct evidence that the per-device merged config, not a stub, +is what the picker captures against. Under the old `"{}"` stub no endpoint reached the capture at +all. The probe device + its tag were deleted afterwards; the rig is back to its pre-gate state. + +### The gate found a real defect — Gitea #539 (AbCip discovery drops the authored port) + +The negative leg was first run against `ab://10.100.0.35:44999/1,0` (nothing listening on 44999) and +**browsed successfully**, returning the fixture's nine tags — while **Test Connect on the same merged +config correctly failed** `CONNECT FAILED: CONNECTIONREFUSED`. That divergence is not this change: the +AbCip discovery path passes libplctag the bare host, so libplctag substitutes its own 44818 default — +Gitea **#534**'s defect surviving in `LibplctagTagEnumerator.cs:33` and `LibplctagTemplateReader.cs:24` +(the data path was fixed and uses `LibplctagGateway`). Consequence: browsing a device on a non-default +port shows **whatever answers on 44818**, which on a plant network is another PLC. + +Re-pointing the device at `ab://127.0.0.1/1,0` produced the expected failure, which is the run +recorded in the table above. Two things worth carrying forward: + +- ⚠️ **A "bad endpoint" chosen by changing only the port is not a valid negative control for + anything libplctag-backed** — the port may never reach the wire. Change the **host**. +- The fixture sitting on the default 44818 is exactly why #534's discovery half survived its own + fix: on 44818 the bug is invisible by construction, so no existing test could see it.