spec: restore run detail post-execution proof (spec 335)

This commit is contained in:
Ahmed Darrazi 2026-05-29 00:30:18 +02:00
parent 1e45a29937
commit db8da62906
7 changed files with 905 additions and 0 deletions

View File

@ -0,0 +1,41 @@
# Specification Quality Checklist: Spec 335 - Restore Run Detail / Post-Execution Proof Productization
**Purpose**: Validate specification completeness and quality before implementation planning and execution.
**Created**: 2026-05-29
**Feature**: `specs/335-restore-run-detail-post-execution-proof-productization/spec.md`
## Content Quality
- [x] No application implementation is included in the preparation artifacts.
- [x] Focused on operator value, safety, proof visibility, and post-execution decision support.
- [x] All mandatory repository sections are completed.
- [x] Spec preserves TenantPilot terminology and workspace/environment route context.
## Requirement Completeness
- [x] No `[NEEDS CLARIFICATION]` markers remain.
- [x] Requirements are testable and unambiguous.
- [x] Acceptance criteria are explicit and safety-focused.
- [x] Scope is clearly bounded to Restore Run detail productization.
- [x] Dependencies and assumptions are identified.
## Constitution / Guardrail Alignment
- [x] Spec Candidate Check is filled and passes SPEC-GATE-001.
- [x] UI Surface Impact and UI/Productization Coverage are filled for the changed detail surface.
- [x] Proportionality review rejects new persisted truth, enums/status families, and backend rewrites; any presenter is derived-only.
- [x] RBAC, workspace/environment isolation, and proof/evidence boundary semantics are addressed.
- [x] Test governance and validation lanes are explicit.
## Feature Readiness
- [x] `spec.md`, `plan.md`, `tasks.md`, `repo-truth-map.md`, and `restore-result-state-contract.md` exist.
- [x] Tasks are ordered, small, verifiable, and implementation-ready.
- [x] Screenshot artifacts path is present.
- [x] Close alternatives and follow-up candidates are kept out of scope.
## Notes
- EvidenceSnapshot is model-real, but restore-linked evidence availability must remain repo-truthful (unavailable unless linked evidence exists).
- Implementation must not claim recovery is verified unless the repo introduces explicit verification semantics (out of scope here).

View File

