diff --git a/docs/plans/2026-09-10-handshake-reset-echo-design.md b/docs/plans/2026-09-10-handshake-reset-echo-design.md index 19998577..ced2069d 100644 --- a/docs/plans/2026-09-10-handshake-reset-echo-design.md +++ b/docs/plans/2026-09-10-handshake-reset-echo-design.md @@ -170,9 +170,10 @@ not a `HandshakeResult` naming the phase it died in. change). - `docker/seed-delmia-sim.sh` — unchanged behaviour (static attributes; cache updates synchronously so the race cannot occur); add a comment saying so. -- **Rig live gate** — `docker/seed-handshake-demo.sh`: a template with two data-sourced Boolean - attributes on writable OPC UA sim nodes (`Motor.Running` class, `CurrentReadOrWrite`, not - simulated so they hold what is written), a `Call` script using the new overload, and a +- **Rig live gate** — `docker/seed-handshake-demo.sh`: a template with two data-sourced **String** + attributes on the rig's two writable OPC UA String nodes (not simulated, so they hold what is + written; String rather than Boolean because of deferred-work register row 120, found by this + very gate), a `Call` script using the new overload, and a ValueChange "device" script that sets the complete flag when the trigger rises. Proves the reset echo round-trips through a real subscription and that `Phase` reports correctly. - Deferred-work register — one row: *port the QA/prod MES receiver scripts (13/14/15/16/25/26/36/ @@ -186,3 +187,28 @@ Additive only: a new overload, two new Commons types, no message/proto/schema ch scripts compile and behave identically. An older site receiving a script that uses the overload fails the deploy gate's compile (the member does not exist there), which is the intended mixed-version outcome — upgrade sites before porting scripts. + +## 10. Live gate 2026-09-10 (docker rig, main after the #36 merge) + +`docker/seed-handshake-demo.sh` → instance `handshake-demo-1` on site-a, flags on the rig's two +writable OPC UA **String** nodes (`TestChildObject.TestString` = Trigger, `JoeAppEngine.BTCS` = +Complete). The Boolean/Double nodes rejected the scalar writes with `BadTypeMismatch` +(`0x80740000`) — a pre-existing gap in the data-sourced scalar write path (only List values are +decoded before the DCL write; the OPC UA client sends the encoded string as a String variant), +recorded as deferred-work register row 120. The ordering this gate proves is identical on String +flags. `flow-debug run-script --instance-id --script Handshake --show-logs`, two consecutive +runs, traced steps as reported by the CLI: + +| Leg | Run 1 | Run 2 (cache holds run 1's `True`) | +|---|---|---| +| reset write `Complete = "False"` | 1 ms | 1 ms | +| reset-echo wait (`Complete == "False"`) | 217 ms, satisfied | **751 ms, satisfied** | +| batch + trigger write `Trigger = "True"` | 7 ms | 1 ms | +| response wait (`Complete == "True"`) | 2009 ms, satisfied | 2029 ms, satisfied | +| script result | `Matched=true, Phase=Response` | `Matched=true, Phase=Response` | + +Run 2 is the #36 case: the cache still held `True` from run 1, the reset wait did **not** +fast-path, and the trigger was not written until the device echoed the reset 751 ms later. The +response wait is dominated by the Device script's own two data writes plus the subscription +round-trip. The optional negative control (planting a stale `True` with the OPC UA tool) was +skipped: `infra/tools/opcua_tool.py` needs the `asyncua` module, which is not installed here.