#+#+#+#+
# Implementation Plan: Golden Master / Baseline Governance v1 (R1.1–R1.4)

**Branch**: `101-golden-master-baseline-governance-v1` | **Date**: 2026-02-19 | **Spec**: [spec.md](spec.md)
**Input**: Feature specification from [spec.md](spec.md)

## Summary

Implement a workspace-owned **Golden Master baseline** that can be captured from a tenant into an immutable snapshot, assigned to tenants, and compared (“Soll vs Ist”) to generate drift findings + a compact operational summary.

This feature reuses existing patterns:
- tenant-scoped `OperationRun` for capture/compare observability + idempotency
- `findings` for drift tracking with sha256 fingerprints

## Technical Context

**Language/Version**: PHP 8.4.x
**Framework**: Laravel 12
**Admin UI**: Filament v5 (requires Livewire v4.0+)
**Storage**: PostgreSQL (Sail locally); SQLite is used in some tests
**Testing**: Pest v4 (`vendor/bin/sail artisan test`)
**Target Platform**: Docker via Laravel Sail (macOS dev)
**Project Type**: Laravel monolith (server-rendered Filament + Livewire)
**Performance Goals**:
- Compare completes within ~2 minutes for typical tenants (≤ 500 in-scope policies)
**Constraints**:
- Baseline/monitoring pages must be DB-only at render time (no outbound HTTP)
- Operation start surfaces enqueue-only (no remote work inline)
**Scale/Scope**:
- Multi-tenant, workspace isolation is an authorization boundary

## Constitution Check

*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*

- Inventory-first: compare operates on “last observed” inventory/policy versions; baseline snapshot is an explicit immutable capture.
- Read/write separation: capture/compare are operational jobs; any mutations are confirmed, audited, and tested.
- Graph contract path: no Graph calls on UI surfaces; any Graph usage (if introduced) must go through `GraphClientInterface` and `config/graph_contracts.php`.
- Deterministic capabilities: new baseline capabilities are added to the canonical registry and role maps.
- RBAC-UX semantics: non-member is 404; member but missing capability is 403.
- Run observability: capture/compare are always `OperationRun`-tracked; start surfaces only create/reuse runs and enqueue work.
- Data minimization: workspace-owned baseline snapshots are minimized and must not store tenant secrets.
- Badge semantics (BADGE-001): finding severity/status uses existing `BadgeCatalog` mapping.
- Filament Action Surface Contract: resources/pages created or modified must define Header/Row/Bulk/Empty-State + inspect affordance.

✅ Phase 0 and Phase 1 design choices satisfy the constitution. No violations are required.

## Project Structure

### Documentation (this feature)

```text
specs/101-golden-master-baseline-governance-v1/
├── plan.md
├── spec.md
├── research.md
├── data-model.md
├── quickstart.md
└── contracts/
   └── baseline-governance.openapi.yaml
```

### Source Code (repository root)

```text
app/
├── Filament/
├── Jobs/
├── Models/
├── Policies/
├── Services/
└── Support/

database/
└── migrations/

resources/
└── views/

tests/
├── Feature/
└── Unit/
```

**Structure Decision**: Implement baseline governance as standard Laravel models, migrations, services, jobs, and Filament resources/pages under the existing `app/` conventions.

## Phase 0 — Research (completed)

Outputs:
- [research.md](research.md)

Key decisions captured:
- Workspace-owned, data-minimized baseline snapshots (reusable across tenants)
- `OperationRun` types `baseline_capture` and `baseline_compare` using `ensureRunWithIdentity()` for idempotent starts
- Precondition failures return 422 with stable `reason_code` and do not create runs
- Findings reuse `findings` with sha256 fingerprints; Phase 2 adds `findings.source` to satisfy `source = baseline.compare`

## Phase 1 — Design & Contracts (completed)

Outputs:
- [data-model.md](data-model.md)
- [contracts/baseline-governance.openapi.yaml](contracts/baseline-governance.openapi.yaml)
- [quickstart.md](quickstart.md)

### UI Surfaces (Filament v5)

- Workspace-context: Governance → Baselines
  - Resource for baseline profile CRUD
  - Capture action (manage capability)
  - Tenant assignment management (manage capability)
- Tenant-context: “Soll vs Ist” landing page
  - Compare-now action (view capability)
  - Links to latest compare run + findings

### Authorization & capabilities

- Add new workspace capabilities:
  - `workspace_baselines.view`
  - `workspace_baselines.manage`
- Enforce membership as 404; capability denial as 403.

### Operation types

- `baseline_capture` (tenant = source tenant)
- `baseline_compare` (tenant = target/current tenant)

### Agent context update (completed)

The agent context update script was run during planning. It should be re-run after this plan update if the automation depends on parsed plan values.

## Phase 2 — Execution Plan (to be translated into tasks.md)

1) **Migrations + models**
  - Add baseline tables (`baseline_profiles`, `baseline_snapshots`, `baseline_snapshot_items`, `baseline_tenant_assignments`)
  - Add `findings.source` column + index to meet FR-015

2) **Services**
  - Baseline scope resolution (profile scope ∩ assignment override)
  - Snapshot identity calculation and dedupe strategy
  - Compare engine to produce drift items and severity mapping (FR-009)

3) **Jobs (queued)**
  - `CaptureBaselineSnapshotJob` (creates snapshot, items, updates active snapshot when applicable)
  - `CompareBaselineToTenantJob` (creates/updates findings + writes run summary_counts)

4) **Filament UI**
  - Baseline profiles resource (list/view/edit) with action surfaces per spec matrix
  - Tenant assignment UI surface (v1: single baseline per tenant)
  - “Soll vs Ist” tenant landing page and dashboard card action

5) **RBAC + policies**
  - Capability registry + role maps + UI enforcement
  - Regression tests for 404 vs 403 semantics

6) **Tests (Pest)**
  - CRUD authorization + action surface expectations
  - Capture snapshot dedupe
  - Compare finding fingerprint idempotency
  - Precondition failures return 422 and create no `OperationRun`

7) **Formatting**
  - Run `vendor/bin/sail bin pint --dirty`

## Complexity Tracking

None.
