Second slice of the 2026-09-09 whole-system review remediation
(docs/plans/2026-09-09-arch-review.md §10), on top of the High slice 146a1323.
Runtime/devices: SR-2 alarm on-trigger integration scope; SR-3 correlated NativeAlarmActor
subscribe retry; SR-4 immutable audited DB target; SR-5 ordered InstanceActor stop/flush;
SR-12 rehydration fence; SR-13 S&F gate recheck per delivery; DC-4 no OPC UA security
downgrade; DC-5 alarm snapshot for every new subscriber; ORCH-1 sync-dispose joins the pump.
Management/UI: MG-2 site scope on audit tree + Flow Debugger Replay; MG-3 stale-probe memo
removed; MG-4 server-owned bulk-deploy deadline; UI-5 sandbox runs in a killable child
process (new CentralUI.SandboxWorker project); UI-14 bounded sandbox output/IPC.
Edge/audit: EI-1 relay audit ownership; EI-2 SkipBodyCapture suppresses error text; EI-3/EI-11
error-field redaction + caps; EI-4 single relay deadline, pre-execution-only retry; EI-5
authenticated relay provenance; EI-10 body cap before audit read.
Persistence/contracts: DL-1 global Instance.UniqueName unique index + conflict translation;
DL-2 DataConnection protocol config encrypted at rest (migration
20260909203046_EnforceGlobalInstanceNamesAndProtectProtocolConfiguration — coordinated
central upgrade, old binaries cannot read protected rows); DL-3 bounded Replay paging;
DL-6 cross-site Overwrite of a deployed instance rejected; XC-4 proto descriptor contract test.
Config/hygiene: XC-1 central listener isolation by local port; XC-2/XC-3 inert SMTP + cron
keys removed from rig settings; CM-2 env2 bootstrap guard enabled; DC-6 deploy site exit code;
DC-7 notifier retries only explicit standby rejection; XC-5 ClusterClient purged from docs.
Gates recorded in the report: build 0/0, 9 397 passed / 0 failed, rig redeployed on all
eight nodes with the migration applied. 46 Low findings remain open.
FLOW_ONLY note now names step J. Live gate on the docker rig (8 nodes rebuilt
from this branch via docker/deploy.sh, FlowLogDemo seeded by
docker/seed-flow-log-demo.sh — idempotent, add then update proven):
J step logs live+replay -> YES
live: YES root=5793ddc2-5273-4e62-86c2-ccfc8de0e080 logs=3 levels=debug,info,warn scriptRun=Failed error=CALL_FAILED
replay: YES root=5793ddc2-5273-4e62-86c2-ccfc8de0e080 logs=3 levels=debug,info,warn scriptRun=Failed
H, H2 and I stayed YES in the same run.
Browser check (Playwright, /deployment/flow-debugger?executionId=<J root>,
screenshot /tmp/flow-log-demo.png): the SCRIPT RUN node is red with subtitle
"InvalidOperationException: demo failure" and badge "! 1 ≡ 2"; the WRITE node
carries no badge; the strip reads "LOG 0 errors · 1 warnings · 2 info"; the
detail panel opens on "Log (3)" with the full System.InvalidOperationException
block and the three info/debug/warn script lines.
FlowDebugRunner.RunMethodAsync now passes InboundScriptResult.ErrorDetail through to the
synthesized inbound audit row's errorDetail, so a SCRIPT_ERROR run's exception ToString() lands
on AuditDetails.ErrorDetail for the Flow Debugger's inbound node to read (never surfaced to the
HTTP caller). FlowDebugRunResult grows an additive LogsTruncated (default false, last positional
member) reporting the inline FlowTraceCollector's low-priority (ScriptLog) truncation separately
from Truncated (step-row fidelity); RunMethodAsync/RunScriptAsync thread collector.LogsTruncated
through on their two collector-backed results.
Task 5 code-review follow-ups:
- I1: ExternalSystemHelper gates its TraceStepScope on a new isTraced ctor arg
(default false for direct construction), not on `_traceSink is not null` — a
traced run without an inline collector still writes durable ScriptLog rows
that must name their step.
- I2 (design §5): an inline shared script now SHARES its caller's ScriptLogger
via the new `sharedLog` ctor param — one line cap, one anchor, one closing
row. Consequence documented on the Log property: a shared script's lines
carry the PARENT run's ExecutionId and land on the parent's ScriptRun node.
- M3: TraceCapturingLogger swallows a throwing formatter — most of what it
captures is best-effort "audit write failed" warnings logged from inside a
catch block, and a formatting exception must not escape that path.
- Tests: ApiCall step attribution, traced-without-collector, shared-script
logger sharing, nested batch/wait scope attribution + unwind, throwing
formatter; test (c) now also pins the anti-recursion property (EmitLog must
log through the undecorated logger).
CompileSurfaceParityTests stays red until Task 7 mirrors Log on ScriptCompileSurface.