Adds CreateEditDelete_Site_RoundTrips [SkippableFact] to SiteCrudTests.
Exercises the full create → edit → delete UI flow against the live cluster,
with CliRunner best-effort teardown so no zztest-* sites leak on mid-test failure.
Guards against the Akka singleton Ask hang regression: asserts all nine KPI
tiles on /monitoring/health resolve to numeric values and never show the
em-dash degrade placeholder (—). Covers Notification Outbox, Audit, and
Site Call tile groups. Selector disambiguation: Outbox tiles are div.card,
Site Call tiles are button.card — prevents strict-mode collisions on the
shared "Stuck" and "Parked" labels.
Captures the 2026-06-05 coverage audit's gaps and the approved approach for
closing them: ephemeral CLI-provisioned fixtures with outcome-tolerant asserts
for the mutating suites (deploy lifecycle, retry/discard, transport import),
UI CRUD round-trips, nav render hardening, a Health KPI load test, and a
standardized skip-and-log policy. Next: writing-plans turns this into tasks.
Per-probe health-check child scopes were disposing the AddTransient-bridged
ActorSystem (IDisposable), terminating the live cluster node ~4s after boot and
leaving every singleton-proxy Ask to hang the full 30s QueryTimeout — the central
report pages (/notifications, /site-calls, /monitoring/health) loaded in ~30s.
Bridge it as a singleton via a new lazy AkkaHostedService.GetOrCreateActorSystem()
so child-scope disposal never touches it. Verified: 0 post-startup terminates,
healthy active/standby, report pages ~0.05s, Playwright 68 passed / 0 failed.
infra/ no longer runs scadabridge-ldap (retired); central nodes bind the shared
zb-shared-glauth on 10.100.0.35:3893 (dc=zb,dc=local). Source of truth:
scadaproj/infra/glauth/. test_infra_ldap.md banner-marked SUPERSEDED.
Completes the multi-role test user's 4th role. HasData row Id=5
(SCADA-Viewers->Viewer) + the SCADA-Viewers group in the (now-retired) local
glauth config. The live shared dir is scadaproj/infra/glauth/.
Both :9000 (docker) and :9100 (docker-env2) central nodes now bind the shared dev
GLAuth (scadaproj/infra/glauth/, dc=zb,dc=local) via the cn=serviceaccount search
account instead of the bundled scadabridge-ldap container (now commented out in
infra/docker-compose.yml, kept for rollback). Verified: multi-role -> all 4 roles
on both clusters with scadabridge-ldap stopped.
TemplateEngine (alarm-script-ref ordering, native-alarm-sources not in
revision hash, composition cycle checks, 9-step pipeline), SiteRuntime
(alarm on-trigger scripts run with a restricted context; PreStart seeds
children from defaults before overrides arrive), DataConnectionLayer
(UnsubscribeAlarmsRequest stashed in Connecting), StoreAndForward (InFlight/
Delivered are dead enum values; notifications can park at 50 retries),
ExternalSystemGateway (CachedWrite returns void + enqueues directly; log levels).
Brainstormed design: generate 25 StyleGuide-conformant developer-reference
docs derived from src/ code (pilot AuditLog, then parallel fan-out, then
accuracy/conformance verification). Complements the requirements specs;
leaves src/, XML docs, and specs untouched.
The auth cookie name was hardcoded to ZB.MOM.WW.ScadaBridge.Auth. Because
browser cookies are scoped by host+path but NOT by port, two ScadaBridge
clusters on the same host (the local docker stack on localhost:9000 and
docker-env2 on localhost:9100) shared one cookie jar: signing into one
overwrote the other's cookie, and since the clusters use different JWT
signing keys + separate Data Protection key rings, the overwritten side
could no longer validate its cookie and the session died.
Add SecurityOptions.CookieName (default = canonical ZB.MOM.WW.ScadaBridge.Auth,
blank falls back to the default) applied via the SecurityOptions-bound cookie
PostConfigure. Override it to ...Auth.env2 in both docker-env2 Central nodes so
the two local clusters no longer collide; the primary cluster keeps the default
so its live sessions and production are unaffected. Adds 3 Security.Tests cases.
Resolve all 622 issues flagged by the enhanced CommentChecker: add missing
<returns> tags (incl. the standard phrasing on non-generic Task methods),
add missing <summary> tags, and replace misused/redundant <inheritdoc/> on
members that override or implement nothing with real documentation.
Documentation-only — no behavior change; solution builds clean.
The Auth/Config normalization made ScadaBridge:InboundApi:ApiKeyPepper a hard
Central-only startup requirement (>=16 chars), but the local dev composes never
supplied it, so deploy.sh's freshly-built image crash-looped both Central nodes
on ConfigPreflight validation. Add a clearly-marked DEV-ONLY, insecure pepper
inline to each cluster's Central environment (distinct per environment). These
are NOT real secrets — production injects a true per-env secret out-of-band per
docs/operations/inbound-api-key-reissue.md; the inline values exist only so the
local docker / docker-env2 clusters start.
Host/App.razor uses the kit's <ThemeHead/>/<ThemeScripts/>, but Host had no direct
PackageReference — it relied on CentralUI re-exporting the package transitively.
Add a versionless <PackageReference Include="ZB.MOM.WW.Theme"/> (version pinned by
central PM at Directory.Packages.props) so the declared dependency matches actual
usage and survives any future PrivateAssets/refactor on CentralUI. Additive only;
Host builds clean (0/0).
The .sidebar/#sidebar-collapse/.nav-link/.nav-section-toggle block is orphaned —
the side rail is now the ZB.MOM.WW.Theme kit's .side-rail/.rail-link shell, and
no markup references these selectors. Kept the app-only #reconnect-modal and
.script-editor-modal rules (not provided by the kit). 95 lines removed; builds clean.