TenantAtlas/specs/117-baseline-drift-engine/plan.md
ahmido f08924525d Spec 117: Baseline Drift Engine + evidence fidelity/provenance (#142)
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
2026-03-03 07:23:01 +00:00

138 lines
6.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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: 0500+ 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.