@ -0,0 +1,148 @@
# Implementation Plan: Spec 335 - Restore Run Detail / Post-Execution Proof Productization
- **Branch**: `335-restore-run-detail-post-execution-proof-productization`
- **Date**: 2026-05-29
- **Spec**: `specs/335-restore-run-detail-post-execution-proof-productization/spec.md`
- **Input**: User-provided draft + repo inspection for truth (RestoreRun/OperationRun/EvidenceSnapshot + current Filament view implementation)
## Summary
Refactor the Restore Run detail surface into a decision-first post-execution result/proof/evidence view.
This work is UI/productization only:
- derive a top-level "restore result decision" contract from existing persisted fields (`restore_runs.results`, `restore_runs.metadata`, `restore_runs.operation_run_id`) and (when present) linked `evidence_snapshots`
- render one default-visible hierarchy: status/reason/impact/next action first; proof/evidence state explicit; diagnostics collapsed
- keep raw payloads and diagnostics behind disclosure
- preserve RBAC, tenant/workspace isolation, and existing route/context behavior
No restore execution backend changes are in scope.
## Technical Context
- **Language/Version**: PHP 8.4.x
- **Primary Dependencies**: Laravel 12.x, Filament v5, Livewire v4
- **Storage**: PostgreSQL (tenant-owned `restore_runs`, `operation_runs`, `evidence_snapshots`)
- **Testing**: Pest v4 + Livewire component testing; Browser tests for smoke/screenshots
- **Validation Lanes**: confidence + browser
- **Target Platform**: Laravel Sail (local); Dokploy (deploy) posture unchanged
- **Project Type**: Laravel monolith under `apps/platform`
- **Performance Goals**: avoid new expensive queries; prefer existing eager loads; only query evidence snapshots when an `operation_run_id` exists
- **Constraints**: no new packages; no migrations unless explicitly justified and approved in-spec
- **Scale/Scope**: one Filament view surface + related presenters/blade entries + tests/screenshots
## UI / Surface Guardrail Plan
- **Guardrail scope**: changed operator-facing detail surface (dangerous workflow result/proof)
- **Affected routes/pages/actions/states/navigation/panel/provider surfaces**:
- Restore Run detail view (`RestoreRunResource` view page)
- Restore result presentation (existing infolist entry view: `filament/infolists/entries/restore-results.blade.php`)
- Restore proof/evidence presentation (new or reused proof-aside surface)
- **Native vs custom classification summary**: native Filament page with shared primitives + a small amount of custom Blade in infolist entries
- **Shared-family relevance**: status messaging + proof/evidence deep links; diagnostics disclosure; shared OperationRun/Evidence viewers
- **State layers in scope**: page + detail + URL (optional dashboard context param already exists)
- **Audience modes in scope**: operator-MSP; no customer-facing change
- **Decision/diagnostic/raw hierarchy plan**: decision-first; diagnostics collapsed and secondary
- **Raw/support gating plan**: collapsed disclosures; never default-show raw payloads, exception text, or Graph error details as primary message
- **One-primary-action / duplicate-truth control**: exactly one dominant next action in the decision card; avoid repeating equivalent banners/cards in multiple sections
- **Handling modes**: review-mandatory (truth boundary / dangerous-workflow UX)
- **Special surface test profiles**: shared-detail-family + dangerous workflow proof surface
- **Required tests or manual smoke**: Feature/Livewire tests for contract visibility + RBAC/isolation; Browser smoke for screenshots and dark mode
- **Exception path and spread control**: if evidence is not repo-backed for restore runs, UI must state "unavailable" (do not invent)
- **Active feature PR close-out entry**: Guardrail / Exception / Smoke Coverage
- **UI/Productization coverage decision**: existing route/archetype; cover via Spec 335 screenshots + Feature/Browser tests
## Shared Pattern & System Fit
- **Cross-cutting feature marker**: yes (proof/evidence link semantics, decision-first status hierarchy)
- **Systems touched**:
- `App\Support\RestoreSafety\RestoreSafetyResolver` (result attention truth)
- `App\Support\Badges\BadgeRenderer` (status/evidence badge semantics)
- `App\Support\OperationRunLinks` + `OperationRunResource` (proof deep link)
- `EvidenceSnapshotResource` (evidence deep link, when present)
- **Shared abstractions reused**: reuse existing copy/badges and link resolvers; do not create new global status frameworks
- **New abstraction introduced?**: optional, narrow presenter for the Restore Run detail decision contract (derived only, no persistence)
- **Bounded deviation / spread control**: any presenter must live feature-locally and remain a pure derived view-model (no caching, no global registry)
## OperationRun UX Impact
- Link UX only: the Restore Run detail page will expose "Operation proof" and deep-link to the existing OperationRun view.
- No start/enqueue/dedupe semantics change.
- URLs must be generated via existing link helpers (`OperationRunLinks` / Filament resource `getUrl(...)`) to preserve workspace/environment context.
## Data / Migrations
- No migrations planned.
- No new persisted fields planned.
- Evidence is read-only: if evidence snapshots are present for the linked `operation_run_id`, show them; otherwise show honest "unavailable".
## Implementation Approach
### Phase 1 - Repo Truth (pre-work)
- Document restore run model fields/statuses and result structures in `repo-truth-map.md`.
- Document the visible result/proof state machine in `restore-result-state-contract.md`.
- Confirm existing Restore Run view implementation and tests (current infolist entries and `RestoreResultAttentionSurfaceTest`).
### Phase 2 - Result Presenter / View Model (derived only)
- If needed, introduce a derived presenter that returns the UI contract:
- status label + reason + impact + primary next action
- operation proof state + URL (when authorized)
- post-run evidence state + URL (when repo-backed)
- result summary counts (from `restore_runs.metadata` and `restore_runs.results`)
- diagnostics default = collapsed
### Phase 3 - Detail Page UI
- Switch Restore Run view from "entries list" toward a main/aside layout:
- Main: decision card + result summary + item outcomes (table) + secondary run details
- Aside: proof panel (source backup, target environment, requested by, operation proof, post-run evidence, audit trail) + diagnostics disclosure
- Ensure raw payloads remain behind disclosure.
### Phase 4 - Proof/Evidence Links
- Operation proof:
- show status and link to OperationRun view when the restore run is linked to an operation run
- show "unavailable" when no operation run exists
- Evidence:
- query evidence snapshots for the restore run's `operation_run_id` (tenant-scoped) and surface state + link when present
- otherwise show "unavailable" (no fake "recovery verified")
### Phase 5 - Tests + Browser Screenshots
- Add/extend Feature tests to assert:
- decision question and status label for key states
- operation proof and evidence states are explicit
- diagnostics collapsed by default; raw payload not visible by default
- tenant/workspace isolation and capability gating (deny-as-not-found vs forbidden semantics preserved)
- Add a Browser smoke/screenshot test that captures the required screenshot set under the Spec 335 artifact path.
## Validation Commands
Planned (narrow) commands for implementation review:
```bash
cd apps/platform
./vendor/bin/sail artisan test \
tests/Feature/Filament/Spec335RestoreRunDetailProductizationTest.php \
tests/Feature/Filament/RestoreResultAttentionSurfaceTest.php \
--compact
```
```bash
cd apps/platform
./vendor/bin/sail php vendor/bin/pest \
tests/Browser/Spec335RestoreRunDetailProductizationSmokeTest.php \
--compact
```
```bash
cd apps/platform
./vendor/bin/sail pint --dirty
git diff --check
```

View File

