TenantAtlas/specs/363-explicit-uiactioncontext-contract/plan.md
Ahmed Darrazi 9e435ea91f
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 1m2s
feat: implement explicit UiActionContext contract
2026-06-07 13:12:02 +02:00

17 KiB

Implementation Plan: Spec 363 - Explicit UiActionContext Contract for Scoped No-Record Actions

Branch: feat/363-explicit-uiactioncontext-contract | Preparation Branch: 363-explicit-uiactioncontext-contract | Date: 2026-06-07 | Spec: /Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/363-explicit-uiactioncontext-contract/spec.md Input: Feature specification from /Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/363-explicit-uiactioncontext-contract/spec.md

Note: This plan is repo-aware and preparation-only. No application implementation is performed in this step.

Summary

Add an explicit action-context contract for workspace- and environment-scoped no-record Filament actions.

The implementation should:

  • introduce a narrow request-time UiActionContext contract
  • harden UiEnforcement so scoped no-record actions cannot silently use implicit Filament::getTenant() as product scope truth
  • preserve record-backed action behavior where scope comes from the record
  • retrofit representative latent-risk no-record actions
  • add first-click modal/no-run test helpers and action lifecycle tests
  • add a static guard that fails future risky scoped no-record actions without explicit context

No migrations, panel/provider changes, global-search changes, asset strategy changes, or new product workflows are planned.

Technical Context

Language/Version: PHP 8.4.15 Primary Dependencies: Laravel 12.52, Filament 5.2.1, Livewire 4.1.4, Pest 4.3.1 Storage: PostgreSQL via Sail, but no schema changes are planned Testing: Pest Unit + Feature/Filament-Livewire + Architecture/guard; Browser optional only if visible UI hierarchy/copy changes materially Validation Lanes: fast-feedback, confidence, browser optional Target Platform: Laravel monolith in Sail / Dokploy container workflow Project Type: single web application (apps/platform) Performance Goals: no Graph calls during render/action-state/modal mount; static scan remains bounded and deterministic Constraints: no new persistence, no operation type, no capability string, no panel/provider, no asset registration, no global-search change, no compatibility shim, no broad record-backed action rewrite Scale/Scope: no-record scoped actions first, plus representative action retrofits and static recurrence guard

UI / Surface Guardrail Plan

  • Guardrail scope: changed existing actions on existing pages
  • Affected routes/pages/actions/states/navigation/panel/provider surfaces:
    • Inventory list run_inventory_sync
    • Policy list/header sync and related Policy Sync start surface
    • Entra Groups sync_groups
    • Evidence Snapshot create_snapshot and create_first_snapshot
    • Review Pack generate_pack and generate_first
    • Environment Review create_review
    • Environment Diagnostics bootstrapOwner and mergeDuplicateMemberships
    • Restore Run create entrypoint and create wizard
    • Environment Dashboard support request / support diagnostics actions
  • No-impact class, if applicable: N/A, because existing high-impact actions change context behavior
  • Native vs custom classification summary: native Filament pages/resources/actions with shared RBAC enforcement
  • Shared-family relevance: header/page/empty-state action family, RBAC UI enforcement family, OperationRun start family
  • State layers in scope: page render, action visibility, action disabled state, first-click modal mount, submit/execute handler
  • Audience modes in scope: operator-MSP and support-platform
  • Decision/diagnostic/raw hierarchy plan: show safe action state and missing-context copy only; keep low-level Livewire/Filament request details out of UI
  • Raw/support gating plan: no raw request, referer, token, Graph, credential, or payload data in visible UI
  • One-primary-action / duplicate-truth control: do not duplicate run outcome truth in action modals; after submit reuse existing OperationRun links/toasts
  • Handling modes by drift class or surface: review-mandatory for any scoped no-record action that opens a modal, dispatches work, creates an OperationRun, or mutates state
  • Repository-signal treatment: record-backed actions are context only unless the static guard proves they behave like no-record scoped actions
  • Special surface test profiles: standard-native-filament plus action-lifecycle-contract
  • Required tests or manual smoke: Unit + Feature/Filament-Livewire + static guard; Browser only if implementation changes visible copy/hierarchy materially
  • Exception path and spread control: bounded static-guard exceptions must name the file/action and why record/page scope is safe
  • Active feature PR close-out entry: Guardrail / Smoke Coverage
  • UI/Productization coverage decision: no new UI coverage registry update is expected because no new route/page family is introduced
  • Coverage artifacts to update: none by default
  • No-impact rationale: N/A
  • Navigation / Filament provider-panel handling: no panel provider, panel path, navigation, or cluster change
  • Screenshot or page-report need: no by default

