chore(rig): ScriptTrace retention override; verify-delmia-notifier step H = Flow Debugger live run + replay
Both central nodes gain a root AuditLog:PerChannelRetentionDays:ScriptTrace=30 (validator
floor). verify-delmia-notifier.sh step H: finds DelmiaRecipeDownload via api-method list,
runs flow-debug run-method with the drill parameters and asserts completed=true plus the
kind set {InboundRequest, RouteCall, ScriptRun, AttributeWrite, AttributeWait} from each
event's detailsJson, then flow-debug replay on the root ExecutionId with the same check,
retried up to 40 s for the 5 s site telemetry push; prints 'H live+replay -> YES'.
VERIFICATION PENDING: the image scadabridge:latest was built from this branch
(docker/build.sh, exit 0) but the containers have not been recreated and step H has not
run yet — the next step is a recreate through the MAIN checkout's compose file (deploy.sh
refuses a worktree, register row 68: bind-mounted appsettings would rehome), a fresh
DelmiaRecipeDownload-scoped key, and the drill.
Claude-Session: https://claude.ai/code/session_01GSLkkHKz9JrAtmJjmQK3cP
This commit is contained in:
+1
-1
@@ -99,7 +99,7 @@ docker/
|
||||
├── seed-live-probe.sh # Seed one deployable live-data instance on site-a (stream traffic)
|
||||
├── seed-delmia-sim.sh # Seed the in-memory Delmia machine stand-in (DelmiaSim01) on site-a
|
||||
├── seed-delmia-api.sh # Seed the DelmiaRecipeDownload inbound method + a scoped API key (token printed once)
|
||||
├── verify-delmia-notifier.sh # DelmiaNotifier end-to-end vs the rig: standby relay, active-central crash/takeover, rejoin
|
||||
├── verify-delmia-notifier.sh # DelmiaNotifier end-to-end vs the rig: standby relay, active-central crash/takeover, rejoin; step H = Flow Debugger live run + replay (CLI flow-debug)
|
||||
├── teardown.sh # Stop and remove containers
|
||||
├── central-node-a/
|
||||
│ ├── appsettings.Central.json # Central node A configuration
|
||||
|
||||
@@ -104,5 +104,10 @@
|
||||
"Logging": {
|
||||
"MinimumLevel": "Information"
|
||||
}
|
||||
},
|
||||
"AuditLog": {
|
||||
"PerChannelRetentionDays": {
|
||||
"ScriptTrace": 30
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,5 +104,10 @@
|
||||
"Logging": {
|
||||
"MinimumLevel": "Information"
|
||||
}
|
||||
},
|
||||
"AuditLog": {
|
||||
"PerChannelRetentionDays": {
|
||||
"ScriptTrace": 30
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,8 @@ set -euo pipefail
|
||||
# E active KILLED, after survivor /health/active=200 -> YES (first URL refused -> failover)
|
||||
# F victim restarted and rejoined (memberCount=2) -> YES
|
||||
# G reject path (DownloadPath *.bad) -> NO + "Simulated reject"
|
||||
# H Flow Debugger live run + replay -> YES (flow-debug run-method returns the traced
|
||||
# site steps inline; flow-debug replay rebuilds the same chain from the central audit store)
|
||||
|
||||
: "${DELMIA_API_KEY:?export DELMIA_API_KEY=sbk_... first}"
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"; PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
@@ -91,4 +93,42 @@ echo " victim ready + memberCount=2 on survivor after $(( $(date +%s) - T1 ))
|
||||
notify F YES
|
||||
|
||||
echo "== G reject path"; notify G NO -d 'C:\recipes\x.bad' || true
|
||||
|
||||
# H — Flow Debugger (design 2026-09-05). A Live run executes the real method on the active node
|
||||
# with tracing on, so the site's ScriptRun / AttributeWrite / AttributeWait rows come back inline
|
||||
# in the same reply; Replay reads the same chain back from the central AuditLog, which the site
|
||||
# feeds through the 5 s telemetry push — hence the bounded retry. Both must show the full kind set.
|
||||
echo "== H Flow Debugger live run + replay"
|
||||
ACT=$(active)
|
||||
H_ARGS=(--url "$(url_of "$ACT")" --username "${SCADABRIDGE_USERNAME:-multi-role}" --password "${SCADABRIDGE_PASSWORD:-password}" --format json)
|
||||
h_check() { # stdin = FlowDebugRunResult JSON; prints a one-line verdict, exits 1 when incomplete or kinds missing
|
||||
python3 -c '
|
||||
import json, sys
|
||||
r = json.load(sys.stdin)
|
||||
kinds = sorted(json.loads(e["detailsJson"]).get("kind", "?") for e in r.get("events", []))
|
||||
need = ["AttributeWait", "AttributeWrite", "InboundRequest", "RouteCall", "ScriptRun"]
|
||||
missing = [k for k in need if k not in kinds]
|
||||
ok = r.get("completed") is True and not missing
|
||||
print(("YES" if ok else "NO") + " root=" + str(r.get("rootExecutionId")) + " events=" + str(len(kinds)) + " kinds=" + ",".join(kinds)
|
||||
+ (" missing=" + ",".join(missing) if missing else "") + (" error=" + str(r.get("errorCode")) if r.get("errorCode") else ""))
|
||||
sys.exit(0 if ok else 1)'
|
||||
}
|
||||
METHOD_ID=$("$CLI" api-method list "${H_ARGS[@]}" | python3 -c 'import json,sys; ms=json.load(sys.stdin); print(next(m["id"] for m in ms if m["name"]=="DelmiaRecipeDownload"))')
|
||||
H_PARAMS=$(python3 -c 'import json,sys; print(json.dumps({"MachineCode":sys.argv[1],"DownloadPath":"C:\\recipes\\wo1.nc","WorkOrderNumber":"WO-H","PartNumber":"PN-1","JobStepNumber":"0100","Username":"drill"}))' "$MACHINE")
|
||||
set +e
|
||||
H_RUN=$("$CLI" flow-debug run-method --method-id "$METHOD_ID" --params "$H_PARAMS" "${H_ARGS[@]}")
|
||||
H_RC=$?; set -e
|
||||
[ "$H_RC" -eq 0 ] || { echo "FAIL: flow-debug run-method exited $H_RC: $H_RUN"; exit 1; }
|
||||
H_LIVE=$(echo "$H_RUN" | h_check) || { echo "FAIL: live run incomplete: $H_LIVE"; exit 1; }
|
||||
echo " live: $H_LIVE"
|
||||
H_ROOT=$(echo "$H_RUN" | python3 -c 'import json,sys; print(json.load(sys.stdin)["rootExecutionId"])')
|
||||
H_REPLAY=""
|
||||
for i in $(seq 1 20); do
|
||||
set +e; H_REPLAY=$("$CLI" flow-debug replay --execution-id "$H_ROOT" "${H_ARGS[@]}" | h_check); H_RRC=$?; set -e
|
||||
[ "$H_RRC" -eq 0 ] && break
|
||||
sleep 2
|
||||
done
|
||||
[ "${H_RRC:-1}" -eq 0 ] || { echo "FAIL: replay never showed the full chain after 40 s: $H_REPLAY"; exit 1; }
|
||||
echo " replay: $H_REPLAY"
|
||||
echo "H live+replay -> YES"
|
||||
echo "== done. Notifier log: $RUN_DIR/delmia-notifier.log"
|
||||
|
||||
Reference in New Issue
Block a user