test(mtconnect): live gate on an isolated rig — 4/5 legs pass, deploy leg blocked on a cookie collision (Task 21)

This commit is contained in:
Joseph Doherty
2026-07-24 20:55:55 -04:00
parent 71ccccef7c
commit 1d0989d3b4
2 changed files with 107 additions and 0 deletions
+62
View File
@@ -894,6 +894,68 @@ git commit -m "test(mtconnect): live /run gate on docker-dev — browse/read/sub
---
### LIVE-GATE RESULT (2026-07-24) — 4 of 5 legs PASSED; the deploy leg is BLOCKED on a rig artifact, not a defect
**Rig.** The shared `otopcua-dev` rig was NOT used: three sibling driver worktrees
(`modbus-rtu`, `mqtt-sparkplug`, `sql-poll-driver`) share its `otopcua-host:dev` image, and it had
been up for hours. Instead an isolated stack was built from this worktree —
`otopcua-host:mtconnect`, compose project `otopcua-mtc`, overlay
`docker-dev/docker-compose.mtconnect.yml`, MAIN pair only, ports AdminUI **9220** / OPC UA **4860**
/ SQL **14340**. Mirrors how the mqtt worktree isolated itself. The `otopcua-dev` rig and every
sibling worktree were left untouched.
**Fixture.** `mtconnect/agent:2.7.0.12` + the SHDR adapter deployed to
`/opt/otopcua-mtconnect/` on the shared docker host and brought up healthy; `http://10.100.0.35:5000`
serves the seeded `OtFixtureCnc` model with live-moving values. Note it answers in the MTConnect
**2.0** namespace while the canned fixtures are 1.3 — the namespace-agnostic `LocalName` parsing
(Task 6) is what makes both work, now demonstrated rather than argued.
| Leg | Result | Evidence |
|---|---|---|
| Integration suite vs. a REAL Agent | ✅ **12/12** | incl. `Discovery_types_an_upper_snake_numeric_event_as_Int64` (the `PART_COUNT` regression), `Read_and_subscribe_key_on_RawPath_when_the_artifact_supplies_RawTags` (the blocker fix), `Subscribe_delivers_a_changed_value_from_the_live_sample_stream`, `Discovery_binds_FullName_to_the_DataItem_id_when_the_name_differs` |
| 1. Driver creatable in `/raw` | ✅ | `MTConnect` present in `RawDriverTypeDialog`; `mtc-1` created. Proves the Host `Register` call is genuinely wired — **the one thing no test guards** (deleting it leaves the guard test green and substitutes a `StubbedDriver` while the deploy still seals green). |
| 2. Typed config modal renders | ✅ | "Configure driver · MTConnect" with all four sections (Agent / Polling / Connectivity probe / Reconnect), **not** the "no typed config form" banner. **This is the mutation that survived all 749 AdminUI tests** — the `switch` in `DriverConfigModal.razor` compiles to `BuildRenderTree` and is unreachable by reflection. |
| 3. Config persists + round-trips | ✅ | Stored `{"agentUri":"http://10.100.0.35:5000","requestTimeoutMs":5000,…,"probe":{"enabled":true,…},"reconnect":{…}}`; reopening the modal displays the saved URI (Razor binding verified — no bUnit in this repo). |
| 4. Browse picker → commit | ✅ | "Connect & browse" dialled the live Agent; tree rendered `Agent` + `OtFixtureCnc` with `Favail` (name ≠ id) beside id-named leaves, proving `browseName = Name ?? Id`. Committed TagConfig is **`{"fullName":"fixture_asset_changed","dataType":"String"}`** — the `fullName`-not-`address` fix, live. Wave-0 #468 did **not** block this. |
| 5. Deploy → OPC UA read/subscribe | ⛔ **BLOCKED — rig artifact** | see below |
**Why leg 5 is blocked, and why it is not a product defect.** Browser cookies are scoped to a
**host, not a port**, so the AdminUI antiforgery cookie issued by the still-running `otopcua-dev`
rig on `localhost:9200` is sent to the isolated stack on `localhost:9220`, whose data-protection
keys differ:
```
Microsoft.AspNetCore.Antiforgery.AntiforgeryValidationException: The antiforgery token could not be decrypted.
```
The `Deploy current configuration` POST is rejected before reaching any MTConnect code — no
`Deployment` row is created, and the UI surfaces nothing. Clearing JS-visible cookies does not help
(the antiforgery cookie is `HttpOnly`). This is a two-stacks-on-one-host collision, entirely outside
the driver.
**To finish leg 5**, do any one of: (a) use a distinct host so cookies don't collide (a hosts entry,
or bind `127.0.0.2`), (b) drive `:9220` from an incognito/separate browser profile, or (c) stop the
`otopcua-dev` rig first. Then Deploy and:
`dotnet run --project src/Client/ZB.MOM.WW.OtOpcUa.Client.CLI -- read -u opc.tcp://localhost:4860 -n "ns=2;s=docker-dev/mtc-1/vmc/fixture_asset_changed"`.
Note the RawPath keying is already proven at the driver seam by the live integration test above;
what leg 5 adds is the `DeploymentArtifact` → address-space → OPC UA materialisation on top.
**Two incidental findings from the rig work, worth separate follow-up:**
1. **`ClusterNode` in this schema has no `MaintenanceMode` column** (nor `AkkaPort`/`GrpcPort`),
although CLAUDE.md documents `MaintenanceMode` as the landed maintenance hatch and the mesh
Phase-1 columns as present. Reducing the seeded topology required deleting the SITE-A/SITE-B
rows instead. Either the doc or the migration is ahead of the other — reconcile.
2. `sqlcmd` against this schema needs `-I` (`SET QUOTED_IDENTIFIER ON`); without it every DML
statement fails with `Msg 1934` because of the filtered/computed indexes.
**Teardown when done:**
```bash
docker compose -p otopcua-mtc -f docker-dev/docker-compose.yml -f docker-dev/docker-compose.mtconnect.yml down -v
ssh dohertj2@10.100.0.35 'cd /opt/otopcua-mtconnect && docker compose down'
```
---
## Task 22: Docs + deferred-writeback note; update the tracking doc
**Classification:** trivial