@ -0,0 +1,184 @@
# Spec 335 Repo Truth Map - Restore Run Detail / Post-Execution Proof
This file documents the repo-backed truth needed to productize the Restore Run detail/result/proof surface.
Legend:
- `repo-verified`: directly confirmed in code/migrations/tests in this repo
- `derived from existing model`: computed/derived from existing persisted fields
- `foundation-real`: persisted model exists, but linkage for this workflow may not be produced today
- `not available`: no repo-backed data exists today
- `deferred`: requires additional repo inspection before implementation
## RestoreRun Model (repo-verified)
Source:
- `apps/platform/app/Models/RestoreRun.php`
- `apps/platform/database/migrations/2025_12_10_000150_create_restore_runs_table.php`
- `apps/platform/database/migrations/2026_02_10_115908_add_operation_run_id_to_restore_runs_table.php`
Key fields:
- `managed_environment_id` (tenant/environment)
- `workspace_id` (tenant-owned isolation)
- `backup_set_id`
- `requested_by` (nullable)
- `is_dry_run` (boolean; "preview-only")
- `status` (string, see `RestoreRunStatus`)
- `requested_items` (json array of backup item ids; nullable)
- `preview` (json; nullable)
- `results` (json; nullable)
- `metadata` (json; nullable)
- `failure_reason` (nullable)
- `started_at` / `completed_at` (nullable)
- `operation_run_id` (nullable; FK to `operation_runs`)
Relationships (repo-verified):
- `$restoreRun->tenant()` -> `ManagedEnvironment` via `managed_environment_id`
- `$restoreRun->backupSet()` -> `BackupSet` via `backup_set_id` (withTrashed)
- `$restoreRun->operationRun()` -> `OperationRun` via `operation_run_id`
## RestoreRun Statuses (repo-verified)
Source:
- `apps/platform/app/Support/RestoreRunStatus.php`
Values:
- pre-execution/draft: `draft`, `scoped`, `checked`, `previewed`, `pending`
- execution: `queued`, `running`
- terminal: `completed`, `partial`, `failed`, `cancelled`
- legacy/compat: `aborted`, `completed_with_errors`
Implementation note:
- Spec 335 must map multiple persisted statuses into a smaller UI-facing decision model (derived), without inventing new persisted truth.
## Restore Results Shape (repo-verified)
Primary persistence source:
- `apps/platform/app/Services/Intune/RestoreService.php` (result assembly + `restore_runs.results` + `restore_runs.metadata`)
Persisted shape:
- `restore_runs.results` is stored as:
- `results.foundations`: list of foundation entries
- `results.items`: map keyed by `backup_item_id` (values are item outcome arrays)
Counts / summary (repo-verified):
- `restore_runs.metadata` includes (at least):
- `total`, `succeeded`, `failed`, `skipped`, `partial`, `non_applied`, `foundations_skipped`
- `scope_basis`, `check_basis`, `preview_basis` (see `RestoreRun` helpers)
- `execution_safety_snapshot` (used by result/preview surfaces)
Derived availability classification:
- Result summary counts: `derived from existing model` (from `metadata`)
- Item outcome table: `derived from existing model` (from `results.items` and related metadata)
## Restore Result Attention Contract (repo-verified)
Sources:
- `apps/platform/app/Support/RestoreSafety/RestoreSafetyResolver.php` (`resultAttentionForRun`)
- `apps/platform/app/Support/RestoreSafety/RestoreResultAttention.php`
- UI: `apps/platform/resources/views/filament/infolists/entries/restore-results.blade.php`
- Tests: `apps/platform/tests/Feature/Filament/RestoreResultAttentionSurfaceTest.php`
Contract fields (repo-verified):
- `state` in `{ not_executed, completed, partial, failed, completed_with_follow_up }`
- `summary`
- `primary_next_action`
- `primary_cause_family`
- `recovery_claim_boundary` (notably enforces "completed != recovery proven")
- `tone`
Gap vs Spec 335 UX:
- OperationRun proof state is not part of this contract today (`not available` in this contract).
- Post-run evidence state is not part of this contract today (`not available` in this contract).
## OperationRun Proof (repo-verified)
Sources:
- `apps/platform/app/Models/OperationRun.php`
- `apps/platform/app/Support/OperationRunStatus.php`
- `apps/platform/app/Support/OperationRunOutcome.php`
RestoreRun link (repo-verified):
- `restore_runs.operation_run_id` -> `operation_runs.id`
Notes:
- OperationRun "proof" is repo-real for restore runs that have `operation_run_id`.
- UI link helpers exist (repo-verified): `apps/platform/app/Support/OperationRunLinks.php` and Filament `OperationRunResource`.
## EvidenceSnapshot (post-run evidence) (foundation-real)
Sources:
- `apps/platform/app/Models/EvidenceSnapshot.php`
- `apps/platform/database/migrations/2026_03_19_000000_create_evidence_snapshots_table.php`
- Filament: `apps/platform/app/Filament/Resources/EvidenceSnapshotResource.php`
Linkage:
- Evidence snapshots can be linked to an `OperationRun` via `evidence_snapshots.operation_run_id`.
- Evidence snapshots are tenant-scoped: `(workspace_id, managed_environment_id)` and have `status` + `completeness_state`.
Evidence availability for restore runs:
- Model + viewer exist (`foundation-real`).
- Whether restore execution produces an evidence snapshot is workflow-dependent and must be verified at runtime/fixtures (`deferred`).
## Current Restore Run Detail UI (repo-verified)
Primary surface:
- Filament page: `apps/platform/app/Filament/Resources/RestoreRunResource/Pages/ViewRestoreRun.php`
- Infolist schema: `apps/platform/app/Filament/Resources/RestoreRunResource.php::infolist()`
Custom entries already in use:
- Preview entry view: `apps/platform/resources/views/filament/infolists/entries/restore-preview.blade.php`
- Results entry view: `apps/platform/resources/views/filament/infolists/entries/restore-results.blade.php`
Known gap:
- No dedicated proof/evidence aside on the detail page today (proof panel exists for Create wizard, not for View).
## Existing Tests (repo-verified)
Most relevant existing coverage:
- Result attention rendering: `apps/platform/tests/Feature/Filament/RestoreResultAttentionSurfaceTest.php`
- Restore Run UI enforcement / access semantics: `apps/platform/tests/Feature/Filament/RestoreRunUiEnforcementTest.php`
- Dashboard deep-link copy (subheading): `ViewRestoreRun::getSubheading()` covered indirectly by feature tests
Browser tests exist for Restore Create (Spec 332/333), not for Restore Run detail productization yet.
## Permissions / Capabilities (repo-verified)
RestoreRunResource access checks:
- `apps/platform/app/Filament/Resources/RestoreRunResource.php::canViewAny()` uses:
- membership + `Capabilities::TENANT_VIEW`
Detail record resolution:
- `RestoreRunResource::resolveScopedRecordOrFail()` routes through tenant-owned record resolution, preserving tenant/workspace scoping.
## Open Truth Questions (deferred)
- Do restore execution operations in current fixtures produce an `EvidenceSnapshot` linked to the restore `OperationRun`?
- If multiple evidence snapshots exist for one operation run, which one should be linked (latest active vs latest any)?
- What are the RBAC rules for viewing EvidenceSnapshot and OperationRun from the Restore Run detail surface (capability names, deny-as-not-found vs forbidden)?

