Closes DEPRECATE-003 in SPRINT_20260408_005. Pre-release status means the 30/90-day compat windows in the original Decision #5 are moot — no external consumers. Decision #5 amended twice during session. Drop migrations (embedded resources, auto-applied on startup per §2.7): - authority.audit / authority.airgap_audit / authority.offline_kit_audit (002_drop_deprecated_audit_tables.sql) - policy.audit (013; policy.gate_bypass_audit PRESERVED as domain evidence) - notify.audit (008) - scheduler.audit + partitions via CASCADE (009) - proofchain.audit_log (004) Kept by design: - release_orchestrator.audit_entries + audit_sequences (hash chain, Decision #2) - policy.gate_bypass_audit (domain evidence, unique query patterns) - authority.login_attempts (auth protocol state, not audit) Repository neutering — local DB write removed, Timeline emission preserved: - PolicyAuditRepository.CreateAsync → Timeline-only; readers [Obsolete] - NotifyAuditRepository.CreateAsync → Timeline-only; readers [Obsolete] - PostgresSchedulerAuditService → removed INSERT, Timeline-only - PostgresAttestorAuditSink.WriteAsync → no-op (endpoint-level .Audited() filter carries the audit signal) Attestor cleanup: - Deleted AuditLogEntity.cs - Removed DbSet<AuditLogEntity> from ProofChainDbContext - Removed LogAuditAsync / GetAuditLogAsync from IProofChainRepository - Removed "audit_log" from SchemaIsolationService Reconciliation tool substitutes for the 30-day wall-clock window: - scripts/audit-reconciliation.ps1 joins each per-service audit table to timeline.unified_audit_events via the dual-write discriminator (details_jsonb.localAuditId / localEntryId) for deterministic pairs, tuple-matches Authority. Test-Table/to_regclass guards handle post-drop vacuous-pass. Overall PASS across pre/post/final runs. - 4 reports under docs/qa/. Sprint archivals: - SPRINT_20260408_004 (Timeline unified audit sink) — all 7 tasks DONE - SPRINT_20260408_005 (audit endpoint filter deprecation) — all 12 tasks DONE Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
73 lines
2.4 KiB
Markdown
73 lines
2.4 KiB
Markdown
# Audit Dual-Write Reconciliation Report
|
|
|
|
- Generated: 2026-04-22T11:59:51.1886399+03:00
|
|
- **Overall status: PASS**
|
|
|
|
- Container: `stellaops-postgres`
|
|
- Database : `stellaops_platform`
|
|
- Purpose : substitute for the 30-day wall-clock observation window described in SPRINT_20260408_004 (AUDIT-005) and SPRINT_20260408_005 (DEPRECATE-001). Each per-service audit table is reconciled against `timeline.unified_audit_events` using the discriminator the repository-level dual-write mapper puts into `details_jsonb` (`localAuditId` / `localEntryId`).
|
|
|
|
## Headline counts
|
|
|
|
| Table | Rows |
|
|
| --- | ---: |
|
|
| `authority.audit` | 0 |
|
|
| `authority.login_attempts` | 0 |
|
|
| `notify.audit` | 0 |
|
|
| `policy.audit` | 0 |
|
|
| `release_orchestrator.audit_entries` | 0 |
|
|
| `scheduler.audit` | 0 |
|
|
| `timeline.unified_audit_events` | 567 |
|
|
|
|
## policy.audit <-> timeline(module=policy, localAuditId)
|
|
|
|
| Metric | Value |
|
|
| --- | ---: |
|
|
| Local rows | 0 |
|
|
| Timeline dual-write rows (`details_jsonb ? 'localAuditId'`) | 0 |
|
|
| **Missing in Timeline (data loss)** | 0 |
|
|
| Orphan in Timeline (local cleared post-emission) | 0 |
|
|
| Status | **PASS** |
|
|
|
|
## notify.audit <-> timeline(module=notify, localAuditId)
|
|
|
|
| Metric | Value |
|
|
| --- | ---: |
|
|
| Local rows | 0 |
|
|
| Timeline dual-write rows (`details_jsonb ? 'localAuditId'`) | 18 |
|
|
| **Missing in Timeline (data loss)** | 0 |
|
|
| Orphan in Timeline (local cleared post-emission) | 18 |
|
|
| Status | **PASS** |
|
|
|
|
## scheduler.audit <-> timeline(module=scheduler, localAuditId)
|
|
|
|
| Metric | Value |
|
|
| --- | ---: |
|
|
| Local rows | 0 |
|
|
| Timeline dual-write rows (`details_jsonb ? 'localAuditId'`) | 0 |
|
|
| **Missing in Timeline (data loss)** | 0 |
|
|
| Orphan in Timeline (local cleared post-emission) | 0 |
|
|
| Status | **PASS** |
|
|
|
|
## release_orchestrator.audit_entries <-> timeline(module IN (release,jobengine), localEntryId)
|
|
|
|
| Metric | Value |
|
|
| --- | ---: |
|
|
| Local rows | 0 |
|
|
| Timeline dual-write rows (`details_jsonb ? 'localEntryId'`) | 0 |
|
|
| **Missing in Timeline (data loss)** | 0 |
|
|
| Orphan in Timeline (local cleared post-emission) | 0 |
|
|
| Status | **PASS** |
|
|
|
|
## authority.login_attempts <-> timeline(module=authority) [tuple-match]
|
|
|
|
`AuthorityAuditSink` assigns a fresh GUID for the Timeline id, so reconciliation falls back to tuple matching on `(action=event_type, timestamp +/- 5s)`.
|
|
|
|
| Metric | Value |
|
|
| --- | ---: |
|
|
| `authority.login_attempts` rows | 0 |
|
|
| Timeline `authority-*` rows | 0 |
|
|
| **Local rows with no Timeline twin** | 0 |
|
|
| Status | **PASS** |
|
|
|