# Implementation Plan: Operations Auto-Refresh Pass

**Branch**: `[123-operations-auto-refresh]` | **Date**: 2026-03-08 | **Spec**: [spec.md](./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](./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 `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](./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](./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](./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 — `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)

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

### Source Code (repository root)

```text
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.
