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
6.5 KiB
Implementation Plan: Golden Master Baseline Drift — Deep Settings Drift via Provider Chain
Branch: 117-baseline-drift-engine | Date: 2026-03-02 | Spec: specs/117-baseline-drift-engine/spec.md
Summary
Implement a single, batch-oriented “current state hash resolver” for Golden Master baseline capture + compare.
- For each tenant subject, resolve best available evidence via provider chain (content via
PolicyVersionsince baseline snapshot captured time; else meta via Inventory meta contract). - Compare baseline snapshot item hash vs current resolved hash to emit drift findings.
- Findings store + display baseline and current evidence provenance (fidelity, source, observed timestamp for each side) and add a fidelity badge + filter.
- Compare remains read-only (no new external calls during compare) and continues to run via
OperationRun.
Technical Context
Language/Version: PHP 8.4 (Laravel 12)
Primary Dependencies: Filament v5, Livewire v4, Pest v4
Storage: PostgreSQL (Sail)
Testing: Pest (vendor/bin/sail artisan test --compact)
Target Platform: Docker containers (Laravel Sail)
Project Type: Web application (Laravel + Filament)
Performance Goals: Baseline scope ~500 subjects resolves + compares within ~2 minutes (staging target from spec)
Constraints:
- v1.5 compare MUST NOT initiate any upstream/Graph calls; DB-only + existing stored evidence only.
- Batch resolution (no per-subject query loops; chunk + set-based queries).
- Baseline snapshot items MUST NOT persist tenant identifiers. Scale/Scope: Per-run: 0–500+ subjects; per-tenant: multiple policy types; mixed evidence fidelity expected.
Constitution Check
GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.
- Inventory-first: PASS — “meta evidence” comes from
inventory_items(last observed); snapshot items remain immutable standards. - Read/write separation: PASS — compare/capture are operational runs; no new write surfaces; findings are operational artifacts.
- Graph contract path: PASS — v1.5 compare uses only local DB evidence (no Graph calls).
- Deterministic capabilities: PASS — no new capabilities introduced.
- RBAC-UX / workspace+tenant isolation: PASS — use existing tenant-context Filament routes; non-members 404; members lacking capability 403.
- Run observability: PASS — both capture + compare are queued
OperationRuns usingOperationRunService. - Ops-UX 3-surface feedback: PASS — existing run-start surfaces already enqueue; run detail is canonical.
- Ops-UX summary counts: PASS — any new detail stays in
context; summary keys remain fromOperationSummaryKeys::all(). - Badge semantics: PASS — new badges/filters will follow existing UI patterns (no ad-hoc status mappings).
- Filament action surface contract: PASS — modifying Finding list UI adds filter + badge only; no new destructive actions.
Project Structure
Documentation (this feature)
specs/117-baseline-drift-engine/
├── spec.md
├── plan.md
├── research.md
├── data-model.md
├── quickstart.md
└── contracts/
└── openapi.yaml
Next: generate specs/117-baseline-drift-engine/tasks.md via /speckit.tasks.
Source Code (repository root)
app/
├── Jobs/
│ ├── CaptureBaselineSnapshotJob.php
│ └── CompareBaselineToTenantJob.php
├── Models/
│ ├── BaselineSnapshot.php
│ ├── BaselineSnapshotItem.php
│ ├── InventoryItem.php
│ ├── Policy.php
│ ├── PolicyVersion.php
│ └── Finding.php
├── Services/
│ ├── Baselines/
│ │ ├── BaselineCompareService.php
│ │ ├── BaselineSnapshotIdentity.php
│ │ └── (new) CurrentStateHashResolver + providers
│ └── Drift/
│ ├── DriftHasher.php
│ └── Normalizers/SettingsNormalizer.php
└── Filament/
├── Pages/BaselineCompareLanding.php
└── Resources/FindingResource.php
database/migrations/
└── (new) add evidence_fidelity to findings (required for filtering)
tests/
└── Feature/ (new/updated Pest tests for resolver + compare + UI filter)
Structure Decision: Implement as an incremental change within existing Baselines/Findings domains (no new modules).
Complexity Tracking
No constitution violations are required for v1.5. (Table intentionally empty.)
Phase 0 — Research (output: research.md)
Goals:
- Confirm current baseline capture/compare logic and identify the precise extension points.
- Decide where fidelity/provenance should be stored (JSONB vs columns) to support filtering.
- Confirm real route URIs/names for contracts (Filament + Monitoring).
Deliverable: specs/117-baseline-drift-engine/research.md
Phase 1 — Design (output: data-model.md + contracts/* + quickstart.md)
Deliverables:
- Data model changes and JSON shapes: specs/117-baseline-drift-engine/data-model.md
- Endpoint reference contract (no new APIs; documented existing routes): specs/117-baseline-drift-engine/contracts/openapi.yaml
- Developer quickstart: specs/117-baseline-drift-engine/quickstart.md
Post-design constitution re-check: PASS (see Phase 1 notes in research/design outputs).
Phase 2 — Implementation Planning (high-level)
- Implement
CurrentStateHashResolver(provider chain + batch resolution). - Update baseline capture to store best available hash (content if present, else meta) + provenance.
- Update baseline compare to:
- use resolver with
since = baseline_snapshots.captured_at - record evidence gaps in run context
- emit findings with baseline+current provenance
- use resolver with
- Update Findings UI:
- show fidelity badge
- add fidelity filter (content/meta)
- display baseline+current provenance fields
- Add migration for
findings.evidence_fidelity(required for fast, stable fidelity filtering). - Add Pest tests (resolver behavior, compare integration, UI filter query behavior).
- Run
vendor/bin/sail bin pint --dirty --format agentand focused tests.
Scope note (v2.0)
- v2.0 “full content capture mode for Golden Master” is explicitly out of scope for v1.5 implementation tasks.
- v1.5 remains opportunistic: compare is DB-only and consumes only existing stored evidence.