docs(auditlog): mark follow-ups complete in roadmap; refresh stale comments
This commit is contained in:
@@ -11,12 +11,17 @@
|
|||||||
>
|
>
|
||||||
> **Deferred to v1.x (out of scope, intentionally not implemented):** hash-chain tamper
|
> **Deferred to v1.x (out of scope, intentionally not implemented):** hash-chain tamper
|
||||||
> evidence (`audit verify-chain` ships as a no-op stub), Parquet export (`format=parquet`
|
> evidence (`audit verify-chain` ships as a no-op stub), Parquet export (`format=parquet`
|
||||||
> returns HTTP 501), per-channel retention overrides. **Deferred follow-ups noted during
|
> returns HTTP 501), per-channel retention overrides. **Follow-ups noted during
|
||||||
> implementation:** the real site→central gRPC push client (M6 wired the pull RPC + a mockable
|
> implementation — now complete:** the five follow-ups deferred above (the real
|
||||||
> push seam; `NoOpSiteStreamAuditClient` remains the production binding); consolidation of the
|
> site→central push client; consolidation of the 4 DTO mapper copies; the Site Calls UI
|
||||||
> 4 DTO mapper copies; Site Calls UI page + its Audit drill-in; multi-value filter dimensions
|
> page + its Audit drill-in; multi-value filter dimensions; audit-results-grid drag
|
||||||
> (`AuditLogQueryFilter` is single-value per dimension, so UI chips / CLI flags collapse to the
|
> resize/reorder UX) were all implemented on the `feature/audit-log-followups` branch
|
||||||
> first value); audit-results-grid drag resize/reorder UX.
|
> per `docs/plans/2026-05-21-audit-log-followups.md`. The site→central transport shipped
|
||||||
|
> as a **ClusterClient-based push** (`ClusterClientSiteAuditClient`, reusing the same
|
||||||
|
> ClusterClient command/control transport notifications use) rather than the gRPC push
|
||||||
|
> originally sketched here — `ClusterClientSiteAuditClient` is now the production binding
|
||||||
|
> for site roles, with `NoOpSiteStreamAuditClient` retained only for central/test
|
||||||
|
> composition roots; and `AuditLogQueryFilter` is now multi-value per dimension.
|
||||||
>
|
>
|
||||||
> **For Claude:** REQUIRED SUB-SKILL FLOW per milestone: `brainstorming` → `writing-plans` → `subagent-driven-development`. Use `docs/requirements/Component-AuditLog.md` + `alog.md` as the spec; this document is the roadmap that sequences milestones and locks acceptance criteria for each. **M1 carries full TDD-level task detail; M2–M8 are milestone-shape detail and will be expanded into bite-sized plans by their own writing-plans pass when their turn comes.**
|
> **For Claude:** REQUIRED SUB-SKILL FLOW per milestone: `brainstorming` → `writing-plans` → `subagent-driven-development`. Use `docs/requirements/Component-AuditLog.md` + `alog.md` as the spec; this document is the roadmap that sequences milestones and locks acceptance criteria for each. **M1 carries full TDD-level task detail; M2–M8 are milestone-shape detail and will be expanded into bite-sized plans by their own writing-plans pass when their turn comes.**
|
||||||
|
|
||||||
|
|||||||
@@ -34,15 +34,17 @@ namespace ScadaLink.AuditLog.Site.Telemetry;
|
|||||||
/// returns normally.
|
/// returns normally.
|
||||||
/// </para>
|
/// </para>
|
||||||
/// <para>
|
/// <para>
|
||||||
/// <b>Wire push deferred to M6.</b> M3 keeps this forwarder synchronous
|
/// <b>Local-write only — the wire push is the drain actor's job.</b> This
|
||||||
/// against the local stores: there is no site→central gRPC channel yet, so
|
/// forwarder is deliberately synchronous against the two site-local SQLite
|
||||||
/// the <see cref="ISiteStreamAuditClient.IngestCachedTelemetryAsync"/> RPC
|
/// stores and never pushes to central itself. The site→central transport is
|
||||||
/// is registered on the interface (Bundle E1) but the production binding
|
/// now live: <c>ClusterClientSiteAuditClient</c> is the production binding of
|
||||||
/// remains <c>NoOpSiteStreamAuditClient</c>. Once M6 wires a real client the
|
/// <see cref="ISiteStreamAuditClient"/> on site roles (with
|
||||||
/// drain pattern from <c>SiteAuditTelemetryActor</c> can be reused — the
|
/// <c>NoOpSiteStreamAuditClient</c> retained only for central/test composition
|
||||||
/// <c>AuditEvent</c> rows already live in SQLite tagged
|
/// roots). The push happens out-of-band: <see cref="SiteAuditTelemetryActor"/>
|
||||||
/// <see cref="AuditForwardState.Pending"/>, so a single drain loop sweeps
|
/// sweeps the <c>AuditEvent</c> rows this forwarder wrote — they live in SQLite
|
||||||
/// both M2 and M3 emissions.
|
/// tagged <see cref="AuditForwardState.Pending"/> — and drains them to central
|
||||||
|
/// via that client. A single drain loop therefore covers both the audit-only
|
||||||
|
/// emissions and the cached-call emissions this forwarder produces.
|
||||||
/// </para>
|
/// </para>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public sealed class CachedCallTelemetryForwarder : ICachedCallTelemetryForwarder
|
public sealed class CachedCallTelemetryForwarder : ICachedCallTelemetryForwarder
|
||||||
|
|||||||
@@ -355,6 +355,14 @@ public class CommunicationService
|
|||||||
/// owning site and replies a <see cref="RetrySiteCallResponse"/> carrying a
|
/// owning site and replies a <see cref="RetrySiteCallResponse"/> carrying a
|
||||||
/// distinct site-unreachable outcome. Central never mutates the central
|
/// distinct site-unreachable outcome. Central never mutates the central
|
||||||
/// <c>SiteCalls</c> mirror row.
|
/// <c>SiteCalls</c> mirror row.
|
||||||
|
/// <para>
|
||||||
|
/// This outer Ask uses <see cref="CommunicationOptions.QueryTimeout"/>
|
||||||
|
/// (default 30s), which must outlive the inner site relay Ask the
|
||||||
|
/// <c>SiteCallAuditActor</c> issues with <c>SiteCallAuditOptions.RelayTimeout</c>
|
||||||
|
/// (default 10s). The inner relay must time out first so its distinct
|
||||||
|
/// <c>SiteUnreachable</c> outcome reaches us; were this outer Ask to expire
|
||||||
|
/// first, that outcome would be lost to a generic Ask-timeout exception.
|
||||||
|
/// </para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public async Task<RetrySiteCallResponse> RetrySiteCallAsync(
|
public async Task<RetrySiteCallResponse> RetrySiteCallAsync(
|
||||||
RetrySiteCallRequest request, CancellationToken cancellationToken = default)
|
RetrySiteCallRequest request, CancellationToken cancellationToken = default)
|
||||||
|
|||||||
@@ -681,9 +681,10 @@ akka {{
|
|||||||
// Per Bundle E's brief: the SiteAuditTelemetryActor takes its
|
// Per Bundle E's brief: the SiteAuditTelemetryActor takes its
|
||||||
// collaborators through its constructor, so we resolve them from DI
|
// collaborators through its constructor, so we resolve them from DI
|
||||||
// and pass them in via Props.Create rather than relying on a future
|
// and pass them in via Props.Create rather than relying on a future
|
||||||
// FactoryProvider. This also lets the M6 follow-up swap the
|
// FactoryProvider. The real site→central client is constructed and
|
||||||
// NoOpSiteStreamAuditClient registration for the real gRPC client
|
// wired immediately below: a ClusterClientSiteAuditClient (ClusterClient
|
||||||
// without touching this site wiring.
|
// transport, not gRPC) replaces the DI-default NoOpSiteStreamAuditClient
|
||||||
|
// for site roles, without disturbing the rest of this wiring.
|
||||||
var siteAuditOptions = _serviceProvider
|
var siteAuditOptions = _serviceProvider
|
||||||
.GetRequiredService<IOptions<ScadaLink.AuditLog.Site.Telemetry.SiteAuditTelemetryOptions>>();
|
.GetRequiredService<IOptions<ScadaLink.AuditLog.Site.Telemetry.SiteAuditTelemetryOptions>>();
|
||||||
var siteAuditQueue = _serviceProvider
|
var siteAuditQueue = _serviceProvider
|
||||||
|
|||||||
@@ -32,6 +32,16 @@ public class SiteCallAuditOptions
|
|||||||
/// reports a <c>SiteUnreachable</c> outcome. Default 10 seconds: long enough
|
/// reports a <c>SiteUnreachable</c> outcome. Default 10 seconds: long enough
|
||||||
/// to absorb a healthy cross-cluster round-trip, short enough that an
|
/// to absorb a healthy cross-cluster round-trip, short enough that an
|
||||||
/// operator clicking Retry on an offline site gets a fast, honest answer.
|
/// operator clicking Retry on an offline site gets a fast, honest answer.
|
||||||
|
/// <para>
|
||||||
|
/// <b>Ordering invariant:</b> <c>RelayTimeout</c> must stay below
|
||||||
|
/// <c>CommunicationOptions.QueryTimeout</c> (default 30s), the timeout the
|
||||||
|
/// outer <c>CommunicationService.RetrySiteCallAsync</c>/<c>DiscardSiteCallAsync</c>
|
||||||
|
/// Ask of the <c>SiteCallAuditActor</c> uses. The outer Ask must outlive this
|
||||||
|
/// inner site relay Ask so the inner relay times out first and yields the
|
||||||
|
/// distinct <c>SiteUnreachable</c> outcome; if the outer Ask expired first,
|
||||||
|
/// that outcome would be lost to a generic Ask-timeout exception. The
|
||||||
|
/// defaults (10s < 30s) satisfy this — keep the gap when tuning either.
|
||||||
|
/// </para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public TimeSpan RelayTimeout { get; set; } = TimeSpan.FromSeconds(10);
|
public TimeSpan RelayTimeout { get; set; } = TimeSpan.FromSeconds(10);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user