refactor: rename ScadaLink → ZB.MOM.WW.ScadaBridge (code + projects + namespaces)
Solution + 23 src projects + 26 test projects renamed; folders, csproj, namespaces, and ScadaLinkDbContext/ScadaBridgeDbContext class updated. ActorSystem "scadalink" → "scadabridge", Akka seed-node URLs migrated. SQL roles/logins, LDAP domains, CLI command name, and CLI config dir (~/.scadalink → ~/.scadabridge) also renamed. Build green; 5 Host.Tests fail awaiting SQL login rename in next commit. Pre-existing StaleTagMonitor timing flakes unchanged. Rename script committed at tools/rename-to-scadabridge.sh.
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| Module | `src/ScadaLink.StoreAndForward` |
|
||||
| Module | `src/ZB.MOM.WW.ScadaBridge.StoreAndForward` |
|
||||
| Design doc | `docs/requirements/Component-StoreAndForward.md` |
|
||||
| Status | Reviewed |
|
||||
| Last reviewed | 2026-05-28 |
|
||||
@@ -89,7 +89,7 @@ concurrent discard / sweep delete), re-introducing the StoreAndForward-016 stand
|
||||
divergence in that corner. `StoreAndForward-021` (Medium) is a design-doc-vs-code drift
|
||||
that should be reconciled in the doc: the **operation tracking table** is documented
|
||||
inside Component-StoreAndForward.md as a S&F responsibility (lines 21, 49, 77–87, 108,
|
||||
114), but the actual `OperationTrackingStore` lives in `src/ScadaLink.SiteRuntime/
|
||||
114), but the actual `OperationTrackingStore` lives in `src/ZB.MOM.WW.ScadaBridge.SiteRuntime/
|
||||
Tracking/` and is not consumed by S&F at all — the brief's own note flags this. The
|
||||
design doc should be updated to point at SiteRuntime, or the store moved to
|
||||
StoreAndForward.
|
||||
@@ -122,7 +122,7 @@ shutdown sequence (the DI container) can then NRE through the still-running swee
|
||||
| 6 | Performance & resource management | ☑ | No new findings — the connection-per-call documented trade-off and pooled `OpenAsync` remain acceptable. |
|
||||
| 7 | Design-document adherence | ☑ | Operation Tracking Table documented in StoreAndForward but actually lives in SiteRuntime (021); notification non-parking guarantee broken by 018 + 019. |
|
||||
| 8 | Code organization & conventions | ☑ | `IStoreAndForwardSiteContext` silently defaults `SiteId` to empty (023) — a configuration hole rather than an entity placement issue. |
|
||||
| 9 | Testing coverage | ☑ | The seven new findings have no regression tests in `tests/ScadaLink.StoreAndForward.Tests/` — particularly the notification-doesn't-park invariant (018, 019), the requeue-after-reload-null replication gap (020), and the stop-during-sweep behaviour (024). |
|
||||
| 9 | Testing coverage | ☑ | The seven new findings have no regression tests in `tests/ZB.MOM.WW.ScadaBridge.StoreAndForward.Tests/` — particularly the notification-doesn't-park invariant (018, 019), the requeue-after-reload-null replication gap (020), and the stop-during-sweep behaviour (024). |
|
||||
| 10 | Documentation & comments | ☑ | `CachedCallAttemptOutcome.ParkedMaxRetries` XML doc says "S&F semantics" but the code applies it to notifications too if 018/019 fire — minor drift, captured under 018. The `TrackedOperationId.TryParse` silent-skip behaviour in `NotifyCachedCallObserverAsync` is documented in the source but not on the public observer contract (022). |
|
||||
|
||||
## Checklist coverage
|
||||
@@ -149,7 +149,7 @@ shutdown sequence (the DI container) can then NRE through the still-running swee
|
||||
| Severity | Critical |
|
||||
| Category | Error handling & resilience |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.StoreAndForward/ReplicationService.cs:40`, `:53`, `:66`; `src/ScadaLink.StoreAndForward/StoreAndForwardService.cs:155`, `:212`, `:222`, `:236` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.StoreAndForward/ReplicationService.cs:40`, `:53`, `:66`; `src/ZB.MOM.WW.ScadaBridge.StoreAndForward/StoreAndForwardService.cs:155`, `:212`, `:222`, `:236` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -193,7 +193,7 @@ commit whose message references `StoreAndForward-001`.
|
||||
| Original severity | High (re-triaged down to Low on 2026-05-16 — see Re-triage note) |
|
||||
| Category | Error handling & resilience |
|
||||
| Status | Deferred |
|
||||
| Location | `src/ScadaLink.StoreAndForward/StoreAndForwardService.cs:162`, `:201` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.StoreAndForward/StoreAndForwardService.cs:162`, `:201` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -221,7 +221,7 @@ transient condition with bounded logging rather than a permanent no-op.
|
||||
|
||||
The finding's central factual claim — *"No caller in the codebase ever calls
|
||||
`RegisterDeliveryHandler`"* and therefore *"every buffered message lands in this dead
|
||||
state"* — is **no longer true at the reviewed code**. `ScadaLink.Host`
|
||||
state"* — is **no longer true at the reviewed code**. `ZB.MOM.WW.ScadaBridge.Host`
|
||||
(`AkkaHostedService.RegisterSiteActors`, `AkkaHostedService.cs:353-379`) registers all
|
||||
three delivery handlers (`ExternalSystem`, `CachedDbWrite`, `Notification`) at site
|
||||
startup, immediately after `StoreAndForwardService.StartAsync()`. The finding was
|
||||
@@ -249,7 +249,7 @@ should be made deliberately rather than forced here.
|
||||
|
||||
_Deferred 2026-05-16 (re-triaged High → Low). Verified again against the source in this
|
||||
pass: the finding's premise (no `RegisterDeliveryHandler` caller anywhere) is stale —
|
||||
`ScadaLink.Host` wires all three handlers at site startup — so the High-severity
|
||||
`ZB.MOM.WW.ScadaBridge.Host` wires all three handlers at site startup — so the High-severity
|
||||
"engine cannot deliver anything" outcome no longer occurs. The residual gap (a message
|
||||
enqueued for a category that genuinely has no handler is buffered then skipped forever)
|
||||
is real but minor. The prescribed fix — making `EnqueueAsync` reject when no handler is
|
||||
@@ -266,7 +266,7 @@ pending that decision rather than forced here._
|
||||
| Severity | High |
|
||||
| Category | Correctness & logic bugs |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.StoreAndForward/StoreAndForwardService.cs:153`, `:229`, `:233` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.StoreAndForward/StoreAndForwardService.cs:153`, `:229`, `:233` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -316,7 +316,7 @@ corrected semantics.
|
||||
| Severity | Medium |
|
||||
| Category | Documentation & comments |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.StoreAndForward/StoreAndForwardService.cs:38`, `:60` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.StoreAndForward/StoreAndForwardService.cs:38`, `:60` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -355,7 +355,7 @@ Documentation-only change — no behavioural code touched, so no regression test
|
||||
| Original severity | Medium |
|
||||
| Category | Concurrency & thread safety |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.StoreAndForward/StoreAndForwardService.cs:184`, `:266`, `:280` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.StoreAndForward/StoreAndForwardService.cs:184`, `:266`, `:280` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -423,7 +423,7 @@ other writer's `RetryCount`).
|
||||
| Severity | Low |
|
||||
| Category | Performance & resource management |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.StoreAndForward/StoreAndForwardStorage.cs:166`, `:175` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.StoreAndForward/StoreAndForwardStorage.cs:166`, `:175` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -466,7 +466,7 @@ finding's recommendation.
|
||||
| Severity | Low |
|
||||
| Category | Akka.NET conventions |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.StoreAndForward/ParkedMessageHandlerActor.cs:34`, `:68`, `:87` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.StoreAndForward/ParkedMessageHandlerActor.cs:34`, `:68`, `:87` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -511,7 +511,7 @@ is a concrete non-virtual type with no failure-injection seam.
|
||||
| Severity | Low |
|
||||
| Category | Performance & resource management |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.StoreAndForward/StoreAndForwardStorage.cs:28`, `:61`, `:93`, `:117`, `:144`, `:162`, `:199`, `:221`, `:237`, `:267`, `:285`, `:305`, `:319` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.StoreAndForward/StoreAndForwardStorage.cs:28`, `:61`, `:93`, `:117`, `:144`, `:162`, `:199`, `:221`, `:237`, `:267`, `:285`, `:305`, `:319` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -550,7 +550,7 @@ touched, so no regression test (the connection-pool reliance is not test-observa
|
||||
| Severity | Low |
|
||||
| Category | Concurrency & thread safety |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.StoreAndForward/StoreAndForwardService.cs:46`, `:309` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.StoreAndForward/StoreAndForwardService.cs:46`, `:309` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -596,7 +596,7 @@ with `WasBuffered == false` and an empty buffer) and
|
||||
| Severity | Medium |
|
||||
| Category | Correctness & logic bugs |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.StoreAndForward/StoreAndForwardStorage.cs:203`, `:101` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.StoreAndForward/StoreAndForwardStorage.cs:203`, `:101` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -637,7 +637,7 @@ cleared, message excluded from the retry-due set) and passes post-fix.
|
||||
| Severity | Low |
|
||||
| Category | Design-document adherence |
|
||||
| Status | Deferred |
|
||||
| Location | `src/ScadaLink.Commons/Types/Enums/StoreAndForwardMessageStatus.cs:9`; `src/ScadaLink.StoreAndForward/StoreAndForwardService.cs:219`, `:235` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.Commons/Types/Enums/StoreAndForwardMessageStatus.cs:9`; `src/ZB.MOM.WW.ScadaBridge.StoreAndForward/StoreAndForwardService.cs:219`, `:235` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -663,8 +663,8 @@ StoreAndForward module only ever assigns `Pending` and `Parked`, and `InFlight`
|
||||
`Delivered` are never assigned anywhere (delivered messages are deleted, not marked).
|
||||
The design doc's `retrying` state is unmodelled. Both options the recommendation offers
|
||||
— (a) drop the unused `InFlight`/`Delivered` members, or (b) add a `Retrying` member —
|
||||
require editing `StoreAndForwardMessageStatus.cs`, which lives in `src/ScadaLink.Commons`
|
||||
(outside this review's edit scope: only `src/ScadaLink.StoreAndForward/**` may be
|
||||
require editing `StoreAndForwardMessageStatus.cs`, which lives in `src/ZB.MOM.WW.ScadaBridge.Commons`
|
||||
(outside this review's edit scope: only `src/ZB.MOM.WW.ScadaBridge.StoreAndForward/**` may be
|
||||
changed). The enum is also referenced by IntegrationTests and HealthMonitoring tests, so
|
||||
removing members is a cross-module change. The defect is real but cannot be resolved
|
||||
in-module; **Deferred** to a change that owns the Commons enum and the design doc
|
||||
@@ -677,7 +677,7 @@ together._
|
||||
| Severity | Low |
|
||||
| Category | Code organization & conventions |
|
||||
| Status | Deferred |
|
||||
| Location | `src/ScadaLink.StoreAndForward/StoreAndForwardMessage.cs:9` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.StoreAndForward/StoreAndForwardMessage.cs:9` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -706,8 +706,8 @@ mapping to `sf_messages` and is also carried across Akka remoting inside
|
||||
component assembly rather than the Commons `Entities`/`Messages` hierarchy. The
|
||||
recommendation's primary remedy — moving `StoreAndForwardMessage` (and
|
||||
`ReplicationOperation`) into Commons — crosses module boundaries (it would add a type to
|
||||
`src/ScadaLink.Commons`, outside this review's edit scope of
|
||||
`src/ScadaLink.StoreAndForward/**`, and change every referencing module). The alternative
|
||||
`src/ZB.MOM.WW.ScadaBridge.Commons`, outside this review's edit scope of
|
||||
`src/ZB.MOM.WW.ScadaBridge.StoreAndForward/**`, and change every referencing module). The alternative
|
||||
"separate replication DTO" still leaves the persistence entity in the component, so it
|
||||
does not actually resolve the finding's core concern (entity placement / contract-
|
||||
evolution governance). Resolving this is a deliberate code-organisation decision that
|
||||
@@ -721,7 +721,7 @@ cross-module follow-up._
|
||||
| Severity | Medium |
|
||||
| Category | Testing coverage |
|
||||
| Status | Resolved |
|
||||
| Location | `tests/ScadaLink.StoreAndForward.Tests/` (whole directory); `src/ScadaLink.StoreAndForward/StoreAndForwardStorage.cs:101`; `src/ScadaLink.StoreAndForward/ParkedMessageHandlerActor.cs` |
|
||||
| Location | `tests/ZB.MOM.WW.ScadaBridge.StoreAndForward.Tests/` (whole directory); `src/ZB.MOM.WW.ScadaBridge.StoreAndForward/StoreAndForwardStorage.cs:101`; `src/ZB.MOM.WW.ScadaBridge.StoreAndForward/ParkedMessageHandlerActor.cs` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -768,7 +768,7 @@ These are coverage-gap tests over already-correct code, so they pass on first ru
|
||||
| Severity | Medium |
|
||||
| Category | Error handling & resilience |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.StoreAndForward/StoreAndForwardStorage.cs:26` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.StoreAndForward/StoreAndForwardStorage.cs:26` |
|
||||
|
||||
**Found 2026-05-16** while verifying the store-and-forward fixes — this defect was
|
||||
not part of the original baseline review.
|
||||
@@ -806,7 +806,7 @@ all six `SiteActorPathTests` now pass. Fixed by the commit whose message referen
|
||||
| Severity | Medium |
|
||||
| Category | Documentation & comments |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.StoreAndForward/StoreAndForwardService.cs:114`–`:130`, `:285` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.StoreAndForward/StoreAndForwardService.cs:114`–`:130`, `:285` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -873,7 +873,7 @@ test-observable so no regression test was added.
|
||||
| Severity | Medium |
|
||||
| Category | Error handling & resilience |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.StoreAndForward/StoreAndForwardService.cs:339`–`:362`; `src/ScadaLink.StoreAndForward/ReplicationService.cs:131`–`:136` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.StoreAndForward/StoreAndForwardService.cs:339`–`:362`; `src/ZB.MOM.WW.ScadaBridge.StoreAndForward/ReplicationService.cs:131`–`:136` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -942,7 +942,7 @@ requeued row and calls `_replication?.ReplicateRequeue`, and the standby's
|
||||
| Severity | Low |
|
||||
| Category | Correctness & logic bugs |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.StoreAndForward/StoreAndForwardService.cs:344`, `:358` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.StoreAndForward/StoreAndForwardService.cs:344`, `:358` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -992,7 +992,7 @@ the StoreAndForward-016 replication) — and pass it to `RaiseActivity` (falling
|
||||
| Severity | High |
|
||||
| Category | Design-document adherence |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.StoreAndForward/NotificationForwarder.cs:62`–`:69`, `:105`–`:122`; `src/ScadaLink.StoreAndForward/StoreAndForwardService.cs:369`–`:397` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.StoreAndForward/NotificationForwarder.cs:62`–`:69`, `:105`–`:122`; `src/ZB.MOM.WW.ScadaBridge.StoreAndForward/StoreAndForwardService.cs:369`–`:397` |
|
||||
|
||||
**Resolution** — `NotificationForwarder.DeliverAsync` now discards a corrupt
|
||||
buffered payload instead of returning false. The corrupt path logs a Warning
|
||||
@@ -1053,7 +1053,7 @@ parking exception specifically for notifications, and revise the resolved
|
||||
StoreAndForward-017 wording; (b) treat `JsonException` as transient (would retry-forever
|
||||
on a corrupt payload — bad); (c) introduce a per-category park-allowed flag on the
|
||||
engine and gate the retry-path park behind it for the Notification category.
|
||||
Add a regression test in `tests/ScadaLink.StoreAndForward.Tests/NotificationForwarderTests.
|
||||
Add a regression test in `tests/ZB.MOM.WW.ScadaBridge.StoreAndForward.Tests/NotificationForwarderTests.
|
||||
cs` asserting that a corrupt-payload notification reaches a terminal **non-Parked**
|
||||
state — today the corrupt-payload behaviour is uncovered.
|
||||
|
||||
@@ -1068,7 +1068,7 @@ _Unresolved._
|
||||
| Severity | Medium |
|
||||
| Category | Error handling & resilience |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.StoreAndForward/StoreAndForwardService.cs:229`, `:407`–`:437`; `src/ScadaLink.StoreAndForward/StoreAndForwardOptions.cs:18`; `src/ScadaLink.SiteRuntime/Scripts/ScriptRuntimeContext.cs:1773`–`:1778`; `src/ScadaLink.NotificationService/NotificationDeliveryService.cs:149`–`:156` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.StoreAndForward/StoreAndForwardService.cs:229`, `:407`–`:437`; `src/ZB.MOM.WW.ScadaBridge.StoreAndForward/StoreAndForwardOptions.cs:18`; `src/ZB.MOM.WW.ScadaBridge.SiteRuntime/Scripts/ScriptRuntimeContext.cs:1773`–`:1778`; `src/ZB.MOM.WW.ScadaBridge.NotificationService/NotificationDeliveryService.cs:149`–`:156` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -1112,7 +1112,7 @@ parking violation under the engine's normal max-retries policy.
|
||||
|
||||
Make the notification enqueue paths pass `maxRetries: 0` so the documented "no limit /
|
||||
never parked" semantics apply, and guard against regression by adding an integration
|
||||
test in `tests/ScadaLink.StoreAndForward.Tests/NotificationForwarderTests.cs` that runs
|
||||
test in `tests/ZB.MOM.WW.ScadaBridge.StoreAndForward.Tests/NotificationForwarderTests.cs` that runs
|
||||
a sweep many more times than `DefaultMaxRetries` against an always-failing handler and
|
||||
asserts the buffered notification's status stays `Pending` (not `Parked`). A cleaner
|
||||
alternative is to special-case the `Notification` category inside
|
||||
@@ -1135,7 +1135,7 @@ applies uniformly (including to notifications) and that `maxRetries: 0` is the e
|
||||
escape hatch for callers that need unbounded retry. Added a `StoreAndForward-019` block
|
||||
to `StoreAndForwardOptions.DefaultMaxRetries`'s XML doc explaining the same invariant.
|
||||
No behavioural code change — existing tests (104 in
|
||||
`ScadaLink.StoreAndForward.Tests`) continue to pass.
|
||||
`ZB.MOM.WW.ScadaBridge.StoreAndForward.Tests`) continue to pass.
|
||||
|
||||
### StoreAndForward-020 — `RetryParkedMessageAsync` skips standby replication when the message is deleted between local update and re-load
|
||||
|
||||
@@ -1144,7 +1144,7 @@ No behavioural code change — existing tests (104 in
|
||||
| Severity | Medium |
|
||||
| Category | Concurrency & thread safety |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.StoreAndForward/StoreAndForwardService.cs:599`–`:616` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.StoreAndForward/StoreAndForwardService.cs:599`–`:616` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -1239,7 +1239,7 @@ the activity log uses the captured `Category` directly.
|
||||
| Severity | Medium |
|
||||
| Category | Design-document adherence |
|
||||
| Status | Resolved |
|
||||
| Location | `docs/requirements/Component-StoreAndForward.md:21`, `:49`–`:51`, `:77`–`:87`, `:108`, `:114`; `src/ScadaLink.SiteRuntime/Tracking/OperationTrackingStore.cs:37`; `src/ScadaLink.StoreAndForward/` (whole module) |
|
||||
| Location | `docs/requirements/Component-StoreAndForward.md:21`, `:49`–`:51`, `:77`–`:87`, `:108`, `:114`; `src/ZB.MOM.WW.ScadaBridge.SiteRuntime/Tracking/OperationTrackingStore.cs:37`; `src/ZB.MOM.WW.ScadaBridge.StoreAndForward/` (whole module) |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -1257,12 +1257,12 @@ this component:
|
||||
each site node holds a **site-local operation tracking table** in SQLite. … Each row
|
||||
records the operation kind (`TrackedOperationKind`) …"
|
||||
|
||||
The actual implementation lives outside this module: `src/ScadaLink.SiteRuntime/
|
||||
The actual implementation lives outside this module: `src/ZB.MOM.WW.ScadaBridge.SiteRuntime/
|
||||
Tracking/OperationTrackingStore.cs` (and `IOperationTrackingStore`, `OperationTrackingOptions`).
|
||||
The StoreAndForward project contains no references to the tracking store, owns no
|
||||
`operation_tracking` table, and `StoreAndForwardService.NotifyCachedCallObserverAsync`
|
||||
is only a hook handing telemetry context to an `ICachedCallLifecycleObserver` — the
|
||||
audit bridge wired in `ScadaLink.AuditLog`. The S&F module is **not** the table's
|
||||
audit bridge wired in `ZB.MOM.WW.ScadaBridge.AuditLog`. The S&F module is **not** the table's
|
||||
owner; SiteRuntime is.
|
||||
|
||||
This is a real design-doc drift, not a code defect, and is flagged explicitly in the
|
||||
@@ -1271,7 +1271,7 @@ discussion of the lifecycle — "immediate success writes a terminal Delivered t
|
||||
row directly here", "operator discard sets terminal `Discarded`", "central never
|
||||
mutates the mirror row directly" — places coordination responsibilities on the wrong
|
||||
component. A reader looking for the source of truth for `Tracking.Status(id)` would
|
||||
read `Component-StoreAndForward.md` and search `src/ScadaLink.StoreAndForward/` in
|
||||
read `Component-StoreAndForward.md` and search `src/ZB.MOM.WW.ScadaBridge.StoreAndForward/` in
|
||||
vain. The doc also lists Site Call Audit / Audit Log telemetry-emission as a S&F
|
||||
responsibility (line 22), but the emission actually happens via the `AuditLog` site
|
||||
component subscribing to `ICachedCallLifecycleObserver`.
|
||||
@@ -1313,7 +1313,7 @@ not owned here.
|
||||
| Severity | Low |
|
||||
| Category | Documentation & comments |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.StoreAndForward/StoreAndForwardService.cs:484`–`:515` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.StoreAndForward/StoreAndForwardService.cs:484`–`:515` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -1332,7 +1332,7 @@ TrackedOperationId threaded in)", but the documented contract is broken in two w
|
||||
so a misconfigured caller bypasses the audit hot path with zero feedback.
|
||||
|
||||
2. **The contract is hidden in field-level XML.** The `ICachedCallLifecycleObserver`
|
||||
public interface contract (defined in `ScadaLink.Commons`) does not document that
|
||||
public interface contract (defined in `ZB.MOM.WW.ScadaBridge.Commons`) does not document that
|
||||
the observer will be silently skipped when the underlying S&F message id is not a
|
||||
GUID. A consumer reading the interface contract reasonably expects every cached-call
|
||||
attempt to surface — the audit pipeline depends on it. The silent-drop is an
|
||||
@@ -1377,7 +1377,7 @@ is on `_observer.Notifications` being empty, which is unchanged.
|
||||
| Severity | Low |
|
||||
| Category | Code organization & conventions |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.StoreAndForward/ServiceCollectionExtensions.cs:43`–`:53`; `src/ScadaLink.StoreAndForward/StoreAndForwardService.cs:99`, `:524` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.StoreAndForward/ServiceCollectionExtensions.cs:43`–`:53`; `src/ZB.MOM.WW.ScadaBridge.StoreAndForward/StoreAndForwardService.cs:99`, `:524` |
|
||||
|
||||
**Description**
|
||||
|
||||
@@ -1436,7 +1436,7 @@ normalisation is a no-op there.
|
||||
| Severity | Low |
|
||||
| Category | Concurrency & thread safety |
|
||||
| Status | Resolved |
|
||||
| Location | `src/ScadaLink.StoreAndForward/StoreAndForwardService.cs:122`–`:127`, `:136`–`:143`, `:303`–`:329` |
|
||||
| Location | `src/ZB.MOM.WW.ScadaBridge.StoreAndForward/StoreAndForwardService.cs:122`–`:127`, `:136`–`:143`, `:303`–`:329` |
|
||||
|
||||
**Resolution (2026-05-28):** the timer callback now captures the sweep task
|
||||
into a `_sweepTask` field via `Volatile.Write`, and `StopAsync` disposes the
|
||||
|
||||
Reference in New Issue
Block a user