Implements Spec 117 (Golden Master Baseline Drift Engine): - Adds provider-chain resolver for current state hashes (content evidence via PolicyVersion, meta evidence via inventory) - Updates baseline capture + compare jobs to use resolver and persist provenance + fidelity - Adds evidence_fidelity column/index + Filament UI badge/filter/provenance display for findings - Adds performance guard test + integration tests for drift, fidelity semantics, provenance, filter behavior - UX fix: Policies list shows "Sync from Intune" header action only when records exist; empty-state CTA remains and is functional Tests: - `vendor/bin/sail artisan test --compact tests/Feature/Filament/PolicySyncCtaPlacementTest.php` - `vendor/bin/sail artisan test --compact --filter=Baseline` Checklist: - specs/117-baseline-drift-engine/checklists/requirements.md ✓ Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #142
3.9 KiB
Research — Spec 117 Baseline Drift Engine (v1.5)
This document resolves planning unknowns for implementing specs/117-baseline-drift-engine/spec.md in the existing Laravel + Filament codebase.
Decision 1 — Provider chain for evidence
Decision: Implement a batch-capable resolver (service) that selects evidence per subject via a provider chain:
- Content evidence:
PolicyVersion.snapshot(normalized) captured since baseline snapshot captured time. - Meta evidence: Inventory meta contract hash (existing
BaselineSnapshotIdentity::hashItemContent(...)). - No evidence: return
nulland record evidence gap (no finding emitted).
Rationale:
- Matches spec’s “since” rule: baseline snapshot
captured_atis the temporal reference. - Enables v1.5 requirement: compare is read-only and must not fetch upstream.
- Batch resolution avoids N+1 DB queries.
Alternatives considered:
- Per-subject resolving inside compare job (rejected: N+1 + harder to test).
- Always meta-only (rejected: violates “deep settings drift” requirement).
Decision 2 — Fidelity calculation
Decision: Compute finding fidelity as the weaker-of the two sides:
contentis stronger thanmeta.- If either side is
meta, overall fidelity ismeta.
Rationale:
- Matches clarified spec rule.
- Easy to implement and consistent with UX badge/filter semantics.
Alternatives considered:
- “best-of” fidelity (rejected: misleading; would claim content-level confidence when one side is meta-only).
Decision 3 — Provenance storage (both sides)
Decision: Store provenance for both baseline and current evidence on each finding:
baseline:{ fidelity, source, observed_at, observed_operation_run_id? }current:{ fidelity, source, observed_at, observed_operation_run_id? }
Rationale:
- Required by accepted clarification (Q4).
- Enables UI to show the “why” behind confidence.
Alternatives considered:
- Store a single combined provenance blob (rejected: loses per-side data).
Decision 4 — Fidelity filter implementation (JSONB vs column)
Decision: Add a dedicated findings.evidence_fidelity column (enum-like string: content|meta) and keep full provenance in evidence_jsonb.
Rationale:
- Filtering on a simple indexed column is clean, fast, and predictable.
- Avoids complex JSONB query conditions and reduces coupling to evidence JSON structure.
Alternatives considered:
- JSONB filter over
evidence_jsonb->>'fidelity'(rejected: harder indexing, more brittle).
Decision 5 — Coverage and evidence-gap reporting location
Decision: Put coverage breakdown and evidence-gap counts in operation_runs.context under baseline_compare.coverage and baseline_compare.evidence_gaps.
Rationale:
OperationRun.summary_countsis restricted to numeric keys fromOperationSummaryKeys.- Coverage details are operational diagnostics, not a general-purpose KPI.
Alternatives considered:
- Add new summary keys (rejected: violates key whitelist / contract).
Decision 6 — No new HTTP APIs
Decision: No new controllers/endpoints. Changes are:
- queued job behavior + persistence (findings + run context)
- Filament UI (Finding list filters + columns/details)
Rationale:
- The app is Filament-first; current functionality is already represented by panel routes.
Alternatives considered:
- Add REST endpoints for compare (rejected: not needed for v1.5).
Notes on current codebase (facts observed)
- Baseline capture stores meta contract hash into
baseline_snapshot_items.baseline_hashand provenance-like fields inmeta_jsonb. - Baseline compare recomputes current meta hash and currently hardcodes run context fidelity to
meta. - Findings UI lacks fidelity filtering today.
Open Questions
None blocking Phase 1 design. Any remaining unknowns are implementation details that will be validated with focused tests.