# Tasks: IA Semantics — Scope vs Filter vs Targeting (Monitoring + Manage)

**Input**: Design documents from `/specs/103-ia-scope-filter-semantics/`
**Prerequisites**: plan.md (loaded), spec.md (loaded), research.md (loaded), data-model.md (loaded), quickstart.md (loaded)

**Tests**: Required (Pest feature tests). This feature changes runtime behavior (copy, query filtering, form layout).
**Operations**: N/A — no long-running/remote/queued/scheduled work introduced.
**RBAC**: N/A — no authorization changes. Existing RBAC enforcement unchanged.
**Filament UI Action Surfaces**: Manage pages have header actions removed (informational indicators, not mutation actions). No new actions added. Action surface contract satisfied.
**Filament UI UX-001**: AlertRule form adds Section grouping (conforming to "all fields inside Sections/Cards"). No new pages or custom layouts.
**Badges**: N/A — no status badges added or changed.

**Organization**: Tasks are grouped by user story to enable independent implementation and testing of each story.

## Format: `[ID] [P?] [Story] Description`

- **[P]**: Can run in parallel (different files, no dependencies)
- **[Story]**: Which user story this task belongs to (e.g., US1, US2, US3)
- Include exact file paths in descriptions

---

## Phase 1: Setup

**Purpose**: No project setup needed — existing Laravel monolith. This phase validates prerequisites only.

- [x] T001 Verify Sail is running and database is migrated (`vendor/bin/sail up -d && vendor/bin/sail artisan migrate`)
- [x] T002 Run existing test suite baseline (`vendor/bin/sail artisan test --compact`) to confirm green before changes

**Checkpoint**: Baseline green — changes can begin.

---

## Phase 2: Foundational (Blocking Prerequisites)

**Purpose**: The `OperateHubShell::scopeLabel()` change is the single foundation all other stories depend on. It must be updated first because US2 tests need the new copy, US3 verifies its absence, and US1 tests assert it directly.

**⚠️ CRITICAL**: US2/US3/US4/US5 tests reference the new indicator copy. This phase must complete first.

- [x] T003 Update `scopeLabel()` return values in `app/Support/OperateHub/OperateHubShell.php`: change `'Scope: Tenant — '.$activeTenant->name` to `'Filtered by tenant: '.$activeTenant->name` and `'Scope: Workspace — all tenants'` to `'All tenants'` (line 23–33)

**Checkpoint**: `scopeLabel()` emits new copy. All Monitoring pages that call `scopeLabel()` or `headerActions()` now show the new labels automatically. No tests pass yet — existing test assertions reference old copy.

---

## Phase 3: User Story 1 — Monitoring Page Tenant Indicator (Priority: P1) 🎯 MVP

**Goal**: Monitoring canonical pages display "Filtered by tenant: {name}" or "All tenants" instead of "Scope: …" labels.

**Independent Test**: Visit any Monitoring page with/without tenant-context and assert the indicator text.

### Tests for User Story 1

- [x] T004 [US1] Update existing assertions in `tests/Feature/OpsUx/OperateHubShellTest.php`: replace all `assertSee('Scope: Workspace — all tenants')` with `assertSee('All tenants')` and all `assertSee('Scope: Tenant')` patterns with `assertSee('Filtered by tenant:')`. Also add `assertDontSee('Scope: Tenant')` and `assertDontSee('Scope: Workspace')` to existing test cases.
- [x] T005 [US1] Run OperateHubShell tests to confirm they pass with new copy: `vendor/bin/sail artisan test --compact --filter=OperateHubShell`

**Checkpoint**: US1 complete — Monitoring indicator shows correct copy. FR-001, FR-002, FR-003 satisfied.

---

## Phase 4: User Story 2 — Alerts KPI Widget Tenant Resolution Bugfix (Priority: P1)

**Goal**: `AlertsKpiHeader::deliveriesQueryForViewer()` uses `OperateHubShell::activeEntitledTenant()` instead of `Filament::getTenant()`, so KPI numbers always match the indicator banner.

**Independent Test**: Set tenant-context via lastTenantId session fallback only, render KPI widget, assert query includes `tenant_id` filter.

### Implementation for User Story 2

