TenantAtlas/specs/333-restore-create-ux-final-productization/artifacts/restore-preview-step-audit.md
ahmido 1e45a29937 feat: finalize restore create ux productization (#403)
## Summary
- finalize the restore create wizard productization across safety, validation, preview, and confirmation steps
- refine the restore presenter output and Blade component rendering for clearer proof, scope, resolver, and execution-readiness states
- add and update feature and browser coverage plus Spec 333 artifacts and screenshots

## Testing
- Not run as part of this commit/PR task

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #403
2026-05-28 22:04:32 +00:00

23 KiB

Restore Preview Step Audit - Spec 333

Executive Summary

  • readiness: not ready
  • top findings:
    • P0: Step 04 can show Next gate: Confirmation while execution readiness is unavailable and canProceedToConfirm is false. Browser verification confirmed Next stays on Step 04 and raises Execution blocked, so progression is protected, but the visible gate is contradictory.
    • P1: Preview rows do not carry an explicit review reason. Operators must infer why review is needed from generic row chips.
    • P1: Assignment and scope-tag preview data is repo-backed only as booleans and aggregate counts, not as detailed diffs.
    • P2: Next remains visually enabled before preview and after blocked execution readiness; enforcement happens through the wizard validation hook.
    • P2: Preview copy still exposes implementation terms such as normalized diff and uses preview notifications that say items "will be updated during execution."
  • recommended implementation strategy: keep changes narrow in the presenter and preview Blade. Fix gate wording/action state first, then add a derived review_reason row contract from already-available preview fields. Do not add new persisted entities for assignment or scope-tag details until the diff generator can produce them.

Repo Safety

  • command snapshot:
    • git status --short --branch
    • git diff --name-only
  • branch: 333-restore-create-ux-final-productization
  • base commit recorded before audit: 3bbea1bd feat: productize restore wizard preview safety gates and process flow (#399)
  • dirty files existed before this audit and were treated as protected user/agent work.
  • runtime files that looked related to Spec 333 and were not edited by this audit:
    • apps/platform/app/Filament/Resources/RestoreRunResource.php
    • apps/platform/app/Filament/Resources/RestoreRunResource/Pages/CreateRestoreRun.php
    • apps/platform/app/Filament/Resources/RestoreRunResource/Presenters/RestoreRunCreatePresenter.php
    • apps/platform/app/Support/RestoreSafety/RestoreSafetyResolver.php
    • apps/platform/resources/views/filament/forms/components/restore-run-preview.blade.php
    • apps/platform/resources/views/filament/forms/components/restore-run-confirm-panel.blade.php
    • apps/platform/resources/views/filament/forms/components/restore-run-safety-*.blade.php
    • apps/platform/tests/Browser/Spec333RestoreCreateUxFinalProductizationSmokeTest.php
    • apps/platform/tests/Feature/Filament/Spec333RestoreCreateUxFinalProductizationTest.php
  • dirty files not to touch during this audit:
    • existing Spec 332 screenshots and tests
    • existing runtime PHP, Blade, and test changes
    • any staged or untracked runtime files
  • files created by this audit:
    • specs/333-restore-create-ux-final-productization/artifacts/restore-preview-step-audit.md
    • screenshots under specs/333-restore-create-ux-final-productization/artifacts/screenshots/preview-audit/

Repo Truth

Data sources

  • Backup item and restore source: backup_items.payload, backup_items.assignments, backup_items.metadata.scope_tag_ids.
  • Current target state: latest policy_versions.snapshot, policy_versions.assignments, policy_versions.scope_tags.
  • Preview generation: App\Services\Intune\RestoreDiffGenerator::generate().
  • Preview state in wizard: preview_summary, preview_diffs, preview_ran_at, preview_basis, preview_invalidation_reasons.
  • Presenter contract: RestoreRunCreatePresenter::make() and previewSummary().
  • Visible UI: restore-run-preview.blade.php.
  • Gate/proof data: RestoreSafetyResolver, PreviewIntegrityState, ChecksIntegrityState, ExecutionReadinessState, process-flow and proof partials.

Diff data availability

  • repo-verified: per-policy diff.summary.added, removed, changed.
  • repo-verified: bounded raw diff arrays exist in diff.added, diff.removed, diff.changed, but current Step 04 does not render raw diff details by default.
  • repo-verified: diff_omitted and diff_truncated exist for limit handling.
  • derived from existing model: needsAttentionDiffs is derived from diff counts, assignments_changed, and scope_tags_changed.
  • not available: row-level human review reason as a first-class field.

Assignment and scope-tag availability

  • repo-verified: assignments_changed boolean per preview entry.
  • repo-verified: aggregate assignments_changed policy count in preview summary.
  • repo-verified: scope_tags_changed boolean per preview entry.
  • repo-verified: aggregate scope_tags_changed policy count in preview summary.
  • not available: assignment added/removed/changed counts.
  • not available: scope-tag added/removed/changed counts.
  • deferred: mapping-specific assignment/scope-tag explanation in preview rows.

Preview action availability

  • repo-verified: RestoreDiffGenerator emits action = update when a current version exists and action = create otherwise.
  • foundation-real but not generated here: Blade contains a delete label path, but the generator path audited here does not produce deletes.
  • derived from existing model: UI displays unchanged rows as No policy changes even though generator action can still be update.
  • not available: a persisted no-op action type.

Review, warning, and blocker categories

  • repo-verified: validation blockers/warnings come from check summary and check results.
  • repo-verified: execution readiness can block confirmation even when validation and preview are current.
  • repo-verified: preview/check integrity states are not_generated, invalidated, stale, and current.
  • derived from existing model: canProceedToConfirm = checksAreCurrent && previewIsCurrent && executionAllowed.
  • current gap: nextGateLabel currently returns Confirmation when checks and preview are current, even if executionAllowed is false.

Browser Fixture / URLs

  • local target: http://localhost/admin
  • fixture used for reachable diff state:
    • workspace: spec332-audit-dbdw18
    • environment: spec332-audit-env-tazinm
    • user: spec332-audit-i5optd@example.test
    • backup set: 18 (Spec332 Audit Usable Backup)
  • route pattern used:
    • /admin/local/smoke-login?...&redirect=/admin/workspaces/spec332-audit-dbdw18/environments/spec332-audit-env-tazinm/restore-runs/create?backup_set_id=18
  • capture method:
    • Integrated Browser was used to navigate and verify interactions.
    • In-app screenshot capture timed out on Page.captureScreenshot, so image files were captured with the repo-installed Playwright package in apps/platform.
  • no restore run was created.

Reachable states

  • Preview generated with differences: reachable.
  • Needs attention: reachable.
  • Safety/proof disclosure: reachable.
  • Dark mode: reachable.
  • Next before preview: reachable; visually enabled, halted by hook.
  • Next after generated preview with execution unavailable: reachable; visually enabled, halted by hook.

Not reachable states

  • Preview generated with no changes: not reachable with current workspace-scoped fixtures. No-change local backups exist in legacy non-workspace-scoped data (backup_set_id 4/14), but not in the Spec 332/333 scoped route.
  • Preview with assignment changes: data exists in backup_set_id 19, but browser flow stops at Step 03 with a validation blocker: 1 group assignment targets are missing in the tenant and require mapping (or skip).
  • Preview with scope-tag changes: repo-supported by generator fields, but no current scoped browser fixture was found.
  • Preview blocked/unavailable on Step 04: not directly reachable because Step 03 validation blockers halt progression before Step 04. The presenter can render unavailable states from state, but the wizard path did not expose them without adding fixtures.

Screenshot Index

State Screenshot Notes
Preview generated summary screenshots/preview-audit/01-preview-generated-summary.png Diff state with current preview, execution unavailable
Needs attention screenshots/preview-audit/02-preview-needs-attention.png Row shows policy diff, assignments, scope tags
Details expanded screenshots/preview-audit/03-preview-details-expanded.png All reviewed items opened
All reviewed collapsed screenshots/preview-audit/04-preview-all-reviewed-collapsed.png Default collapsed disclosure
No changes not captured No workspace-scoped no-change fixture found
Assignment change not captured Existing fixture blocked by missing group mapping at validation
Scope-tag change not captured No scoped browser fixture found
Blocked preview not captured Wizard halts before Step 04 for blocker fixture
Safety/proof disclosure screenshots/preview-audit/09-preview-safety-proof-disclosure.png Safety gates and proof opened
Dark mode screenshots/preview-audit/10-preview-dark-mode.png Step 04 summary in dark theme

Current UI Assessment

Decision Summary

  • Strong: summary-first layout is clear, quiet, and scannable.
  • Strong: counts for policies reviewed, changed, unchanged, review, assignments, scope tags, blockers, warnings, and next gate are visible above details.
  • Gap: Next gate can say Confirmation while Execution says Unavailable and Next is blocked.
  • Gap: the primary next action text says to resolve Microsoft permission readiness, but the metric card still says Confirmation.
  • Gap: Next is visually enabled before preview and when execution readiness blocks confirmation.

Preview Details

  • Strong: details are not a card flood on desktop; changed items render in a table-like hierarchy with clear labels.
  • Strong: raw JSON/provider payloads are hidden by default.
  • Gap: row does not include a Review reason.
  • Gap: Update existing is clearer than Update, but it still does not explain what changed by itself.
  • Gap: unchanged rows still have an underlying generated action of update; the UI derives No policy changes, but the contract is not explicit in data.

Needs Attention

  • Strong: changed rows are separated from unchanged rows.
  • Gap: the warning text is generic: Review policy diff, assignments, and scope tags before confirmation.
  • Gap: if only one dimension changed, the row still references all dimensions instead of the precise reason.

All Reviewed Items

  • Strong: collapsed by default and not dominant.
  • Strong: useful as a complete audit list.
  • Gap: because changed rows are already shown above, the disclosure duplicates data. That is acceptable if the later implementation keeps it compact.

Safety / Proof Disclosure

  • Strong: visible but below the preview decision and details.
  • Strong: full safety/proof content is progressively disclosed.
  • Gap: Preview evidence appears both in the preview summary and in the lower evidence/proof section, which can blur whether it means diff evidence or gate evidence.
  • Gap: Execution unavailable is visible, but its relationship to Next gate: Confirmation is contradictory.

Buttons / Interactions

Action Visible state Expected behavior Actual behavior Preserves state? Gate effect Label clear? Severity Recommended fix
Next before preview Visible and enabled Should be disabled or clearly blocked until preview exists Click stays on Step 04 through validation hook yes no gate advance weak P2 Disable or relabel with preview requirement
Next after preview, execution unavailable Visible and enabled Should not advertise Confirmation if execution readiness blocks confirmation Click stays on Step 04 and shows Execution blocked yes no gate advance contradictory P0 Set next gate/action to prerequisites blocked, or disable Next
Back Visible Return to Step 03 preserving state Works in normal wizard flow yes previous step clear P3 No change
Cancel Visible earlier in wizard Navigate away/cancel create flow Standard Filament behavior n/a exits flow clear P3 No change
Generate preview Visible before preview Generate current preview Works yes preview current clear enough P2 Avoid normalized diff helper copy
Regenerate preview Visible after preview Refresh preview for current basis Works yes preview refreshed clear P3 Keep
Clear Visible after preview Clear preview state Visible; not tested to avoid losing audit state likely yes preview not generated acceptable P3 Label could be Clear preview for specificity
All reviewed items disclosure Visible after preview Expand complete list Works yes none clear P3 Keep collapsed
View safety gates and restore proof Visible after preview Expand safety/proof details Works yes none mostly clear P2 Avoid duplicate proof terminology if proof is incomplete
Diagnostics Present in partials/tests, not prominent in captured state Show technical details only on demand Not a dominant control in Step 04 yes none acceptable P3 Keep behind disclosure

Copy / Terminology

Problematic or mixed terms found:

  • Generate a normalized diff preview before confirmation.
    • classification: P2 copy issue
    • reason: normalized diff is implementation language.
  • 1 policy will be updated during execution.
    • classification: P2/P1 depending context
    • reason: generated from preview stage; not create/no-op aware and implies execution certainty.
  • Next gate: Confirmation
    • classification: P0 in the verified fixture
    • reason: contradicted by Execution unavailable and blocked Next.
  • Execution unavailable
    • classification: repo-safe, but relationship to confirmation is unclear.
  • Update existing
    • classification: acceptable label, but insufficient without review reason.
  • Not observed in Step 04 capture:
    • Graph works again
    • technical startability
    • write-gate
    • hard-blocker

Preview Row Contract Recommendation

Column Data source Available? Classification Fallback if missing Recommended label
Policy preview_diffs[].display_name, policy_identifier, policy_type, platform yes repo-verified policy identifier plus type Policy
Restore action preview_diffs[].action plus derived unchanged state partial repo-verified for create/update, derived for no-change Review required Restore action
Policy diff preview_diffs[].diff.summary yes repo-verified Diff unavailable Policy diff
Assignments preview_diffs[].assignments_changed yes, boolean only repo-verified Unavailable Assignments
Scope tags preview_diffs[].scope_tags_changed yes, boolean only repo-verified Unavailable Scope tags
Review reason derived from diff counts, assignment boolean, scope-tag boolean, action, degraded/source states not stored derived from existing model Review preview evidence before confirmation Review reason
Row action no row-level action currently exists no not available use disclosure only Action only if an actual action is added

Recommended derived review reasons:

  • Policy settings differ from current target state.
  • Assignments differ from current target state.
  • Scope tags differ from current target state.
  • Target policy is missing and would be created if restore proceeds.
  • No restore changes detected.
  • Preview detail is unavailable because the diff was omitted by limits.

State Matrix

State Validation state Preview data state Expected status Expected next gate Expected primary action Can continue? Proof claims allowed? Current UI Gap
Preview not generated current checks none preview required Preview Generate preview no validation proof only Shows Next gate: Preview; Next enabled but halted Button state weak
Preview generated, no changes current checks current, no changed rows preview current Confirmation if execution allowed, otherwise prerequisites Continue only if execution allowed only if execution allowed not browser-reached Needs fixture
Preview generated, changes current checks current, changed rows preview current Confirmation if execution allowed, otherwise prerequisites Review rows only if execution allowed preview proof only Shows changes clearly Missing review reason
Preview generated, needs attention current checks current, needs attention review required Confirmation if execution allowed, otherwise prerequisites Review reasons only if execution allowed preview proof only Generic review text Row reason missing
Preview generated, blocker blocked checks or execution blocked current or unavailable blocked Resolve blockers Resolve blockers no no execution proof Shows Confirmation in verified execution-blocked fixture P0 gate contradiction
Preview stale after scope/mapping change check or preview basis mismatch stale/invalidated regenerate required Validation or Preview rerun checks/preview no prior proof only as stale repo-supported Not browser-captured
Validation blocked blocked none/current irrelevant blocked Validation resolve blockers no no execution proof browser reached on group mapping backup at Step 03 Step 04 not reachable
Validation passed with warnings current with warnings current or none review warnings Preview/Confirmation depending preview and execution review warnings maybe warning proof only repo-supported Not browser-captured
Validation passed clean current clean current ready if execution allowed Confirmation continue yes only if execution allowed preview/check proof allowed, no execution proof execution still unavailable in fixture Gate wording conflict

Findings

P0 Blockers

  1. Step 04 shows the wrong next gate when execution readiness blocks confirmation.
    • Evidence: browser fixture shows Next gate: Confirmation, Execution: Unavailable, and primary text resolve Microsoft permission readiness before confirmation.
    • Actual click behavior: Next remains on Step 04 and shows Execution blocked.
    • Risk: operator sees a contradictory decision state.
    • Recommended fix: nextGateLabel must account for ! executionAllowed; use Prerequisites or Execution readiness instead of Confirmation, and make the primary action match.

P1 High

  1. Preview rows lack explicit review reason.
    • Evidence: row shows Update existing, 0 added, 0 removed, 1 changed, No change, No change.
    • Risk: review intent remains implicit and brittle for assignment/scope-tag-only changes.
    • Recommended fix: add a derived Review reason field/column in presenter or view helpers.
  2. Assignment and scope-tag detail is not available beyond boolean change flags.
    • Evidence: generator emits assignments_changed and scope_tags_changed, plus aggregate counts.
    • Risk: UI can truthfully say changed/no change, but not explain which assignments or tags changed.
    • Recommended fix: do not invent detail. Label as changed/no change/mapping required/unavailable until generator supports detailed normalized diffs.
  3. Preview notification overstates execution certainty.
    • Evidence: 1 policy will be updated during execution.
    • Risk: preview stage is not execution, and action mix can include create/no-change.
    • Recommended fix: Preview found 1 policy with restore differences.

P2 Medium

  1. Next is visually enabled when the next action is blocked by missing preview or execution readiness.
    • Evidence: browser click before preview stays on Step 04; after preview and execution unavailable stays on Step 04.
    • Recommended fix: disable or change label/helper when canProceedToConfirm is false.
  2. normalized diff copy is developer-facing.
    • Evidence: helper text says Generate a normalized diff preview before confirmation.
    • Recommended fix: Generate a preview of policy, assignment, and scope-tag changes before confirmation.
  3. Preview evidence is used for both diff currentness and lower proof/gate area.
    • Risk: evidence language can imply more proof than exists.
    • Recommended fix: use Preview status for currentness and Safety gates for lower proof area.
  4. Browser fixture coverage is incomplete for no-change, assignment-change-after-mapping, scope-tag-change, stale, and blocked Step 04 states.
    • Recommended fix: add focused browser fixtures or component-state browser harness only after the UI contract is finalized.

P3 Polish

  1. Clear should be Clear preview for specificity.
  2. All reviewed items is useful but duplicates changed rows; keep it collapsed and compact.
  3. The row layout is acceptable on desktop, but mobile cards should keep fixed label/value spacing to avoid repeated card bulk.
  • narrow changes only:
    • presenter gate logic
    • preview row contract helpers
    • preview Blade labels/copy
    • focused tests
  • files to touch later:
    • apps/platform/app/Filament/Resources/RestoreRunResource/Presenters/RestoreRunCreatePresenter.php
    • apps/platform/resources/views/filament/forms/components/restore-run-preview.blade.php
    • apps/platform/app/Filament/Resources/RestoreRunResource.php only for action label/helper/disabled-state adjustments
    • existing Spec 333 feature/browser tests
  • tests to add/update later:
    • presenter test for executionAllowed=false producing non-Confirmation next gate
    • feature test for derived review reasons across policy diff, assignment change, scope-tag change, create, and no-change rows
    • browser smoke for blocked Next state and clean preview state if fixtures are added
  • screenshots to update later:
    • no-change state
    • assignment-change state after mapping/skip fixture
    • scope-tag-change state
    • blocked/prerequisite state

DoD for Later Implementation

  • Next gate never says Confirmation unless canProceedToConfirm is true.
  • Next behavior and visible label/helper match the current gate.
  • Preview rows include:
    • Policy
    • Restore action
    • Policy diff
    • Assignments
    • Scope tags
    • Review reason
  • Assignment and scope-tag columns do not imply unavailable detail.
  • Raw JSON/provider payloads remain hidden by default.
  • Copy avoids implementation terms and false execution/recovery proof claims.
  • Tests cover Filament/Livewire v5/v4 component behavior through Livewire components, not static resource classes.
  • No global assets are introduced; filament:assets deployment requirement remains unchanged.

Filament v5 Audit Notes

  • Livewire compliance: application is on Livewire 4.1.4, satisfying Filament v5's Livewire v4 requirement.
  • Provider registration: panel/provider registration remains in apps/platform/bootstrap/providers.php; this audit made no provider changes.
  • Global search: RestoreRunResource::getPages() includes a view page, satisfying the v5 hard rule if the resource is globally searchable.
  • Destructive actions: Step 04 generate/regenerate/clear preview actions are not destructive restore execution actions. The dangerous execution gate remains later in the wizard and must continue to require confirmation and authorization.
  • Asset strategy: no Filament assets were added. Deployment php artisan filament:assets remains unchanged.
  • Testing plan for later implementation: use Pest/Livewire component tests for wizard state and Filament action tests for Step 04 actions.