docs: Flow Debugger — component specs, CLAUDE.md, CLI README, register row 110

Component-CentralUI (new Flow Debugger page section), Component-InboundAPI (TraceAllCalls
property, always-on RouteCall row + Trace flag under Routing Behavior, new 'Flow Debugger
runs' section), Component-SiteRuntime (Instance Actor trace arm; Script Actor traced runs;
CallScript flag inheritance), Component-AuditLog (ScriptTrace channel in Scope, the
PullTraceEvents point-read note + mixed-version caveat under Reconciliation, per-channel
retention example), Component-Communication (§4 trace flag + inline events with proto field
numbers; §8 PullTraceEvents; RPC list), Component-ScriptAnalysis (REQ-SA-7 FlowShapePredictor),
CLAUDE.md UI bullet, deferred-work register row 110 (vertical-trace list toggle + console
capture), design doc status → implemented. CLI README sections landed in Tasks 3/16.
Umbrella index (../scadaproj/CLAUDE.md) checked: its ScadaBridge row records stack/wire
relationships only, unchanged by a new page — no edit.

Claude-Session: https://claude.ai/code/session_01GSLkkHKz9JrAtmJjmQK3cP
This commit is contained in:
Joseph Doherty
2026-09-06 00:38:41 -04:00
parent 66d5a67e4f
commit 0a9ef87b54
9 changed files with 60 additions and 3 deletions
@@ -192,6 +192,9 @@ flowchart TD
- Holds current alarm states (active/normal), updated by child Alarm Actors.
- Publishes attribute value changes and alarm state changes to the site-wide Akka stream.
### Trace arm (Flow Debugger, 2026-09-05)
- A `SetStaticAttributeCommand` / `SetDataAttribute` carrying `Trace = true` and a `SourceExecutionId` **arms** the attribute on the Instance Actor for `TraceArmWindowSeconds` (default 30, validated `> 0`). A static write publishes `AttributeValueChanged` with the writer's `SourceExecutionId` and `Trace` immediately; a **data-sourced** write is a real tag write, and the next device echo of that attribute inside the window consumes the arm and is published with the same ids — so the script run the echo triggers is parented to the writer's execution and runs traced. An echo outside the window, or a second echo, is an ordinary untraced change. Batch-write echoes are not armed (design §5.3); only the single-attribute write path arms.
### Initialization
1. Load all attribute values from the flattened configuration (static defaults).
2. Set quality to **uncertain** for all attributes that have a data source reference. Static attributes (no data source reference) have quality **good**. The uncertain quality persists until the first value update arrives from the Data Connection Layer, distinguishing "not yet received" from "known good" or "connection lost."
@@ -276,9 +279,16 @@ When the Instance Actor is stopped (due to disable, delete, or redeployment), Ak
- **Concurrent runs per script are capped (WP3.1).** `MaxConcurrentRunsPerScript` (default 4) bounds runs in flight — queued or executing — for any one script or alarm on-trigger script. Over the cap the **newest** run is shed: the four already in flight are closest to their own deadlines and already charged against them, so nothing is ever reordered and no extra queue is needed (the scheduler's FIFO already is the queue). A shed increments `ISiteHealthCollector.IncrementScriptRunShed` (surfaced as `ScriptRunShedCount`), emits a `script`/`Warning` site event **rate-limited to one per script per minute** so a hot trigger cannot flood `site_events`, and — for an Ask-based `CallScript` — replies with an explicit error so a nested call or inbound-API route fails fast instead of hanging.
- **The cap gates only depth-0 launches (review fix).** A trigger fire or a depth-0 `CallScript`/inbound-API route counts against `MaxConcurrentRunsPerScript`; a *nested* `Instance.CallScript` self-recursion (`callDepth > 0`) is exempt — it is already bounded by `MaxScriptCallDepth` instead, and the calling run is holding one of the four cap slots itself while it awaits the callee, so counting the nested launch too would spuriously shed legitimate self-recursion.
#### Traced runs (Flow Debugger, 2026-09-05)
- A run is **traced** when its `ScriptCallRequest.Trace` flag is set (a routed inbound call with `TraceAllCalls` or a Flow Debugger Live run), or when it was spawned by a value change whose `AttributeValueChanged.Trace` was set (see *Trace arm* under the Instance Actor). `ScriptRunLauncher` passes `isTraced` + a per-run `FlowTraceCollector` (cap 500 events, `Truncated` flag) into `ScriptRuntimeContext`, and on completion — success, timeout or failure — emits one `ScriptTrace.ScriptRun` audit row (occurred-at = run start, `Extra.triggerKind` = `call` or `valuechange` with the trigger attribute/value/source) through the site `IAuditWriter`.
- Every trace row is **also** collected in the run's collector and returned inline on `ScriptCallResult.TraceEvents` (with `ScriptCallResult.ExecutionId`), which `DeploymentManagerActor` maps onto `RouteToCallResponse.ChildExecutionId` / `TraceEvents` — Live gets its steps in the same reply; Replay reads the same rows from the Audit Log after the 5 s telemetry push.
- A value-change run spawned by a traced write inherits the writer's execution id as `ParentExecutionId` and runs traced itself, so a Flow Debugger value-change entry sees the run the write caused.
- Untraced runs emit nothing new — the flag defaults to `false` on every record and the collector is null.
### Handling `Instance.CallScript`
- When an external caller (another script run, an alarm on-trigger run, or a routed call from the Inbound API) sends a `CallScript` message to the Script Actor, it launches a run to handle the call.
- The caller uses the **Akka ask pattern** and receives the return value when the execution completes.
- **Trace flag inheritance:** `ScriptRuntimeContext.CallScript` forwards the calling run's `IsTraced` on `ScriptCallRequest.Trace`, and `CreateChildContextForSharedScript` hands the same flag + collector to an inline shared-script context, so a nested run's `ScriptRun` / `AttributeWrite` / `AttributeWait` rows land in the same flow.
---