- [x] T006 [US2] Fix `deliveriesQueryForViewer()` in `app/Filament/Widgets/Alerts/AlertsKpiHeader.php`: replace `Filament::getTenant()` with `app(OperateHubShell::class)->activeEntitledTenant(request())` and update the null-check to use `instanceof Tenant` (line 101–118). Add `use App\Support\OperateHub\OperateHubShell;` and `use App\Models\Tenant;` imports if not already present.

### Tests for User Story 2

- [x] T007 [US2] Add test in `tests/Feature/OpsUx/OperateHubShellTest.php` (or new test file `tests/Feature/Filament/Alerts/AlertsKpiHeaderTest.php`): (a) test that when tenant-context is set only via `WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY` session (Filament::getTenant() returns null), the KPI widget's delivery query includes a `where tenant_id = ?` clause matching the fallback tenant; (b) test that when tenant-context is set via `Filament::setTenant()`, the KPI widget's delivery query filters by that tenant's ID (regression guard for US2 acceptance scenario 2).
- [x] T008 [US2] Add test: when no tenant-context is active, the KPI widget's delivery query does NOT include a `tenant_id` filter (workspace-wide counts).
- [x] T009 [US2] Run KPI tests: `vendor/bin/sail artisan test --compact --filter=AlertsKpiHeader`

**Checkpoint**: US2 complete — KPI numbers are consistent with indicator banner. FR-004, FR-005 satisfied.

---

## Phase 5: User Story 3 — Manage Pages Suppress Tenant Indicator (Priority: P2)

**Goal**: Alert Rules list and Alert Destinations list no longer show any tenant indicator/banner.

**Independent Test**: Visit `/admin/alert-rules` with tenant-context active, assert absence of "Filtered by tenant" text.

### Implementation for User Story 3

- [x] T010 [P] [US3] Remove `...app(OperateHubShell::class)->headerActions(...)` spread from `getHeaderActions()` in `app/Filament/Resources/AlertRuleResource/Pages/ListAlertRules.php`. Keep only the `CreateAction::make()`. Remove unused `OperateHubShell` import if no other references remain.
- [x] T011 [P] [US3] Remove `...app(OperateHubShell::class)->headerActions(...)` spread from `getHeaderActions()` in `app/Filament/Resources/AlertDestinationResource/Pages/ListAlertDestinations.php`. Keep only the `CreateAction::make()`. Remove unused `OperateHubShell` import if no other references remain.

### Tests for User Story 3

- [x] T012 [US3] Add test: visit `/admin/alert-rules` list page with tenant-context active (via Filament tenant or lastTenantId fallback), assert `assertDontSee('Filtered by tenant')` and `assertDontSee('Scope: Tenant')` and `assertDontSee('Scope: Workspace')`.
- [x] T013 [US3] Add test: visit `/admin/alert-destinations` list page with tenant-context active, assert absence of any tenant indicator text.
- [x] T014 [US3] Run Manage page tests: `vendor/bin/sail artisan test --compact --filter="ListAlertRules|ListAlertDestinations|ManagePage"`

**Checkpoint**: US3 complete — Manage pages show no tenant indicator. FR-006 satisfied.

---

## Phase 6: User Story 4 — AlertRule Form Labels (Priority: P2)

**Goal**: AlertRule edit form uses targeting semantics: "Applies to tenants" with options "All tenants" / "Selected tenants", helper texts, and "Selected tenants" field label.

**Independent Test**: Visit AlertRule edit page, assert new labels/helper texts appear and old labels are absent.

### Implementation for User Story 4

- [x] T015 [US4] In `app/Filament/Resources/AlertRuleResource.php` form method: add explicit `->label('Applies to tenants')` to `Select::make('tenant_scope_mode')`, change option display from `'Allowlist'` to `'Selected tenants'`, add `->helperText('This rule is workspace-wide. Use this to limit where it applies.')`.
- [x] T016 [US4] In `app/Filament/Resources/AlertRuleResource.php` form method: change `Select::make('tenant_allowlist')->label('Tenant allowlist')` to `->label('Selected tenants')`, add `->helperText('Only these tenants will trigger this rule.')`.

### Tests for User Story 4