View File

@ -0,0 +1,135 @@
# Spec 335 Restore Result State Contract (Decision-First)
This contract defines the minimum decision-first states the Restore Run detail page must support.
It is intentionally derived: it may combine multiple persisted statuses into one operator-facing decision state.
## Fields (required on first screen)
- Status (label)
- Reason
- Impact
- Primary next action
- Operation proof state (OperationRun)
- Post-run evidence state (EvidenceSnapshot, repo-backed only)
- Result summary (repo-backed only)
- Diagnostics default state: collapsed
## State Matrix
### 1) Not Executed (Draft / Preview Only)
- **State**: `not_executed`
- **Persisted triggers** (repo-verified):
- `restore_runs.is_dry_run = true`, OR
- `restore_runs.status in { draft, scoped, checked, previewed }` (pre-execution)
- **Visible status**: Not executed
- **Reason**: This record proves preview truth, not environment recovery.
- **Impact**: No execution proof or post-run evidence exists yet.
- **Primary next action**: Review preview / continue preparation (contextual to available actions)
- **Operation proof state**: Unavailable
- **Post-run evidence state**: Unavailable
- **Result summary**:
- If `restore_runs.metadata` has counts: show them
- Otherwise: show "Result summary unavailable" (no fake zeros)
- **Allowed proof claims**: "Preview evidence exists" (never "recovery verified")
- **Diagnostics default**: Collapsed
### 2) Execution In Progress (Queued / Running)
- **State**: `in_progress`
- **Persisted triggers** (repo-verified):
- `restore_runs.status in { queued, running }`, OR
- linked `operation_runs.status in { queued, running }`
- **Visible status**: Execution in progress
- **Reason**: Restore execution is currently running.
- **Impact**: Results and evidence are not final yet.
- **Primary next action**: View operation progress
- **Operation proof state**: In progress
- **Post-run evidence state**: Unavailable
- **Result summary**: show only repo-backed partial counts (if present); otherwise show "In progress"
- **Allowed proof claims**: "Execution in progress" only
- **Diagnostics default**: Collapsed
### 3) Completed (Recovery Proof Incomplete)
- **State**: `completed_proof_incomplete`
- **Persisted triggers**:
- terminal restore run (`status in { completed, partial, completed_with_errors }`) AND operation proof is present (`operation_run_id != null`)
- post-run evidence snapshot not present or not current for the operation run
- **Visible status**: Completed, recovery proof incomplete
- **Reason**: Execution completed, but post-run evidence is not available yet.
- **Impact**: Do not treat this restore as verified recovery until evidence has been reviewed.
- **Primary next action**: Review restored details
- **Operation proof state**: Available
- **Post-run evidence state**: Unavailable
- **Result summary**: repo-backed counts from `restore_runs.metadata` when present
- **Allowed proof claims**: "Execution proof available" (never "recovery verified")
- **Diagnostics default**: Collapsed
### 4) Completed (Evidence Available)
- **State**: `completed_with_evidence`
- **Persisted triggers**:
- terminal restore run AND operation proof present
- at least one evidence snapshot exists for the same `operation_run_id` and tenant, with status/currentness appropriate to repo truth
- **Visible status**: Completed with evidence available
- **Reason**: Execution proof and post-run evidence are available.
- **Impact**: Review evidence before treating the restore as recovery proof.
- **Primary next action**: Open evidence
- **Operation proof state**: Available
- **Post-run evidence state**: Available
- **Result summary**: repo-backed counts from `restore_runs.metadata`
- **Allowed proof claims**:
- allowed: "Evidence snapshot available"
- forbidden: "Recovery verified", "Healthy", "Compliant", "Customer-safe"
- **Diagnostics default**: Collapsed
### 5) Completed With Items Needing Review (Partial / Follow-Up)
- **State**: `needs_review`
- **Persisted triggers** (repo-verified via `RestoreResultAttention`):
- `RestoreSafetyResolver::resultAttentionForRun(...).state in { partial, completed_with_follow_up }`, OR
- `restore_runs.status = partial`
- **Visible status**: Completed with items needing review
- **Reason**: Some items were skipped, partially applied, or failed.
- **Impact**: Review item outcomes before relying on the result.
- **Primary next action**: Review item outcomes
- **Operation proof state**: Available (if `operation_run_id` exists), otherwise Unavailable
- **Post-run evidence state**: Available/Unavailable (repo-backed only; never implied)
- **Result summary**: show repo-backed counts (failed/skipped/partial/non_applied) when present
- **Allowed proof claims**: "Follow-up required" / "Skipped items exist" etc (no recovery claims)
- **Diagnostics default**: Collapsed
### 6) Failed
- **State**: `failed`
- **Persisted triggers** (repo-verified):
- `restore_runs.status = failed`, OR
- linked operation run outcome = `failed`
- **Visible status**: Restore failed
- **Reason**: The restore did not complete successfully.
- **Impact**: Some requested changes may not have been applied.
- **Primary next action**: Review failure details
- **Operation proof state**: Available (if `operation_run_id` exists); otherwise Unavailable
- **Post-run evidence state**: Unavailable (unless repo truth indicates otherwise)
- **Result summary**: show repo-backed counts when present; otherwise show "Failure details required"
- **Allowed proof claims**: "Execution failed" only; never "recovery verified"
- **Diagnostics default**: Collapsed
### 7) Cancelled / Blocked
- **State**: `blocked_or_cancelled`
- **Persisted triggers**:
- `restore_runs.status = cancelled`, OR
- linked operation run outcome = `blocked`
- **Visible status**: Restore blocked / cancelled
- **Reason**: Restore did not execute due to cancellation or blocker.
- **Impact**: No recovery proof exists.
- **Primary next action**: Review blocker
- **Operation proof state**: Available (if operation run exists); otherwise Unavailable
- **Post-run evidence state**: Unavailable
- **Result summary**: show "Unavailable" unless repo-backed
- **Allowed proof claims**: none beyond the above
- **Diagnostics default**: Collapsed

