Files
ScadaBridge/docs/deployment/deploy-prep/2026-11-12-gates-52-131
Joseph Doherty a92a418d7f docs(deploy): prepare the #52 / #131 site-script fixes for DEV and QA (not applied)
Read-only export of DEV vd03 and QA vq03 (2026-11-12): the only
Children["DelmiaRecv"] user is CvdReactor.ProcessRecipeDownload (script 4,
identical on both envs; DEV 3 / QA 9 instances), and the only ScriptAlarm
.Severity reader is DEV TestMesMachine.AlarmStatus (script 42, SBTEST01/02).
QA has no #131 work.

Adds the original (rollback) and fixed bodies, a guarded check/apply/rollback
script that re-sends every script field, and the apply plan: #52 any time,
#131 with or after the dd4f1c2a binary. The old #131 body still compiles on
main but returns banded values; the fixed body is what fails to compile on the
deployed binaries. Rig evidence for both gates is in the README.

Refs #52 #131

Claude-Session: https://claude.ai/code/session_01GT67ACmpMR7b9LGRPLijMi
2026-11-12 23:19:07 -05:00
..

Deploy prep: site-script fixes for Gitea #52 and #131

Prepared: 2026-11-12. Not applied to DEV or QA. Applying it is a deploy and needs the owner's approval.

Where the facts come from: a read-only export of DEV vd03 and QA vq03 taken at 2026-11-12 ~23:10 EST. The export used template list|get --detail, shared-script list, api-method list|get, instance list and instance diff, and nothing was written.

  • DEV runs DisableLogin, so any credentials work.
  • QA has login enabled. It authenticates against the box-local GLAuth (ScadaBridge-LDAP service), so the export used the documented multi-role test user there. The username and password were passed through environment variables, never on the command line.

Validated: on the docker rig (main binary, which includes dd4f1c2a). See Rig evidence.

Files