Shared Pattern & System Fit

  • Cross-cutting feature marker: yes
  • Systems touched:
    • apps/platform/app/Support/Rbac/UiEnforcement.php
    • apps/platform/app/Support/Rbac/WorkspaceUiEnforcement.php as reference/comparison only unless small shared context support is justified
    • new apps/platform/app/Support/Rbac/Actions/ contract classes if implementation confirms this namespace is still best
    • apps/platform/app/Filament/Concerns/ResolvesPanelTenantContext.php
    • selected existing Filament resources/pages/actions
    • selected existing action tests and new guard/test helper
  • Shared abstractions reused: existing RBAC helpers, capability resolvers, policies/gates, page context resolvers, OperationRun start helpers, Filament action testing helpers
  • New abstraction introduced? why?: yes, a narrow UiActionContext request-time contract is allowed because the problem is RBAC/isolation/queue legitimacy-critical and already repo-verified across multiple surfaces
  • Why the existing abstraction was sufficient or insufficient: UiEnforcement is the right shared path, but it currently allows ambiguous nullable no-record context and implicit Filament tenant fallback
  • Bounded deviation / spread control: keep new classes under an RBAC/action namespace; do not create a generic UI framework, presenter, workflow engine, or action catalog rewrite

OperationRun UX Impact

  • Touches OperationRun start/completion/link UX?: yes, start/mount/submit lifecycle only
  • Central contract reused: existing OperationRunService, run dispatch handlers, OperationRunLinks, OperationUxPresenter, and OpsUxBrowserEvents
  • Delegated UX behaviors: queued toasts, run links, run-enqueued browser events, and terminal lifecycle notifications remain unchanged
  • Surface-owned behavior kept local: action form values and confirmation/missing-context copy
  • Queued DB-notification policy: unchanged
  • Terminal notification path: unchanged
  • Exception path: if broader execution reauthorization is weaker than UI gating, stop and propose OperationRun Start Authorization Contract Hardening

Provider Boundary & Portability Fit

  • Shared provider/platform boundary touched?: no new provider seam
  • Provider-owned seams: existing Graph/provider jobs and services remain provider-owned and are not modified beyond receiving explicit, reauthorized scope
  • Platform-core seams: workspace/environment action context and RBAC UI enforcement
  • Neutral platform terms / contracts preserved: workspace, environment, record, system, product scope, action context
  • Retained provider-specific semantics and why: only current Microsoft/Graph semantics inside existing actions/jobs remain
  • Bounded extraction or follow-up path: none unless broader OperationRun execution authorization weakness is discovered

Constitution Check

GATE: Must pass before implementation starts. Re-check if scope changes.

  • Inventory-first: PASS. No inventory truth changes; Inventory Sync action context becomes explicit only.
  • Read/write separation: PASS. Modal open remains non-mutating; submit/execute must reauthorize before writes/jobs.
  • Graph contract path: PASS. No new Graph calls; render/mount must remain no-Graph.
  • Deterministic capabilities: PASS. Existing capabilities remain authoritative.
  • Workspace and tenant isolation: PASS. Explicit context improves workspace/environment scope safety.
  • RBAC-UX: PASS. UI state remains affordance only; server-side policies/gates remain execution truth.
  • TEST-GOV-001: PASS. Unit + Feature/action + static guard are the narrowest honest proof.
  • PROP-001 / ABSTR-001: PASS only because the new abstraction is security/isolation/action-lifecycle critical and already justified by repeated repo evidence.
  • PERSIST-001 / STATE-001: PASS. No new persisted truth or persisted status family is introduced.
  • XCUT-001 / LAYER-001: PASS. Extend the existing shared UiEnforcement path instead of adding local one-off action rules.
  • UI-COV-001: PASS. Existing reachable surfaces are classified; no new page family is expected.
  • LEAN-001: PASS. No compatibility shim for old no-record fallback behavior.

