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

22 KiB

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.

  • T001 [P] Extend mixed-family and superseded-review fixture helpers in apps/platform/tests/Feature/Concerns/BuildsPortfolioTriageFixtures.php
  • 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.

  • T003 [P] Add deterministic fingerprint and concern-family separation coverage in apps/platform/tests/Unit/Support/PortfolioTriage/TenantTriageReviewFingerprintTest.php
  • T004 [P] Add active-row precedence and current-set summary coverage in apps/platform/tests/Unit/Support/PortfolioTriage/TenantTriageReviewStateResolverTest.php
  • T005 [P] Add centralized review-state badge mapping coverage in apps/platform/tests/Unit/Badges/TenantTriageReviewStateBadgesTest.php
  • T006 Create the tenant_triage_reviews schema in apps/platform/database/migrations/*_create_tenant_triage_reviews_table.php
  • T007 [P] Create the persisted review-state model and factory in apps/platform/app/Models/TenantTriageReview.php and apps/platform/database/factories/TenantTriageReviewFactory.php
  • T008 [P] Implement deterministic concern fingerprint generation in apps/platform/app/Support/PortfolioTriage/TenantTriageReviewFingerprint.php
  • T009 Implement batch review-state resolution and current-set progress aggregation in apps/platform/app/Support/PortfolioTriage/TenantTriageReviewStateResolver.php
  • 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

  • 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
  • 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

  • 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
  • T014 [US1] Implement markReviewed() and markFollowUpNeeded() with superseded-row resolution and AuditRecorder writes in apps/platform/app/Services/PortfolioTriage/TenantTriageReviewService.php
  • 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
  • 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
  • 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

  • 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
  • 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

  • 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
  • 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
  • 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
  • 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

  • T024 [P] [US3] Extend stale-review precedence and fingerprint-mismatch coverage in apps/platform/tests/Unit/Support/PortfolioTriage/TenantTriageReviewStateResolverTest.php
  • 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

  • T026 [US3] Add changed_since_review precedence and mismatch handling in apps/platform/app/Support/PortfolioTriage/TenantTriageReviewStateResolver.php
  • T027 [US3] Refine stable fingerprint inputs for backup and recovery concern changes in apps/platform/app/Support/PortfolioTriage/TenantTriageReviewFingerprint.php
  • 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
  • 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

  • T030 [P] [US4] Add current-set-only progress and calm-tenant exclusion coverage in apps/platform/tests/Feature/Filament/WorkspaceOverviewTriageReviewProgressTest.php
  • 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

  • T032 [US4] Extend current-set progress derivation with TenantTriageReviewStateResolver in apps/platform/app/Support/Workspaces/WorkspaceOverviewBuilder.php
  • 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
  • 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
  • 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.

  • 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
  • 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
  • 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
  • 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
  • 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

# 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

# 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

# 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

# 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.