- [x] T017 [US4] Add test: visit AlertRule edit form, `assertSee('Applies to tenants')`, `assertSee('This rule is workspace-wide')`, `assertDontSee('Tenant scope mode')`, `assertDontSee('Tenant allowlist')`.
- [x] T018 [US4] Update any existing label-dependent assertions in `tests/Feature/Filament/Alerts/AlertRuleCrudTest.php` if they reference old "Tenant scope mode" or "Tenant allowlist" labels.
- [x] T019 [US4] Run AlertRule form tests: `vendor/bin/sail artisan test --compact --filter=AlertRuleCrud`

**Checkpoint**: US4 complete — AlertRule form uses targeting semantics. FR-007, FR-008, FR-009, FR-010 satisfied.

---

## Phase 7: User Story 5 — AlertRule Form Sections (Priority: P3)

**Goal**: AlertRule edit form fields are grouped into three sections: "Rule", "Applies to", "Delivery".

**Independent Test**: Load the edit form and assert the presence of three section headings.

### Implementation for User Story 5

- [x] T020 [US5] In `app/Filament/Resources/AlertRuleResource.php` form method: add `use Filament\Schemas\Components\Section;` import (if not already present). Wrap Name, Enabled, Event type, Minimum severity fields in `Section::make('Rule')`.
- [x] T021 [US5] Wrap tenant_scope_mode and tenant_allowlist fields in `Section::make('Applies to')`.
- [x] T022 [US5] Wrap Cooldown, Quiet hours, Destinations fields in `Section::make('Delivery')`.

### Tests for User Story 5

- [x] T023 [US5] Add test: visit AlertRule edit form, `assertSee('Rule')` (section heading), `assertSee('Applies to')` (section heading), `assertSee('Delivery')` (section heading).
- [x] T024 [US5] Run section tests: `vendor/bin/sail artisan test --compact --filter=AlertRuleCrud`

**Checkpoint**: US5 complete — AlertRule form is organized in sections. FR-011 satisfied.

---

## Phase 8: User Story 6 — "Add Current Tenant" Button (Priority: P3, Optional)

**Goal**: When editing an AlertRule with tenant-context active and "Selected tenants" mode visible, an action button "Add current tenant to selected tenants" appears.

**Independent Test**: Render form with tenant-context + allowlist visible, click button, assert tenant is added.

**⚠️ NOTE**: Only implement if T001–T024 are complete and PR scope permits. Skip entirely if budget exceeded.

### Implementation for User Story 6

- [ ] T025 [US6] In `app/Filament/Resources/AlertRuleResource.php` form method: add a form action button on the `tenant_allowlist` field (or as a suffix action) that resolves `OperateHubShell::activeEntitledTenant(request())` and appends its ID to the `tenant_allowlist` field state. Button visible only when tenant-context is active AND `tenant_scope_mode` is `allowlist`.

### Tests for User Story 6

- [ ] T026 [US6] Add test: render AlertRule edit form with tenant-context active + allowlist mode, click "Add current tenant to selected tenants", assert the tenant ID is added to the field state.
- [ ] T027 [US6] Add test: render AlertRule edit form with no tenant-context (or "All tenants" mode), assert the "Add current tenant" button is NOT visible.
- [ ] T028 [US6] Run convenience button tests: `vendor/bin/sail artisan test --compact --filter=AlertRuleCrud`

**Checkpoint**: US6 complete (if implemented). Optional enhancement delivered.

---

## Phase 9: Polish & Cross-Cutting Concerns

**Purpose**: Final validation, formatting, and full-suite regression check.

- [x] T029 Run Pint code formatter: `vendor/bin/sail bin pint --dirty`
- [x] T030 Run full test suite to confirm zero regressions: `vendor/bin/sail artisan test --compact`
- [x] T031 Verify no remaining instances of "Scope: Tenant" or "Scope: Workspace" in source code: `grep -r "Scope: Tenant\|Scope: Workspace" app/ tests/` should return zero matches (excluding comments/docs)

---

## Dependencies & Execution Order

### Phase Dependencies

