chore: commit all changes (automated)
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 1m31s
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 1m31s
This commit is contained in:
parent
867bd92370
commit
c1f4ebaa05
@ -13,9 +13,11 @@
|
|||||||
$operationsIndexUrl = $tenant ? \App\Support\OpsUx\OperationRunUrl::index($tenant) : null;
|
$operationsIndexUrl = $tenant ? \App\Support\OpsUx\OperationRunUrl::index($tenant) : null;
|
||||||
$primaryActionLabel = $usesCollectivePrimaryAction ? 'Review operations' : 'View operation';
|
$primaryActionLabel = $usesCollectivePrimaryAction ? 'Review operations' : 'View operation';
|
||||||
$bannerTitle = $hasTerminalVisibleRuns ? 'Operation updates' : 'Active operations';
|
$bannerTitle = $hasTerminalVisibleRuns ? 'Operation updates' : 'Active operations';
|
||||||
$bannerHelper = $hasTerminalVisibleRuns
|
$bannerHelper = match (true) {
|
||||||
? 'Recent operation updates stay inside the tenant shell until you need the diagnostics view.'
|
$hasTerminalFollowUpVisibleRuns => 'Review needed operation updates stay visible until you open Operations or acknowledge them in this browser session.',
|
||||||
: 'Queued and running work stays inside the tenant shell until you need the diagnostics view.';
|
$hasTerminalVisibleRuns => 'Successful operation updates stay briefly visible so you can confirm completion and keep working.',
|
||||||
|
default => 'Queued and running work stays inside the tenant shell until you need the diagnostics view.',
|
||||||
|
};
|
||||||
$primaryActionUrl = null;
|
$primaryActionUrl = null;
|
||||||
|
|
||||||
if ($usesCollectivePrimaryAction) {
|
if ($usesCollectivePrimaryAction) {
|
||||||
@ -24,9 +26,9 @@
|
|||||||
$primaryActionUrl = \App\Support\OpsUx\OperationRunUrl::view($primaryRun, $tenant);
|
$primaryActionUrl = \App\Support\OpsUx\OperationRunUrl::view($primaryRun, $tenant);
|
||||||
}
|
}
|
||||||
|
|
||||||
$tertiaryActionLabel = $hasActiveVisibleRuns
|
$tertiaryActionLabel = $hasTerminalFollowUpVisibleRuns
|
||||||
? 'Hide activity'
|
? 'Acknowledge'
|
||||||
: ($hasTerminalFollowUpVisibleRuns ? ($visibleRunCount > 1 ? 'Dismiss updates' : 'Dismiss') : 'Dismiss');
|
: ($hasActiveVisibleRuns ? 'Hide activity' : 'Dismiss');
|
||||||
@endphp
|
@endphp
|
||||||
|
|
||||||
{{-- Cleanup is delegated to the shared poller helper, which uses teardownObserver and new MutationObserver. --}}
|
{{-- Cleanup is delegated to the shared poller helper, which uses teardownObserver and new MutationObserver. --}}
|
||||||
|
|||||||
@ -196,3 +196,87 @@ function operationActivityFeedbackSmokeLoginUrl(User $user, Tenant $tenant, stri
|
|||||||
->assertNoConsoleLogs()
|
->assertNoConsoleLogs()
|
||||||
->assertDontSee('Show activity');
|
->assertDontSee('Show activity');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('keeps terminal follow-up acknowledge local to the browser session and reopens for new work', function (): void {
|
||||||
|
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||||
|
|
||||||
|
$failedRun = OperationRun::factory()->create([
|
||||||
|
'tenant_id' => (int) $tenant->getKey(),
|
||||||
|
'workspace_id' => (int) $tenant->workspace_id,
|
||||||
|
'user_id' => (int) $user->getKey(),
|
||||||
|
'type' => 'inventory_sync',
|
||||||
|
'status' => 'completed',
|
||||||
|
'outcome' => 'failed',
|
||||||
|
'started_at' => now()->subMinutes(3),
|
||||||
|
'completed_at' => now()->subSeconds(8),
|
||||||
|
]);
|
||||||
|
|
||||||
|
visit(operationActivityFeedbackSmokeLoginUrl($user, $tenant))
|
||||||
|
->waitForText('Dashboard')
|
||||||
|
->assertNoJavaScriptErrors()
|
||||||
|
->assertNoConsoleLogs();
|
||||||
|
|
||||||
|
$page = visit(InventoryItemResource::getUrl('index', panel: 'tenant', tenant: $tenant))
|
||||||
|
->resize(1440, 1200)
|
||||||
|
->waitForText('Inventory Items')
|
||||||
|
->waitForText('Acknowledge')
|
||||||
|
->assertSee('Review needed')
|
||||||
|
->assertNoJavaScriptErrors()
|
||||||
|
->assertNoConsoleLogs();
|
||||||
|
|
||||||
|
$page
|
||||||
|
->click('[data-testid="ops-ux-activity-feedback-toggle"]')
|
||||||
|
->wait(1)
|
||||||
|
->assertScript(<<<'JS'
|
||||||
|
(() => {
|
||||||
|
const banner = document.querySelector('[data-testid="ops-ux-activity-feedback-banner"]');
|
||||||
|
|
||||||
|
return banner !== null && window.getComputedStyle(banner).display === 'none';
|
||||||
|
})()
|
||||||
|
JS, true)
|
||||||
|
->refresh()
|
||||||
|
->waitForText('Inventory Items')
|
||||||
|
->assertScript(<<<'JS'
|
||||||
|
(() => {
|
||||||
|
const banner = document.querySelector('[data-testid="ops-ux-activity-feedback-banner"]');
|
||||||
|
|
||||||
|
return banner !== null && window.getComputedStyle(banner).display === 'none';
|
||||||
|
})()
|
||||||
|
JS, true)
|
||||||
|
->assertNoJavaScriptErrors()
|
||||||
|
->assertNoConsoleLogs();
|
||||||
|
|
||||||
|
expect($failedRun->refresh()->status)->toBe('completed')
|
||||||
|
->and($failedRun->outcome)->toBe('failed');
|
||||||
|
|
||||||
|
OperationRun::factory()->create([
|
||||||
|
'tenant_id' => (int) $tenant->getKey(),
|
||||||
|
'workspace_id' => (int) $tenant->workspace_id,
|
||||||
|
'user_id' => (int) $user->getKey(),
|
||||||
|
'type' => 'inventory_sync',
|
||||||
|
'status' => 'running',
|
||||||
|
'outcome' => 'pending',
|
||||||
|
'started_at' => now()->subSeconds(10),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$page->script(<<<'JS'
|
||||||
|
window.dispatchEvent(new CustomEvent('ops-ux:run-enqueued', {
|
||||||
|
detail: {
|
||||||
|
tenantId: Number(document.querySelector('[data-testid="ops-ux-activity-feedback-root"]')?.dataset.tenantId || 0),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
JS);
|
||||||
|
|
||||||
|
$page
|
||||||
|
->waitForText('Review operations')
|
||||||
|
->waitForText('Acknowledge')
|
||||||
|
->assertScript(<<<'JS'
|
||||||
|
(() => {
|
||||||
|
const banner = document.querySelector('[data-testid="ops-ux-activity-feedback-banner"]');
|
||||||
|
|
||||||
|
return banner !== null && window.getComputedStyle(banner).display !== 'none';
|
||||||
|
})()
|
||||||
|
JS, true)
|
||||||
|
->assertNoJavaScriptErrors()
|
||||||
|
->assertNoConsoleLogs();
|
||||||
|
});
|
||||||
|
|||||||
@ -3,10 +3,90 @@
|
|||||||
use App\Filament\Resources\InventoryItemResource;
|
use App\Filament\Resources\InventoryItemResource;
|
||||||
use App\Livewire\BulkOperationProgress;
|
use App\Livewire\BulkOperationProgress;
|
||||||
use App\Models\OperationRun;
|
use App\Models\OperationRun;
|
||||||
|
use App\Models\Tenant;
|
||||||
use App\Support\OpsUx\OperationRunUrl;
|
use App\Support\OpsUx\OperationRunUrl;
|
||||||
use Filament\Facades\Filament;
|
use Filament\Facades\Filament;
|
||||||
use Livewire\Livewire;
|
use Livewire\Livewire;
|
||||||
|
|
||||||
|
it('keeps the shell inert when no tenant context is selected', function (): void {
|
||||||
|
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||||
|
|
||||||
|
$this->actingAs($user);
|
||||||
|
Filament::setTenant(null, true);
|
||||||
|
|
||||||
|
OperationRun::factory()->create([
|
||||||
|
'tenant_id' => (int) $tenant->getKey(),
|
||||||
|
'workspace_id' => (int) $tenant->workspace_id,
|
||||||
|
'user_id' => (int) $user->getKey(),
|
||||||
|
'type' => 'inventory_sync',
|
||||||
|
'status' => 'running',
|
||||||
|
'outcome' => 'pending',
|
||||||
|
'started_at' => now()->subMinute(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Livewire::actingAs($user)
|
||||||
|
->test(BulkOperationProgress::class)
|
||||||
|
->call('refreshRuns')
|
||||||
|
->assertSet('disabled', true)
|
||||||
|
->assertSet('hasVisibleRuns', false)
|
||||||
|
->assertDontSee('Inventory sync')
|
||||||
|
->assertDontSee('Active operations');
|
||||||
|
})->group('ops-ux');
|
||||||
|
|
||||||
|
it('keeps the shell inert when the actor cannot view operation runs', function (): void {
|
||||||
|
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||||
|
|
||||||
|
$this->actingAs($user);
|
||||||
|
Filament::setTenant($tenant, true);
|
||||||
|
session()->forget(\App\Support\Workspaces\WorkspaceContext::SESSION_KEY);
|
||||||
|
|
||||||
|
OperationRun::factory()->create([
|
||||||
|
'tenant_id' => (int) $tenant->getKey(),
|
||||||
|
'workspace_id' => (int) $tenant->workspace_id,
|
||||||
|
'user_id' => (int) $user->getKey(),
|
||||||
|
'type' => 'inventory_sync',
|
||||||
|
'status' => 'running',
|
||||||
|
'outcome' => 'pending',
|
||||||
|
'started_at' => now()->subMinute(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Livewire::actingAs($user)
|
||||||
|
->test(BulkOperationProgress::class)
|
||||||
|
->call('refreshRuns')
|
||||||
|
->assertSet('disabled', true)
|
||||||
|
->assertSet('hasVisibleRuns', false)
|
||||||
|
->assertDontSee('Inventory sync')
|
||||||
|
->assertDontSee('Active operations');
|
||||||
|
})->group('ops-ux');
|
||||||
|
|
||||||
|
it('does not expose another tenant run through the selected tenant shell', function (): void {
|
||||||
|
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||||
|
$foreignTenant = Tenant::factory()->create([
|
||||||
|
'workspace_id' => (int) $tenant->workspace_id,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->actingAs($user);
|
||||||
|
Filament::setTenant($tenant, true);
|
||||||
|
|
||||||
|
OperationRun::factory()->create([
|
||||||
|
'tenant_id' => (int) $foreignTenant->getKey(),
|
||||||
|
'workspace_id' => (int) $foreignTenant->workspace_id,
|
||||||
|
'type' => 'policy.sync',
|
||||||
|
'status' => 'running',
|
||||||
|
'outcome' => 'pending',
|
||||||
|
'initiator_name' => 'Foreign tenant run',
|
||||||
|
'started_at' => now()->subMinute(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
Livewire::actingAs($user)
|
||||||
|
->test(BulkOperationProgress::class)
|
||||||
|
->call('refreshRuns')
|
||||||
|
->assertSet('disabled', false)
|
||||||
|
->assertSet('hasVisibleRuns', false)
|
||||||
|
->assertDontSee('Policy sync')
|
||||||
|
->assertDontSee('Foreign tenant run');
|
||||||
|
})->group('ops-ux');
|
||||||
|
|
||||||
it('renders three visible run summaries while grouping banner actions in one action area', function (): void {
|
it('renders three visible run summaries while grouping banner actions in one action area', function (): void {
|
||||||
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||||
|
|
||||||
@ -125,7 +205,7 @@
|
|||||||
->and($html)->not->toContain('role="progressbar"');
|
->and($html)->not->toContain('role="progressbar"');
|
||||||
})->group('ops-ux');
|
})->group('ops-ux');
|
||||||
|
|
||||||
it('renders terminal follow-up states with dismiss instead of hide activity', function (): void {
|
it('renders terminal follow-up states with acknowledge instead of dismiss semantics', function (): void {
|
||||||
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
||||||
|
|
||||||
$this->actingAs($user);
|
$this->actingAs($user);
|
||||||
@ -147,13 +227,16 @@
|
|||||||
->call('refreshRuns');
|
->call('refreshRuns');
|
||||||
|
|
||||||
$html = html_entity_decode($component->html(), ENT_QUOTES | ENT_HTML5);
|
$html = html_entity_decode($component->html(), ENT_QUOTES | ENT_HTML5);
|
||||||
|
$pageText = preg_replace('/\s+/', ' ', strip_tags($html));
|
||||||
|
|
||||||
expect($component->get('hasActiveRuns'))->toBeFalse()
|
expect($component->get('hasActiveRuns'))->toBeFalse()
|
||||||
->and($html)->toContain('Operation updates')
|
->and($html)->toContain('Operation updates')
|
||||||
|
->and($pageText)->toContain('Review needed')
|
||||||
|
->and($pageText)->toContain('Review the operation details before retrying.')
|
||||||
->and($html)->toContain('View operation')
|
->and($html)->toContain('View operation')
|
||||||
->and($html)->not->toContain('Review operations')
|
->and($html)->not->toContain('Review operations')
|
||||||
->and($html)->toContain('Dismiss')
|
->and($html)->toContain('Acknowledge')
|
||||||
->and($html)->not->toContain('Acknowledge')
|
->and($html)->not->toContain('Dismiss')
|
||||||
->and($html)->not->toContain('data-testid="ops-ux-activity-feedback-indeterminate"')
|
->and($html)->not->toContain('data-testid="ops-ux-activity-feedback-indeterminate"')
|
||||||
->and($html)->not->toContain('role="progressbar"')
|
->and($html)->not->toContain('role="progressbar"')
|
||||||
->and($html)->not->toContain('Hide activity');
|
->and($html)->not->toContain('Hide activity');
|
||||||
@ -196,7 +279,8 @@
|
|||||||
expect($html)->toContain('Review operations')
|
expect($html)->toContain('Review operations')
|
||||||
->and($html)->toContain('Operation updates')
|
->and($html)->toContain('Operation updates')
|
||||||
->and($html)->not->toContain('View operation')
|
->and($html)->not->toContain('View operation')
|
||||||
->and($html)->toContain('Hide activity')
|
->and($html)->toContain('Acknowledge')
|
||||||
|
->and($html)->not->toContain('Dismiss updates')
|
||||||
->and($html)->toContain(OperationRunUrl::index($tenant))
|
->and($html)->toContain(OperationRunUrl::index($tenant))
|
||||||
->and($html)->not->toContain(OperationRunUrl::view($runningRun, $tenant))
|
->and($html)->not->toContain(OperationRunUrl::view($runningRun, $tenant))
|
||||||
->and($pageText)->toContain('Execution failed');
|
->and($pageText)->toContain('Execution failed');
|
||||||
|
|||||||
@ -105,8 +105,8 @@
|
|||||||
->assertSee('Inventory sync')
|
->assertSee('Inventory sync')
|
||||||
->assertSee('View operation')
|
->assertSee('View operation')
|
||||||
->assertDontSee('Review operations')
|
->assertDontSee('Review operations')
|
||||||
->assertSee('Dismiss')
|
->assertSee('Acknowledge')
|
||||||
->assertDontSee('Acknowledge')
|
->assertDontSee('Dismiss')
|
||||||
->assertDontSee('Waiting for worker.')
|
->assertDontSee('Waiting for worker.')
|
||||||
->assertDontSee('Hide activity');
|
->assertDontSee('Hide activity');
|
||||||
})->group('ops-ux');
|
})->group('ops-ux');
|
||||||
@ -143,7 +143,8 @@
|
|||||||
->assertSee('Review operations')
|
->assertSee('Review operations')
|
||||||
->assertDontSee('View operation')
|
->assertDontSee('View operation')
|
||||||
->assertSee('Show all operations')
|
->assertSee('Show all operations')
|
||||||
->assertSee('Hide activity');
|
->assertSee('Acknowledge')
|
||||||
|
->assertDontSee('Dismiss updates');
|
||||||
})->group('ops-ux');
|
})->group('ops-ux');
|
||||||
|
|
||||||
it('shows likely stale runs in the progress overlay and keeps polling when only stale runs remain', function () {
|
it('shows likely stale runs in the progress overlay and keeps polling when only stale runs remain', function () {
|
||||||
|
|||||||
@ -1318,8 +1318,7 @@ # TenantPilot Enterprise UI Standards**Status:** Active **Owner:** Product / En
|
|||||||
|
|
||||||
- Hide activity for queued or running rows
|
- Hide activity for queued or running rows
|
||||||
- Dismiss or Close for terminal-success rows
|
- Dismiss or Close for terminal-success rows
|
||||||
- Dismiss for a single unresolved terminal follow-up row
|
- Acknowledge for unresolved terminal follow-up rows, including grouped states
|
||||||
- Dismiss updates when multiple unresolved terminal follow-up rows are visible and no active work remains
|
|
||||||
|
|
||||||
use Show all operations to open the canonical Operations collection with the current tenant encoded as the contextual tenant_id prefilter
|
use Show all operations to open the canonical Operations collection with the current tenant encoded as the contextual tenant_id prefilter
|
||||||
|
|
||||||
@ -1331,7 +1330,12 @@ # TenantPilot Enterprise UI Standards**Status:** Active **Owner:** Product / En
|
|||||||
|
|
||||||
switch terminal-success rows to success-state copy instead of showing active progress after completion
|
switch terminal-success rows to success-state copy instead of showing active progress after completion
|
||||||
|
|
||||||
keep hide or dismiss behavior browser-session-only and re-open the hint when a new run-enqueued event is accepted for the current tenant
|
separate successful completion from unresolved terminal follow-up in the shell helper copy:
|
||||||
|
|
||||||
|
- successful terminal rows use no-action-needed completion copy and remain locally dismissible
|
||||||
|
- unresolved terminal follow-up rows use review-needed copy and MUST NOT inherit generic Dismiss semantics
|
||||||
|
|
||||||
|
keep hide, dismiss, or acknowledge behavior browser-session-only and re-open the hint when a new run-enqueued event is accepted for the current tenant
|
||||||
|
|
||||||
It MUST NOT:
|
It MUST NOT:
|
||||||
|
|
||||||
@ -1347,6 +1351,8 @@ # TenantPilot Enterprise UI Standards**Status:** Active **Owner:** Product / En
|
|||||||
|
|
||||||
persist hide or dismiss state in the database or on the OperationRun record
|
persist hide or dismiss state in the database or on the OperationRun record
|
||||||
|
|
||||||
|
persist acknowledge state in the database or on the OperationRun record
|
||||||
|
|
||||||
render as a fixed overlay that can cover findings row actions, table actions, or page-primary actions
|
render as a fixed overlay that can cover findings row actions, table actions, or page-primary actions
|
||||||
|
|
||||||
30. Maintenance Rules
|
30. Maintenance Rules
|
||||||
@ -1412,4 +1418,3 @@ ## UI Standards CheckChanged custom UI surfaces:- ...Patterns used:- Card / Surf
|
|||||||
Do not imply Customer Review Workspace maturity unless repo-verifiedUse Review Pack / Export Artifact wording when that is what exists
|
Do not imply Customer Review Workspace maturity unless repo-verifiedUse Review Pack / Export Artifact wording when that is what exists
|
||||||
Blade
|
Blade
|
||||||
Render onlyDo not invent domain logicDo not invent routesDo not infer capabilities
|
Render onlyDo not invent domain logicDo not invent routesDo not infer capabilities
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,56 @@
|
|||||||
|
# Specification Quality Checklist: OperationRun Terminal Outcome Feedback v1
|
||||||
|
|
||||||
|
**Purpose**: Validate specification completeness, boundedness, and repo fit before implementation
|
||||||
|
**Created**: 2026-05-05
|
||||||
|
**Feature**: [spec.md](../spec.md)
|
||||||
|
|
||||||
|
## Content Quality
|
||||||
|
|
||||||
|
- [x] The package stays on one bounded terminal-outcome refinement over the existing shell activity hint instead of widening into a new activity center, dashboard card, or notification rewrite.
|
||||||
|
- [x] The spec remains product- and behavior-oriented and does not read like a low-level implementation diff.
|
||||||
|
- [x] The package explicitly names the repo-real anchors it builds on: `BulkOperationProgress`, the current shell activity view, `OperationUxPresenter`, `OperationRunProgressContract`, `ActiveRuns`, and the existing browser-session event flow.
|
||||||
|
- [x] Mandatory repo sections for scope, RBAC, Ops-UX, testing, proportionality, and candidate rationale are completed.
|
||||||
|
|
||||||
|
## Requirement Completeness
|
||||||
|
|
||||||
|
- [x] No `[NEEDS CLARIFICATION]` markers remain.
|
||||||
|
- [x] Requirements are testable and stay bounded to current shell terminal-success and terminal-follow-up semantics only.
|
||||||
|
- [x] The package explicitly preserves canonical `View operation` and `Show all operations` link generation instead of reopening routing decisions.
|
||||||
|
- [x] The package makes the lifecycle-sensitive tertiary contract explicit: `Hide activity` while active, `Dismiss` or `Close` for terminal success, and `Acknowledge` for unresolved terminal follow-up.
|
||||||
|
- [x] The package keeps acknowledgement browser-session-only and forbids DB-backed review state.
|
||||||
|
- [x] Planned validation commands match across `spec.md`, `plan.md`, and `tasks.md`.
|
||||||
|
|
||||||
|
## Candidate Selection Gate
|
||||||
|
|
||||||
|
- [x] The selected candidate exists in `docs/product/spec-candidates.md` and aligns with the roadmap's manual-promotion backlog.
|
||||||
|
- [x] The active queue remains intentionally empty, so this package records itself as a deliberate manual promotion rather than an automatic next-best-prep target.
|
||||||
|
- [x] No existing `269-*` spec package exists, and the current repo truth still leaves an open semantic gap even though Spec 268 and current code already introduced the broader shell activity surface.
|
||||||
|
- [x] The chosen slice is smaller and more repo-ready than deferred alternatives because it tightens one live shell contract before dashboard or broader progress follow-ups.
|
||||||
|
|
||||||
|
## Feature Readiness
|
||||||
|
|
||||||
|
- [x] The package reuses existing `OperationRun` truth and current shell helpers instead of introducing a second lifecycle or persisted projection.
|
||||||
|
- [x] The package explicitly leaves dashboard, tray, notification-policy, and progress-rollout work out of scope.
|
||||||
|
- [x] The package preserves current tenant-bound visibility and current Operations drill-through ownership.
|
||||||
|
- [x] The standards document update is included in the same slice so the terminal outcome rule becomes durable repo guidance.
|
||||||
|
|
||||||
|
## Test Governance
|
||||||
|
|
||||||
|
- [x] Planned proof stays bounded to focused Feature coverage plus one named browser smoke for the shell interaction contract.
|
||||||
|
- [x] No new heavy-governance, discovery, or browser family is introduced by default.
|
||||||
|
- [x] Fixture growth stays bounded to current `OperationRun` factories, tenant helpers, and existing shell smoke helpers.
|
||||||
|
- [x] The review outcome, workflow outcome, and test-governance outcome are carried into `plan.md` and `tasks.md`.
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
- Reviewed against `docs/product/spec-candidates.md`, `docs/product/roadmap.md`, `.specify/memory/constitution.md`, `apps/platform/app/Livewire/BulkOperationProgress.php`, `apps/platform/resources/views/livewire/bulk-operation-progress.blade.php`, `apps/platform/tests/Feature/OpsUx/ActivityFeedbackSurfaceTest.php`, `apps/platform/tests/Feature/OpsUx/BulkOperationProgressDbOnlyTest.php`, and `apps/platform/tests/Browser/OpsUx/OperationActivityFeedbackSmokeTest.php` on 2026-05-05.
|
||||||
|
- Related-spec guardrail: Spec 268 remains the current shell-activity foundation and must not be rewritten back into prep-only state. This package only narrows the still-open terminal-outcome semantics seam.
|
||||||
|
- No application implementation was performed while preparing this package.
|
||||||
|
|
||||||
|
## Review Outcome
|
||||||
|
|
||||||
|
- **Outcome class**: `acceptable-special-case`
|
||||||
|
- **Workflow outcome**: `keep`
|
||||||
|
- **Test-governance outcome**: `keep`
|
||||||
|
- **Reason**: The automatic queue is intentionally empty, but this manual promotion is still justified because current repo truth shows an open terminal-outcome semantics gap on a live shell surface that is smaller and safer than the deferred dashboard or broader progress follow-ups.
|
||||||
|
- **Workflow result**: Ready for implementation.
|
||||||
260
specs/269-operationrun-terminal-outcome-feedback/plan.md
Normal file
260
specs/269-operationrun-terminal-outcome-feedback/plan.md
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
# Implementation Plan: OperationRun Terminal Outcome Feedback v1
|
||||||
|
|
||||||
|
**Branch**: `269-operationrun-terminal-outcome-feedback` | **Date**: 2026-05-05 | **Spec**: [spec.md](./spec.md)
|
||||||
|
**Input**: Feature specification from `/specs/269-operationrun-terminal-outcome-feedback/spec.md`
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
This plan prepares one bounded refinement over the repo's existing shell activity feedback. The current `BulkOperationProgress` surface already shows active work and recent terminal rows, but terminal success and unresolved follow-up still share too much generic terminal-update behavior. The implementation path is to keep the existing shell host, links, and progress contract intact while splitting terminal success from terminal follow-up copy and browser-session tertiary semantics, then record the final rule in `docs/ui/tenantpilot-enterprise-ui-standards.md`.
|
||||||
|
|
||||||
|
Filament remains on Livewire v4, no panel-provider registration changes are required (`apps/platform/bootstrap/providers.php` remains authoritative), no globally searchable resource is added, no asset registration change is expected, and no destructive action is introduced.
|
||||||
|
|
||||||
|
## Inherited Baseline / Explicit Delta
|
||||||
|
|
||||||
|
### Inherited baseline
|
||||||
|
|
||||||
|
- `OperationRun` already provides the execution-truth model and current tenant/workspace scoping.
|
||||||
|
- `BulkOperationProgress` already hosts the shell activity surface on tenant-scoped pages.
|
||||||
|
- `OperationUxPresenter`, `OperationStatusNormalizer`, `OperationRunProgressContract`, `OperationRunLinks`, `OperationRunUrl`, and `ActiveRuns` already own the current status, progress, and link semantics.
|
||||||
|
- `ActivityFeedbackSurfaceTest`, `BulkOperationProgressDbOnlyTest`, and `OperationActivityFeedbackSmokeTest` already prove core shell behavior.
|
||||||
|
|
||||||
|
### Explicit delta in this plan
|
||||||
|
|
||||||
|
- split terminal-success shell behavior from unresolved terminal-follow-up shell behavior
|
||||||
|
- preserve active-state helper, progress, and canonical-link behavior unchanged unless terminal-outcome refinement requires a local adjustment
|
||||||
|
- keep unresolved terminal follow-up explicitly reviewable instead of generically dismissible
|
||||||
|
- keep terminal success briefly dismissible and clearly no-action-needed during the current 30-second shell-visible success window from `ActiveRuns`
|
||||||
|
- keep acknowledge and dismiss behavior browser-session-only
|
||||||
|
- update `docs/ui/tenantpilot-enterprise-ui-standards.md` with the terminal outcome contract
|
||||||
|
|
||||||
|
## Technical Context
|
||||||
|
|
||||||
|
**Language/Version**: PHP 8.4, Laravel 12, Filament v5, Livewire v4
|
||||||
|
**Primary Dependencies**: current Ops-UX support classes, native Filament widgets or Blade, current badge infrastructure, Pest v4
|
||||||
|
**Storage**: PostgreSQL via existing `operation_runs`; browser-session state only for current shell collapse or acknowledgement behavior; no new DB storage
|
||||||
|
**Testing**: Pest Feature coverage plus one required browser smoke
|
||||||
|
**Validation Lanes**: fast-feedback, confidence, browser
|
||||||
|
**Target Platform**: existing Laravel monolith in `apps/platform`, admin or operator plane only
|
||||||
|
**Project Type**: Web application (Laravel monolith with Filament)
|
||||||
|
**Performance Goals**: no new query families, no duplicate polling loops, and no additional shell host surfaces
|
||||||
|
**Constraints**: no new persistence, no new lifecycle family, no new notification policy, no dashboard card, and no panel/provider/asset changes
|
||||||
|
**Scale/Scope**: one current shell host, one standards update, and one browser-session tertiary-action rule
|
||||||
|
|
||||||
|
## Likely Affected Repo Surfaces
|
||||||
|
|
||||||
|
- `apps/platform/app/Livewire/BulkOperationProgress.php`
|
||||||
|
- `apps/platform/resources/views/livewire/bulk-operation-progress.blade.php`
|
||||||
|
- `apps/platform/app/Support/OpsUx/OperationUxPresenter.php`
|
||||||
|
- `apps/platform/app/Support/OpsUx/ActiveRuns.php`
|
||||||
|
- `apps/platform/public/js/tenantpilot/ops-ux-progress-widget-poller.js`
|
||||||
|
- `apps/platform/tests/Feature/OpsUx/ActivityFeedbackSurfaceTest.php`
|
||||||
|
- `apps/platform/tests/Feature/OpsUx/BulkOperationProgressDbOnlyTest.php`
|
||||||
|
- `apps/platform/tests/Browser/OpsUx/OperationActivityFeedbackSmokeTest.php`
|
||||||
|
- `docs/ui/tenantpilot-enterprise-ui-standards.md`
|
||||||
|
|
||||||
|
## UI / Filament & Livewire Fit
|
||||||
|
|
||||||
|
- Keep the changed shell host Filament-native and local to the existing Livewire component.
|
||||||
|
- The shell remains decision-first: one dominant primary action, one concise helper line, and one lifecycle-sensitive tertiary action.
|
||||||
|
- Monitoring collection and detail pages remain diagnostics-first drill-through targets. The shell must not restate their evidence-heavy content.
|
||||||
|
- Successful terminal rows stay briefly visible with no-action-needed semantics; unresolved terminal follow-up stays explicitly reviewable.
|
||||||
|
- Browser-session `Acknowledge` stays local to the current browser session and must not become a server-side workflow state.
|
||||||
|
- No new asset registration, panel configuration, or provider registration change is planned.
|
||||||
|
|
||||||
|
## RBAC / Policy Fit
|
||||||
|
|
||||||
|
- Existing `OperationRun` policies remain the first and only visibility gate.
|
||||||
|
- The shell continues to derive rows only after tenant context and policy filtering.
|
||||||
|
- No plane expansion, no new action surface, and no new authorization rule are introduced.
|
||||||
|
- Canonical Operations collection and detail pages remain the only drill-through owners for deeper diagnostics.
|
||||||
|
|
||||||
|
## Audit / Logging Fit
|
||||||
|
|
||||||
|
- Existing queued toasts, browser events, and terminal DB notifications remain authoritative and unchanged.
|
||||||
|
- Existing Monitoring and audit behavior remain the only audit trail. No page-view audit stream is introduced.
|
||||||
|
- Because the slice changes presentation only, `OperationRun.status` and `OperationRun.outcome` ownership remain service-owned and unchanged.
|
||||||
|
|
||||||
|
## Data & Query Fit
|
||||||
|
|
||||||
|
- The shell host continues to derive rows from current-tenant `OperationRun` truth.
|
||||||
|
- The current 30-second terminal-success grace window in `ActiveRuns::shellVisibleQueryForTenantId()` remains the source of truth for recent successful terminal visibility in this slice.
|
||||||
|
- Terminal success and terminal follow-up remain derived display states only; they do not create new persisted fields.
|
||||||
|
- Acknowledge and dismiss remain browser-session scoped and must not be written to the database or to the run record.
|
||||||
|
|
||||||
|
## UI / Surface Guardrail Plan
|
||||||
|
|
||||||
|
- **Guardrail scope**: changed surfaces
|
||||||
|
- **Native vs custom classification summary**: native Filament plus a bounded local shell refinement
|
||||||
|
- **Shared-family relevance**: Ops UX lifecycle feedback, canonical run links
|
||||||
|
- **State layers in scope**: shell, page, browser-session
|
||||||
|
- **Audience modes in scope**: operator-MSP
|
||||||
|
- **Decision/diagnostic/raw hierarchy plan**: decision-first on the shell host, diagnostics-first on Operations collection/detail
|
||||||
|
- **Raw/support gating plan**: raw and support detail stay on existing diagnostics surfaces only
|
||||||
|
- **One-primary-action / duplicate-truth control**: each visible shell state keeps one dominant primary action; grouped `Review operations` remains only the label variant of the canonical collection link also exposed as `Show all operations`, and the shell differentiates `success` from `follow-up` through helper and tertiary wording instead of duplicate diagnostics
|
||||||
|
- **Handling modes by drift class or surface**: review-mandatory
|
||||||
|
- **Repository-signal treatment**: review-mandatory
|
||||||
|
- **Special surface test profiles**: global-context-shell
|
||||||
|
- **Required tests**: functional-core, named-browser-smoke
|
||||||
|
- **Exception path and spread control**: none planned; any attempt to add persisted acknowledgement, dashboard work, or a second lifecycle surface resolves as `reject-or-split`
|
||||||
|
- **Active feature PR close-out entry**: Guardrail / Smoke Coverage
|
||||||
|
|
||||||
|
## Shared Pattern & System Fit
|
||||||
|
|
||||||
|
- **Cross-cutting feature marker**: yes
|
||||||
|
- **Systems touched**: current shell hint, canonical run links, current run guidance, current progress contract, current shell poller, UI standards
|
||||||
|
- **Shared abstractions reused**: `OperationUxPresenter`, `OperationStatusNormalizer`, `OperationRunProgressContract`, `OperationRunLinks`, `OperationRunUrl`, `ActiveRuns`, `OpsUxBrowserEvents`
|
||||||
|
- **New abstraction introduced? why?**: none planned; keep the change local to the existing shell component and helper seams unless a tiny readability helper becomes necessary during implementation
|
||||||
|
- **Why the existing abstraction was sufficient or insufficient**: the repo already owns truthful state and links; the missing piece is the terminal-outcome decision contract on the shell
|
||||||
|
- **Bounded deviation / spread control**: do not create a second terminal-outcome presenter family, a registry, or a persisted acknowledgement model
|
||||||
|
|
||||||
|
## OperationRun UX Impact
|
||||||
|
|
||||||
|
- **Touches OperationRun start/completion/link UX?**: yes, for post-completion shell follow-through and drill-through links only
|
||||||
|
- **Central contract reused**: current Ops-UX shell contract via `OperationUxPresenter`, `OperationRunLinks`, `OperationRunUrl`, `OperationRunProgressContract`, and `OpsUxBrowserEvents`
|
||||||
|
- **Delegated UX behaviors**: current queued toast wording, canonical `View operation`, grouped `Review operations`, and `Show all operations` links, current browser-event dispatch, and existing terminal DB-notification lifecycle remain delegated to the shared contract
|
||||||
|
- **Surface-owned behavior kept local**: success vs follow-up helper copy and lifecycle-sensitive tertiary action wording only
|
||||||
|
- **Queued DB-notification policy**: `N/A` - unchanged
|
||||||
|
- **Terminal notification path**: unchanged central lifecycle mechanism
|
||||||
|
- **Exception path**: none
|
||||||
|
|
||||||
|
## Provider Boundary & Portability Fit
|
||||||
|
|
||||||
|
- **Shared provider/platform boundary touched?**: no
|
||||||
|
- **Provider-owned seams**: `N/A`
|
||||||
|
- **Platform-core seams**: existing `OperationRun` truth, links, and operator vocabulary only
|
||||||
|
- **Neutral platform terms / contracts preserved**: `Operation`, `View operation`, `Review operations`, `Show all operations`, `completed successfully`, `review needed`
|
||||||
|
- **Retained provider-specific semantics and why**: none
|
||||||
|
- **Bounded extraction or follow-up path**: none
|
||||||
|
|
||||||
|
## Constitution Check
|
||||||
|
|
||||||
|
*GATE: Must pass before implementation begins and again before merge.*
|
||||||
|
|
||||||
|
- Inventory-first: PASS. The slice is fully derived from existing `OperationRun` truth.
|
||||||
|
- Read/write separation: PASS. No new write path or retry surface is introduced.
|
||||||
|
- Graph contract path: PASS. No Graph/provider interaction is added.
|
||||||
|
- Deterministic capabilities: PASS. Existing `OperationRun` policies remain authoritative.
|
||||||
|
- RBAC-UX: PASS. No plane expansion; tenant/admin visibility stays on current guards and deny-as-not-found semantics.
|
||||||
|
- Run observability: PASS. Existing start contract, terminal notifications, and Monitoring ownership remain unchanged while the shell only refines terminal-outcome meaning.
|
||||||
|
- Ops-UX lifecycle: PASS. No change to service-owned status/outcome transitions or `summary_counts` semantics.
|
||||||
|
- Data minimization: PASS. The shell remains compact and does not surface raw evidence by default.
|
||||||
|
- Test governance: PASS. Proof stays bounded to focused Feature coverage plus one browser smoke.
|
||||||
|
- Proportionality / no premature abstraction: PASS. The default implementation stays local to the existing shell host and standards document.
|
||||||
|
- Persisted truth / behavioral state: PASS. No new table, no new lifecycle, no new persisted acknowledgement or dismiss state.
|
||||||
|
- Shared pattern first / UI semantics / Filament-native UI: PASS. Existing helpers and badge semantics stay central, and the shell moves closer to a precise decision-first contract.
|
||||||
|
- Provider boundary: PASS. No provider/platform seam changes.
|
||||||
|
- Filament/Laravel panel safety: PASS. Filament v5 stays on Livewire v4, provider registration remains in `apps/platform/bootstrap/providers.php`, no globally searchable resource is introduced, and no new assets are planned.
|
||||||
|
|
||||||
|
**Gate evaluation**: PASS.
|
||||||
|
|
||||||
|
## Test Governance Check
|
||||||
|
|
||||||
|
- **Test purpose / classification by changed surface**: Feature for terminal-outcome shell behavior; one required browser smoke for live shell interaction
|
||||||
|
- **Affected validation lanes**: fast-feedback, confidence, browser
|
||||||
|
- **Why this lane mix is the narrowest sufficient proof**: Feature coverage proves success vs follow-up copy, tertiary actions, browser-session-only acknowledgement, and the absence of progress UI after completion. The browser smoke remains reserved for real shell interaction and re-open behavior.
|
||||||
|
- **Narrowest proving command(s)**:
|
||||||
|
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/OpsUx/ActivityFeedbackSurfaceTest.php tests/Feature/OpsUx/BulkOperationProgressDbOnlyTest.php`
|
||||||
|
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Browser/OpsUx/OperationActivityFeedbackSmokeTest.php`
|
||||||
|
- **Fixture / helper / factory / seed / context cost risks**: low to moderate; reuse current `OperationRun` factories, tenant helpers, and shell smoke helpers instead of introducing new provider-heavy defaults
|
||||||
|
- **Expensive defaults or shared helper growth introduced?**: no
|
||||||
|
- **Heavy-family additions, promotions, or visibility changes**: none
|
||||||
|
- **Surface-class relief / special coverage rule**: `global-context-shell`
|
||||||
|
- **Closing validation and reviewer handoff**: reviewers should rerun the focused commands above, then confirm that unresolved terminal follow-up uses `Acknowledge` or review wording, successful completion stays dismissible, and new run-enqueue events still reopen the shell.
|
||||||
|
- **Budget / baseline / trend follow-up**: none expected beyond a small feature-local increase
|
||||||
|
- **Review-stop questions**: did the shell stay bounded, did unresolved follow-up stop using generic dismiss semantics, did terminal rows stay progress-free, and did acknowledgement remain browser-session-only?
|
||||||
|
- **Escalation path**: `reject-or-split` for any dashboard expansion, persisted acknowledgement state, or notification-policy change
|
||||||
|
- **Active feature PR close-out entry**: Guardrail / Smoke Coverage
|
||||||
|
- **Why no dedicated follow-up spec is needed**: this package already narrows the live shell contract to the remaining terminal-outcome seam; larger dashboard or progress topics remain explicit follow-up candidates instead of hidden work here.
|
||||||
|
|
||||||
|
## Authorization Verification Fit
|
||||||
|
|
||||||
|
- Reuse the existing shell Feature proof to verify no-tenant and no-capability suppression, tenant-safe filtering, and the absence of inaccessible run exposure on the shell host.
|
||||||
|
- Keep that verification local to the current shell test family; do not create a separate authorization test family for this slice.
|
||||||
|
|
||||||
|
## Preparation Review Outcome
|
||||||
|
|
||||||
|
- **Review outcome class**: `acceptable-special-case`
|
||||||
|
- **Workflow outcome**: `keep`
|
||||||
|
- **Test-governance outcome**: `keep`
|
||||||
|
- **Reason**: the automatic candidate queue is intentionally empty, but this manual promotion is still justified because current repo truth leaves a bounded terminal-outcome gap on a live shell surface that is smaller and safer than the deferred dashboard or broader progress follow-ups.
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
### Documentation (this feature)
|
||||||
|
|
||||||
|
```text
|
||||||
|
specs/269-operationrun-terminal-outcome-feedback/
|
||||||
|
├── spec.md
|
||||||
|
├── plan.md
|
||||||
|
├── tasks.md
|
||||||
|
└── checklists/
|
||||||
|
└── requirements.md
|
||||||
|
```
|
||||||
|
|
||||||
|
This preparation package intentionally stays on the core artifacts plus the readiness checklist. The repo already contains the relevant Ops-UX truth, shell host, and proof surfaces, so no extra research, data-model, quickstart, or contracts package is required for a bounded implementation handoff.
|
||||||
|
|
||||||
|
### Source Code (expected implementation surfaces)
|
||||||
|
|
||||||
|
```text
|
||||||
|
apps/platform/app/Livewire/BulkOperationProgress.php
|
||||||
|
apps/platform/resources/views/livewire/bulk-operation-progress.blade.php
|
||||||
|
apps/platform/app/Support/OpsUx/OperationUxPresenter.php
|
||||||
|
apps/platform/app/Support/OpsUx/ActiveRuns.php
|
||||||
|
apps/platform/public/js/tenantpilot/ops-ux-progress-widget-poller.js
|
||||||
|
apps/platform/tests/Feature/OpsUx/ActivityFeedbackSurfaceTest.php
|
||||||
|
apps/platform/tests/Feature/OpsUx/BulkOperationProgressDbOnlyTest.php
|
||||||
|
apps/platform/tests/Browser/OpsUx/OperationActivityFeedbackSmokeTest.php
|
||||||
|
docs/ui/tenantpilot-enterprise-ui-standards.md
|
||||||
|
```
|
||||||
|
|
||||||
|
**Structure Decision**: keep the implementation local to the existing Ops-UX shell seams and standards document. Do not introduce a second activity framework or a dashboard-owned run-state model in this slice.
|
||||||
|
|
||||||
|
## Data / Migration Implications
|
||||||
|
|
||||||
|
- No migration or new table is planned.
|
||||||
|
- No new persisted user preference is allowed.
|
||||||
|
- No new cache layer, backfill, or deploy step should be required.
|
||||||
|
|
||||||
|
## Rollout Considerations
|
||||||
|
|
||||||
|
- Filament remains v5 on Livewire v4. No panel-provider change is required, and provider registration remains in `apps/platform/bootstrap/providers.php`.
|
||||||
|
- No global search change is required because the slice changes a shell widget, not a resource.
|
||||||
|
- No destructive action is added.
|
||||||
|
- No new asset registration is expected; if future work ever registers assets, deployment still runs `cd apps/platform && php artisan filament:assets` outside this slice.
|
||||||
|
|
||||||
|
## Risk Controls
|
||||||
|
|
||||||
|
- Reject any implementation that leaves unresolved terminal follow-up on generic `Dismiss` semantics.
|
||||||
|
- Reject any implementation that introduces a new `OperationRun` lifecycle, a persisted acknowledgement model, or a dashboard active-operations card in this slice.
|
||||||
|
- Reject any implementation that reintroduces progress UI after terminal transition.
|
||||||
|
- Reject any implementation that changes notification policy, route ownership, or shell polling scope.
|
||||||
|
|
||||||
|
## Implementation Phases
|
||||||
|
|
||||||
|
### Phase 0 - Confirm Current Terminal Outcome Truth
|
||||||
|
|
||||||
|
- Verify the current shell host, current helper seams, and current proof owners for successful terminal items, unresolved terminal follow-up, and browser-session collapse or acknowledge behavior.
|
||||||
|
|
||||||
|
### Phase 1 - Split Success From Follow-Up Semantics
|
||||||
|
|
||||||
|
- Keep terminal success calm and dismissible.
|
||||||
|
- Make unresolved terminal follow-up explicitly reviewable and acknowledge-only at the shell level.
|
||||||
|
|
||||||
|
### Phase 2 - Keep Browser-Session Outcome Actions Local
|
||||||
|
|
||||||
|
- Preserve current browser-session-only shell calmness.
|
||||||
|
- Ensure new run-enqueue events reopen the shell.
|
||||||
|
|
||||||
|
### Phase 3 - Record The Guardrail And Validate
|
||||||
|
|
||||||
|
- Update the standards document.
|
||||||
|
- Run the focused Feature proof and the named browser smoke.
|
||||||
|
|
||||||
|
## Proportionality Review
|
||||||
|
|
||||||
|
- **Current operator problem**: terminal follow-up still looks too much like harmless completion in the live shell surface.
|
||||||
|
- **Existing structure is insufficient because**: the broader shell feedback exists already, but its current terminal-outcome semantics are still too generic for honest decision-first behavior.
|
||||||
|
- **Narrowest correct implementation**: refine the existing shell component, helper text, and browser-session tertiary actions only.
|
||||||
|
- **Ownership cost created**: minimal shell branching plus focused tests and one standards update.
|
||||||
|
- **Alternative intentionally rejected**: a tiny copy-only patch was rejected because it would not define the durable `success vs follow-up` action contract or prevent regression.
|
||||||
|
- **Release truth**: current-release truth. The repo already ships the shell activity surface; this slice only hardens the remaining terminal-outcome seam.
|
||||||
237
specs/269-operationrun-terminal-outcome-feedback/spec.md
Normal file
237
specs/269-operationrun-terminal-outcome-feedback/spec.md
Normal file
@ -0,0 +1,237 @@
|
|||||||
|
# Feature Specification: OperationRun Terminal Outcome Feedback v1
|
||||||
|
|
||||||
|
**Feature Branch**: `269-operationrun-terminal-outcome-feedback`
|
||||||
|
**Created**: 2026-05-05
|
||||||
|
**Status**: Ready for implementation
|
||||||
|
**Input**: Manual promotion from `docs/product/spec-candidates.md` after repo-based verification against the current shell implementation, tests, and roadmap backlog.
|
||||||
|
|
||||||
|
## Spec Candidate Check *(mandatory - SPEC-GATE-001)*
|
||||||
|
|
||||||
|
- **Problem**: The tenant shell already shows recent terminal `OperationRun` states, but the current surface still collapses successful completion and unresolved follow-up into one generic terminal-update model. Terminal follow-up rows can still read like they are safely dismissible instead of clearly needing review.
|
||||||
|
- **Today's failure**: A blocked, partial, or failed run can render with the same generic terminal banner framing and `Dismiss` semantics as a no-action-needed success. That weakens the shell's decision-first promise because unresolved work can look like harmless noise.
|
||||||
|
- **User-visible improvement**: Operators can immediately distinguish `done, no action needed` from `completed, review still needed` in the shell without opening Monitoring first. Successful terminal items stay briefly calm and dismissible, while unresolved follow-up states use explicit acknowledge or review wording.
|
||||||
|
- **Smallest enterprise-capable version**: tighten the current tenant-shell activity hint only: keep active-state behavior intact, keep canonical links intact, split terminal success from terminal follow-up copy and tertiary actions, and keep acknowledgement browser-session-only.
|
||||||
|
- **Explicit non-goals**: no new activity tray, no dashboard active-operations card, no new `OperationRun` lifecycle, no new progress contract, no notification-policy rewrite, no persisted acknowledgement state, and no new diagnostics surface.
|
||||||
|
- **Permanent complexity imported**: one tighter shell-state contract, small copy or action branching in the existing shell helper or view, focused Feature plus browser proof, and one standards-document update.
|
||||||
|
- **Why now**: repo truth already includes the broader shell activity surface from Spec 268, and the next visible gap is no longer active-work feedback. It is terminal-outcome honesty on the same surface.
|
||||||
|
- **Why not local**: a one-line copy tweak would not encode the lifecycle-specific action contract, the `success vs follow-up` distinction, or the durable UI guardrail that stops this seam from drifting again.
|
||||||
|
- **Approval class**: Workflow Compression
|
||||||
|
- **Red flags triggered**: shared interaction family, shell-level operator surface
|
||||||
|
- **Score**: Nutzen: 2 | Dringlichkeit: 2 | Scope: 2 | Komplexitaet: 2 | Produktnaehe: 2 | Wiederverwendung: 1 | **Gesamt: 11/12**
|
||||||
|
- **Decision**: approve
|
||||||
|
|
||||||
|
## Spec Scope Fields *(mandatory)*
|
||||||
|
|
||||||
|
- **Scope**: tenant
|
||||||
|
- **Primary Routes**:
|
||||||
|
- `/admin/t/{tenant}/...` tenant-scoped start and work surfaces that host the shell activity hint
|
||||||
|
- `/admin/operations` remains the canonical collection drill-through
|
||||||
|
- `/admin/operations/{run}` remains the canonical detail drill-through
|
||||||
|
- **Data Ownership**: existing tenant-owned `OperationRun` truth only; no new persisted projection, no new user preference store, and no new queue or notification state
|
||||||
|
- **RBAC**: current `OperationRun` policies remain authoritative. Non-members or out-of-scope tenant contexts stay deny-as-not-found (`404` semantics through current tenant/admin boundaries). In-scope actors only see terminal states they can already view through the canonical Operations routes.
|
||||||
|
|
||||||
|
## Cross-Cutting / Shared Pattern Reuse *(mandatory)*
|
||||||
|
|
||||||
|
- **Cross-cutting feature?**: yes
|
||||||
|
- **Interaction class(es)**: shell status messaging, navigation links, lifecycle-sensitive tertiary actions
|
||||||
|
- **Systems touched**: `BulkOperationProgress`, `OperationUxPresenter`, `OperationStatusNormalizer`, `OperationRunProgressContract`, `ActiveRuns`, `OperationRunLinks`, `OperationRunUrl`, `OpsUxBrowserEvents`, and `docs/ui/tenantpilot-enterprise-ui-standards.md`
|
||||||
|
- **Existing pattern(s) to extend**: current shell activity feedback, canonical `View operation` and `Show all operations` links, current progress-contract enforcement, and browser-session collapse behavior
|
||||||
|
- **Shared contract / presenter / builder / renderer to reuse**: `App\Support\OpsUx\OperationUxPresenter`, `App\Support\OpsUx\OperationStatusNormalizer`, `App\Support\OpsUx\OperationRunProgressContract`, `App\Support\OpsUx\OperationRunUrl`, `App\Support\OpsUx\ActiveRuns`, `App\Support\OpsUx\OpsUxBrowserEvents`, and `App\Support\OperationRunLinks`
|
||||||
|
- **Why the existing shared path is sufficient or insufficient**: the repo already owns truthful link, status, and progress semantics. What remains open is a narrower shell-level terminal-outcome contract, not a new framework.
|
||||||
|
- **Allowed deviation and why**: none planned. Keep the refinement local to the existing shell component and its helpers.
|
||||||
|
- **Consistency impact**: `Hide activity`, `Dismiss` or `Close`, `Acknowledge`, `View operation`, grouped `Review operations`, and the banner helper copy must describe active, successful, and unresolved follow-up states consistently across Feature proof, browser smoke, and the standards document. `Review operations` is the grouped label variant of the same canonical collection link also exposed as `Show all operations`, not a second collection action.
|
||||||
|
- **Review focus**: verify that unresolved follow-up no longer inherits generic dismiss semantics, that terminal success stays no-action-needed, and that the shell still uses canonical links with no new lifecycle or persistence.
|
||||||
|
|
||||||
|
## OperationRun UX Impact *(mandatory)*
|
||||||
|
|
||||||
|
- **Touches OperationRun start/completion/link UX?**: yes
|
||||||
|
- **Shared OperationRun UX contract/layer reused**: existing Ops-UX shell contract through `OperationUxPresenter`, `OperationRunUrl`, `OperationRunLinks`, `OperationRunProgressContract`, and `OpsUxBrowserEvents`
|
||||||
|
- **Delegated start/completion UX behaviors**: current queued-toast wording, canonical Operations links, current browser event contract, and existing terminal DB-notification lifecycle remain delegated to the shared path
|
||||||
|
- **Local surface-owned behavior that remains**: terminal success vs follow-up copy, lifecycle-sensitive tertiary action wording, and browser-session-only acknowledge or dismiss behavior on the shell host
|
||||||
|
- **Queued DB-notification policy**: `N/A` - unchanged
|
||||||
|
- **Terminal notification path**: unchanged central lifecycle mechanism
|
||||||
|
- **Exception required?**: none
|
||||||
|
|
||||||
|
## Provider Boundary / Platform Core Check *(mandatory)*
|
||||||
|
|
||||||
|
N/A - no shared provider or platform-core seam changes. The slice only tightens shell semantics over existing platform-owned `OperationRun` truth.
|
||||||
|
|
||||||
|
## UI / Surface Guardrail Impact *(mandatory)*
|
||||||
|
|
||||||
|
| Surface / Change | Operator-facing surface change? | Native vs Custom | Shared-Family Relevance | State Layers Touched | Exception Needed? | Low-Impact / `N/A` Note |
|
||||||
|
|---|---|---|---|---|---|---|
|
||||||
|
| Tenant shell activity hint | yes | Native Filament + existing Livewire/Blade shell surface | Ops UX lifecycle feedback, canonical run links, browser-session calmness | shell, page, browser-session | no | Tightens terminal outcome semantics only; no new surface family |
|
||||||
|
|
||||||
|
## Decision-First Surface Role *(mandatory)*
|
||||||
|
|
||||||
|
| Surface | Decision Role | Human-in-the-loop Moment | Immediately Visible for First Decision | On-Demand Detail / Evidence | Why This Is Primary or Why Not | Workflow Alignment | Attention-load Reduction |
|
||||||
|
|---|---|---|---|---|---|---|---|
|
||||||
|
| Tenant shell activity hint | Primary Decision Surface | Decide whether the most recent terminal outcome needs no action, acknowledgement, or immediate review | Operation label, lifecycle state, terminal recency, one next-step cue, and one canonical primary action | Full diagnostics, logs, payloads, and evidence stay in Operations collection/detail | Primary because this is the post-start and post-completion surface where operators decide whether to keep working or inspect a run | Follows start-surface workflow, not diagnostics-page storage structure | Prevents unresolved follow-up from blending into harmless completion noise |
|
||||||
|
|
||||||
|
## Audience-Aware Disclosure *(mandatory)*
|
||||||
|
|
||||||
|
| Surface | Audience Modes In Scope | Decision-First Default-Visible Content | Operator Diagnostics | Support / Raw Evidence | One Dominant Next Action | Hidden / Gated By Default | Duplicate-Truth Prevention |
|
||||||
|
|---|---|---|---|---|---|---|---|
|
||||||
|
| Tenant shell activity hint | operator-MSP | Operation label, terminal success or follow-up state, short recency line, concise next-step cue, and canonical primary action | Detailed failure context, run history, and full outcome diagnostics remain on Operations pages | Raw payloads, log details, and support-only evidence stay off the shell | `View operation` for one visible item or `Review operations` when unresolved follow-up is mixed or grouped | Raw and support detail stay diagnostics-only; acknowledge stays browser-session-only | The shell states the next decision once and does not restate full Monitoring prose |
|
||||||
|
|
||||||
|
## UI/UX Surface Classification *(mandatory)*
|
||||||
|
|
||||||
|
| Surface | Action Surface Class | Surface Type | Likely Next Operator Action | Primary Inspect/Open Model | Row Click | Secondary Actions Placement | Destructive Actions Placement | Canonical Collection Route | Canonical Detail Route | Scope Signals | Canonical Noun | Critical Truth Visible by Default | Exception Type / Justification |
|
||||||
|
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
||||||
|
| Tenant shell activity hint | Monitoring hint | Activity shell hint | Decide whether to review a just-finished run or keep working | One explicit `View operation` or grouped `Review operations` action | forbidden | One grouped overflow path to `Show all operations` plus one lifecycle-sensitive tertiary action | none | `/admin/operations` in current tenant context | `/admin/operations/{run}` in current tenant context | Current tenant shell context | Operations / Operation | Terminal success vs unresolved follow-up, recency, and the next action | none |
|
||||||
|
|
||||||
|
## Operator Surface Contract *(mandatory)*
|
||||||
|
|
||||||
|
| Surface | Primary Persona | Decision / Operator Action Supported | Surface Type | Primary Operator Question | Default-visible Information | Diagnostics-only Information | Status Dimensions Used | Mutation Scope | Primary Actions | Dangerous Actions |
|
||||||
|
|---|---|---|---|---|---|---|---|---|---|---|
|
||||||
|
| Tenant shell activity hint | Tenant operator | Decide whether a recent terminal outcome is safely complete or still needs review | Start-surface shell hint | Does this run need anything from me now? | Operation label, terminal outcome, recency, concise guidance, and canonical open or review action | Operations detail, logs, and evidence | lifecycle, follow-up-needed, progress-availability | none | `View operation`, `Review operations`, `Show all operations` | none |
|
||||||
|
|
||||||
|
**UI Action Matrix**: `N/A - no Filament Resource, RelationManager, or Page action matrix changes are introduced. The shell hint remains a widget-level monitoring hint with one dominant navigation action and one browser-session tertiary affordance.`
|
||||||
|
|
||||||
|
## Proportionality Review *(mandatory when structural complexity is introduced)*
|
||||||
|
|
||||||
|
- **New source of truth?**: no
|
||||||
|
- **New persisted entity/table/artifact?**: no
|
||||||
|
- **New abstraction?**: no
|
||||||
|
- **New enum/state/reason family?**: no
|
||||||
|
- **New cross-domain UI framework/taxonomy?**: no
|
||||||
|
- **Current operator problem**: terminal follow-up still inherits generic dismiss semantics on the shell, which blurs `review needed` with `done, no action needed`.
|
||||||
|
- **Existing structure is insufficient because**: the current shell already has terminal rows, but its copy and tertiary action rules are still too broad to encode lifecycle-correct operator decisions.
|
||||||
|
- **Narrowest correct implementation**: refine the existing shell component, helper text, and browser-session tertiary actions only, then document the rule in the standards file.
|
||||||
|
- **Ownership cost**: small shell branching plus focused Feature and browser coverage.
|
||||||
|
- **Alternative intentionally rejected**: a copy-only tweak was rejected because it would not define the durable `success vs follow-up` action contract or stop future regression.
|
||||||
|
- **Release truth**: current-release truth. The repo already ships the shell activity surface; this slice only hardens its terminal semantics.
|
||||||
|
|
||||||
|
### Compatibility posture
|
||||||
|
|
||||||
|
This feature assumes a pre-production environment.
|
||||||
|
|
||||||
|
Backward compatibility, legacy aliases, migration shims, historical fixtures, and compatibility-specific tests are out of scope unless explicitly required by this spec.
|
||||||
|
|
||||||
|
Canonical replacement is preferred over preservation.
|
||||||
|
|
||||||
|
## Testing / Lane / Runtime Impact *(mandatory)*
|
||||||
|
|
||||||
|
- **Test purpose / classification**: Feature plus one required browser smoke for the shell action and overlap contract
|
||||||
|
- **Validation lane(s)**: fast-feedback, confidence, browser
|
||||||
|
- **Why this classification and these lanes are sufficient**: Feature coverage proves the lifecycle-specific terminal copy, tertiary actions, and browser-session-only acknowledgement semantics on the current shell host. The browser smoke is the narrowest credible proof that the tightened terminal actions stay reachable without reintroducing obstruction.
|
||||||
|
- **New or expanded test families**: extend `apps/platform/tests/Feature/OpsUx/ActivityFeedbackSurfaceTest.php`, extend `apps/platform/tests/Feature/OpsUx/BulkOperationProgressDbOnlyTest.php`, and extend `apps/platform/tests/Browser/OpsUx/OperationActivityFeedbackSmokeTest.php`
|
||||||
|
- **Fixture / helper cost impact**: low to moderate. Reuse current `OperationRun` factories, tenant helpers, and shell smoke helpers; do not add provider-heavy setup or persisted acknowledgement fixtures.
|
||||||
|
- **Heavy-family visibility / justification**: no heavy-governance family. The browser proof stays explicit and bounded to the shell overlap plus action-label contract.
|
||||||
|
- **Special surface test profile**: global-context-shell
|
||||||
|
- **Standard-native relief or required special coverage**: standard Feature coverage is primary; one browser smoke remains required for live shell interaction
|
||||||
|
- **Reviewer handoff**: reviewers must confirm that successful terminal items stay dismissible, unresolved follow-up uses acknowledge or review semantics, terminal rows never show progressbars, and the shell still reopens on new run-enqueue events.
|
||||||
|
- **Budget / baseline / trend impact**: small feature-local increase only
|
||||||
|
- **Escalation needed**: `reject-or-split` if implementation widens into dashboard cards, new notification policy, new persistence, or a second `OperationRun` lifecycle surface
|
||||||
|
- **Active feature PR close-out entry**: Guardrail / Smoke Coverage
|
||||||
|
- **Planned validation commands**:
|
||||||
|
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/OpsUx/ActivityFeedbackSurfaceTest.php tests/Feature/OpsUx/BulkOperationProgressDbOnlyTest.php`
|
||||||
|
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Browser/OpsUx/OperationActivityFeedbackSmokeTest.php`
|
||||||
|
|
||||||
|
## User Scenarios & Testing *(mandatory)*
|
||||||
|
|
||||||
|
### User Story 1 - Terminal Success Feels Complete, Not Risky (Priority: P1)
|
||||||
|
|
||||||
|
As a tenant operator, I need successful terminal runs to stay briefly visible with calm success semantics, so I can see that work finished and dismiss it without confusing it with unresolved follow-up.
|
||||||
|
|
||||||
|
**Why this priority**: post-completion trust is the first decision point after work finishes, and it should stay explicitly no-action-needed.
|
||||||
|
|
||||||
|
**Independent Test**: seed one recently completed successful run, open a tenant-scoped shell surface, and verify the shell shows success-specific copy, no active progress UI, and `Dismiss` or `Close` semantics during the current 30-second shell-visible success window preserved by `ActiveRuns`.
|
||||||
|
|
||||||
|
**Acceptance Scenarios**:
|
||||||
|
|
||||||
|
1. **Given** a run completes successfully, **When** the shell refreshes during the current 30-second terminal-success grace window from `ActiveRuns::shellVisibleQueryForTenantId()`, **Then** the shell shows success-specific copy, keeps `View operation` as the canonical primary action, and uses `Dismiss` or `Close` as the tertiary action.
|
||||||
|
2. **Given** a recent successful terminal item is visible, **When** the shell renders it, **Then** it does not show a determinate or indeterminate progress bar.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### User Story 2 - Terminal Follow-Up Stays Explicitly Reviewable (Priority: P1)
|
||||||
|
|
||||||
|
As a tenant operator, I need unresolved terminal runs to stay clearly review-worthy on the shell, so I do not treat a failed or partial outcome as safely dismissible noise.
|
||||||
|
|
||||||
|
**Why this priority**: unresolved terminal outcomes are the real decision risk in the current shell semantics.
|
||||||
|
|
||||||
|
**Independent Test**: seed one failed, partial, or blocked terminal run, open a tenant-scoped shell surface, and verify the shell shows follow-up-specific copy, canonical review or detail navigation, and `Acknowledge` instead of generic dismiss semantics.
|
||||||
|
|
||||||
|
**Acceptance Scenarios**:
|
||||||
|
|
||||||
|
1. **Given** a run completes with a follow-up-needed outcome, **When** the shell refreshes, **Then** the shell keeps the run visible with follow-up-specific guidance and uses `Acknowledge` as the local tertiary action.
|
||||||
|
2. **Given** both active work and unresolved terminal follow-up are visible, **When** the shell chooses its grouped primary action, **Then** the grouped action favors review-oriented wording over no-action-needed success wording.
|
||||||
|
3. **Given** a terminal follow-up item is visible, **When** the shell renders it, **Then** it does not show active-progress UI and does not use `Dismiss` as the tertiary label.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### User Story 3 - Acknowledge Stays Browser-Session Only (Priority: P1)
|
||||||
|
|
||||||
|
As a tenant operator, I need terminal follow-up acknowledgement to stay local to my current browser session, so the shell can stay calm without inventing a server-side review state.
|
||||||
|
|
||||||
|
**Why this priority**: the slice must remain a presentation refinement, not a new workflow system.
|
||||||
|
|
||||||
|
**Independent Test**: acknowledge an unresolved terminal item in the current browser session, then trigger a new run-enqueued event and verify the shell reopens without any database-backed acknowledgement state.
|
||||||
|
|
||||||
|
**Acceptance Scenarios**:
|
||||||
|
|
||||||
|
1. **Given** an unresolved terminal item is visible, **When** the operator clicks `Acknowledge`, **Then** the shell hides that item only for the current browser session.
|
||||||
|
2. **Given** the shell is hidden or acknowledged in the current browser session, **When** a new run is enqueued for the current tenant, **Then** the shell reopens so the operator does not miss new work.
|
||||||
|
|
||||||
|
### Edge Cases
|
||||||
|
|
||||||
|
- Successful terminal items must not overwrite unresolved follow-up emphasis when both types are visible in the same shell state.
|
||||||
|
- Unresolved terminal follow-up must not inherit generic `Dismiss updates` copy when the shell shows a grouped primary action.
|
||||||
|
- Terminal outcome items must not reintroduce progressbars, indeterminate bars, or fake percentages after completion.
|
||||||
|
- No tenant context or no `viewAny OperationRun` capability keeps the shell inert and leak-free.
|
||||||
|
- Browser-session acknowledgement must not mutate the `OperationRun` record or persist across new browser sessions.
|
||||||
|
- The current 30-second terminal-success grace window from `ActiveRuns::shellVisibleQueryForTenantId()` remains the source of truth unless a later spec deliberately changes it.
|
||||||
|
|
||||||
|
## Requirements *(mandatory)*
|
||||||
|
|
||||||
|
**Constitution alignment summary**: This feature adds no Graph calls, no new write path, no new `OperationRun` lifecycle, no new notification policy, and no new persistence. It reuses the current shell activity surface, current progress contract, current canonical links, and current browser-session event flow.
|
||||||
|
|
||||||
|
### Functional Requirements
|
||||||
|
|
||||||
|
- **FR-001**: The shell MUST continue deriving terminal outcome presentation from existing `OperationRun` truth and current shared helpers. It MUST NOT create a second lifecycle, status taxonomy, or persisted shell state.
|
||||||
|
- **FR-002**: Recent successful terminal items MUST use success-specific shell copy and a no-action-needed posture, keep canonical Operations navigation, and use `Dismiss` or `Close` as the browser-session tertiary action during the current 30-second terminal-success grace window preserved in `ActiveRuns::shellVisibleQueryForTenantId()`.
|
||||||
|
- **FR-003**: Unresolved terminal follow-up items that still require operator review MUST use follow-up-specific shell copy and `Acknowledge` as the browser-session tertiary action. They MUST NOT reuse generic dismiss semantics.
|
||||||
|
- **FR-004**: Mixed shell states that include unresolved terminal follow-up MUST preserve review-oriented emphasis in grouped helper copy and primary action wording. Successful completion MUST NOT dominate unresolved follow-up messaging.
|
||||||
|
- **FR-005**: Terminal success and terminal follow-up items MUST NOT render determinate or indeterminate progress UI after completion.
|
||||||
|
- **FR-006**: Canonical `View operation`, grouped `Review operations`, and `Show all operations` links MUST remain helper-generated through the existing shared path. `Review operations` is only the grouped label variant of the canonical collection link. The slice MUST NOT introduce raw route strings.
|
||||||
|
- **FR-007**: Browser-session `Hide activity`, `Dismiss` or `Close`, and `Acknowledge` behavior MUST remain browser-session-only. The implementation MUST NOT persist acknowledgement or dismiss state on the `OperationRun` record or in a new table.
|
||||||
|
- **FR-008**: A new accepted run in the current browser session MUST reopen the shell if it was previously hidden or acknowledged locally.
|
||||||
|
- **FR-009**: `docs/ui/tenantpilot-enterprise-ui-standards.md` MUST record the terminal outcome contract for the shell activity hint, including the difference between success dismissal and follow-up acknowledgement semantics.
|
||||||
|
|
||||||
|
### Authorization and Safety Requirements
|
||||||
|
|
||||||
|
- **AR-001**: Current tenant/admin-plane authorization semantics remain unchanged: out-of-scope tenant access stays deny-as-not-found (`404` semantics) and in-scope visibility continues to reuse server-side `OperationRun` policies.
|
||||||
|
- **AR-002**: No shell state in this slice may expose a run the actor cannot already reach through the canonical Operations routes.
|
||||||
|
- **AR-003**: No destructive or mutating action is introduced. Acknowledge and dismiss are browser-session-only presentation controls.
|
||||||
|
|
||||||
|
### Non-Functional Requirements
|
||||||
|
|
||||||
|
- **NFR-001**: Filament remains v5 on Livewire v4. No panel-provider registration change is allowed, and `apps/platform/bootstrap/providers.php` remains authoritative.
|
||||||
|
- **NFR-002**: No new panel, no new globally searchable resource, and no new asset registration strategy are allowed.
|
||||||
|
- **NFR-003**: Polling remains bounded to the current shell host. The slice MUST NOT add a second polling loop or a second active-awareness host surface.
|
||||||
|
- **NFR-004**: Existing progress-contract and badge semantics remain authoritative. No page-local terminal-status color mapping or progress heuristics may be introduced.
|
||||||
|
|
||||||
|
## Deferred Follow-Ups / Explicit Non-Goals
|
||||||
|
|
||||||
|
- Tenant dashboard active-operations summary card
|
||||||
|
- New `OperationRun` progress-contract or counted-progress rollout work
|
||||||
|
- Phase or composite progress modeling
|
||||||
|
- A persisted reviewed, investigated, or acknowledged state over terminal follow-up
|
||||||
|
- Activity tray or inbox v2
|
||||||
|
- Notification-policy changes for queued or terminal lifecycle events
|
||||||
|
|
||||||
|
## Key Entities
|
||||||
|
|
||||||
|
- **Terminal success shell item**: a derived, non-persisted shell item for a recently completed successful run that stays briefly visible, conveys no-action-needed completion, and remains locally dismissible.
|
||||||
|
- **Terminal follow-up shell item**: a derived, non-persisted shell item for a terminal run that still needs operator review and therefore uses acknowledge or review semantics instead of generic dismissal.
|
||||||
|
- **Browser-session terminal-outcome state**: non-persisted shell-level state that remembers local hide, dismiss, and acknowledge choices only for the current browser session.
|
||||||
|
|
||||||
|
## Success Criteria *(mandatory)*
|
||||||
|
|
||||||
|
### Measurable Outcomes
|
||||||
|
|
||||||
|
- **SC-001**: Focused Feature proof shows a recent successful terminal item with success-specific copy, no active-progress UI, and `Dismiss` or `Close` semantics.
|
||||||
|
- **SC-002**: Focused Feature proof shows an unresolved terminal follow-up item with review-specific copy and `Acknowledge` semantics instead of generic dismiss wording.
|
||||||
|
- **SC-003**: Focused Feature proof shows mixed active-plus-follow-up shell states keeping follow-up emphasis in grouped helper copy and grouped primary action wording.
|
||||||
|
- **SC-004**: The named browser smoke continues to prove that the shell actions remain reachable, collapse or acknowledge behavior stays browser-session-only, and new run-enqueue events reopen the shell.
|
||||||
159
specs/269-operationrun-terminal-outcome-feedback/tasks.md
Normal file
159
specs/269-operationrun-terminal-outcome-feedback/tasks.md
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
---
|
||||||
|
description: "Task list for OperationRun Terminal Outcome Feedback v1"
|
||||||
|
---
|
||||||
|
|
||||||
|
# Tasks: OperationRun Terminal Outcome Feedback v1
|
||||||
|
|
||||||
|
**Input**: Design documents from `specs/269-operationrun-terminal-outcome-feedback/`
|
||||||
|
**Prerequisites**: `specs/269-operationrun-terminal-outcome-feedback/spec.md`, `specs/269-operationrun-terminal-outcome-feedback/plan.md`, `specs/269-operationrun-terminal-outcome-feedback/checklists/requirements.md`
|
||||||
|
|
||||||
|
**Review Artifact**: `specs/269-operationrun-terminal-outcome-feedback/checklists/requirements.md` is the outcome-of-record for the review outcome class, workflow outcome, and test-governance outcome. If implementation widens into dashboard work, new persistence, or notification-policy changes, update that artifact before continuing.
|
||||||
|
|
||||||
|
**Tests**: REQUIRED (Pest). Keep proof bounded to focused Feature coverage for terminal-outcome shell semantics plus one named browser smoke for the live shell interaction contract.
|
||||||
|
**Operations**: No new `OperationRun` type, no new queue family, no new notification policy, and no new lifecycle ownership. Existing queued toasts, terminal notifications, canonical Operations drill-through routes, and browser enqueue events remain authoritative.
|
||||||
|
**RBAC**: Reuse current `OperationRun` policies and tenant context guards. No tenantless leakage from tenant surfaces; the shell stays inert when no selected tenant or `viewAny` capability exists.
|
||||||
|
**Shared Pattern Reuse**: Reuse `BulkOperationProgress`, `OperationUxPresenter`, `OperationStatusNormalizer`, `OperationRunProgressContract`, `OperationRunLinks`, `OperationRunUrl`, `ActiveRuns`, `OpsUxBrowserEvents`, and `docs/ui/tenantpilot-enterprise-ui-standards.md`. Do not create a second lifecycle, a second shell host, or a DB-backed acknowledgement model.
|
||||||
|
**Filament / Panel Guardrails**: Filament remains v5 on Livewire v4. Provider registration remains unchanged in `apps/platform/bootstrap/providers.php`. No new panel, resource, or asset strategy is allowed.
|
||||||
|
**Organization**: Tasks are grouped by user story so terminal success, unresolved follow-up, and browser-session acknowledgement remain independently reviewable.
|
||||||
|
|
||||||
|
## Test Governance Notes
|
||||||
|
|
||||||
|
- Lane mix stays Feature plus one named browser smoke for live shell interaction.
|
||||||
|
- Prefer extending `ActivityFeedbackSurfaceTest`, `BulkOperationProgressDbOnlyTest`, and `OperationActivityFeedbackSmokeTest` before adding any new families.
|
||||||
|
- Planned proving test commands must stay identical to `spec.md` and `plan.md` and run through Sail. Formatting remains a separate repo-hygiene step.
|
||||||
|
|
||||||
|
## Phase 1: Setup (Shared Context)
|
||||||
|
|
||||||
|
**Purpose**: confirm the bounded slice, the current shell truth, and the current proof owners before runtime edits begin.
|
||||||
|
|
||||||
|
- [x] T001 Review `specs/269-operationrun-terminal-outcome-feedback/spec.md`, `specs/269-operationrun-terminal-outcome-feedback/plan.md`, `specs/269-operationrun-terminal-outcome-feedback/checklists/requirements.md`, `docs/product/spec-candidates.md`, `docs/product/roadmap.md`, and `.specify/memory/constitution.md` together so the slice stays on the bounded manual-promotion target.
|
||||||
|
- [x] T002 [P] Confirm the current terminal-outcome seams in `apps/platform/app/Livewire/BulkOperationProgress.php`, `apps/platform/resources/views/livewire/bulk-operation-progress.blade.php`, `apps/platform/app/Support/OpsUx/OperationUxPresenter.php`, `apps/platform/app/Support/OpsUx/ActiveRuns.php`, and `apps/platform/public/js/tenantpilot/ops-ux-progress-widget-poller.js`.
|
||||||
|
- [x] T003 [P] Confirm the current proof owners in `apps/platform/tests/Feature/OpsUx/ActivityFeedbackSurfaceTest.php`, `apps/platform/tests/Feature/OpsUx/BulkOperationProgressDbOnlyTest.php`, `apps/platform/tests/Browser/OpsUx/OperationActivityFeedbackSmokeTest.php`, and `docs/ui/tenantpilot-enterprise-ui-standards.md`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 2: Foundational (Blocking Prerequisites)
|
||||||
|
|
||||||
|
**Purpose**: settle the proof seams before runtime edits widen.
|
||||||
|
|
||||||
|
**Critical**: no user-story runtime work should begin until this phase is complete.
|
||||||
|
|
||||||
|
- [x] T004 [P] Create or extend failing Feature coverage in `apps/platform/tests/Feature/OpsUx/ActivityFeedbackSurfaceTest.php` for no-tenant and no-capability suppression, no inaccessible run exposure, terminal success copy, follow-up-specific `Acknowledge` semantics, grouped follow-up emphasis, and the absence of progress UI after terminal transition.
|
||||||
|
- [x] T005 [P] Extend `apps/platform/tests/Feature/OpsUx/BulkOperationProgressDbOnlyTest.php` only as needed for single-item versus grouped primary-action wording, grouped `Review operations` as the label variant of the canonical collection link, and terminal tertiary-action labels.
|
||||||
|
- [x] T006 [P] Extend `apps/platform/tests/Browser/OpsUx/OperationActivityFeedbackSmokeTest.php` for browser-session-only acknowledge or dismiss behavior and shell re-open on new run-enqueue events.
|
||||||
|
|
||||||
|
**Checkpoint**: the success-versus-follow-up proof owner is settled before implementation begins.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 3: User Story 1 - Terminal Success Feels Complete, Not Risky (Priority: P1)
|
||||||
|
|
||||||
|
**Goal**: keep successful terminal runs briefly visible with success-specific copy and dismissible browser-session behavior.
|
||||||
|
|
||||||
|
**Independent Test**: seed a recent successful terminal run, open a tenant-scoped shell surface, and verify the shell shows success-specific copy, no progress UI, and `Dismiss` or `Close` semantics.
|
||||||
|
|
||||||
|
### Implementation for User Story 1
|
||||||
|
|
||||||
|
- [x] T007 [US1] Refine `apps/platform/resources/views/livewire/bulk-operation-progress.blade.php` and `apps/platform/app/Support/OpsUx/OperationUxPresenter.php` so successful terminal items render success-specific helper or guidance copy and keep `Dismiss` or `Close` semantics without reusing follow-up wording. Existing `OperationUxPresenter` success guidance was sufficient; no presenter edit was needed.
|
||||||
|
- [x] T008 [US1] Update `apps/platform/app/Livewire/BulkOperationProgress.php` and `apps/platform/app/Support/OpsUx/ActiveRuns.php` only as needed so recent successful terminal items remain visible for the current 30-second `ActiveRuns` grace window without changing active-run truth or polling ownership. Existing `ActiveRuns` grace-window truth remained correct; no runtime edit was needed.
|
||||||
|
|
||||||
|
**Checkpoint**: User Story 1 is independently functional when successful terminal rows stay calm and dismissible.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 4: User Story 2 - Terminal Follow-Up Stays Explicitly Reviewable (Priority: P1)
|
||||||
|
|
||||||
|
**Goal**: keep unresolved terminal outcomes clearly review-worthy instead of generically dismissible.
|
||||||
|
|
||||||
|
**Independent Test**: seed failed, partial, or blocked terminal runs, open a tenant-scoped shell surface, and verify the shell shows follow-up-specific guidance, `Acknowledge` semantics, and review-oriented grouped copy when mixed with active work.
|
||||||
|
|
||||||
|
### Implementation for User Story 2
|
||||||
|
|
||||||
|
- [x] T009 [US2] Refine `apps/platform/resources/views/livewire/bulk-operation-progress.blade.php` and `apps/platform/app/Support/OpsUx/OperationUxPresenter.php` so unresolved terminal follow-up uses explicit review-needed copy, `Acknowledge` tertiary wording, and review-oriented grouped helper text. Existing `OperationUxPresenter` follow-up guidance was sufficient; the shell view owns the label split.
|
||||||
|
- [x] T010 [US2] Update `apps/platform/app/Support/OpsUx/ActiveRuns.php` and `apps/platform/app/Livewire/BulkOperationProgress.php` only as needed so unresolved terminal follow-up remains shell-visible until locally acknowledged and never reuses success dismissal semantics. Existing shell-visible query and Livewire state already kept terminal follow-up visible; no edit was needed.
|
||||||
|
|
||||||
|
**Checkpoint**: User Story 2 is independently functional when unresolved terminal follow-up stops looking like harmless completion noise.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 5: User Story 3 - Acknowledge Stays Browser-Session Only (Priority: P1)
|
||||||
|
|
||||||
|
**Goal**: preserve shell calmness without creating a new persisted review state.
|
||||||
|
|
||||||
|
**Independent Test**: acknowledge an unresolved terminal item in the current browser session, trigger a new run-enqueue event, and verify the shell reopens without any DB-backed acknowledgement state.
|
||||||
|
|
||||||
|
### Implementation for User Story 3
|
||||||
|
|
||||||
|
- [x] T011 [US3] Update `apps/platform/public/js/tenantpilot/ops-ux-progress-widget-poller.js`, `apps/platform/app/Livewire/BulkOperationProgress.php`, and the shell view only as needed so `Hide activity`, `Dismiss` or `Close`, and `Acknowledge` remain browser-session-only and new work reopens the shell. Existing poller sessionStorage and `ops-ux:run-enqueued` reopen behavior covered the renamed tertiary semantics; browser smoke verified no JS edit was needed.
|
||||||
|
- [x] T012 [US3] Update `docs/ui/tenantpilot-enterprise-ui-standards.md` with the shell terminal-outcome contract, including success dismissal, follow-up acknowledgement, and the ban on generic dismiss semantics for unresolved follow-up.
|
||||||
|
|
||||||
|
**Checkpoint**: User Story 3 is independently functional when terminal-outcome calmness stays local to the browser session and the standards document records the durable rule.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Phase 6: Polish & Cross-Cutting Validation
|
||||||
|
|
||||||
|
**Purpose**: validate the bounded slice, stop drift, and hand off a clean implementation path.
|
||||||
|
|
||||||
|
- [x] T013 [P] Run `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/OpsUx/ActivityFeedbackSurfaceTest.php tests/Feature/OpsUx/BulkOperationProgressDbOnlyTest.php`.
|
||||||
|
- [x] T014 [P] Run `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Browser/OpsUx/OperationActivityFeedbackSmokeTest.php`.
|
||||||
|
- [x] T015 [P] Run `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent` for touched platform files.
|
||||||
|
- [x] T016 [P] Review touched code to confirm Filament stays on Livewire v4, provider registration remains unchanged in `apps/platform/bootstrap/providers.php`, no new globally searchable resource was introduced, and no asset registration or notification-policy change slipped into the slice.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Dependencies & Execution Order
|
||||||
|
|
||||||
|
### Phase Dependencies
|
||||||
|
|
||||||
|
- **Phase 1 (Setup)**: no dependencies; start immediately.
|
||||||
|
- **Phase 2 (Foundational)**: depends on Phase 1 and blocks user-story work.
|
||||||
|
- **Phase 3 (US1)**: depends on Phase 2 and establishes success-specific terminal semantics.
|
||||||
|
- **Phase 4 (US2)**: depends on Phase 2 and should ship with US1 so terminal outcomes stay honest across both no-action-needed and follow-up-needed cases.
|
||||||
|
- **Phase 5 (US3)**: depends on Phase 2 and hardens browser-session-only calmness after terminal semantics exist.
|
||||||
|
- **Phase 6 (Polish)**: depends on all desired user stories being complete.
|
||||||
|
|
||||||
|
### User Story Dependencies
|
||||||
|
|
||||||
|
- **US1 (P1)**: independently testable after Phase 2 and delivers the no-action-needed terminal success contract.
|
||||||
|
- **US2 (P1)**: independently testable after Phase 2 and should ship with US1 so unresolved follow-up never inherits success semantics.
|
||||||
|
- **US3 (P1)**: independently testable after Phase 2 and is required to keep the slice presentation-only instead of inventing a persisted workflow state.
|
||||||
|
|
||||||
|
### Within Each User Story
|
||||||
|
|
||||||
|
- Write or extend the listed Pest coverage first and make it fail for the intended gap.
|
||||||
|
- Land shell-host runtime changes before widening browser-session action behavior.
|
||||||
|
- Re-run the narrowest affected validation command after each story checkpoint before moving on.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Implementation Strategy
|
||||||
|
|
||||||
|
### Suggested MVP Scope
|
||||||
|
|
||||||
|
- MVP = **US1 + US2 + US3 together**. The manual-promotion target is only complete when terminal success is calm, unresolved follow-up is explicitly reviewable, and acknowledgement stays browser-session-only.
|
||||||
|
|
||||||
|
### Incremental Delivery
|
||||||
|
|
||||||
|
1. Complete Phase 1 and Phase 2.
|
||||||
|
2. Deliver US1.
|
||||||
|
3. Deliver US2 on top of the same shell host.
|
||||||
|
4. Add US3 browser-session-only action hardening and the standards update.
|
||||||
|
5. Finish with the focused Feature proof and the named browser smoke.
|
||||||
|
|
||||||
|
### Team Strategy
|
||||||
|
|
||||||
|
1. Settle the shell proof owner first.
|
||||||
|
2. Parallelize Feature and browser proof updates while keeping the runtime change local to the existing shell component.
|
||||||
|
3. Serialize merges around `BulkOperationProgress` and the standards document so the terminal-outcome contract stays coherent.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Deferred Follow-Ups / Non-Goals
|
||||||
|
|
||||||
|
- Tenant dashboard active-operations summary card
|
||||||
|
- New `OperationRun` progress-contract or rollout work
|
||||||
|
- Phase or composite progress modeling
|
||||||
|
- Persistent reviewed, investigated, or acknowledged semantics over unresolved terminal runs
|
||||||
|
- Activity center or tray v2
|
||||||
|
- Notification-policy changes for queued or terminal lifecycle events
|
||||||
Loading…
Reference in New Issue
Block a user