Path What
original/CvdReactor.ProcessRecipeDownload.cs The live body of CvdReactor script 4. It is byte-identical on DEV and QA. Rollback body.
original/TestMesMachine.AlarmStatus.cs The live body of DEV TestMesMachine script 42. Rollback body.
original/*.meta.json Each script's other fields: trigger, parameters, return definition, lock and timeouts.
fixed/CvdReactor.ProcessRecipeDownload.cs Changes one line: Children["DelmiaRecv"] becomes Children["DelmiaReceiver"].
fixed/TestMesMachine.AlarmStatus.cs Changes three a.Severity reads to a.Priority. It is byte-identical to ALARM_CODE in docker/seed-mes-test-machine.sh at dd4f1c2a.
apply.sh Takes check, apply or rollback and a gate number (52 or 131). Details below.

What apply.sh does

  • check only reads.
  • apply and rollback refuse to touch a script unless its live body is byte-identical to the expected file.
  • Metadata: they re-send every metadata field. template script update replaces the parameter and return definitions, so a bare --code update would wipe them. They then read the fields back and compare them.
  • Deploy: they deploy the affected instances. --no-deploy skips this step.

Inventory (live, 2026-11-12)

The export searched every template script and inbound API method on each env for Children["…"] names that aren't compositions, and for .Severity reads on a ScriptAlarm. There are no shared scripts on either env. Every instance's instance diff reports isStale=false, so the deployed scripts are the template bodies listed below.

Env Template / script Problem Instances to redeploy
DEV vd03 CvdReactor (1) / ProcessRecipeDownload (4) Children["DelmiaRecv"]. The only composition is DelmiaReceiver. #52 Z28061 (1), Z28062 (2), Z28061Sim (8)
QA vq03/vq04 CvdReactor (1) / ProcessRecipeDownload (4) Same body, byte for byte. #52 Z28061 (1), Z28062 (2), Z28063 (9), Z28064 (11), Z28065 (12), Z28066 (13), Z28067 (10), Z28068 (14), Z28069 (15)
DEV vd03 TestMesMachine (30) / AlarmStatus (42) Reads a.Severity in 3 places: the MinSeverity and MaxSeverity predicates and Severity = a.Severity. #131 SBTEST01 (9), SBTEST02 (10)
QA — No #131 work. QA has no TestMesMachine. Its CvdReactor.AlarmStatus (39) is a stub that returns Alarms = []. No other script calls Alarms.*. —

Every other Children[...] reference on both envs resolves: TestMesMachine's LeftMESReceiver, RightMESReceiver and DelmiaReceiver.

The inbound methods SimpleAlarmStatusRequest and AlarmStatusRequest only pass MinSeverity/MaxSeverity to the site script as arguments. They never read a ScriptAlarm, so they need no change.

Two corrections to the issue texts:

  • #131: the old body still compiles on main. ScriptAlarm.Severity still exists after dd4f1c2a; it now holds the banded value. So the deployed scripts keep compiling and running on the new binary, but they return wrong numbers and inverted filters (rig evidence, Q1–Q3). The compile problem runs the other way: the fixed body references ScriptAlarm.Priority, which the deployed binaries don't have. Neither DEV 424db155 nor QA b3021e7c contains dd4f1c2a. On the rig, a body with an unknown ScriptAlarm member saves fine, because save does no compile check. Deploying it is refused with Pre-deployment validation failed: … ScriptCompilation.
  • #131: DEV's CvdReactor has no AlarmStatus script at all. So SimpleAlarmStatusRequest for Z2806x answers "not supported". The CvdReactor.SimpleAlarmStatus/AlarmStatus pattern in docs/plans/2026-06-30-mes-alarm-status-api.md §5.3 is a doc pattern and is not deployed anywhere. If it is ever authored, write it with a.Priority.

Order relative to the ScadaBridge binary deploy

#52: any time, independent of the binary

The fixed body uses only APIs that the DEV and QA binaries already run, because the current body already uses them. The fix is one string literal.

  • Recommended: apply it in the same window as the next binary deploy, so the instances redeploy only once.
  • Z28061 on the wonder boxes is also used by another team. Agree a slot before redeploying it; the redeploy restarts the instance actor. Z28062 is the safe one to test against.

#131: DEV only, with or after the binary that contains dd4f1c2a, in the same window

  1. Deploy the new ScadaBridge binary to central and site.
  2. Immediately run apply.sh apply 131, before MES alarm traffic is trusted again.

Applied before the binary: the template saves, but the SBTEST instance deploys are refused by pre-deployment compilation. The site keeps the old body, which is harmless. Run apply.sh rollback 131 --no-deploy to put the template back.

Binary without this step: MES alarm-status output for SBTEST01/02 changes. Values come back banded (800→250, 300→750, 700→500), and the MinSeverity and MaxSeverity filters select the wrong alarms.

Alternative: re-run docker/seed-mes-test-machine.sh against vd03. It produces the same AlarmStatus body. But it also rewrites the inbound methods SimpleAlarmStatusRequest and AlarmStatusRequest and every other TestMesMachine script, so diff those first. apply.sh changes only the one script.

Apply (from the Mac, after approval)

cd ~/Desktop/ScadaBridge && dotnet build src/ZB.MOM.WW.ScadaBridge.CLI   # apply.sh uses bin/Debug/net10.0/scadabridge (override: SB_CLI)
P=docs/deployment/deploy-prep/2026-11-12-gates-52-131

# DEV (DisableLogin: any credentials)
export SCADABRIDGE_URL=http://wonder-app-vd03.zmr.zimmer.com:8085 SCADABRIDGE_USERNAME=x SCADABRIDGE_PASSWORD=x
bash $P/apply.sh check 52;  bash $P/apply.sh apply 52          # any time
bash $P/apply.sh check 131                                       # after the dd4f1c2a+ binary is up on DEV…
bash $P/apply.sh apply 131                                       # …in the same window

# QA (login enabled; box-local GLAuth; export the password from a prompt, not argv)
export SCADABRIDGE_URL=http://wonder-app-vq03.zmr.zimmer.com:8085 SCADABRIDGE_USERNAME=multi-role
read -rs SCADABRIDGE_PASSWORD && export SCADABRIDGE_PASSWORD
bash $P/apply.sh check 52;  bash $P/apply.sh apply 52          # 9 instances; vq03 is the active central

Manual equivalent:

  1. Update the script with scadabridge template script update, passing every flag:
    • --id <script id> --name <name> --trigger-type <type> --code "$(cat fixed/<x>.cs)"
    • --parameters "<parameterDefinitions>" and --return-def "<returnDefinition>", both from original/<x>.meta.json
  2. Run scadabridge instance deploy --id <n> for each instance in the inventory.

Verify

  • #52 (read-only first): run scadabridge debug snapshot --id 2 on Z28062. DelmiaReceiver.ReadyFlag is the value the fixed script now reads.
  • #52 end-to-end: a DelmiaRecipeDownload call drives the real Galaxy handshake on Z28062, so it needs the owner's go-ahead. Use either a live WWNotifier call or scadabridge flow-debug run-method --method-id 4 --params '{"MachineCode":"Z28062",…}'.
    • The answer must no longer be Receiver ready flag not set to true while the flag is true.
    • The DEV site log must stop showing GetAttribute: attribute 'DelmiaRecv.ReadyFlag' not found.
  • #131: on vd03, run SCADABRIDGE_URL=http://wonder-app-vd03.zmr.zimmer.com:8085 bash docker/verify-mes-test-machine.sh (the RECIPE_ROOT/RECIPE_OUTSIDE values are in its header). Groups C and D must pass: C3 Severity == 800, C7 MinSeverity 500, C9 MaxSeverity 750. These are the same values the scripts returned before #129.
  • Record the apply in docs/deployment/deployment-records/.

Rollback

bash $P/apply.sh rollback 52 and bash $P/apply.sh rollback 131 write back original/*.cs, byte for byte, and redeploy. Rollback is guarded the same way: it refuses if the live body is not the fixed file.

Rolling #131 back while the new binary is still running brings back the banded values. Only roll it back together with the binary.

Rig evidence

Setup: the docker rig on main, with AlarmPriorityBands in the deployed Commons. The rig was idle: no management calls in the previous 60 min.

#52

A temporary rig template CvdReactor held the DEV ProcessRecipeDownload body and its parameter schema. It composed the rig's static DelmiaReceiverSim as DelmiaReceiver. The template and its instance GATE52RIG were deleted afterwards. Each run was driven by flow-debug run-script, and the ReadyFlag value was confirmed in debug snapshot first.

Body ReadyFlag Result
original true Receiver ready flag not set to true; site WRN attribute 'DelmiaRecv.ReadyFlag' not found on instance 'GATE52RIG'
original false Receiver ready flag not set to true
fixed true Got past the flag check into the batch write: Batch write failed: Attribute 'DelmiaReceiver.DownloadPath' is not a data-sourced attribute (expected, see below)
fixed false Receiver ready flag not set to true (negative control: the flag really is read)

The rig receiver is static, and WriteBatchAndWaitAsync only accepts data-sourced attributes. On the wonder boxes, DelmiaReceiver.* is Galaxy-bound, so the batch write proceeds there. The handshake code after the flag check is unchanged by this fix.

apply → rollback → apply round-tripped. The revision hash returned to sha256:b2058525… on rollback and sha256:1da04831… on apply. A repeat apply was a no-op.

#131

The rig's TestMesMachine (5305) AlarmStatus was byte-identical to DEV's script 42 when the test started. Alarms were tripped with VacuumPressure=12, DoorOpen=true and SensorStatus=-1, which raises HighVacuumFault (priority 800, MES), DoorOpenAlarm (300) and SensorFault (700; MES on SBTEST02). Values are shown as (name, Severity, IsFlaggedForMES).

Query Original body on main (wrong) Fixed body on main
Q1 SBTEST01 all Door 750, HighVac 250, Sensor 500 Door 300, HighVac 800, Sensor 700
Q2 MinSeverity=500 Door, Sensor HighVac, Sensor
Q3 SBTEST02 FlaggedOnly + MaxSeverity=750 HighVac, Sensor Sensor
Q4 FlaggedOnly HighVac 250 HighVac 800
  • The fixed column matches the pre-#129 expectations in docker/verify-mes-test-machine.sh (C3, C7, C9).
  • Compile gate (positive control): a body with an unknown ScriptAlarm member saved, and its deploy was refused with Pre-deployment validation failed: … ScriptCompilation. That is what the fixed body would hit on the current DEV binary.
  • Guard: with that unknown body live, apply.sh apply 131 answered REFUSED: live body is UNKNOWN.
  • Round trip: rollback → apply round-tripped.
  • Rig end state: SBTEST01/02 are left on the fixed body (what seed-mes-test-machine.sh seeds since dd4f1c2a) with the alarm sources reset.