Test Governance Check

  • Test purpose / classification by changed surface:
    • Unit: UiActionContext, scope/source enums, resolver helpers, missing-context behavior, UiEnforcement context resolution
    • Feature/Filament-Livewire: selected page/resource actions, first-click modal mount, no-run/no-job on modal open, submit reauthorization, wrong-context/readonly behavior
    • Architecture/Feature guard: static source scan for risky scoped no-record actions without explicit context
    • Browser: optional smoke only if visible hierarchy/copy changes materially
  • Affected validation lanes: fast-feedback, confidence, browser optional
  • Why this lane mix is the narrowest sufficient proof: the behavior is request-time action lifecycle and static source guard behavior, not DB schema or provider API behavior
  • Narrowest proving command(s):
    • cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Support/Rbac/Actions tests/Unit/Support/Rbac/UiEnforcementScopedActionContextTest.php
    • cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Architecture/ScopedUiActionContextContractTest.php tests/Feature/Filament/InventoryItemResourceTest.php tests/Feature/PolicySyncStartSurfaceTest.php tests/Feature/RunStartAuthorizationTest.php
    • cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament/EntraGroupAdminScopeTest.php tests/Feature/Evidence/EvidenceSnapshotResourceTest.php tests/Feature/ReviewPack/ReviewPackResourceTest.php tests/Feature/Filament/RestoreRunUiEnforcementTest.php
  • Fixture / helper / factory / seed / context cost risks: keep workspace/environment/member/capability setup explicit; do not introduce full-context defaults in shared helpers
  • Expensive defaults or shared helper growth introduced?: no
  • Heavy-family additions, promotions, or visibility changes: none by default
  • Surface-class relief / special coverage rule: standard-native-filament plus action-lifecycle-contract
  • Closing validation and reviewer handoff: reviewers should verify no hidden Filament::getTenant() product-scope fallback for scoped no-record actions, no modal-open side effects, and no compatibility path
  • Budget / baseline / trend follow-up: none expected
  • Review-stop questions: did implementation broaden into record-backed action migration, OperationRun redesign, UI redesign, or product features?
  • Escalation path: document-in-feature for contained static-guard false positives; follow-up-spec for broader execution authorization weakness; reject-or-split for scope creep
  • Active feature PR close-out entry: Guardrail / Smoke Coverage
  • Why no dedicated follow-up spec is needed now: the root issue is explicit enough to solve as one bounded action-context contract

Repo-Verified Runtime Surfaces Likely Affected

Core RBAC / Context

  • apps/platform/app/Support/Rbac/UiEnforcement.php
  • apps/platform/app/Support/Rbac/WorkspaceUiEnforcement.php (context/reference only unless sharing is justified)
  • apps/platform/app/Filament/Concerns/ResolvesPanelTenantContext.php
  • new apps/platform/app/Support/Rbac/Actions/UiActionContext.php
  • new apps/platform/app/Support/Rbac/Actions/UiActionScope.php
  • new apps/platform/app/Support/Rbac/Actions/UiActionContextSource.php
  • new apps/platform/app/Support/Rbac/Actions/ResolvesUiActionContext.php

Representative Action Surfaces

  • apps/platform/app/Filament/Resources/InventoryItemResource/Pages/ListInventoryItems.php
  • apps/platform/app/Filament/Resources/PolicyResource.php
  • apps/platform/app/Filament/Resources/PolicyResource/Pages/ListPolicies.php
  • apps/platform/app/Filament/Resources/EntraGroupResource/Pages/ListEntraGroups.php
  • apps/platform/app/Filament/Resources/EvidenceSnapshotResource.php
  • apps/platform/app/Filament/Resources/EvidenceSnapshotResource/Pages/ListEvidenceSnapshots.php
  • apps/platform/app/Filament/Resources/ReviewPackResource.php
  • apps/platform/app/Filament/Resources/EnvironmentReviewResource.php
  • apps/platform/app/Filament/Pages/EnvironmentDiagnostics.php
  • apps/platform/app/Filament/Resources/RestoreRunResource.php
  • apps/platform/app/Filament/Resources/RestoreRunResource/Pages/CreateRestoreRun.php
  • apps/platform/app/Filament/Pages/EnvironmentDashboard.php

