## 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
4.1 KiB
4.1 KiB
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.TenantlessOperationRunVieweralready delegates its infolist rendering toOperationRunResource, 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 helper’s active-versus-terminal behavior, which reduces the amount of new logic that needs fresh regression coverage.
Alternatives considered
- Hard-code a new fixed
10sinterval insideTenantlessOperationRunViewer— 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
RunDetailPollinglogic 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
ReviewPackStatusdefines a card-specific lifecycle:queued,generating,ready,failed,expired.- The widget view already renders
queuedandgeneratingas the same in-progress state and rendersready,failed, andexpiredas terminal states. ReviewPackServicecreates new records inqueued, andGenerateReviewPackJobadvances them intogeneratingbefore landing inreadyorfailed.- 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
TenantReviewPackCardis a plain FilamentWidget, not a table or stats widget.- The closest established pattern is
NeedsAttention, which computes apollingIntervalin PHP and conditionally emitswire:poll.{interval}on the root Blade element. - A root-level
wire:poll.10skeeps 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.phpalready verifies the canonical helper stops polling on terminal operation states and remains active forqueued/runningruns.tests/Feature/ReviewPack/ReviewPackWidgetTest.phpalready covers the widget’s empty, active, and terminal render states and is the most direct place to add polling assertions.tests/Feature/Operations/TenantlessOperationRunViewerTest.phpalready 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.