9.2 KiB
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
OperationRunrecords 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;
OperationRunServiceremains 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
queuedandgeneratingas 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
pollingInterval→wire: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.
OperationRunremains the source of truth for run-detail polling decisions.ReviewPackremains 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
TenantReviewPackCardwidget 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 tenant’s latest pack only.
- Run observability: PASS —
OperationRunreuse remains intact; no inline work added to render surfaces. - Ops-UX lifecycle ownership: PASS — plan introduces no direct
status/outcomemutation 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.phptests/Feature/Operations/TenantlessOperationRunViewerTest.phptests/Feature/ReviewPack/ReviewPackWidgetTest.phptests/Feature/ReviewPack/ReviewPackGenerationTest.phptests/Feature/ReviewPack/ReviewPackRbacTest.phpfor 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.