View File

@ -0,0 +1,268 @@
# Feature Specification: Spec 335 - Restore Run Detail / Post-Execution Proof Productization
- **Feature Branch**: `335-restore-run-detail-post-execution-proof-productization`
- **Created**: 2026-05-29
- **Status**: Draft
- **Type**: Runtime UX productization / Restore result proof surface / no backend rewrite
- **Runtime posture**: Productize the existing Restore Run detail surface using repo-backed `RestoreRun` + `OperationRun` + (when present) `EvidenceSnapshot`. No restore engine rewrite.
- **Input**: User-provided draft (originally drafted as "Spec 334"; number `334-*` is already used in this repo, so this package is Spec 335).
## Dependency Context
This spec is intentionally downstream of Restore Create.
- Spec 332 - Product Process Flow System v1
- Spec 333 - Restore Create UX Final Productization
- Spec 329 - Evidence / Audit Log Disclosure Productization
- Spec 328 - Operations Hub Decision-First Workbench Productization
- Spec 325 - Screenshot-Anchored Strategic Target Images
## Summary
Spec 333 productized the Restore Create wizard. Spec 335 productizes what happens after a restore run exists:
- What was requested?
- What executed, what was skipped, what failed?
- Is execution proof available via `OperationRun`?
- Is post-run evidence available (repo-backed), or missing?
- What is the next safest operator action?
The goal is to prevent Restore Run detail from reading like a raw record view, log dump, or technical payload surface.
## Product Goal
The Restore Run detail page must answer:
```text
Was this restore executed safely, and is recovery proof available?
```
First screen (default-visible) must show:
```text
Status
Reason
Impact
Primary next action
OperationRun proof
Post-run evidence state
Restore result summary
Diagnostics collapsed
```
Raw logs, payloads, and item JSON must not be required to understand outcome.
## Spec Candidate Check *(mandatory - SPEC-GATE-001)*
- **Problem**: Restore Run "View" is still a mixed detail surface where operators can miss the distinction between execution completion, execution proof, and post-run recovery evidence.
- **Today's failure**: "Completed" can read as "safe/verified" unless the UI explicitly frames proof and evidence boundaries and presents one decision-first outcome model.
- **User-visible improvement**: Restore Run detail becomes decision-first: explicit status, reason, impact, and one primary next action; execution proof and post-run evidence are shown separately with honest availability states.
- **Smallest enterprise-capable version**: Productize the existing view surface using derived state from existing `RestoreRun.results/metadata` + `OperationRun` link + optional `EvidenceSnapshot` link(s). No new restore execution behavior. No new tables or migrations.
- **Explicit non-goals**: No new restore engine behavior, no new Graph calls, no new `OperationRun` types or lifecycle semantics, no new evidence generation pipeline, no new backend "recovery verified" semantics, no new packages, no new deployment steps.
- **Permanent complexity imported**: A small view-model/presenter (only if needed), refined Blade/Infolist layout, focused Feature/Browser tests, and spec screenshots.
- **Why now**: Restore is a high-risk workflow. Spec 333 made Create safe and decision-first; the next operator moment is post-execution truth and proof.
- **Why not local**: This is a cross-cutting truth/presentation boundary (execution proof vs evidence) that must be made explicit once and reused; page-local ad-hoc copy will drift.
- **Approval class**: Core Enterprise
- **Red flags triggered**: Dangerous workflow UX, status/proof messaging, evidence claims. Defense: bounded UI productization only; no new truth sources; explicit boundaries; tests + screenshots.
- **Score**: Nutzen: 2 | Dringlichkeit: 2 | Scope: 2 | Komplexitaet: 2 | Produktnaehe: 2 | Wiederverwendung: 1 | **Gesamt: 11/12**
- **Decision**: approve
## Spec Scope Fields *(mandatory)*
- **Scope**: tenant / managed-environment operator surface
- **Primary Routes**:
- `/admin/workspaces/{workspace}/environments/{environment}/restore-runs/{record}` (Restore Run detail)
- **Data Ownership**:
- Tenant-owned: `restore_runs` (JSON fields `preview`, `results`, `metadata`) + `operation_runs` (execution proof) + optional `evidence_snapshots` (post-run evidence).
- No new persisted entity/table.
- **RBAC**:
- Existing workspace membership + tenant entitlement remains authoritative.
- Existing `Capabilities::TENANT_VIEW` gates access; non-member access remains deny-as-not-found (404); member missing capability remains 403.
## UI Surface Impact *(mandatory - UI-COV-001)*
Does this spec add, remove, rename, or materially change any reachable UI surface?
- [ ] No UI surface impact
- [x] Existing page changed
- [ ] New page/route added
- [ ] Navigation changed
- [ ] Filament panel/provider surface changed
- [ ] New modal/drawer/wizard/action added
- [x] New table/form/state added
- [ ] Customer-facing surface changed
- [ ] Dangerous action changed
- [x] Status/evidence/review presentation changed
- [x] Workspace/environment context presentation changed
## UI/Productization Coverage
- **Route/page/surface**: Restore Run detail (`RestoreRunResource` view page; infolist + Blade entries)
- **Current or new page archetype**: Domain Pattern Surface (post-execution result/proof)
- **Design depth**: Manual Review Required (dangerous-workflow truth surface)
- **Repo-truth level**: repo-verified (existing view surface + existing result attention contract + existing `OperationRun` relation)
- **Existing pattern reused**: existing `RestoreResultAttention` truth, BADGE-001 badges, existing restore proof panel patterns, OperationRun/Evidence resources.
- **New pattern required**: decision-first "result contract" wrapper that includes operation proof + evidence state explicitly (no new truth sources).
- **Screenshot required**: yes, `specs/335-restore-run-detail-post-execution-proof-productization/artifacts/screenshots/`
- **Page audit required**: no (existing route/archetype); screenshots are the primary proof artifact
- **Customer-safe review required**: no (operator surface)
- **Dangerous-action review required**: yes (restore workflow semantics; avoid false recovery claims)
- **Coverage files updated or explicitly not needed**:
- [x] `N/A - existing route/archetype; proof via Spec 335 screenshots`
## Cross-Cutting / Shared Pattern Reuse
- **Cross-cutting feature?**: yes
- **Interaction class(es)**: status messaging, deep links, evidence/proof viewers, diagnostics disclosure
- **Systems touched**:
- `RestoreSafetyResolver::resultAttentionForRun()` (existing result attention truth)
- `OperationRunLinks` + `OperationRunResource` (execution proof)
- `EvidenceSnapshotResource` (post-run evidence viewer, when repo-backed)
- `BadgeRenderer` domains (status + evidence badges)
- **Existing pattern(s) to extend**: restore "what this proves / what it does not prove" boundary copy; decision-first card hierarchy; diagnostics collapsed by default
- **Allowed deviation and why**: none; any new presenter must remain a thin derived view-model (no persisted truth)
- **Consistency impact**: restore result decision copy + proof availability labels must remain stable across view + dashboards (no parallel local wording)
- **Review focus**: no false "recovery verified" claim; one primary next action; diagnostics and raw payload stay collapsed/secondary; links stay tenant/workspace-safe
## OperationRun UX Impact
- **Touches OperationRun start/completion/link UX?**: link UX only (deep-link to operation proof)
- **Shared OperationRun UX contract/layer reused**: `OperationRunLinks` (no local URL composition)
- **Delegated start/completion UX behaviors**: `Open operation` link only; no new toasts/events/dedupe
- **Queued DB-notification policy**: `N/A`
- **Terminal notification path**: `N/A`
- **Exception required?**: none
## Provider Boundary / Platform Core Check
N/A - no shared provider/platform boundary is changed. This is presentation/productization on existing persisted truth.
## Repo-Truth First Requirement *(hard requirement)*
Before runtime changes, this package must include a repo truth map:
- `specs/335-restore-run-detail-post-execution-proof-productization/repo-truth-map.md`
The map must classify each data point as:
```text
repo-verified | derived from existing model | foundation-real | not available | deferred
```
Do not invent post-run proof states that are not repo-backed.
## Required UX Contract
The visible UI must expose a top-level result decision model (fields may be derived from existing contracts):
```php
[
'status' => 'completed_recovery_proof_incomplete',
'status_label' => 'Completed, recovery proof incomplete',
'reason' => 'Execution completed, but post-run evidence is not available yet.',
'impact' => 'Do not treat this restore as verified recovery until evidence has been reviewed.',
'primary_next_action' => 'Review restored details',
'primary_next_url' => null,
'operation_proof' => [
'state' => 'available',
'label' => 'Operation proof available',
'url' => '...',
],
'post_run_evidence' => [
'state' => 'unavailable',
'label' => 'Post-run evidence unavailable',
'url' => null,
],
'result_summary' => [
'requested' => 10,
'applied' => 8,
'skipped' => 1,
'failed' => 1,
'needs_review' => 2,
],
'diagnostics_state' => 'collapsed',
]
```
Exact implementation may differ, but the visible page must uphold this hierarchy and boundary.
## Restore Result States
Minimum supported product states are defined in:
- `specs/335-restore-run-detail-post-execution-proof-productization/restore-result-state-contract.md`
The UI must not imply "recovery verified" unless repo-backed verification semantics exist.
## Scope
### In Scope
- Productize Restore Run detail view surface (decision-first result/proof/evidence)
- OperationRun proof panel (link + status context, not raw logs first)
- Post-run evidence availability state (link when repo-backed)
- Result summary and item outcome table (only when repo-backed)
- Diagnostics/raw details collapsed by default
- Spec 335 tests and screenshots
### Out of Scope
- Restore engine / execution backend changes
- New Graph calls or provider gateway behavior
- New `OperationRun` semantics or model rewrites
- New evidence generation pipeline or migrations (unless explicitly justified and added to the spec first)
- New packages, env vars, scheduler/queue/storage changes
- Restore Create wizard redesign (Spec 333 owns Create UX)
## Proportionality Review *(mandatory when structural complexity is introduced)*
This spec may introduce a small presenter/view-model.
- **New source of truth?**: no
- **New persisted entity/table/artifact?**: no (spec artifacts + screenshots only)
- **New abstraction?**: yes, a thin derived presenter if the page needs one decision-contract output (no persistence, no global framework)
- **New enum/state/reason family?**: no persisted family; any "status label" is derived display-only
- **Current operator problem**: post-execution restore truth/proof/evidence is not decision-first enough.
- **Narrowest correct implementation**: derived view-model + layout/product copy refinements on existing persisted data.
- **Alternative intentionally rejected**: introducing new persisted "recovery proof" models or new workflow frameworks.
- **Release truth**: current-release UX productization.
### Compatibility posture
Pre-production: prefer replacement over shims. No legacy alias paths are introduced.
## Testing / Lane / Runtime Impact *(mandatory for runtime behavior changes)*
- **Test purpose / classification**: Feature/Livewire + Browser (plus Unit if a presenter is introduced)
- **Validation lane(s)**: confidence + browser; formatting via Pint; whitespace guard via `git diff --check`
- **Why sufficient**: this is a user-facing operator detail surface with truth-boundary risk; Feature tests prove default-visible hierarchy; Browser smoke provides final UI proof and screenshots.
## Acceptance Criteria
### Product
- Restore Run detail is decision-first.
- First screen answers whether execution proof and post-run evidence are available.
- OperationRun proof is visible and linked where authorized.
- Post-run evidence state is visible and truthful.
- Result summary and item outcomes are shown only when repo-backed.
- Diagnostics are collapsed by default.
### Safety
- Completed execution does not imply recovery verified.
- No false evidence claim is displayed.
- Raw payloads/logs are hidden by default.
### Context / RBAC
- Workspace/environment isolation is preserved.
- Cross-workspace proof/evidence is not visible.
- No legacy `/admin/t` or tenant query alias is introduced.
### Technical
- No backend rewrite.
- No migrations unless explicitly justified and added to this spec before implementation.
- No new packages.

