# 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.
