docs: arch-review remediation — component docs sweep, execution log, residuals register
Final consistency sweep per plan §6: verified component docs against shipped WP1-WP3 + adversarial-review-fix state, corrected drift found in SiteRuntime (recursion-exempt run cap, stale ScriptExecutionActor/AlarmExecutionActor references), TemplateEngine (BundleImporter watermark path), DeploymentManager (phase-2 PendingDeployment staging), CentralUI (shared KPI cache, dedup'd alarm poll, render coalescing), StoreAndForward (rate-limited drop logging), and ConfigurationDatabase (documented DbContext-pooling non-adoption). Updated the docs/components/ developer-reference set (SiteRuntime, SiteEventLogging, InboundAPI) to drop the deleted per-run actor classes. Amended one known-issue for the superseding MaxBatchSize:64 read-page pin. Added CLAUDE.md bullets for stream graceful-completion reconnect, the required site audit DB path, honest CLI HTTP timeouts, bulk DeploySiteAsync, and LocalDb 0.2.1. New execution log records the phase→commit map, gate results, adversarial-review tally, the three test-flake root causes, and the nine-item residuals register.
This commit is contained in:
@@ -241,7 +241,7 @@ The inbound body-capture cap for audit is configured separately under `AuditLog:
|
||||
|
||||
- [Commons (#16)](./Commons.md) — owns `ApiMethod`, `ParameterDefinition`, `ScriptParameters`, `ScriptParameterException`, the `RouteToCall*` / `RouteToGetAttributes*` / `RouteToSetAttributes*` message records, `IInboundApiRepository`, and `IInstanceLocator`. Also owns `ICentralAuditWriter` (via `ZB.MOM.WW.Audit`), `AuditChannel`, `AuditKind`, `AuditStatus`, and `ScadaBridgeAuditEventFactory`.
|
||||
- [Configuration Database (#17)](./ConfigurationDatabase.md) — provides the `IInboundApiRepository` implementation (`GetMethodByNameAsync`, `GetAllApiMethodsAsync`, CRUD). Method definitions persist in the central MS SQL configuration database.
|
||||
- [Central–Site Communication (#5)](./Communication.md) — `CommunicationServiceInstanceRouter` delegates every `Route.To()` operation to `CommunicationService`. The routed call travels from the central `CentralCommunicationActor` to the target site via `ClusterClient`, reaches the target `InstanceActor`, and a `ScriptExecutionActor` executes the named script. The return value flows back synchronously.
|
||||
- [Central–Site Communication (#5)](./Communication.md) — `CommunicationServiceInstanceRouter` delegates every `Route.To()` operation to `CommunicationService`. The routed call travels from the central `CentralCommunicationActor` to the target site over gRPC (`CentralControlService`/`SiteCommandService` — `ClusterClient` was removed in the ClusterClient→gRPC migration), reaches the target `InstanceActor`, and the named script runs via `ScriptRunLauncher` (no per-run child actor since WP3.1). The return value flows back synchronously.
|
||||
- [Audit Log (#23)](./AuditLog.md) — `AuditWriteMiddleware` resolves `ICentralAuditWriter` to emit the `ApiInbound` row via the central direct-write path. The inbound request is the parent execution for any site script it spawns: the middleware's `ExecutionId` becomes `RouteToCallRequest.ParentExecutionId` on every routed `Call`. Cross-link: `AuditWriteMiddleware.InboundExecutionIdItemKey` / `AuditWriteMiddleware.AuditActorItemKey` are the `HttpContext.Items` keys that tie the endpoint handler and middleware together.
|
||||
- [Security (#10)](./Security.md) — API key verification (`IApiKeyVerifier`, `AddZbApiKeyAuth`) is registered by the Host. The inbound API uses a dedicated key scheme independent of LDAP/AD session auth.
|
||||
- [Cluster Infrastructure (#13)](./ClusterInfrastructure.md) — `IActiveNodeGate` (interface in this project; implementation in the Host) gates the endpoint to the active central node. A standby returns `503` without running any script logic.
|
||||
|
||||
@@ -157,7 +157,7 @@ public class EventLogHandlerActor : ReceiveActor
|
||||
Callers resolve `ISiteEventLogger` from DI. Because the write is non-blocking and best-effort, site actors discard the returned `Task` with `_ =` rather than awaiting it on the hot path:
|
||||
|
||||
```csharp
|
||||
// ScriptExecutionActor — reporting a script failure
|
||||
// ScriptRunLauncher (via ScriptActor) — reporting a script failure
|
||||
_ = siteEventLogger?.LogEventAsync(
|
||||
"script", "Error", instanceName, $"ScriptActor:{scriptName}", errorMsg, ex.ToString());
|
||||
|
||||
@@ -196,7 +196,7 @@ The docker cluster appsettings (`ScadaBridge:SiteEventLog`) sets `RetentionDays:
|
||||
|
||||
- [Commons (#16)](./Commons.md) — defines the `EventLogQueryRequest` / `EventLogQueryResponse` / `EventLogEntry` message contracts in `ZB.MOM.WW.ScadaBridge.Commons.Messages.RemoteQuery`, shared across the site query path and the central dispatch path (`QueryEventLogsCommand`).
|
||||
- [Central–Site Communication (#5)](./Communication.md) — the `SiteCommunicationActor` dispatches inbound `EventLogQueryRequest` messages to `EventLogHandlerActor` and carries the `EventLogQueryResponse` back to central. The query timeout is 30 s.
|
||||
- [Site Runtime (#3)](./SiteRuntime.md) — `ScriptActor` and `ScriptExecutionActor` log `script`-type events: trigger expression failures, script execution errors, and timeouts. `ISiteEventLogger` is resolved from DI inside execution actors.
|
||||
- [Site Runtime (#3)](./SiteRuntime.md) — `ScriptActor` and `AlarmActor` log `script`-type events (via `ScriptRunLauncher`, no per-run child actor since WP3.1): trigger expression failures, script execution errors, and timeouts. `ISiteEventLogger` is resolved from DI for the run.
|
||||
- [Data Connection Layer (#4)](./DataConnectionLayer.md) — `DataConnectionActor` logs `connection`-type events: connection loss, reconnection, and endpoint failover. `DataConnectionManagerActor` may also log connection-category events.
|
||||
- [Store-and-Forward Engine (#6)](./StoreAndForward.md) — logs `store_and_forward`-type events on the site→central notification forward path (forward failures, long-buffered notifications). Routine enqueue and forward-success events are not logged; central's `Notifications` table is the authoritative record.
|
||||
- [Host (#15)](./Host.md) — `SiteServiceRegistration` calls `AddSiteEventLogging` and binds `SiteEventLogOptions`. `AkkaHostedService` wires `EventLogHandlerActor` as a cluster singleton scoped to `"site-{SiteId}"`. The `SiteEventLogActiveNodeCheck` delegate is an optional seam defined in `SiteEventLogging` for the Host to register when it wants to gate the purge to the active node only; the Host does not currently register it, so the purge defaults to always-active and runs on every node.
|
||||
|
||||
@@ -4,12 +4,12 @@ The Site Runtime component runs the site-side actor hierarchy that executes depl
|
||||
|
||||
## Overview
|
||||
|
||||
Site Runtime (#3) operates exclusively on site clusters. Its entry point is the `DeploymentManagerActor` cluster singleton, which re-creates the full actor hierarchy on every site startup or failover. Each deployed enabled instance gets an `InstanceActor` child; each `InstanceActor` spawns `ScriptActor` and `AlarmActor` coordinator children, plus a `NativeAlarmActor` peer for every configured native alarm source. Script invocations spawn short-lived `ScriptExecutionActor` children; alarm on-trigger invocations spawn short-lived `AlarmExecutionActor` children.
|
||||
Site Runtime (#3) operates exclusively on site clusters. Its entry point is the `DeploymentManagerActor` cluster singleton, which re-creates the full actor hierarchy on every site startup or failover. Each deployed enabled instance gets an `InstanceActor` child; each `InstanceActor` spawns `ScriptActor` and `AlarmActor` coordinator children, plus a `NativeAlarmActor` peer for every configured native alarm source. **As of WP3.1 (arch-review remediation, 2026-08-15) a script or alarm on-trigger invocation is no longer a per-run child actor** — `ScriptExecutionActor`/`AlarmExecutionActor` were deleted (they were already inert shells: no `Receive` handler, no `PostStop`, never a message target). `ScriptActor`/`AlarmActor` instead launch the run body directly onto the shared script-execution pool via `ScriptRunLauncher`, keyed by instance+script so `MaxConcurrentRunsPerScript` and the deadline-at-enqueue timeout still apply per script.
|
||||
|
||||
The component code lives in `src/ZB.MOM.WW.ScadaBridge.SiteRuntime/`:
|
||||
|
||||
- `Actors/` — `DeploymentManagerActor`, `InstanceActor`, `ScriptActor`, `ScriptExecutionActor`, `AlarmActor`, `AlarmExecutionActor`, `NativeAlarmActor`.
|
||||
- `Scripts/` — `ScriptCompilationService`, `ScriptExecutionScheduler`, `SharedScriptLibrary`, `ScriptRuntimeContext`, `ScopeAccessors`, `TriggerExpressionGlobals`.
|
||||
- `Actors/` — `DeploymentManagerActor`, `InstanceActor`, `ScriptActor`, `AlarmActor`, `NativeAlarmActor`. (`ScriptExecutionActor`/`AlarmExecutionActor` were removed by WP3.1 — see Overview.)
|
||||
- `Scripts/` — `ScriptCompilationService`, `ScriptExecutionScheduler`, `ScriptRunLauncher`, `TriggerEvalGate`, `ScriptRunSummaryRecorder`, `SharedScriptLibrary`, `ScriptRuntimeContext`, `ScopeAccessors`, `TriggerExpressionGlobals`.
|
||||
- `Streaming/` — `SiteStreamManager` (the site-wide Akka broadcast stream).
|
||||
- `Persistence/` — `SiteStorageService` (raw SQLite via `Microsoft.Data.Sqlite`), `SiteStorageInitializer`.
|
||||
- `Repositories/` — `SiteExternalSystemRepository`. (The `SiteNotificationRepository` variant was removed 2026-07-10, arch-review 08 §1.3/#23, because notification config is central-only and never lives on a site.)
|
||||
@@ -36,14 +36,12 @@ The singleton reads all deployed configurations from SQLite in `PreStart`, compi
|
||||
| `ScriptActor` | long-lived coordinator | `OneForOneStrategy` | Stop execution child, keep self |
|
||||
| `AlarmActor` | long-lived coordinator | `OneForOneStrategy` | Stop execution child, keep self |
|
||||
| `NativeAlarmActor` | long-lived coordinator | — | Supervised by Instance Actor (Resume) |
|
||||
| `ScriptExecutionActor` | short-lived per invocation | — | Stops itself; parent logs failure |
|
||||
| `AlarmExecutionActor` | short-lived per invocation | — | Stops itself; parent logs failure |
|
||||
|
||||
Coordinator actors resume on exception because their in-memory state (trigger timers, last execution time, alarm level) must survive child crashes. Short-lived execution actors stop themselves on completion or exception — the coordinator remains available for the next trigger.
|
||||
Coordinator actors resume on exception because their in-memory state (trigger timers, last execution time, alarm level) must survive child crashes. **Since WP3.1 there is no per-run child actor** — `ScriptActor`/`AlarmActor` launch the run body directly via `ScriptRunLauncher` onto the shared pool and observe its completion `Task`; a run failure is caught and reported by the launcher/coordinator, not by an actor `PostStop`.
|
||||
|
||||
### Dedicated script-execution dispatcher
|
||||
|
||||
Script and alarm on-trigger bodies run on the `ScriptExecutionScheduler` (`SiteRuntime-009`): a custom `TaskScheduler` backed by a bounded set of dedicated threads (default 8, `ScriptExecutionThreadCount`). The script body is submitted to this scheduler via `Task.Factory.StartNew(..., scheduler)` inside `ScriptExecutionActor` and `AlarmExecutionActor`. Scripts that block on I/O (database connections, synchronous external system calls) block only the scheduler's threads, leaving the shared .NET thread pool and all Akka dispatchers unaffected.
|
||||
Script and alarm on-trigger bodies run on the `ScriptExecutionScheduler` (`SiteRuntime-009`): a custom `TaskScheduler` backed by a bounded, **instance-scaled, grow-only** set of dedicated threads (`clamp(max(ScriptExecutionThreadCount, ceil(enabledInstances/8)), 1, ScriptExecutionMaxThreadCount)`; floor default 8, ceiling default 32 — WP3.1). The script body is submitted to this scheduler via `Task.Factory.StartNew(..., scheduler)` from `ScriptRunLauncher`, called directly by `ScriptActor`/`AlarmActor` — no per-run actor is spawned. Scripts that block on I/O (database connections, synchronous external system calls) block only the scheduler's threads, leaving the shared .NET thread pool and all Akka dispatchers unaffected. **Expression-trigger evaluation runs on a separate path** — the shared .NET thread pool behind `TriggerEvalGate`, not this scheduler (WP3.1, arch-review finding #4) — so scripts blocked in synchronous I/O can no longer stall every Expression trigger on the node.
|
||||
|
||||
### Tell vs. Ask
|
||||
|
||||
@@ -52,7 +50,7 @@ Script and alarm on-trigger bodies run on the `ScriptExecutionScheduler` (`SiteR
|
||||
|
||||
### Attribute serialization through the Instance Actor
|
||||
|
||||
All in-memory state mutations (attribute values, qualities, alarm states) run inside `InstanceActor`'s mailbox. Multiple `ScriptExecutionActor` instances may run concurrently but all `SetAttribute` calls serialize through the `InstanceActor` mailbox, preventing race conditions. Concurrent script executions may interleave external side effects (HTTP calls, database writes, notifications); those are independent and intentionally not serialized.
|
||||
All in-memory state mutations (attribute values, qualities, alarm states) run inside `InstanceActor`'s mailbox. Multiple script/alarm runs may execute concurrently on the shared pool but all `SetAttribute` calls serialize through the `InstanceActor` mailbox, preventing race conditions. Concurrent script executions may interleave external side effects (HTTP calls, database writes, notifications); those are independent and intentionally not serialized.
|
||||
|
||||
## Architecture
|
||||
|
||||
@@ -61,16 +59,15 @@ All in-memory state mutations (attribute values, qualities, alarm states) run in
|
||||
```text
|
||||
DeploymentManagerActor (Akka.NET cluster singleton)
|
||||
└── InstanceActor "MachineA-001"
|
||||
├── ScriptActor "MonitorSpeed" (coordinator)
|
||||
│ └── ScriptExecutionActor (short-lived, per invocation)
|
||||
├── ScriptActor "MonitorSpeed" (coordinator — launches runs via ScriptRunLauncher, no per-run child)
|
||||
├── ScriptActor "CalculateOEE" (coordinator)
|
||||
│ └── ScriptExecutionActor (short-lived)
|
||||
├── AlarmActor "OverTemp" (coordinator, computed)
|
||||
│ └── AlarmExecutionActor (short-lived, on-trigger)
|
||||
├── AlarmActor "OverTemp" (coordinator, computed — on-trigger runs also via ScriptRunLauncher)
|
||||
├── AlarmActor "LowPressure" (coordinator, computed)
|
||||
└── NativeAlarmActor "OpcUaServer1" (read-only mirror, peer to AlarmActor)
|
||||
```
|
||||
|
||||
Prior to WP3.1 (2026-08-15) each invocation spawned a short-lived `ScriptExecutionActor`/`AlarmExecutionActor` child; those actor classes were deleted (see Overview) and every run now executes on the shared `ScriptExecutionScheduler` pool directly, tracked by `ScriptRunLauncher` rather than by an actor cell.
|
||||
|
||||
`NativeAlarmActor` is a sibling of `AlarmActor` — a peer under the same `InstanceActor` parent. It is not a child of `AlarmActor` and has no relationship to the script engine.
|
||||
|
||||
### Deployment flow
|
||||
@@ -234,17 +231,17 @@ Central sends commands to the site `DeploymentManagerActor` singleton over the C
|
||||
|
||||
### Script API surface
|
||||
|
||||
Scripts run inside `ScriptExecutionActor` with a `ScriptGlobals` object as the Roslyn host object. The `Instance` global is a `ScriptRuntimeContext`. Convenience top-level aliases (`ExternalSystem`, `Database`, `Notify`, `Scripts`, `Attributes`, `Children`, `Parent`) delegate to context methods. Key calls:
|
||||
Scripts run on the shared script-execution pool (via `ScriptRunLauncher`, launched directly by `ScriptActor` — no per-run child actor since WP3.1) with a `ScriptGlobals` object as the Roslyn host object. The `Instance` global is a `ScriptRuntimeContext`. Convenience top-level aliases (`ExternalSystem`, `Database`, `Notify`, `Scripts`, `Attributes`, `Children`, `Parent`) delegate to context methods. Key calls:
|
||||
|
||||
- `Instance.GetAttribute("name")` / `Instance.SetAttribute("name", value)` — Ask to `InstanceActor` for write, in-process for read.
|
||||
- `Instance.CallScript("scriptName", params)` — Ask from `ScriptExecutionActor` to sibling `ScriptActor`, which spawns a new `ScriptExecutionActor`.
|
||||
- `Instance.CallScript("scriptName", params)` — Ask from the running script (via `ScriptRuntimeContext.CallScript`) to sibling `ScriptActor`, which launches a new run via `ScriptRunLauncher`. Nested self-recursion is exempt from `MaxConcurrentRunsPerScript` (bounded instead by `MaxScriptCallDepth`), since the calling run is already holding one of the cap's slots while it awaits the callee.
|
||||
- `Scripts.CallShared("name", params)` — `SharedScriptLibrary.ExecuteAsync`, inline on the current scheduler thread.
|
||||
- `ExternalSystem.Call(...)` — synchronous HTTP call through `IExternalSystemClient`.
|
||||
- `ExternalSystem.CachedCall(...)` / `Database.CachedWrite(...)` — store-and-forwarded; returns a `TrackedOperationId`.
|
||||
- `Tracking.Status(id)` — reads the site-local `OperationTrackingStore` synchronously.
|
||||
- `Notify.To("list").Send(...)` — enqueues a notification in the Store-and-Forward Engine for delivery to central.
|
||||
|
||||
Alarm on-trigger scripts run in `AlarmExecutionActor` with a **restricted** context: they receive an `Alarm` global (`AlarmContext` carrying `Name`, `Level`, `Priority`, `Message`) and have access to the instance/shared-script surface (`Instance.*`, `Scripts.CallShared`, `Instance.CallScript`), but **not** the external-system, database, notification, or audit integration APIs. `AlarmExecutionActor` builds its `ScriptRuntimeContext` without a `serviceProvider`, so `ExternalSystem`, `Database`, `Notify`, and audit writes are unavailable to alarm on-trigger scripts — those APIs are only resolved inside `ScriptExecutionActor` (instance scripts).
|
||||
Alarm on-trigger scripts run via the same `ScriptRunLauncher` path (launched by `AlarmActor`) with a **restricted** context: they receive an `Alarm` global (`AlarmContext` carrying `Name`, `Level`, `Priority`, `Message`) and have access to the instance/shared-script surface (`Instance.*`, `Scripts.CallShared`, `Instance.CallScript`), but **not** the external-system, database, notification, or audit integration APIs. The alarm run's `ScriptRuntimeContext` is built without a `serviceProvider`, so `ExternalSystem`, `Database`, `Notify`, and audit writes are unavailable to alarm on-trigger scripts — those APIs are only resolved for instance-script runs.
|
||||
|
||||
### Debug view
|
||||
|
||||
@@ -261,7 +258,9 @@ All options live in the `ScadaBridge:SiteRuntime` section, bound to `SiteRuntime
|
||||
| `MaxScriptCallDepth` | `10` | Maximum `Instance.CallScript` / `Scripts.CallShared` recursion depth |
|
||||
| `ScriptExecutionTimeoutSeconds` | `30` | Per-script body execution timeout; exceeding it cancels and logs an error |
|
||||
| `StreamBufferSize` | `1000` | Per-subscriber drop-oldest buffer size for the Akka broadcast stream |
|
||||
| `ScriptExecutionThreadCount` | `8` | Dedicated threads in the `ScriptExecutionScheduler` (covers both scripts and alarm on-trigger bodies) |
|
||||
| `ScriptExecutionThreadCount` | `8` | Floor thread count in the `ScriptExecutionScheduler` (covers both scripts and alarm on-trigger bodies) — the pool grows above this with `enabledInstances`, see Dedicated script-execution dispatcher |
|
||||
| `ScriptExecutionMaxThreadCount` | `32` | Ceiling on the instance-scaled pool growth (WP3.1) |
|
||||
| `MaxConcurrentRunsPerScript` | `4` | Runs in flight (queued or executing) per script/alarm on-trigger script before the newest is shed (WP3.1) |
|
||||
| `MirroredAlarmCapPerSource` | `1000` | Maximum mirrored conditions per `NativeAlarmActor` source binding before oldest is dropped and logged |
|
||||
| `NativeAlarmRetryIntervalMs` | `5000` | Milliseconds before retrying a failed native alarm subscription |
|
||||
|
||||
@@ -271,11 +270,11 @@ The SQLite connection string is passed directly to `AddSiteRuntime(connectionStr
|
||||
|
||||
- [Data Connection Layer (#4)](./DataConnectionLayer.md) — supplies `TagValueUpdate` and `ConnectionQualityChanged` messages to `InstanceActor`; receives `SubscribeTagsRequest` and `WriteTagRequest`. Also supplies `NativeAlarmTransitionUpdate` and `NativeAlarmSourceUnavailable` to `NativeAlarmActor` via `SubscribeAlarmsRequest` (connections implementing `IAlarmSubscribableConnection`).
|
||||
- [Central–Site Communication (#5)](./Communication.md) — routes `DeployInstanceCommand`, `DisableInstanceCommand`, `EnableInstanceCommand`, `DeleteInstanceCommand`, `DeployArtifactsCommand`, debug view requests, and Inbound API `RouteToCallRequest` / `RouteToGetAttributesRequest` / `RouteToSetAttributesRequest` to the singleton; receives `DeploymentStatusResponse` and `ArtifactDeploymentResponse` back. The `SiteStreamManager` implements `ISiteStreamSubscriber` so the Communication Layer's `SiteStreamGrpcServer` can subscribe `StreamRelayActor` instances to the broadcast hub.
|
||||
- [Store-and-Forward Engine (#6)](./StoreAndForward.md) — `ScriptRuntimeContext` passes `StoreAndForwardService` (resolved from DI inside `ScriptExecutionActor`) for `ExternalSystem.CachedCall`, `Database.CachedWrite`, and `Notify.To().Send()`. Owns the site-local operation tracking table that `Tracking.Status(id)` reads.
|
||||
- [Store-and-Forward Engine (#6)](./StoreAndForward.md) — `ScriptRuntimeContext` passes `StoreAndForwardService` (resolved from DI for the run, via `ScriptRunLauncher`) for `ExternalSystem.CachedCall`, `Database.CachedWrite`, and `Notify.To().Send()`. Owns the site-local operation tracking table that `Tracking.Status(id)` reads.
|
||||
- [External System Gateway (#7)](./ExternalSystemGateway.md) — `IExternalSystemClient` called by `ScriptRuntimeContext.ExternalSystemHelper` for synchronous and cached external system calls.
|
||||
- [Site Event Logging (#12)](./SiteEventLogging.md) — `ISiteEventLogger` (resolved from DI inside execution actors) receives script error, alarm error, and script execution events.
|
||||
- [Site Event Logging (#12)](./SiteEventLogging.md) — `ISiteEventLogger` (resolved from DI for the run) receives script error, alarm error, and script execution events.
|
||||
- [Health Monitoring (#11)](./HealthMonitoring.md) — `ISiteHealthCollector` (injected into `DeploymentManagerActor`, `InstanceActor`, `ScriptActor`, `AlarmActor`) tracks instance counts (`SetInstanceCounts`), script errors (`IncrementScriptError`), and alarm errors (`IncrementAlarmError`); sets `SetActiveNode` in `DeploymentManagerActor.PreStart`/`PostStop` so the health report reflects which node holds the singleton.
|
||||
- [Audit Log (#23)](./AuditLog.md) — `IAuditWriter` (resolved from DI inside `ScriptExecutionActor`) receives one row per script-trust-boundary call; audit writes are best-effort and never abort the calling script.
|
||||
- [Audit Log (#23)](./AuditLog.md) — `IAuditWriter` (resolved from DI for the run) receives one row per script-trust-boundary call; audit writes are best-effort and never abort the calling script.
|
||||
- [Commons (#16)](./Commons.md) — owns all message contracts (`DeployInstanceCommand`, `AttributeValueChanged`, `AlarmStateChanged`, `ScriptCallRequest`, `NativeAlarmTransitionUpdate`, etc.), the `FlattenedConfiguration` / `ResolvedScript` / `ResolvedAlarm` / `ResolvedNativeAlarmSource` types, and the `AlarmKind` / `AlarmState` / `AlarmLevel` / `AlarmConditionState` / `AlarmTransitionKind` enums.
|
||||
- Local SQLite — `SiteStorageService` owns the site database. Peer SQLite stores (Store-and-Forward buffer, AuditLog, operation tracking, site event log) are owned by their respective components but share the same SQLite file path convention.
|
||||
- Design spec: [Component-SiteRuntime.md](../requirements/Component-SiteRuntime.md).
|
||||
|
||||
Reference in New Issue
Block a user