TenantAtlas/specs/123-operations-auto-refresh/research.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

4.1 KiB
Raw Blame History

Research — Operations Auto-Refresh Pass

Decision: Reuse the shared run-detail polling helper for the tenantless operation run viewer

Rationale

  • The canonical operation detail surface already centralizes conditional polling in App\Support\OpsUx\RunDetailPolling.
  • OperationRunResource::infolist() already applies the established safeguards: stop polling when the browser tab is hidden and when Filament action modals are mounted.
  • TenantlessOperationRunViewer already delegates its infolist rendering to OperationRunResource, so the least-risk implementation path is to keep the tenantless page aligned with that shared detail-view contract instead of introducing a second polling policy.
  • Existing tests already cover the helpers active-versus-terminal behavior, which reduces the amount of new logic that needs fresh regression coverage.

Alternatives considered

  • Hard-code a new fixed 10s interval inside TenantlessOperationRunViewer — rejected because it would fork the run-detail behavior from the canonical operation detail pattern and risk drifting from the shared hidden-tab and modal-open guards.
  • Duplicate the RunDetailPolling logic inside the page class — rejected because it would create a second source of truth for active run polling.

Decision: Treat review pack queued and generating as the only active card states

Rationale

  • ReviewPackStatus defines a card-specific lifecycle: queued, generating, ready, failed, expired.
  • The widget view already renders queued and generating as the same in-progress state and renders ready, failed, and expired as terminal states.
  • ReviewPackService creates new records in queued, and GenerateReviewPackJob advances them into generating before landing in ready or failed.
  • Using the review-pack lifecycle directly avoids over-polling when unrelated tenant operation runs are active.

Alternatives considered

  • Drive the card from tenant-wide ActiveRuns::existForTenant() — rejected because this would keep the card polling for unrelated operations even when review-pack generation is not active.
  • Poll whenever any review pack exists — rejected because terminal states must remain stable and stop refreshing.

Decision: Attach review-pack polling at the widget root using the existing simple-widget Blade pattern

Rationale

  • TenantReviewPackCard is a plain Filament Widget, not a table or stats widget.
  • The closest established pattern is NeedsAttention, which computes a pollingInterval in PHP and conditionally emits wire:poll.{interval} on the root Blade element.
  • A root-level wire:poll.10s keeps the implementation small, readable, and consistent with the other lightweight dashboard widgets in the product.

Alternatives considered

  • Introduce a new shared global polling framework — rejected because the spec explicitly excludes a broader polling rewrite.
  • Move review-pack polling into JavaScript or browser events — rejected because the product already relies on Livewire/Filament polling for similar surfaces and the requested scope is intentionally small.

Decision: Extend existing helper and widget tests instead of inventing new verification infrastructure

Rationale

  • tests/Feature/OpsUx/RunDetailPollingStopsOnTerminalTest.php already verifies the canonical helper stops polling on terminal operation states and remains active for queued/running runs.
  • tests/Feature/ReviewPack/ReviewPackWidgetTest.php already covers the widgets empty, active, and terminal render states and is the most direct place to add polling assertions.
  • tests/Feature/Operations/TenantlessOperationRunViewerTest.php already covers tenantless access semantics and is the right page-level companion if markup-level assertions are needed.

Alternatives considered

  • Add a brand-new standalone polling test suite — rejected because the affected behavior already belongs to well-scoped existing helper and widget tests.
  • Rely on manual QA only — rejected because the spec requires automated coverage for active-versus-terminal polling behavior.