TenantAtlas/specs/123-operations-auto-refresh/plan.md
ahmido 4db73e872e Spec 123: operations auto-refresh pass (#149)
## Summary
- add conditional polling support for the tenantless operation run viewer and tenant review pack card
- add focused Pest coverage for active vs terminal polling behavior and related review pack access regressions
- add the full Spec Kit artifacts for Spec 123, including spec, plan, research, data model, contracts, quickstart, tasks, and checklist

## Testing
- `vendor/bin/sail artisan test --compact tests/Feature/OpsUx/RunDetailPollingStopsOnTerminalTest.php tests/Feature/Operations/TenantlessOperationRunViewerTest.php tests/Feature/ReviewPack/ReviewPackWidgetTest.php tests/Feature/ReviewPack/ReviewPackGenerationTest.php tests/Feature/ReviewPack/ReviewPackRbacTest.php`
- `vendor/bin/sail bin pint --dirty --format agent`

## Notes
- Manual QA task `T014` in the Spec Kit checklist remains to be completed outside this automated flow.
- Livewire v4.0+ compliance is unchanged.
- No panel provider changes were made; provider registration remains in `bootstrap/providers.php`.
- No global-search behavior was changed.
- No destructive actions were added or modified.
- No new Filament assets were introduced; existing deployment expectations for `php artisan filament:assets` remain unchanged.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #149
2026-03-08 11:11:26 +00:00

9.2 KiB
Raw Blame History

Implementation Plan: Operations Auto-Refresh Pass

Branch: [123-operations-auto-refresh] | Date: 2026-03-08 | Spec: spec.md Input: Feature specification from /specs/123-operations-auto-refresh/spec.md

Note: This plan is filled in by the /speckit.plan workflow.

Summary

Add conditional auto-refresh to the canonical tenantless operation run viewer and intentionally reusable tenant-scoped review pack card surfaces by reusing existing product polling patterns instead of inventing new infrastructure. The run viewer will stay aligned with the shared run-detail polling helper and its existing hidden-tab / modal-open safeguards, while the embedded review pack widget will emit a simple 10s Livewire polling interval only when the latest review pack is in an active generation state.

Technical Context

Language/Version: PHP 8.4 runtime target on Laravel 12 code conventions; Composer constraint php:^8.2
Primary Dependencies: Laravel 12, Filament v5.2.1, Livewire v4, Pest v4, Laravel Sail
Storage: PostgreSQL primary app database
Testing: Pest feature tests run through vendor/bin/sail artisan test --compact
Target Platform: Web application rendered through Filament panels on Laravel Sail / containerized deployment
Project Type: Single Laravel web application
Performance Goals: Active monitoring surfaces should refresh automatically without manual input while avoiding unnecessary polling once work is terminal
Constraints: Preserve DB-only render behavior for monitoring surfaces; no WebSockets, no new backend events, no global polling rewrite, no polling on terminal states
Scale/Scope: Two existing UI surfaces, no schema changes, no dependency changes, targeted regression coverage only

Constitution Check

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

  • Inventory-first: PASS — no inventory or snapshot semantics change.
  • Read/write separation: PASS — no new write workflow is introduced; only passive refresh behavior changes.
  • Graph contract path: PASS — no Graph calls or contract registry changes are involved.
  • Deterministic capabilities: PASS — no capability derivation changes.
  • RBAC-UX plane separation: PASS — /admin/operations/{run} remains a canonical Monitoring route and the intentionally reusable tenant-scoped review widget remains tenant-plane only on every host surface, with existing authorization rules unchanged.
  • Workspace isolation: PASS — the tenantless operation viewer continues to rely on existing workspace membership checks and referenced-tenant entitlement checks for tenant-bound runs.
  • Destructive confirmations: PASS — no new destructive actions are added.
  • Global search safety: PASS — feature does not touch global search.
  • Tenant isolation: PASS — review pack polling remains tenant-scoped and uses existing access checks.
  • Run observability: PASS — existing OperationRun records remain the sole source for operation progress; no new run type or lifecycle mutation path is introduced.
  • Ops-UX 3-surface feedback: PASS — queued toast, progress surfaces, and terminal notification behavior are unchanged.
  • Ops-UX lifecycle ownership: PASS — this feature reads run state only; OperationRunService remains the only lifecycle transition owner.
  • Ops-UX summary counts: PASS — unchanged.
  • Ops-UX guards: PASS — existing helper guard coverage is reused and extended where needed.
  • Ops-UX system runs: PASS — unchanged.
  • Automation / idempotency: PASS — unchanged.
  • Data minimization / safe logging: PASS — unchanged.
  • Badge semantics (BADGE-001): PASS — existing badge mappings stay centralized; polling only re-renders them.
  • Filament Action Surface Contract: PASS WITH EXEMPTION — affected surfaces change passive refresh behavior only, not action definitions.
  • Filament UX-001: PASS WITH EXEMPTION — no layout or information-architecture changes are introduced.
  • Livewire v4.0+ compliance: PASS — Filament v5 / Livewire v4 stack remains unchanged.
  • Provider registration location: PASS — no panel-provider changes; Laravel 12 keeps providers in bootstrap/providers.php.

Phase 0 — Research Summary

Research findings are recorded in research.md.

  • Reuse App\Support\OpsUx\RunDetailPolling::interval() for tenantless run detail behavior instead of introducing a second run-detail polling policy.
  • Preserve the existing run-detail suppression guards for hidden browser tabs and mounted Filament actions.
  • Treat review-pack queued and generating as the only active widget states; ready, failed, expired, and empty state are terminal/non-polling.
  • Attach review-pack polling at the widget Blade root using the same pollingIntervalwire:poll.{interval} pattern already used by lightweight dashboard widgets.
  • Extend existing Pest coverage rather than building new test infrastructure.

Phase 1 — Design & Contracts

Data Model

Design details are recorded in data-model.md.

Key design points:

  • No schema changes are required.
  • OperationRun remains the source of truth for run-detail polling decisions.
  • ReviewPack remains the source of truth for review-pack-card polling decisions.
  • Polling state is derived view state (interval string | null), not persisted state.

Contracts

Internal UI behavior contracts are recorded in contracts/polling-contracts.yaml.

Contract scope:

  • Tenantless operation run viewer at /admin/operations/{run}
  • Intentionally reusable tenant-scoped embedded TenantReviewPackCard widget surfaces (component-scoped; no standalone route is owned by the widget itself)

Quickstart

Implementation and verification steps are recorded in quickstart.md.

Post-Design Constitution Re-check

  • Inventory-first: PASS — no data-ownership boundary changes.
  • Read/write separation: PASS — polling remains read-only.
  • Graph contract path: PASS — no remote integrations added.
  • RBAC-UX: PASS — existing 404/403 behavior and capability checks remain authoritative.
  • Workspace isolation: PASS — tenantless run viewer continues to authorize against the run workspace and referenced tenant scope when the run is tenant-bound.
  • Tenant isolation: PASS — review-pack-card polling is based on the current tenants latest pack only.
  • Run observability: PASS — OperationRun reuse remains intact; no inline work added to render surfaces.
  • Ops-UX lifecycle ownership: PASS — plan introduces no direct status / outcome mutation path.
  • BADGE-001: PASS — no new badge semantics introduced.
  • Filament Action Surface Contract: PASS WITH EXEMPTION — no action-surface mutation.
  • UX-001: PASS WITH EXEMPTION — no layout change required for passive refresh.

Project Structure

Documentation (this feature)

specs/123-operations-auto-refresh/
├── plan.md
├── research.md
├── data-model.md
├── quickstart.md
├── contracts/
│   └── polling-contracts.yaml
└── tasks.md

Source Code (repository root)

app/
├── Filament/
│   ├── Pages/Operations/TenantlessOperationRunViewer.php
│   ├── Resources/OperationRunResource.php
│   └── Widgets/
│       ├── Dashboard/NeedsAttention.php
│       └── Tenant/TenantReviewPackCard.php
├── Models/
│   ├── OperationRun.php
│   └── ReviewPack.php
├── Services/
│   └── ReviewPackService.php
└── Support/OpsUx/
    ├── ActiveRuns.php
    ├── OperationStatusNormalizer.php
    └── RunDetailPolling.php

resources/views/
├── filament/pages/operations/tenantless-operation-run-viewer.blade.php
├── filament/widgets/dashboard/needs-attention.blade.php
└── filament/widgets/tenant/tenant-review-pack-card.blade.php

tests/Feature/
├── Operations/TenantlessOperationRunViewerTest.php
├── OpsUx/RunDetailPollingStopsOnTerminalTest.php
└── ReviewPack/ReviewPackWidgetTest.php

Structure Decision: Keep the implementation inside the existing Laravel / Filament structure. Reuse current polling helpers and Blade widget patterns in place, with targeted updates limited to the two affected surfaces and their directly related tests.

Testing Strategy

  • Extend helper-level coverage for run-detail active-versus-terminal polling behavior only if the shared helper changes.
  • Add page/widget assertions that active surfaces emit polling and terminal surfaces do not.
  • Keep verification targeted to:
    • tests/Feature/OpsUx/RunDetailPollingStopsOnTerminalTest.php
    • tests/Feature/Operations/TenantlessOperationRunViewerTest.php
    • tests/Feature/ReviewPack/ReviewPackWidgetTest.php
    • tests/Feature/ReviewPack/ReviewPackGenerationTest.php
    • tests/Feature/ReviewPack/ReviewPackRbacTest.php for unchanged tenant-scope access regression coverage
  • Manual QA will cover one active and one terminal example for each affected surface.

Complexity Tracking

No constitution violations or complexity exemptions are required for this plan.