View File

@ -0,0 +1,128 @@
# Tasks: Spec 335 - Restore Run Detail / Post-Execution Proof Productization
**Input**:
- `specs/335-restore-run-detail-post-execution-proof-productization/spec.md`
- `specs/335-restore-run-detail-post-execution-proof-productization/plan.md`
- `specs/335-restore-run-detail-post-execution-proof-productization/repo-truth-map.md`
- `specs/335-restore-run-detail-post-execution-proof-productization/restore-result-state-contract.md`
**Tests**: Required. This spec changes an operator-facing dangerous-workflow detail surface and must prove decision-first truth boundaries.
## Test Governance Checklist
- [ ] Lane assignment is named and is the narrowest sufficient proof for the changed behavior.
- [ ] New or changed tests stay in the smallest honest family, and browser additions are explicit.
- [ ] Shared helpers, factories, seeds, fixtures, and context defaults stay cheap by default.
- [ ] Planned validation commands cover the change without pulling in unrelated lane cost.
- [ ] The dangerous-workflow proof/evidence surface profile is explicit.
- [ ] Any material budget, baseline, trend, or escalation note is recorded in the active spec or PR.
## Phase 1: Repo Truth (blocks runtime changes)
**Purpose**: Freeze repo truth for RestoreRun results/proof/evidence before changing UI.
- [ ] T001 Re-read `spec.md`, `plan.md`, and this `tasks.md`.
- [ ] T002 Verify current Restore Run view implementation and state sources:
- `apps/platform/app/Filament/Resources/RestoreRunResource.php` (infolist + `detailResultsState`)
- `apps/platform/resources/views/filament/infolists/entries/restore-results.blade.php`
- `apps/platform/app/Support/RestoreSafety/RestoreSafetyResolver.php` (`resultAttentionForRun`)
- [ ] T003 Update/confirm `repo-truth-map.md` is accurate for:
- `RestoreRun` model fields + `RestoreRunStatus` values
- results shape (`results.foundations`, `results.items`) and summary counts (`metadata.total/succeeded/failed/skipped/partial/non_applied`)
- `operation_run_id` relationship + current OperationRun outcome/status behavior
- Evidence snapshot availability (query path, status/completeness enums)
- [ ] T004 Update/confirm `restore-result-state-contract.md` is aligned to repo truth (no invented evidence/proof states).
## Phase 2: Restore Run Detail Presenter (derived view-model, optional)
**Purpose**: Ensure one decision-first UI contract drives the view surface.
- [ ] T005 Decide whether a presenter/view-model is needed. If the view becomes a multi-section surface (decision card + proof panel + evidence state + table), prefer a presenter to avoid page-local logic drift.
- [ ] T006 If introduced, implement a thin derived presenter that outputs:
- `status_label`, `reason`, `impact`, `primary_next_action`
- `operation_proof` state + URL (tenant/workspace-safe, capability-gated)
- `post_run_evidence` state + URL (repo-backed only)
- `result_summary` counts (repo-backed only)
- `diagnostics_state = collapsed`
- [ ] T007 Prove presenter output determinism with Unit tests (no static memoization).
## Phase 3: Detail Page UI (decision-first main/aside)
**Purpose**: Productize the page layout and hierarchy.
- [ ] T008 Refactor Restore Run view page into a main/aside hierarchy:
- Main: decision card + result summary + item outcomes (table) + secondary run details
- Aside: proof panel (source backup, target env, requested by, operation proof, post-run evidence, audit trail) + diagnostics collapsed
- [ ] T009 Ensure diagnostics and raw payloads remain collapsed/secondary by default (no stack traces, no raw JSON as primary UI).
- [ ] T010 Ensure the page does not display "recovery verified", "healthy", "compliant", or "customer-safe" claims unless repo truth supports that semantics.
## Phase 4: Proof/Evidence Links (repo-backed only)
**Purpose**: Make execution proof and post-run evidence explicit, separate, and truthful.
- [ ] T011 Operation proof:
- restore run with `operation_run_id` shows proof state + link to OperationRun detail
- restore run without operation run shows "unavailable" state
- [ ] T012 Post-run evidence:
- when evidence snapshots exist for the linked operation run (tenant-scoped), show state + link to Evidence Snapshot detail
- when absent, show "unavailable" and do not imply recovery proof
## Phase 5: Item Outcomes (table-first, no payload dump)
**Purpose**: Make per-item outcomes reviewable without flooding the page.
- [ ] T013 Render item outcomes as a table (not large cards) when `results.items` exists.
- [ ] T014 Show compact summary counts from `restore_runs.metadata` (only when repo-backed; no fake zeros).
- [ ] T015 Keep raw per-item payload/diff/diagnostics behind disclosure.
## Phase 6: RBAC / Isolation
- [ ] T016 Add at least one positive and one negative authorization test for Restore Run view access.
- [ ] T017 Prove cross-workspace/tenant proof and evidence links cannot leak (deny-as-not-found semantics preserved).
## Phase 7: Tests
- [ ] T018 Add Feature test: `apps/platform/tests/Feature/Filament/Spec335RestoreRunDetailProductizationTest.php` covering:
- decision question visible
- "Completed" does not imply recovery verified
- operation proof state visible
- post-run evidence state visible and truthful
- diagnostics collapsed; raw payload hidden by default
- [ ] T019 Extend or align with existing coverage:
- `apps/platform/tests/Feature/Filament/RestoreResultAttentionSurfaceTest.php`
- [ ] T020 Add Browser smoke/screenshot test: `apps/platform/tests/Browser/Spec335RestoreRunDetailProductizationSmokeTest.php`.
## Phase 8: Screenshots
- [ ] T021 Capture required screenshots under:
- `specs/335-restore-run-detail-post-execution-proof-productization/artifacts/screenshots/`
- [ ] T022 Capture at least:
- `01-restore-run-draft.png`
- `02-restore-run-completed-proof-incomplete.png`
- `03-restore-run-operation-proof.png`
- `04-restore-run-evidence-unavailable.png`
- `05-restore-run-item-outcomes.png`
- `06-restore-run-failed-if-supported.png`
- `07-restore-run-diagnostics-collapsed.png`
- `08-restore-run-dark-mode.png`
If a state is not reachable via fixtures, document why in the Spec 335 notes (do not fake coverage).
## Phase 9: Validation
- [ ] T023 Run:
- `cd apps/platform && ./vendor/bin/sail artisan test tests/Feature/Filament/Spec335RestoreRunDetailProductizationTest.php tests/Feature/Filament/RestoreResultAttentionSurfaceTest.php --compact`
- `cd apps/platform && ./vendor/bin/sail php vendor/bin/pest tests/Browser/Spec335RestoreRunDetailProductizationSmokeTest.php --compact`
- `cd apps/platform && ./vendor/bin/sail pint --dirty`
- `git diff --check`
## Explicit Non-Goals
- [ ] NT001 Do not change restore execution backend behavior.
- [ ] NT002 Do not add new Graph calls or ProviderGateway behavior.
- [ ] NT003 Do not change `OperationRun` lifecycle semantics (link-only).
- [ ] NT004 Do not add migrations, packages, env vars, queues, scheduler, or storage changes.
- [ ] NT005 Do not redesign Restore Create wizard (Spec 333 owns Create UX).
- [ ] NT006 Do not introduce any false recovery-proof claims.