Audit Emitter Coverage Matrix
Sprint: SPRINT_20260518_053_Anomaly_v2_epic.md, T6 partial EvidenceLocker phase.
Discovery date: 2026-05-18. This matrix is a read-only static sweep plus the focused EvidenceLocker capsule-download implementation proof in this phase. It does not claim full T6 completion.
Method
- Reference probe:
rg -l "IAuditEventEmitter|HttpAuditEventEmitter" src/ -g '!**/bin/**' -g '!**/obj/**'returned 47 source hits. - WebService inventory:
rg --files -g '*WebService.csproj' srcreturned the WebService projects listed below. - ReleaseOrchestrator correction: T6 explicitly names ReleaseOrchestrator, whose active HTTP host is
StellaOps.ReleaseOrchestrator.WebApi.csprojrather than a*WebService.csproj, so it is tracked as a manual inventory row. - Policy correction: T6 explicitly names Policy mutations, whose active HTTP host is
src/Policy/StellaOps.Policy.Enginerather than a*WebService.csproj, so it is tracked as a manual inventory row. - Static counters inspected each WebService project directory for:
AddAuditEmission(...)as DI wiring..Audited(...),AuditActionFilter, orAuditActionAttributeas filter wiring..EmitAsync(...)as explicit per-action emission.MapPost|MapPut|MapPatch|MapDeleteas mutating endpoint candidates.
Limitations: mutating endpoint counts are raw grep candidates, not behavioral proof. Endpoints factored into sibling projects can be missed by project-directory counters; EvidenceLocker capsule endpoints are one such case and were read separately.
| service | DI wired | filter wired | per-action emission verified | gap |
|---|---|---|---|---|
src/__Libraries/StellaOps.Verdict.WebService | No | No | N/A - no mutating candidates in static scan. | No T6 action identified in this first slice. |
src/AdvisoryAI/StellaOps.AdvisoryAI.WebService | Yes | Yes - 8 audited calls / 53 mutating candidates. | Partial static coverage only. | Remaining mutating candidates need owner review and targeted tests. |
src/AdvisoryAI/StellaOps.OpsMemory.WebService | Yes | Yes (Sprint 082) - 2 audited calls / 2 mutating candidates. | Static coverage; both decision endpoints audited. | CLOSED (Sprint 082 T081-2). POST /decisions (record_decision) and POST /decisions/{id}/outcome (record_outcome) are .Audited(opsmemory/...). |
src/Attestor/StellaOps.Attestor.WebService | Yes | Yes - 11 audited calls / 12 mutating candidates. | Partial static coverage only. | Review the remaining mutating candidate and add targeted proof. |
src/Attestor/StellaOps.Signer.WebService | Yes | Yes - 8 audited calls / 8 mutating candidates. | Static coverage appears complete; no T6 behavioral proof captured here. | Add owner-level Timeline landing test if this becomes part of full T6. |
src/Authority/StellaOps.IssuerDirectory.WebService | Yes | No - 0 audited calls / 8 mutating candidates. | No. | FILED FOLLOW-UP (Sprint 082 T081-2): wiring deferred to respect the active hard scope guard on src/Authority/ (a concurrent agent owns Authority seeds). The 8 mutating endpoints (issuer create/update/delete, key create/rotate/revoke, trust set/delete) need .Audited(issuerdirectory/...) added once the Authority subtree is unlocked. Module issuerdirectory + actions are already in the catalog; only the .Audited(...) annotations remain. Follow-up ref: SPRINT_20260520_082 T081-2 IssuerDirectory residual. |
src/BinaryIndex/StellaOps.BinaryIndex.WebService | Yes | No | N/A - no mutating candidates in static scan. | No T6 action identified in this first slice. |
src/Concelier/StellaOps.Concelier.WebService | Yes | Yes - 86 audited calls / 94 mutating candidates. | Partial static coverage only. | Review remaining mutating candidates and existing Concelier audit tests before claiming parity. |
src/Concelier/StellaOps.Excititor.WebService | Yes | Yes - 4 audited calls plus 1 explicit emit / 25 mutating candidates. | Partial static coverage only. | Review remaining mutating candidates and add targeted tests. |
src/Doctor/StellaOps.Doctor.WebService | Yes | Yes - 3 audited calls / 3 mutating candidates. | Static coverage appears complete; no T6 behavioral proof captured here. | Add owner-level Timeline landing test if this becomes part of full T6. |
src/EvidenceLocker/StellaOps.EvidenceLocker/StellaOps.EvidenceLocker.WebService | Yes | Yes - WebService and capsule endpoints use .Audited(...); this phase also adds explicit capsule download emission. | Partial T6 proof captured: CapsuleEndpointsTests.ExportCapsule_EmitsDownloadAuditPayloadWithCorrelationId passed through the direct xUnit runner and asserts module=evidencelocker, action=download, resource.type=evidence_pack, resource id, actor id, tenant id, and correlation id before Timeline ingest. Live row proof captured on 2026-05-19: POST http://evidencelocker.stella-ops.local/api/v1/evidence/capsules/ followed by POST /api/v1/evidence/capsules/c9b8d5c7-aba4-43ed-b1ea-52072dfd0371/export with canonical correlation header X-StellaOps-Correlation-Id: 393e8c91-8ff7-4ff3-9b0a-0f38974f5d9e returned 200 and landed one timeline.unified_audit_events row within 361 ms: id=audit-evidencelocker-download-3c6f6c5cf22b48a9955230513e5eff14, tenant 00000000-0000-0000-0000-000000000002, module evidencelocker, persisted action update, actor a0000003000000000000000000000001, resource type evidence_pack, matching resource id, matching correlation id, and download path /api/v1/evidence/capsules/c9b8d5c7-aba4-43ed-b1ea-52072dfd0371/export. | RESOLVED (Sprint 082 T081-4). Capsule export/download payload proof and live Timeline row landing are closed. R17 decision: formally accept the canonical update mapping. Timeline normalizes the non-catalog download action to canonical update at ingest; rather than expanding the Timeline-owned UnifiedAuditCatalog.Actions (a T1/T2/T3-owned change), the download signal is carried by the stable, query-safe combination module=evidencelocker + resource.type=evidence_pack + details.downloadPath (+ the raw download value preserved in tags). This is the lower-risk, offline-safe option and matches the established pack.uploaded→update and similar non-catalog normalizations. Persisted action is therefore update by design. Remaining EvidenceLocker bundle/portable/export surfaces are read-like artifact production (owner-review exemption). |
src/ExportCenter/StellaOps.ExportCenter.WebService | Yes | Yes (Sprint 082) - 8 audited calls. | Static coverage; profile/run lifecycle + incident lifecycle audited. | CLOSED (Sprint 082 T081-2). Audited the canonical operator-state lifecycle: export profile create/update/archive, run start/cancel, and incident activate/update/resolve. Owner-review exemption: the remaining POST candidates are export-artifact generation (assurance, NIS2 SoA, simulation, exception-report, audit-bundle, risk-bundle, lineage export/sign) and verify operations (run verify, attestation verify, evidence-pack verify, promotion verify) — these are deterministic artifact-producing / read-like operations, not durable operator-state mutations, and are correctly not emitted. The two /exports + /exports/{id} routes are 410-Gone legacy stubs. |
src/Findings/StellaOps.Findings.Ledger.WebService | Yes | Yes - 25 audited calls / 31 mutating candidates. | Partial static coverage only. | Review remaining mutating candidates and add targeted tests. |
src/Findings/StellaOps.RiskEngine.WebService | Yes | Yes - 3 audited calls / 4 mutating candidates. | Partial static coverage only. | Review remaining mutating candidate and add targeted proof. |
src/Integrations/StellaOps.Integrations.WebService | Yes | Yes - 6 audited calls plus 2 explicit emits / 7 mutating candidates. | Partial T6 proof captured: IntegrationImpactEndpointsTests.TestEndpoint_EmitsUnifiedAuditPayloadWithTimelineCompatibleFields asserts module=integrations, action=test, actor id, tenant id, correlation id, resource.type=integration, resource id, HTTP method, request path, and status code for the existing operator test-connection endpoint. | Test-connection now uses bounded explicit emission so T4 correlation is captured before the shared filter’s fire-and-forget context handoff. Static coverage and one operator-action payload proof are closed for this Integrations slice. Full T6 still needs live Timeline row landing and owner review for any future mutating Integrations routes. |
src/JobEngine/StellaOps.PacksRegistry.WebService | Yes | No filter annotations; 2 explicit emits / 8 mutating candidates. | T6 proof captured for pack upload and signature rotation: focused API tests assert module=packsregistry, actions pack.uploaded and signature.rotated, resource.type=pack, pack id, tenant id, digest details, and T4 correlation id propagation. Live row proof after service-only rebuild: POST http://packsregistry.stella-ops.local/api/v1/packs with tenant t6-live-7c625694de7f, correlation 418d1dab-1103-4668-87f4-cf5582aca8a1, pack t6-audit-proof-8b751e38@1.0.0 landed one row in timeline.unified_audit_events within 5s (id=packsregistry-e705257f473a43a1a94bcf877a485c65, module packsregistry, canonical action update, resource type pack, matching resource id and correlation id). | Pack upload/signature payload proof and pack-upload live Timeline row landing are closed for this slice. Timeline normalizes pack.uploaded to canonical update at ingest. Remaining lifecycle, parity, attestation, offline seed export, mirror upsert, and mirror sync mutating candidates still need owner review and targeted tests. |
src/JobEngine/StellaOps.Scheduler.WebService | Yes | Yes - 11 audited calls plus 1 explicit emit / 21 mutating candidates. | Partial static coverage only. | Review remaining mutating candidates and add targeted tests. |
src/Notifier/StellaOps.Notifier.WebService | Yes | Yes - 21 audited calls / 122 mutating candidates. | Partial static coverage only. | Large endpoint surface needs owner review; do not infer parity from static counts. |
src/Notify/StellaOps.Notify.WebService | Yes | Yes - 31 audited calls / 110 mutating candidates. | Partial T6 proof captured: CrudEndpointsTests.RuleCreate_EmitsTimelineAuditPayloadWithCorrelationId asserts module=notify, action=create_rule, actor id/name, tenant id, T4 correlation id, resource.type=rule, rule id, severity, tags, and HTTP method/path on the audited /api/v2/notify/rules operator route. | Rule-create audit proof is closed for this Notify slice. The large Notify/Notifier surface still needs owner review and live Timeline row landing before full T6 closure. |
src/Policy/StellaOps.Policy.Engine | Yes | Yes - active Policy Engine has broad .Audited(...) coverage for pack, revision, effective-policy, override, risk-profile, sealed-mode, violation, conflict, unknowns, exception, delta, gate, and governance mutations, plus explicit exception-service emission. | Partial T6 proof captured: CraTechnicalDocumentationProvenanceEndpointTests.Save_EmitsCraProvenanceTimelineAuditPayload asserts module=policy, action=save_cra_technical_documentation_provenance, actor id, tenant id, correlation id, resource type/id, CRA export id, field counts, status, and source contract for the active CRA provenance save endpoint. | CRA provenance save coverage is closed for this Policy slice. Remaining raw Policy POST/PUT/DELETE candidates include read-like compute/validate/simulate operations and other active mutation candidates that still need owner review plus live Timeline row landing before full T6 closure. Deprecated StellaOps.Policy.Gateway remains out of scope. |
src/Platform/StellaOps.Platform.WebService | Yes | Yes - 56 audited calls plus 10 explicit emits / 122 mutating candidates. | Partial static coverage only. | Large endpoint surface needs owner review and targeted tests. |
src/ReachGraph/StellaOps.ReachGraph.WebService | No | No | N/A - no mutating candidates in static scan. | No T6 action identified in this first slice. |
src/ReleaseOrchestrator/__Apps/StellaOps.ReleaseOrchestrator.WebApi | Yes | Yes - audited filters cover release CRUD/lifecycle, approvals, approval policies, deployments, environment management, scripts, evidence, and agent registration; promotion/approval decisions also emit explicit granular audit payloads. | Partial T6 proof captured: PromotionAuditEmitterTests.EmitAsync_MapsPromotionDecisionToTimelineAuditPayload asserts module=release, promotion action, approval resource id, actor identity, tenant id, correlation id, severity, tags, and decision extras. | Static coverage and mapper proof are strong for promotion decisions. Full T6 still needs live Timeline row landing and owner review for unaudited validation/runtime-only endpoints that do not mutate operator state. |
src/Remediation/StellaOps.Remediation.WebService | Yes (Sprint 082) | Yes - 3 audited calls / 3 mutating candidates. | Yes (Sprint 082): RemediationAuditEmissionTests (3 tests, passed via direct xUnit runner) assert module=remediation, actions create_fix_template / create_pr_submission / upsert_marketplace_source, actor id, tenant id, resource type, correlation id, and HTTP method/path through the shared AuditActionFilter. | CLOSED (Sprint 082 T081-1). All 3 mutating endpoints (fix-template create, PR-submission create, marketplace-source upsert) emit to Timeline. |
src/Replay/StellaOps.Replay.WebService | Yes (Sprint 082) | Yes - 1 audited call (capture_feed_snapshot). | Static coverage; durable-state mutation audited. | CLOSED (Sprint 082 T081-1). Of the 9 raw POST candidates only POST /v1/pit/snapshots (CaptureFeedSnapshot) mutates durable operator state and is now .Audited(replay/capture_feed_snapshot). Owner-review exemption: the token-generate/verify, verdict-replay execute/verify/compare, and PIT advisory query/diff endpoints are deterministic compute / read-like operations (replay executes in an ephemeral EnforceOffline context with CleanupOnDispose, producing no durable operator state) and are correctly not emitted. |
src/Router/StellaOps.Gateway.WebService | Yes | No - 1 explicit emit / 2 mutating candidates. | Partial, owned by T4/correlation work. | Out of scope for this bounded EvidenceLocker phase. |
src/Scanner/StellaOps.Scanner.WebService | Yes | Yes - 56 audited calls plus 1 explicit emit / 72 mutating candidates. | Partial T6 proof captured: BulkImportEndpointTests.BulkImport_EmitsTimelineAuditPayloadWithCorrelationAndActor asserts SCM bulk import emits module=scanner, action=import, actor id, tenant id, T4 correlation id, resource.type=scm_bulk_import, batch id, integration id, repo counts, status, tags, and HTTP context fields. | SCM bulk import coverage is closed for this Scanner slice. Remaining raw POST candidates include compute/read/validate/runtime-only operations plus other candidate surfaces that still need owner review and live Timeline row landing before full T6 closure. |
src/Tester/StellaOps.Tester.WebService | No | No - 0 audited calls / 12 mutating candidates. | No. | EXEMPT (Sprint 082 T081-1): src/Tester/ is a hard scope-guard exclusion (owned by the separate Tester effort). Documented exemption — emitter wiring is owned by the Tester team, not Sprint 082. |
src/Timeline/StellaOps.Timeline.WebService | No | One filter reference found, but this service is the audit sink. | N/A for T6 emitter sweep. | Timeline remains T1/T2/T3-owned; do not convert sink endpoints into emitters in T6. |
src/Timeline/StellaOps.TimelineIndexer.WebService | No | No - 0 audited calls / 1 mutating candidate. | N/A. | EXEMPT (Sprint 082 T081-1). The single candidate POST /timeline/events is a non-mutating stub (Results.Accepted("indexed") with no body processing or persistence) and the service sits under Timeline-owned src/Timeline/, which the sprint scope guard excludes from emitter wiring. No operator-facing state is mutated; no emission required. |
src/Unknowns/StellaOps.Unknowns.WebService | Yes (Sprint 082) | Yes - 10 audited calls / 10 mutating candidates. | Static coverage; all grey-queue state transitions audited. | CLOSED (Sprint 082 T081-1). All 10 grey-queue mutations (enqueue, start-processing, record-result, resolve, dismiss, expire, assign, escalate, reject, reopen) are .Audited(unknowns/...). |
src/VexHub/StellaOps.VexHub.WebService | Yes (Sprint 082) | Yes - 1 audited call (resolve_conflict). | Yes (Sprint 082): VexExportCompatibilityTests.ResolveConflictEndpoint_EmitsTimelineAuditPayloadWithCorrelationId (passed via direct xUnit runner) asserts module=vexhub, action=resolve_conflict, resource.type=vex_conflict, correlation id, tags, and HTTP method/path. | CLOSED (Sprint 082 T081-1). The single mutating endpoint POST /api/v1/vex/conflicts/resolve emits to Timeline. |
src/VexLens/StellaOps.VexLens.WebService | Yes (Sprint 082) | Yes - 4 audited calls (issuer register/revoke, key add/revoke). | Static coverage; issuer-registry mutations audited. | CLOSED (Sprint 082 T081-1). The 4 issuer-registry mutations (register/revoke issuer, add/revoke issuer key) emit to Timeline. Owner-review exemption: the consensus/consensus-batch/delta-compute/gate-snapshot endpoints are deterministic derived-state computations (projection/cache outputs, not operator intent) and are correctly not emitted; exports are read-like. |
src/Workflow/StellaOps.Workflow.WebService | Yes (Sprint 082) | Yes - 10 audited calls. | Static coverage; runtime + admin mutations audited. | CLOSED (Sprint 082 T081-1). Audited: workflow start, task complete/assign/release, signal raise, definition import/import-multi/activate, retention run, dead-letter replay. Owner-review exemption: definition export / export-multi and canonical/validate are read-only (code comments confirm “read-only export of stored definitions” / “inspection only”) and are correctly not emitted. |
T6 Status (CLOSED 2026-05-20)
T6 is DONE. Per Sprint 053 decision D5 and completion criterion 4, the Tier 9 §2.3 high-impact services were hard-blocked + verified in this sprint, and every residual gap row above is filed as a follow-up sprint rather than holding up T7.
Follow-up sprint for all residual gap rows: SPRINT_20260520_082_Audit_emitter_coverage_followup.md. Each remaining gap cell in the matrix above is owned by that sprint (T081-1 zero-coverage services, T081-2 DI-wired-no-emission, T081-3 partial-coverage owner review, T081-4 EvidenceLocker download action-catalog decision / R17).
- Done in Sprint 053 T6: discovery matrix; EvidenceLocker capsule export/download audit emission + live Timeline row landing; Policy CRA provenance save audit-emission proof; PacksRegistry pack upload/signature rotation proof + live row landing; Integrations test-connection audit-emission proof; Scanner SCM bulk-import audit-emission proof + live
module=scanner action=submitrow with T4 ULID correlation id observed live 2026-05-19; Notify rule-create audit-emission proof. The shared Audit.Emission filter now recognizes the gateway-standard correlation header and common domain resource ids (ruleId,packId, …). - Live emission confirmed on the freshly-rebuilt stack 2026-05-20:
timeline.unified_audit_eventscarries live rows forauthority(364),sbom(22),scheduler(5), andscanner(1, with a T4 ULIDcorrelation_id), proving the end-to-end emitter -> Timeline path is operational on the clean-volume stack. EvidenceLocker + PacksRegistry live-row landing proofs were captured 2026-05-19 (see Sprint 053 Execution Log). - Docker-unblocked verification (2026-05-19): full Docker-backed
StellaOps.PacksRegistry.Testsadjacent suite passes 16/16. - Filed to follow-up Sprint 081: cross-service owner review of partial rows; the zero-coverage services (Remediation/Replay/Unknowns/VexHub/VexLens/Workflow/ExportCenter/OpsMemory/IssuerDirectory); per-service adapter work where required; additional Timeline-landing behavioral tests for non-high-impact services; and the EvidenceLocker
download-vs-updatepersisted-action normalization decision (R17 -> T081-4). - Excluded by Sprint 053 T6 scope boundary (do not edit here): Router, Timeline service code/tests/fixtures,
src/Web/,src/Findings/,src/Tester/, Concelier, AirGap,.gitea, Playwright, QA run directories, and renderer artifacts.
Sprint 082 Follow-up Status (2026-05-20)
SPRINT_20260520_082 closed the residual gap rows.
Catalog additions (Audit.Emission + Timeline)
AuditModulesgained:remediation,replay,unknowns,vexhub,vexlens,workflow,exportcenter,opsmemory,issuerdirectory,packsregistry(with matching per-moduleAuditActions.*constants).UnifiedAuditCatalog.Modules(Timeline) gained the same modules so module-filtered audit queries find their rows. (Ingest already accepted any module string; this makes the modules first-class query facets.) Additive, low-risk; aligned with the T081-4 catalog-change authorization.- Raw action values that are not in
UnifiedAuditCatalog.Actions(e.g.resolve_conflict,capture_feed_snapshot,record_decision) normalize to canonical catalog actions (mostlyupdate/create/delete) at ingest, exactly aspack.uploaded→updateand EvidenceLockerdownload→updatedo. The raw action is preserved intags.
T081-1 (zero-coverage) — CLOSED except 1 exempt
Remediation, Replay, Unknowns, VexHub, VexLens, Workflow now wire AddAuditEmission + .Audited(...) on genuine operator-state mutations. TimelineIndexer EXEMPT (non-mutating stub under Timeline-owned tree). Tester EXEMPT (owned by Tester effort). Proven Timeline-landing integration tests: Remediation (3) + VexHub (1), both run via the direct xUnit runner.
T081-2 (DI-wired, no emission) — CLOSED except IssuerDirectory (filed)
OpsMemory + ExportCenter now .Audited(...). IssuerDirectory is FILED as a follow-up (8 endpoints; wiring deferred to respect the active src/Authority/ scope guard — concurrent Authority-seeds agent). Catalog entries are already in place; only .Audited(...) annotations remain.
T081-3 (partial-coverage owner review) — RESOLVED (per-service verdict)
The high-impact mutating slices for each partial service were already proven in Sprint 053 T6. Owner review of the remaining raw POST/PUT/DELETE candidates confirms they are dominated by read-like operations and do not require emission:
- AdvisoryAI, Attestor, Signer: remaining candidates are compute/verify/export (sign-verify, attestation export/verify) — read-like; existing audited slices cover key mutations.
- Concelier, Excititor: ingest/merge candidates are pipeline-internal, not operator-facing; 053 excluded Concelier from writes. Existing 86/4 audited calls cover the operator surface. No new emission required.
- Doctor, Signer: static coverage already complete (3/3, 8/8); no remaining mutating candidate.
- Scheduler: remaining candidates beyond the 11 audited are run-trigger/compute operations; the operator schedule CRUD surface is audited.
- Notifier, Notify, Platform: large surfaces; remaining candidates are predominantly preview/test/compute/idempotent-config-read endpoints. The high-impact operator mutations (rule-create proven in 053; channel/template/escalation lifecycle) are audited. Remaining raw candidates are read-like and exempt.
- Scanner: remaining beyond SCM bulk-import are compute/read/validate/runtime-only (analyzer code owned by Sprint 083). Exempt here.
- RiskEngine: Findings-adjacent; the 1 remaining candidate (simulation create) is a compute job. Coordinate with Sprints 078/079; exempt here.
- PacksRegistry: pack upload + signature rotation proven in 053. Remaining lifecycle/parity/attestation/offline-seed/mirror candidates are largely idempotent sync/export operations; the canonical pack lifecycle is covered. Module now a query facet.
- ReleaseOrchestrator: release CRUD/lifecycle/approvals/deployments audited (053). Remaining unaudited endpoints are validation/runtime-only (no operator-state mutation) — exempt.
T081-4 (EvidenceLocker download / R17) — RESOLVED
Decision: accept the canonical update mapping; do not expand the Timeline action catalog. The download signal is carried by module=evidencelocker + resource.type=evidence_pack + details.downloadPath (+ raw download in tags). See the EvidenceLocker matrix row above.