- **Setup (Phase 1)**: No dependencies — start immediately
- **Foundational (Phase 2, T003)**: Depends on Phase 1 — BLOCKS all user stories
- **US1 (Phase 3)**: Depends on Phase 2 (T003) — test-only phase, updates existing assertions
- **US2 (Phase 4)**: Depends on Phase 2 (T003) — can run in parallel with US1
- **US3 (Phase 5)**: Depends on Phase 2 (T003) — can run in parallel with US1/US2
- **US4 (Phase 6)**: No dependency on other user stories — can run in parallel with US1/US2/US3
- **US5 (Phase 7)**: Depends on US4 (T015/T016) completion — same file, must sequence after US4
- **US6 (Phase 8)**: Depends on US4 + US5 — same file, must sequence after US5
- **Polish (Phase 9)**: Depends on all desired user stories being complete

### User Story Dependencies

- **US1 (P1)**: Independent after foundational phase. Can start immediately.
- **US2 (P1)**: Independent after foundational phase. Can run in parallel with US1.
- **US3 (P2)**: Independent. T010 and T011 are parallel (different files).
- **US4 (P2)**: Independent. T015 and T016 edit the same file sequentially.
- **US5 (P3)**: Depends on US4 (same file — `AlertRuleResource.php`).
- **US6 (P3, Optional)**: Depends on US5 (same file — `AlertRuleResource.php`).

### Within Each User Story

- Implementation before tests (tests validate the implementation)
- Exception: US1 is test-only (updates existing assertions for the T003 foundational change)
- Story-specific tests run immediately after implementation

### Parallel Opportunities

- **After Phase 2**: US1 (test updates) + US2 (KPI bugfix) + US3 (Manage page cleanup) can all run in parallel — different files, no dependencies.
- **Within US3**: T010 and T011 are parallel — different files (`ListAlertRules.php` vs `ListAlertDestinations.php`).
- **US4 must precede US5/US6** — all edit `AlertRuleResource.php`.

---

## Parallel Example: After Foundational Phase

```bash
# These three can launch simultaneously after T003 completes:

# Agent A: US1 — Update test assertions
Task T004: Update OperateHubShellTest.php assertions (tests/Feature/OpsUx/)
Task T005: Run OperateHubShell tests

# Agent B: US2 — Fix KPI bug
Task T006: Fix deliveriesQueryForViewer() (app/Filament/Widgets/Alerts/)
Task T007-T009: Add + run KPI tests

# Agent C: US3 — Clean Manage pages
Task T010: Remove header spread from ListAlertRules.php
Task T011: Remove header spread from ListAlertDestinations.php (parallel with T010)
Task T012-T014: Add + run Manage page tests
```

---

## Implementation Strategy

### MVP First (US1 + US2 Only)

1. Complete Phase 1: Setup (verify baseline)
2. Complete Phase 2: Foundational (T003 — `scopeLabel()` copy change)
3. Complete Phase 3: US1 (update test assertions)
4. Complete Phase 4: US2 (KPI bugfix + tests)
5. **STOP and VALIDATE**: All Monitoring pages show correct indicators + KPIs match
6. Deploy/demo if ready — highest-value changes shipped

### Incremental Delivery

1. T003 foundational → scopeLabel copy changed
2. US1 test updates → existing tests green with new copy (MVP ready)
3. US2 KPI bugfix → data consistency fixed (full P1 delivered)
4. US3 Manage pages → no false indicators on workspace-owned pages (P2a)
5. US4 form labels → targeting semantics in AlertRule form (P2b)
6. US5 form sections → improved form organization (P3a)
7. US6 convenience button → optional enhancement (P3b, skip if budget exceeded)
8. Phase 9 polish → Pint + full suite + grep verification

### Single Developer Strategy (Recommended)

Sequential execution in priority order:
1. Phase 1 → Phase 2 → Phase 3 (US1) → Phase 4 (US2) → run full suite
2. Phase 5 (US3) → Phase 6 (US4) → Phase 7 (US5) → run full suite
3. Phase 8 (US6, optional) → Phase 9 (polish)

---

## Notes

- No schema changes — zero migrations needed
- No new files created (except potentially one new test file for US2 KPI tests)
- The `scopeLabel()` method name is NOT renamed — only the return values change (per spec)
- DB column values for `tenant_scope_mode` (`all`, `allowlist`) are UNCHANGED — only display labels
- `Filament\Schemas\Components\Section` is the correct v5 import (confirmed in 11 existing files)
- US6 is explicitly optional — skip without guilt if PR is already large
