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
138 lines
6.5 KiB
Markdown
138 lines
6.5 KiB
Markdown
# 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](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 `PolicyVersion` since 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 `OperationRun`s using `OperationRunService`.
|
||
- 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 from `OperationSummaryKeys::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)
|
||
|
||
```text
|
||
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)
|
||
|
||
```text
|
||
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](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](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](specs/117-baseline-drift-engine/contracts/openapi.yaml)
|
||
- Developer quickstart: [specs/117-baseline-drift-engine/quickstart.md](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)
|
||
|
||
1) Implement `CurrentStateHashResolver` (provider chain + batch resolution).
|
||
2) Update baseline capture to store best available hash (content if present, else meta) + provenance.
|
||
3) Update baseline compare to:
|
||
- use resolver with `since = baseline_snapshots.captured_at`
|
||
- record evidence gaps in run context
|
||
- emit findings with baseline+current provenance
|
||
4) Update Findings UI:
|
||
- show fidelity badge
|
||
- add fidelity filter (content/meta)
|
||
- display baseline+current provenance fields
|
||
5) Add migration for `findings.evidence_fidelity` (required for fast, stable fidelity filtering).
|
||
6) Add Pest tests (resolver behavior, compare integration, UI filter query behavior).
|
||
7) Run `vendor/bin/sail bin pint --dirty --format agent` and 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.
|