Tests / Guards

  • apps/platform/tests/Unit/Support/Rbac/Actions/*
  • apps/platform/tests/Unit/Support/Rbac/UiEnforcementScopedActionContextTest.php
  • apps/platform/tests/Feature/Architecture/ScopedUiActionContextContractTest.php
  • apps/platform/tests/Support/Filament/ScopedActionAssertions.php
  • existing action tests under apps/platform/tests/Feature/Filament, apps/platform/tests/Feature/Evidence, apps/platform/tests/Feature/ReviewPack, and apps/platform/tests/Feature/RunStartAuthorizationTest.php
  • existing support action tests under apps/platform/tests/Feature/SupportDiagnostics and apps/platform/tests/Feature/SupportRequests

Technical Approach

  1. Re-read this spec, plan, tasks, checklist, the constitution, and relevant guidelines before runtime edits.
  2. Re-verify the current action callsites and exact action names.
  3. Add failing Unit coverage for context value objects and UiEnforcement scoped behavior.
  4. Add failing Feature/Filament coverage for the known latent-risk actions.
  5. Add the narrow UiActionContext contract and helper/trait.
  6. Harden UiEnforcement to require explicit context for scoped no-record actions while preserving record-backed paths.
  7. Retrofit representative actions to pass explicit context and reauthorize on submit.
  8. Add reusable first-click modal/no-run helper only where it reduces duplication.
  9. Add the static guard with actionable failures.
  10. Run focused tests, Pint dirty, and diff checks.

Risk Controls

  • Keep the first implementation scoped to no-record workspace/environment actions.
  • Do not remove valid record-backed context resolution.
  • Do not allow Filament::getTenant() as fallback product-scope truth for scoped no-record actions.
  • Keep modal open non-mutating.
  • Keep server-side authorization in handlers/services/policies.
  • Keep missing-context copy enterprise-safe and localizable later.
  • No new migrations, assets, global search, panel provider, navigation, capability, operation type, or route.
  • Stop if implementation needs persistence, broad OperationRun redesign, or many static-guard false positives across record-backed actions.

Implementation Phases

Phase 1: Baseline and Repo-Truth Inventory

Confirm current branch/worktree, re-read dependencies, and inventory exact callsites/action names before edits.

Phase 2: Contract and Unit Tests

Add the action-context value object/enums/trait or equivalent and Unit coverage for workspace, environment, record, system, and missing context behavior.

Phase 3: UiEnforcement Contract

Add explicit scoped-action API or compatible signature changes, remove implicit scoped no-record fallback, preserve record-backed behavior, and cover missing-context classification.

Phase 4: Representative Action Retrofits

Retrofit Inventory Sync, Policy Sync, Entra Group Sync, Evidence Snapshot, Review Pack, Environment Review, Environment Diagnostics, Restore create, and Environment Dashboard support actions.

Phase 5: Test Helper and Static Guard

Add the reusable first-click modal/no-run helper and static architecture guard.

Phase 6: Validation and Close-Out

Run focused tests, optional browser smoke only if needed, Pint dirty, git diff --check, and record no-migration/no-asset/no-provider/global-search status.

Project Structure

Documentation (this feature)

specs/363-explicit-uiactioncontext-contract/
├── spec.md
├── plan.md
├── tasks.md
└── checklists/
    └── requirements.md

Application (later implementation only)

apps/platform/app/Support/Rbac/Actions/
apps/platform/app/Support/Rbac/UiEnforcement.php
apps/platform/app/Filament/...
apps/platform/tests/...

No application files are changed during this preparation step.