TenantAtlas/specs/189-portfolio-triage-review-state/tasks.md
ahmido 2f45ff5a84 feat: add portfolio triage review state tracking (#220)
## Summary
- add tenant triage review-state persistence, fingerprinting, resolver logic, service layer, and migration for current affected-set tracking
- surface review-state and affected-set progress across tenant registry, tenant dashboard arrival continuity, and workspace overview
- extend RBAC, audit/badge support, specs, and test coverage for portfolio triage review-state workflows
- suppress expected hidden-page background transport failures in the global unhandled rejection logger while keeping visible-page failures logged

## Validation
- targeted Pest coverage added for tenant registry, workspace overview, arrival context, RBAC authorization, badges, fingerprinting, resolver behavior, and logger asset behavior
- code formatted with `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`

## Notes
- full suite was not re-run in this final step
- branch includes the spec artifacts under `specs/189-portfolio-triage-review-state/`

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #220
2026-04-10 21:35:17 +00:00

268 lines
22 KiB
Markdown

# Tasks: Portfolio Triage Review State and Operator Progress
**Input**: Design documents from `/specs/189-portfolio-triage-review-state/`
**Prerequisites**: `plan.md`, `spec.md`, `research.md`, `data-model.md`, `contracts/portfolio-triage-review-state.logical.openapi.yaml`, `quickstart.md`
**Tests**: Tests are REQUIRED for this feature. Use Pest unit coverage for fingerprinting, state resolution, and badge semantics; Filament feature coverage for tenant-dashboard continuity, tenant-registry review-state rendering, and workspace-overview progress; and RBAC coverage for `404` versus `403` mutation semantics.
**Operations**: This feature introduces no `OperationRun`, queue, scheduler, or remote call. Review-state writes stay TenantPilot-only and DB-only, but they must record bounded `AuditLog` entries through the existing audit infrastructure and execute only after a bounded pre-execution preview plus explicit confirmation.
**RBAC**: Existing workspace membership and tenant visibility remain authoritative. Tasks must preserve deny-as-not-found `404` behavior for non-members, `403` behavior for in-scope members lacking the mutation capability, canonical capability-registry usage, and visible-but-disabled UI where the surface contract requires it.
**Operator Surfaces**: The affected operator surfaces are workspace overview progress summaries, the tenant registry triage list, and the tenant dashboard arrival continuity block.
**Filament UI Action Surfaces**: Full-row click remains the registry inspect model, the existing tenant-open shortcut remains the only inline safe shortcut, registry review-state mutations live in overflow, and tenant-dashboard review-state mutations live only inside the continuity block.
**Filament UI UX-001**: No create, edit, or view-form layouts change. This slice is limited to additive status rendering, filters, overflow actions, and dashboard continuity controls.
**Badges**: Review-state semantics must use `BadgeDomain` plus a centralized domain mapper. No page-local status-pill styling or ad hoc label mapping is allowed.
**Organization**: Tasks are grouped by user story so each story can be implemented and verified independently once the shared triage-review foundation is in place.
## Phase 1: Setup (Shared Triage-Review Harness)
**Purpose**: Prepare reusable fixtures and acceptance scaffolds for mixed-family triage-review scenarios shared across all stories.
- [X] T001 [P] Extend mixed-family and superseded-review fixture helpers in `apps/platform/tests/Feature/Concerns/BuildsPortfolioTriageFixtures.php`
- [X] T002 [P] Stage focused review-state acceptance scaffolds in `apps/platform/tests/Feature/Filament/TenantDashboardArrivalContextTest.php`, `apps/platform/tests/Feature/Filament/TenantRegistryTriageReviewStateTest.php`, and `apps/platform/tests/Feature/Filament/WorkspaceOverviewTriageReviewProgressTest.php`
**Checkpoint**: Shared fixture and acceptance seams exist for dashboard, registry, and overview review-state work.
---
## Phase 2: Foundational (Blocking Triage-Review Core)
**Purpose**: Establish the persisted review-state model, deterministic fingerprinting, batch state resolution, and centralized badge mapping that every story depends on.
**⚠️ CRITICAL**: No user story work should begin until this phase is complete.
- [X] T003 [P] Add deterministic fingerprint and concern-family separation coverage in `apps/platform/tests/Unit/Support/PortfolioTriage/TenantTriageReviewFingerprintTest.php`
- [X] T004 [P] Add active-row precedence and current-set summary coverage in `apps/platform/tests/Unit/Support/PortfolioTriage/TenantTriageReviewStateResolverTest.php`
- [X] T005 [P] Add centralized review-state badge mapping coverage in `apps/platform/tests/Unit/Badges/TenantTriageReviewStateBadgesTest.php`
- [X] T006 Create the `tenant_triage_reviews` schema in `apps/platform/database/migrations/*_create_tenant_triage_reviews_table.php`
- [X] T007 [P] Create the persisted review-state model and factory in `apps/platform/app/Models/TenantTriageReview.php` and `apps/platform/database/factories/TenantTriageReviewFactory.php`
- [X] T008 [P] Implement deterministic concern fingerprint generation in `apps/platform/app/Support/PortfolioTriage/TenantTriageReviewFingerprint.php`
- [X] T009 Implement batch review-state resolution and current-set progress aggregation in `apps/platform/app/Support/PortfolioTriage/TenantTriageReviewStateResolver.php`
- [X] T010 Register centralized review-state badge semantics in `apps/platform/app/Support/Badges/BadgeDomain.php` and `apps/platform/app/Support/Badges/Domains/TenantTriageReviewStateBadge.php`
**Checkpoint**: One authoritative persisted review-state core exists and can be reused by dashboard, registry, and overview surfaces without N+1 fanout.
---
## Phase 3: User Story 1 - Record That A Concern Was Checked (Priority: P1) 🎯 MVP
**Goal**: Let authorized operators mark the current dashboard concern as reviewed or follow-up needed so progress survives navigation and time.
**Independent Test**: Open a tenant from portfolio triage, trigger the continuity-block preview for `Mark reviewed` or `Mark follow-up needed`, confirm the `TenantPilot only` scope, and verify the active triage-review record, bounded audit entry, and dashboard state update all reflect the new manual state.
### Tests for User Story 1
- [X] T011 [P] [US1] Extend tenant-dashboard continuity coverage for preview-and-confirmation semantics, valid triage-context gating, generic-session suppression, `Mark reviewed`, `Mark follow-up needed`, and bounded reviewer or timestamp context in `apps/platform/tests/Feature/Filament/TenantDashboardArrivalContextTest.php`
- [X] T012 [P] [US1] Add mutation authorization and audit coverage for non-member `404`, member-without-capability `403`, preview-confirmed successful writes, and no action execution without confirmation in `apps/platform/tests/Feature/Rbac/TriageReviewStateAuthorizationTest.php`
### Implementation for User Story 1
- [X] T013 [US1] Add the canonical triage-review mutation capability and audit action IDs in `apps/platform/app/Support/Auth/Capabilities.php` and `apps/platform/app/Support/Audit/AuditActionId.php`
- [X] T014 [US1] Implement `markReviewed()` and `markFollowUpNeeded()` with superseded-row resolution and `AuditRecorder` writes in `apps/platform/app/Services/PortfolioTriage/TenantTriageReviewService.php`
- [X] T015 [US1] Bind resolved review state, bounded preview-and-confirmation actions, `TenantPilot only` scope copy, and generic-session suppression into the dashboard continuity surface in `apps/platform/app/Filament/Widgets/Tenant/TenantTriageArrivalContinuity.php`, `apps/platform/resources/views/filament/widgets/tenant/triage-arrival-continuity.blade.php`, and `apps/platform/app/Filament/Pages/TenantDashboard.php`
- [X] T016 [US1] Enforce visible-but-disabled UI plus server-side mutation gating through `apps/platform/app/Support/Rbac/UiEnforcement.php` and `apps/platform/app/Filament/Widgets/Tenant/TenantTriageArrivalContinuity.php`
- [X] T017 [US1] Run focused US1 verification from `specs/189-portfolio-triage-review-state/quickstart.md` against `apps/platform/tests/Feature/Filament/TenantDashboardArrivalContextTest.php` and `apps/platform/tests/Feature/Rbac/TriageReviewStateAuthorizationTest.php`
**Checkpoint**: Operators can record review intent from the tenant dashboard, and writes are RBAC-safe, auditable, and workspace-shared.
---
## Phase 4: User Story 2 - Work The Remaining Set From The Registry (Priority: P1)
**Goal**: Make the tenant registry show and filter review state so operators can keep working the remaining affected set without losing posture truth.
**Independent Test**: Seed mixed review states, open `/admin/tenants`, and verify the review-state column, highest-priority concern-family labeling, preview-confirmed overflow actions, and all four `review_state` filters (`not_reviewed`, `reviewed`, `follow_up_needed`, `changed_since_review`) all behave correctly while backup posture and recovery evidence remain separately visible.
### Tests for User Story 2
- [X] T018 [P] [US2] Add registry column, highest-priority concern-family labeling, and all four `review_state` filters (`not_reviewed`, `reviewed`, `follow_up_needed`, `changed_since_review`) coverage in `apps/platform/tests/Feature/Filament/TenantRegistryTriageReviewStateTest.php`
- [X] T019 [P] [US2] Extend posture-truth coexistence, overflow action-surface placement, and preview-and-confirmation action coverage in `apps/platform/tests/Feature/Filament/TenantRegistryRecoveryTriageTest.php` and `apps/platform/tests/Feature/Guards/ActionSurfaceContractTest.php`
### Implementation for User Story 2
- [X] T020 [US2] Add review-state row rendering, mixed-family labeling, reuse of `TenantResource::portfolioConcernPriority()` for highest-priority concern selection, and overflow mutation actions with preview-and-confirmation in `apps/platform/app/Filament/Resources/TenantResource.php`
- [X] T021 [US2] Add all four `review_state` filters, current-slice concern-family handling, and empty-state context in `apps/platform/app/Filament/Resources/TenantResource/Pages/ListTenants.php`
- [X] T022 [US2] Reuse `TenantTriageReviewStateResolver` inside `apps/platform/app/Filament/Resources/TenantResource.php` to keep registry rendering query-bounded and posture truth separate from review state
- [X] T023 [US2] Run focused US2 verification from `specs/189-portfolio-triage-review-state/quickstart.md` against `apps/platform/tests/Feature/Filament/TenantRegistryTriageReviewStateTest.php` and `apps/platform/tests/Feature/Filament/TenantRegistryRecoveryTriageTest.php`
**Checkpoint**: The registry becomes a working triage surface for remaining review work without implying that `Reviewed` means `Fixed`.
---
## Phase 5: User Story 3 - Re-review Tenants When The Concern Changes (Priority: P1)
**Goal**: Turn stale manual review records into `Changed since review` when the current concern changes so old progress does not hide renewed risk.
**Independent Test**: Record a review, change the stable concern fingerprint while the tenant remains affected, and verify the dashboard and registry both show `Changed since review` until a new review is recorded.
### Tests for User Story 3
- [X] T024 [P] [US3] Extend stale-review precedence and fingerprint-mismatch coverage in `apps/platform/tests/Unit/Support/PortfolioTriage/TenantTriageReviewStateResolverTest.php`
- [X] T025 [P] [US3] Extend dashboard and registry stale-review rendering coverage in `apps/platform/tests/Feature/Filament/TenantDashboardArrivalContextTest.php` and `apps/platform/tests/Feature/Filament/TenantRegistryTriageReviewStateTest.php`
### Implementation for User Story 3
- [X] T026 [US3] Add `changed_since_review` precedence and mismatch handling in `apps/platform/app/Support/PortfolioTriage/TenantTriageReviewStateResolver.php`
- [X] T027 [US3] Refine stable fingerprint inputs for backup and recovery concern changes in `apps/platform/app/Support/PortfolioTriage/TenantTriageReviewFingerprint.php`
- [X] T028 [US3] Surface `Changed since review` labels and re-review affordances in `apps/platform/app/Filament/Resources/TenantResource.php`, `apps/platform/app/Filament/Widgets/Tenant/TenantTriageArrivalContinuity.php`, and `apps/platform/resources/views/filament/widgets/tenant/triage-arrival-continuity.blade.php`
- [X] T029 [US3] Run focused US3 verification from `specs/189-portfolio-triage-review-state/quickstart.md` against `apps/platform/tests/Unit/Support/PortfolioTriage/TenantTriageReviewFingerprintTest.php`, `apps/platform/tests/Unit/Support/PortfolioTriage/TenantTriageReviewStateResolverTest.php`, `apps/platform/tests/Feature/Filament/TenantDashboardArrivalContextTest.php`, and `apps/platform/tests/Feature/Filament/TenantRegistryTriageReviewStateTest.php`
**Checkpoint**: Previously reviewed tenants become visibly stale when the material concern changes, and re-review becomes the obvious next step.
---
## Phase 6: User Story 4 - See Honest Progress For The Current Affected Set (Priority: P2)
**Goal**: Show workspace-level progress only for the currently affected visible set so review counts stay honest and clearly separate from posture truth.
**Independent Test**: Seed currently affected, resolved, and stale-review tenants, open `/admin`, and verify the overview summaries count only the current visible affected set while still showing weak posture independently from review state.
### Tests for User Story 4
- [X] T030 [P] [US4] Add current-set-only progress and calm-tenant exclusion coverage in `apps/platform/tests/Feature/Filament/WorkspaceOverviewTriageReviewProgressTest.php`
- [X] T031 [P] [US4] Extend overview drilldown honesty and visible-tenant scoping coverage in `apps/platform/tests/Feature/Filament/WorkspaceOverviewSummaryMetricsTest.php`
### Implementation for User Story 4
- [X] T032 [US4] Extend current-set progress derivation with `TenantTriageReviewStateResolver` in `apps/platform/app/Support/Workspaces/WorkspaceOverviewBuilder.php`
- [X] T033 [US4] Render additive reviewed, follow-up-needed, and changed-since-review summaries in `apps/platform/app/Filament/Widgets/Workspace/WorkspaceSummaryStats.php` and `apps/platform/app/Filament/Widgets/Workspace/WorkspaceNeedsAttention.php`
- [X] T034 [US4] Keep overview review-state summaries operator-first and posture-truth-safe in `apps/platform/app/Support/Workspaces/WorkspaceOverviewBuilder.php` and `apps/platform/app/Filament/Pages/WorkspaceOverview.php`
- [X] T035 [US4] Run focused US4 verification from `specs/189-portfolio-triage-review-state/quickstart.md` against `apps/platform/tests/Feature/Filament/WorkspaceOverviewTriageReviewProgressTest.php` and `apps/platform/tests/Feature/Filament/WorkspaceOverviewSummaryMetricsTest.php`
**Checkpoint**: Workspace overview progress stays bounded to the current affected set and never overclaims that reviewed posture is fixed posture.
---
## Phase 7: Polish & Cross-Cutting Concerns
**Purpose**: Finalize guard coverage, performance protection, copy review, formatting, and the focused verification pack across all stories.
- [X] T036 [P] Add no-ad-hoc-badge and no diagnostic-warning guard coverage for the new review-state surfaces in `apps/platform/tests/Feature/Guards/NoAdHocStatusBadgesTest.php` and `apps/platform/tests/Feature/Guards/NoDiagnosticWarningBadgesTest.php`
- [X] T037 [P] Add query-shape regression coverage for registry and overview batch loading in `apps/platform/tests/Feature/Filament/TenantRegistryTriageReviewStateTest.php` and `apps/platform/tests/Feature/Filament/WorkspaceOverviewTriageReviewProgressTest.php`
- [X] T038 [P] Review `Verb + Object` copy and TenantPilot-only mutation-scope helper text in `apps/platform/app/Filament/Resources/TenantResource.php`, `apps/platform/app/Filament/Widgets/Tenant/TenantTriageArrivalContinuity.php`, and `apps/platform/resources/views/filament/widgets/tenant/triage-arrival-continuity.blade.php`
- [X] T039 [P] Run formatting with `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent` using `specs/189-portfolio-triage-review-state/quickstart.md`
- [X] T040 Run the focused verification pack from `specs/189-portfolio-triage-review-state/quickstart.md` against `apps/platform/tests/Unit/Support/PortfolioTriage/TenantTriageReviewFingerprintTest.php`, `apps/platform/tests/Unit/Support/PortfolioTriage/TenantTriageReviewStateResolverTest.php`, `apps/platform/tests/Unit/Badges/TenantTriageReviewStateBadgesTest.php`, `apps/platform/tests/Feature/Filament/TenantDashboardArrivalContextTest.php`, `apps/platform/tests/Feature/Filament/TenantRegistryTriageReviewStateTest.php`, `apps/platform/tests/Feature/Filament/TenantRegistryRecoveryTriageTest.php`, `apps/platform/tests/Feature/Filament/WorkspaceOverviewTriageReviewProgressTest.php`, `apps/platform/tests/Feature/Filament/WorkspaceOverviewSummaryMetricsTest.php`, `apps/platform/tests/Feature/Rbac/TriageReviewStateAuthorizationTest.php`, `apps/platform/tests/Feature/Guards/ActionSurfaceContractTest.php`, `apps/platform/tests/Feature/Guards/NoAdHocStatusBadgesTest.php`, and `apps/platform/tests/Feature/Guards/NoDiagnosticWarningBadgesTest.php`
---
## Dependencies & Execution Order
### Phase Dependencies
- **Setup (Phase 1)**: Starts immediately and prepares shared review-state fixtures plus acceptance scaffolds.
- **Foundational (Phase 2)**: Depends on Setup and blocks all user-story work until the persisted model, fingerprinting, resolver, and badge mapping exist.
- **User Story 1 (Phase 3)**: Starts after Foundational and is the recommended MVP slice because it introduces the first operator write path.
- **User Story 2 (Phase 4)**: Starts after User Story 1 because registry overflow actions reuse the mutation service and capability gating established on the dashboard path.
- **User Story 3 (Phase 5)**: Starts after User Story 1 and User Story 2 because stale-review semantics must reuse the write path and then render truthfully on both dashboard and registry surfaces.
- **User Story 4 (Phase 6)**: Starts after User Story 2 and User Story 3 because workspace progress needs the final registry-facing state family and stale-review semantics in place.
- **Polish (Phase 7)**: Starts after all desired user stories are complete.
### User Story Dependencies
- **US1**: Depends only on the shared triage-review foundation.
- **US2**: Depends on US1 for the canonical mutation service, capability, and audit seam used by registry overflow actions.
- **US3**: Depends on US1 for persisted review records and on US2 for final registry rendering.
- **US4**: Depends on US2 and US3 because honest current-set progress must aggregate the full review-state family across visible tenants.
### Within Each User Story
- Write or extend the story tests first and confirm they fail before implementation is considered complete.
- Land service or resolver changes before UI copy and action wiring in the same story.
- Keep each story shippable on its own before moving to the next priority.
### Parallel Opportunities
- `T001` and `T002` can run in parallel during Setup.
- `T003`, `T004`, and `T005` can run in parallel before the persisted core lands.
- `T007` and `T008` can run in parallel after `T006` defines the storage contract.
- Within US1, `T011` and `T012` can run in parallel, then `T015` and `T016` can be split after `T013` and `T014` establish the write seam.
- Within US2, `T018` and `T019` can run in parallel, then `T020` and `T021` can be split across contributors.
- Within US3, `T024` and `T025` can run in parallel, then `T026` and `T027` can be split before `T028` updates the shared UI surfaces.
- Within US4, `T030` and `T031` can run in parallel, then `T032`, `T033`, and `T034` can be sequenced across builder and widget work.
- Within Phase 7, `T036`, `T037`, and `T038` can run in parallel before formatting and final verification.
---
## Parallel Example: User Story 1
```bash
# User Story 1 tests in parallel
T011 apps/platform/tests/Feature/Filament/TenantDashboardArrivalContextTest.php
T012 apps/platform/tests/Feature/Rbac/TriageReviewStateAuthorizationTest.php
# User Story 1 implementation split after the write seam exists
T015 apps/platform/app/Filament/Widgets/Tenant/TenantTriageArrivalContinuity.php
T016 apps/platform/app/Support/Rbac/UiEnforcement.php
```
## Parallel Example: User Story 2
```bash
# User Story 2 tests in parallel
T018 apps/platform/tests/Feature/Filament/TenantRegistryTriageReviewStateTest.php
T019 apps/platform/tests/Feature/Filament/TenantRegistryRecoveryTriageTest.php
# User Story 2 implementation split
T020 apps/platform/app/Filament/Resources/TenantResource.php
T021 apps/platform/app/Filament/Resources/TenantResource/Pages/ListTenants.php
```
## Parallel Example: User Story 3
```bash
# User Story 3 tests in parallel
T024 apps/platform/tests/Unit/Support/PortfolioTriage/TenantTriageReviewStateResolverTest.php
T025 apps/platform/tests/Feature/Filament/TenantDashboardArrivalContextTest.php
# User Story 3 implementation split
T026 apps/platform/app/Support/PortfolioTriage/TenantTriageReviewStateResolver.php
T027 apps/platform/app/Support/PortfolioTriage/TenantTriageReviewFingerprint.php
```
## Parallel Example: User Story 4
```bash
# User Story 4 tests in parallel
T030 apps/platform/tests/Feature/Filament/WorkspaceOverviewTriageReviewProgressTest.php
T031 apps/platform/tests/Feature/Filament/WorkspaceOverviewSummaryMetricsTest.php
# User Story 4 implementation split
T032 apps/platform/app/Support/Workspaces/WorkspaceOverviewBuilder.php
T033 apps/platform/app/Filament/Widgets/Workspace/WorkspaceSummaryStats.php
```
---
## Implementation Strategy
### MVP First
1. Complete Phase 1: Setup.
2. Complete Phase 2: Foundational.
3. Complete Phase 3: User Story 1.
4. **STOP and VALIDATE**: Confirm dashboard-originated review-state writes persist correctly, stay RBAC-safe, and do not imply posture is fixed.
### Incremental Delivery
1. Deliver Setup plus Foundational to lock the persisted truth, fingerprinting, resolver, and badge semantics.
2. Deliver User Story 1 so operators can record review intent from the tenant dashboard.
3. Deliver User Story 2 so the tenant registry becomes a working queue for remaining review work.
4. Deliver User Story 3 so stale reviews become visible and re-review becomes explicit.
5. Deliver User Story 4 so workspace overview progress stays honest for the current visible affected set.
6. Finish with guard coverage, formatting, and the focused verification pack.
### Parallel Team Strategy
1. One contributor can take persisted-core tests and storage while another prepares the acceptance scaffolds.
2. After Foundational work lands, one contributor can own dashboard mutation wiring while another prepares the registry rendering tests.
3. Once User Story 2 is in place, one contributor can refine stale-review derivation while another prepares overview progress coverage.
4. Rejoin for Polish so guard suites, copy review, formatting, and the verification pack land together.
---
## Notes
- `[P]` tasks target different files or safe concurrent work after prerequisite seams are in place.
- `[US1]`, `[US2]`, `[US3]`, and `[US4]` labels map directly to the user stories in `spec.md`.
- The suggested MVP scope is Phase 1 through Phase 3 only.
- This task plan stays compliant with Filament v5 on Livewire v4, makes no panel-provider changes in `bootstrap/providers.php`, introduces no new globally searchable resource, adds no destructive action, and requires no asset-strategy change beyond the existing deployment process.