1. Request headers in Extra JSON (AuditWriteMiddleware): adds a `requestHeaders`
object to the existing Extra JSON alongside remoteIp/userAgent; headers whose
names appear in AuditLogOptions.HeaderRedactList (Authorization, X-Api-Key,
Cookie, Set-Cookie by default) are replaced with "<redacted>" using
OrdinalIgnoreCase matching — same policy as ScadaBridgeAuditRedactor.
2. AuditInboundCeilingHits counter: new IAuditInboundCeilingHitsCounter interface
+ NoOpAuditInboundCeilingHitsCounter default; AuditCentralHealthSnapshot
implements the interface (Interlocked field, thread-safe) and exposes
AuditInboundCeilingHits on IAuditCentralHealthSnapshot; AddAuditLog registers
the NoOp default, AddAuditLogCentralMaintenance forwards to the snapshot;
AuditWriteMiddleware accepts the counter as an optional ctor arg and increments
it once per request where either the request or response body hit the cap.
3. Per-method SkipBodyCapture opt-out: adds SkipBodyCapture bool to
PerTargetRedactionOverride; AuditWriteMiddleware consults the per-target
override map at the start of InvokeAsync (before EnableBuffering) and, when
set, skips body read + capture entirely — the audit row still emits with
headers/metadata but null RequestSummary/ResponseSummary; truncation flags
are also cleared so the ceiling-hits counter is not bumped for opted-out methods.
Site Call Audit (#22): build the documented periodic reconciliation PULL
self-heal path for the eventually-consistent central SiteCalls mirror, as a
dedicated PullSiteCalls gRPC RPC kept separate from the audit pull. This is the
pull PLUMBING only; the central reconciliation tick is a separate follow-up.
- IOperationTrackingStore.ReadChangedSinceAsync(sinceUtc, batchSize): inclusive
UpdatedAtUtc cursor, oldest-first, batch-capped; SQLite impl projects tracking
rows onto SiteCallOperational (Kind->Channel, TargetSummary->Target, SourceSite
left empty - the store has no site-id column).
- sitestream.proto: rpc PullSiteCalls + PullSiteCallsRequest/Response, mirroring
PullAuditEvents; regenerated checked-in SiteStreamGrpc/*.cs.
- SiteCallDtoMapper.ToDto(SiteCallOperational): inverse of FromDto for the handler.
- SiteStreamGrpcServer.PullSiteCalls handler + SetOperationTrackingStore seam;
Host wires the seam alongside SetSiteAuditQueue (site roles only).
- Central IPullSiteCallsClient + GrpcPullSiteCallsClient (home: AuditLog/Central to
reuse ISiteEnumerator; SiteCallAudit does not reference AuditLog). Re-stamps
SourceSite from the dialed siteId; no-throw on tolerable transport faults;
SpecifyKind (not ToUniversalTime) cursor handling. Central-only DI registration.
Tests: ReadChangedSinceAsync (4), PullSiteCalls handler (6), GrpcPullSiteCallsClient
(8). Full solution build 0 warnings/0 errors (TreatWarningsAsErrors).