docs(audit): roadmap corrections after M2
M3 head now records M2 realities: - enum vocabulary (M1-aligned) drives CachedSubmit/ApiCallCached/etc. - NoOpSiteStreamAuditClient stays until M6; M3 e2e tests reuse Bundle H's DirectActorSiteStreamAuditClient (extract to Integration/Infrastructure/). - Mapper duplication note (gRPC handler inlines DTO->entity decoding; consider moving AuditEventMapper to Commons in M3). - AuditIngestAskTimeout=30s hardcoded; M3 may expose via options. - CachedCallTelemetry message MUST be created from scratch (additive per Commons REQ-COM-5a; never renamed CachedOperationTelemetry). - Central dual-write AuditLog + SiteCalls in one tx; reuse Bundle A duplicate-key swallow pattern for CachedCallId.
This commit is contained in:
@@ -447,7 +447,16 @@ The design for both is merged on `main` (`alog.md` cached-call tracking section;
|
|||||||
|
|
||||||
## M3 — Cached operations + dual-write transaction + (inlined) Site Call Audit foundations
|
## M3 — Cached operations + dual-write transaction + (inlined) Site Call Audit foundations
|
||||||
|
|
||||||
**Goal:** Cached external calls (`ExternalSystem.CachedCall`) and cached DB writes (`Database.CachedWrite`) produce three audit rows per operation (`CachedEnqueued`, `CachedAttempt × N`, `CachedTerminal`) AND populate the operational `SiteCalls` table at central — in one transaction at central, from a single combined telemetry packet.
|
**Goal:** Cached external calls (`ExternalSystem.CachedCall`) and cached DB writes (`Database.CachedWrite`) produce four audit rows per operation (`Kind=CachedSubmit Status=Submitted`, `Kind=ApiCallCached/DbWriteCached Status=Forwarded`, `Kind=ApiCallCached/DbWriteCached Status=Attempted` × N, `Kind=CachedResolve Status=Delivered|Failed|Parked|Discarded`) AND populate the operational `SiteCalls` table at central — in one transaction at central, from a single combined telemetry packet.
|
||||||
|
|
||||||
|
> **M2 realities to honor:**
|
||||||
|
> - **Vocabulary**: use the M1-aligned enums. M3 will be the first code to populate `AuditKind.ApiCallCached`, `DbWriteCached`, `CachedSubmit`, `CachedResolve`. The locked spec (alog.md + Component-AuditLog.md) was reconciled in the M1 merge.
|
||||||
|
> - **Site→central gRPC client deferred to M6**: M2 ships `NoOpSiteStreamAuditClient` as the production default. Site SQLite rows accumulate as `Pending` forever in production until M6. M3 component tests should use Bundle H's `DirectActorSiteStreamAuditClient` pattern (see `tests/ScadaLink.AuditLog.Tests/Integration/SyncCallEmissionEndToEndTests.cs:277-340`). Extract that helper into `tests/ScadaLink.AuditLog.Tests/Integration/Infrastructure/` so M3 cached-call E2E tests can reuse it without re-defining.
|
||||||
|
> - **Mapper duplication**: `SiteStreamGrpcServer.IngestAuditEvents` inlines DTO→entity decoding (intentional, to avoid the AuditLog→Communication project-ref cycle). The mapper lives at `src/ScadaLink.AuditLog/Telemetry/AuditEventMapper.cs`. M3 should add a comment in both spots tying them together, OR move the mapper into `src/ScadaLink.Commons/` (project-ref clean) so both consumers can share it.
|
||||||
|
> - **`AuditIngestAskTimeout = 30s` is hardcoded** in `SiteStreamGrpcServer.cs:37`. M3 may want to expose this via `CommunicationOptions` or `AuditLogOptions` as central reconciliation/dual-write traffic grows.
|
||||||
|
> - **CachedCallTelemetry message**: per CLAUDE.md, the existing `CachedCallTelemetry` message **does not yet exist in code**. M3 must create it from scratch (additively, per Commons REQ-COM-5a — DO NOT rename it `CachedOperationTelemetry`). It carries BOTH the AuditLog rows (4+) AND the SiteCalls upsert in one packet.
|
||||||
|
> - **Dual-write transaction**: central writes `AuditLog` + `SiteCalls` in one MS SQL transaction. The repository's `InsertIfNotExistsAsync` swallows duplicates (M2 Bundle A fix); the SiteCalls upsert uses `MERGE` (or insert-if-not-exists then upsert-on-newer-status per CLAUDE.md). M3 must ensure the same Bundle A swallow pattern applies if duplicate `CachedCallId` arrives.
|
||||||
|
> - **AuditEvent ForwardState semantics in M3**: cached-operation telemetry rows are site-emitted just like sync M2 rows, so the same site SQLite hot-path + `Pending→Forwarded` lifecycle applies. The four lifecycle rows share a CorrelationId (the TrackedOperationId), but each is its own AuditEvent with a distinct EventId.
|
||||||
|
|
||||||
**Affected projects:** `Commons`, `AuditLog`, `SiteCallAudit` (new — minimum-viable surface), `ConfigurationDatabase` (new `SiteCalls` table migration), `ExternalSystemGateway`, `StoreAndForward`, `Host`. Tests across all of them + IntegrationTests.
|
**Affected projects:** `Commons`, `AuditLog`, `SiteCallAudit` (new — minimum-viable surface), `ConfigurationDatabase` (new `SiteCalls` table migration), `ExternalSystemGateway`, `StoreAndForward`, `Host`. Tests across all of them + IntegrationTests.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user