218 lines
19 KiB
Markdown
218 lines
19 KiB
Markdown
# Tasks: Tenant Governance Aggregate Contract
|
|
|
|
**Input**: Design documents from `/specs/168-tenant-governance-aggregate-contract/`
|
|
**Prerequisites**: `plan.md` (required), `spec.md` (required for user stories), `research.md`, `data-model.md`, `contracts/`, `quickstart.md`
|
|
|
|
**Tests**: Tests are REQUIRED for this feature. Use Pest coverage in `tests/Feature/Baselines/BaselineCompareStatsTest.php`, `tests/Feature/Baselines/BaselineCompareSummaryAssessmentTest.php`, `tests/Feature/Baselines/TenantGovernanceAggregateResolverTest.php`, `tests/Feature/Filament/BaselineCompareSummaryConsistencyTest.php`, `tests/Feature/Filament/BaselineCompareNowWidgetTest.php`, `tests/Feature/Filament/BaselineCompareCoverageBannerTest.php`, `tests/Feature/Filament/BaselineCompareLandingAdminTenantParityTest.php`, `tests/Feature/Filament/BaselineCompareLandingDuplicateNamesBannerTest.php`, `tests/Feature/Filament/BaselineCompareLandingRbacLabelsTest.php`, `tests/Feature/Filament/BaselineCompareLandingStartSurfaceTest.php`, `tests/Feature/Filament/BaselineCompareLandingWhyNoFindingsTest.php`, `tests/Feature/Filament/NeedsAttentionWidgetTest.php`, `tests/Feature/Filament/TenantGovernanceAggregateMemoizationTest.php`, and `tests/Feature/Guards/DerivedStateConsumerAdoptionGuardTest.php`.
|
|
**Operations**: This feature does not create a new `OperationRun` type or change run lifecycle ownership. Existing baseline-compare runs remain the only execution surface involved, and all work here is read-time summary consolidation.
|
|
**RBAC**: Existing tenant-context membership, entitlement, and 404 vs 403 semantics remain unchanged. Tasks must preserve current tenant-safe drill-down behavior and ensure request-local reuse never leaks summary state across tenants, workspaces, or no-tenant states.
|
|
**Operator Surfaces**: The tenant dashboard `Baseline Governance` card, tenant dashboard `Needs Attention` widget, tenant governance banner, and Baseline Compare landing must keep operator-first posture, urgency, and next-step guidance above diagnostics.
|
|
**Filament UI Action Surfaces**: No new action inventories are added. The existing Baseline Compare landing `Compare now` action remains confirmation-gated and capability-gated, and all other affected surfaces remain navigation-only summaries.
|
|
**Filament UI UX-001**: No new create, edit, or view layouts are introduced. Existing widget, banner, and landing layouts remain intact while shared summary ownership is refactored.
|
|
**Badges**: Existing compare-posture, severity, and governance-validity semantics must remain sourced from shared badge semantics; no new page-local mappings are introduced.
|
|
|
|
**Organization**: Tasks are grouped by user story so each story can be implemented and verified as an independent increment after the shared aggregate contract is in place.
|
|
|
|
## Phase 1: Setup (Shared Aggregate Scaffolding)
|
|
|
|
**Purpose**: Create the narrow runtime and test scaffolding required for the tenant-governance aggregate.
|
|
|
|
- [X] T001 [P] Create the aggregate runtime scaffolding in `app/Support/Baselines/TenantGovernanceAggregate.php` and `app/Support/Baselines/TenantGovernanceAggregateResolver.php`
|
|
- [X] T002 [P] Create the focused regression scaffolding in `tests/Feature/Baselines/TenantGovernanceAggregateResolverTest.php` and `tests/Feature/Filament/TenantGovernanceAggregateMemoizationTest.php`
|
|
|
|
---
|
|
|
|
## Phase 2: Foundational (Blocking Aggregate Contract)
|
|
|
|
**Purpose**: Build the shared aggregate runtime and request-scoped family contract that all user stories depend on.
|
|
|
|
**⚠️ CRITICAL**: No user story work should begin until this phase is complete.
|
|
|
|
- [X] T003 [P] Extend source-truth regression coverage for aggregate input counts and summary assessment mapping in `tests/Feature/Baselines/BaselineCompareStatsTest.php` and `tests/Feature/Baselines/BaselineCompareSummaryAssessmentTest.php`
|
|
- [X] T004 Implement the derived tenant summary contract fields in `app/Support/Baselines/TenantGovernanceAggregate.php`
|
|
- [X] T005 Implement aggregate resolution and request-scoped reuse from `BaselineCompareStats` and `BaselineCompareSummaryAssessment` in `app/Support/Baselines/TenantGovernanceAggregateResolver.php` and `app/Support/Baselines/BaselineCompareStats.php`
|
|
- [X] T006 [P] Declare the governance aggregate derived-state family, extend the first-slice supported consumer contract, and update the guard in `app/Support/Ui/DerivedState/DerivedStateFamily.php`, `specs/167-derived-state-memoization/contracts/request-scoped-derived-state.logical.openapi.yaml`, and `tests/Feature/Guards/DerivedStateConsumerAdoptionGuardTest.php`
|
|
|
|
**Checkpoint**: The tenant-governance aggregate exists as one derived request-local contract that later surface work can consume.
|
|
|
|
---
|
|
|
|
## Phase 3: User Story 1 - One Tenant, One Governance Posture (Priority: P1)
|
|
|
|
**Goal**: Make the dashboard governance card, tenant banner, and Baseline Compare landing agree on posture family and governance-attention counts for the same tenant.
|
|
|
|
**Independent Test**: Seed one tenant with unavailable prerequisites, compare in progress, compare failed, open findings requiring action, overdue without new drift, lapsed governance without new drift, caution, stale results, and trustworthy all-clear states, then verify the dashboard governance card, banner, and landing summary resolve the same posture family and count family while keeping landing diagnostics secondary.
|
|
|
|
### Tests for User Story 1
|
|
|
|
- [X] T007 [P] [US1] Add aggregate scenario coverage for unavailable, in-progress, failed, open-findings action-required, overdue-without-new-drift, lapsed-without-new-drift, caution, stale, and trustworthy-all-clear states in `tests/Feature/Baselines/TenantGovernanceAggregateResolverTest.php`
|
|
- [X] T008 [P] [US1] Extend cross-surface posture and count parity assertions for the full FR-168-014 state matrix, landing diagnostics-secondary hierarchy, and unchanged compare-start authorization and confirmation semantics in `tests/Feature/Filament/BaselineCompareSummaryConsistencyTest.php`, `tests/Feature/Filament/BaselineCompareNowWidgetTest.php`, `tests/Feature/Filament/BaselineCompareCoverageBannerTest.php`, `tests/Feature/Filament/BaselineCompareLandingStartSurfaceTest.php`, `tests/Feature/Filament/BaselineCompareLandingRbacLabelsTest.php`, `tests/Feature/Filament/BaselineCompareLandingWhyNoFindingsTest.php`, and `tests/Feature/Filament/BaselineCompareLandingDuplicateNamesBannerTest.php`
|
|
|
|
### Implementation for User Story 1
|
|
|
|
- [X] T009 [US1] Route the tenant dashboard `Baseline Governance` summary card through the shared aggregate in `app/Filament/Widgets/Dashboard/BaselineCompareNow.php`
|
|
- [X] T010 [US1] Drive the tenant governance banner from the shared aggregate in `app/Filament/Widgets/Tenant/BaselineCompareCoverageBanner.php`
|
|
- [X] T011 [US1] Replace the Baseline Compare landing default-visible posture summary with the shared aggregate while keeping diagnostics on `BaselineCompareStats`, preserving existing `Compare now` confirmation and capability semantics, and keeping diagnostics secondary in `app/Filament/Pages/BaselineCompareLanding.php`
|
|
- [X] T012 [US1] Keep aggregate posture, tone, and supporting-message semantics aligned to existing compare-summary rules in `app/Support/Baselines/BaselineCompareSummaryAssessor.php` and `app/Support/Baselines/BaselineCompareSummaryAssessment.php`
|
|
- [X] T013 [US1] Run the focused posture parity pack in `tests/Feature/Baselines/TenantGovernanceAggregateResolverTest.php`, `tests/Feature/Filament/BaselineCompareSummaryConsistencyTest.php`, `tests/Feature/Filament/BaselineCompareNowWidgetTest.php`, `tests/Feature/Filament/BaselineCompareCoverageBannerTest.php`, `tests/Feature/Filament/BaselineCompareLandingStartSurfaceTest.php`, `tests/Feature/Filament/BaselineCompareLandingRbacLabelsTest.php`, `tests/Feature/Filament/BaselineCompareLandingWhyNoFindingsTest.php`, and `tests/Feature/Filament/BaselineCompareLandingDuplicateNamesBannerTest.php`
|
|
|
|
**Checkpoint**: Three tenant-facing summary surfaces now share one governance posture and count contract for the same tenant state.
|
|
|
|
---
|
|
|
|
## Phase 4: User Story 2 - Consistent Next Action Across Summary Surfaces (Priority: P1)
|
|
|
|
**Goal**: Make every covered summary surface point operators toward the same class of next step for the same tenant state.
|
|
|
|
**Independent Test**: Seed running-compare, failed-compare, unavailable-prerequisite, open-findings requiring action, overdue-without-new-drift, lapsed-governance without new drift, caution, and stale scenarios, then verify the dashboard governance card, banner, and landing summary expose the same next-action intent and matching operator-facing labels.
|
|
|
|
### Tests for User Story 2
|
|
|
|
- [X] T014 [P] [US2] Add next-action intent regressions for running, failed, unavailable, open-findings action-required, overdue-without-new-drift, lapsed-without-new-drift, caution, and stale scenarios in `tests/Feature/Filament/BaselineCompareSummaryConsistencyTest.php`, `tests/Feature/Filament/BaselineCompareLandingStartSurfaceTest.php`, and `tests/Feature/Filament/BaselineCompareLandingAdminTenantParityTest.php`
|
|
- [X] T015 [P] [US2] Add dashboard governance card and banner next-step assertions, including preserved findings drill-down and open-landing navigation availability, in `tests/Feature/Filament/BaselineCompareNowWidgetTest.php` and `tests/Feature/Filament/BaselineCompareCoverageBannerTest.php`
|
|
|
|
### Implementation for User Story 2
|
|
|
|
- [X] T016 [US2] Add next-action label and target ownership to the aggregate contract in `app/Support/Baselines/TenantGovernanceAggregate.php` and `app/Support/Baselines/TenantGovernanceAggregateResolver.php`
|
|
- [X] T017 [US2] Map shared next-action intent to findings, run, and landing destinations in `app/Filament/Widgets/Dashboard/BaselineCompareNow.php`
|
|
- [X] T018 [US2] Align banner and landing next-action presentation to the shared intent in `app/Filament/Widgets/Tenant/BaselineCompareCoverageBanner.php` and `app/Filament/Pages/BaselineCompareLanding.php`
|
|
- [X] T019 [US2] Run the focused next-action pack in `tests/Feature/Filament/BaselineCompareSummaryConsistencyTest.php`, `tests/Feature/Filament/BaselineCompareNowWidgetTest.php`, `tests/Feature/Filament/BaselineCompareCoverageBannerTest.php`, `tests/Feature/Filament/BaselineCompareLandingStartSurfaceTest.php`, and `tests/Feature/Filament/BaselineCompareLandingAdminTenantParityTest.php`
|
|
|
|
**Checkpoint**: Covered summary surfaces no longer disagree about whether the operator should inspect findings, watch a run, open the landing page, or take no action.
|
|
|
|
---
|
|
|
|
## Phase 5: User Story 3 - Stable Multi-Card Tenant Summary (Priority: P2)
|
|
|
|
**Goal**: Keep multiple governance cards on the same tenant page stable by reusing one request-local aggregate and removing duplicate local findings-count ownership.
|
|
|
|
**Independent Test**: Render the tenant dashboard with both `Needs Attention` and `Baseline Governance` visible, verify both surfaces stay consistent for the same tenant in one request, then switch tenants or remove tenant context and verify no stale summary leaks.
|
|
|
|
### Tests for User Story 3
|
|
|
|
- [X] T020 [P] [US3] Add request-local reuse, tenant-switch, and no-tenant safety coverage in `tests/Feature/Filament/TenantGovernanceAggregateMemoizationTest.php`
|
|
- [X] T021 [P] [US3] Extend multi-card dashboard stability and no-local-requery coverage in `tests/Feature/Filament/NeedsAttentionWidgetTest.php` and `tests/Feature/Filament/BaselineCompareSummaryConsistencyTest.php`
|
|
|
|
### Implementation for User Story 3
|
|
|
|
- [X] T022 [US3] Harden tenant-switch, workspace-scope, and no-tenant key behavior for the second dashboard summary consumer in `app/Support/Ui/DerivedState/DerivedStateFamily.php` and `app/Support/Baselines/TenantGovernanceAggregateResolver.php`
|
|
- [X] T023 [US3] Replace local overdue, expiring, lapsed, and high-severity findings ownership with the shared aggregate in `app/Filament/Widgets/Dashboard/NeedsAttention.php`
|
|
- [X] T024 [US3] Extend governance aggregate consumer declarations and no-local-requery guard coverage to include `NeedsAttention` in `specs/167-derived-state-memoization/contracts/request-scoped-derived-state.logical.openapi.yaml` and `tests/Feature/Guards/DerivedStateConsumerAdoptionGuardTest.php`
|
|
- [X] T025 [US3] Run the focused memoization and guard pack in `tests/Feature/Filament/TenantGovernanceAggregateMemoizationTest.php`, `tests/Feature/Filament/NeedsAttentionWidgetTest.php`, and `tests/Feature/Guards/DerivedStateConsumerAdoptionGuardTest.php`
|
|
|
|
**Checkpoint**: The tenant dashboard can render multiple governance summary surfaces in one request without contradictory counts, posture drift, or tenant leakage.
|
|
|
|
---
|
|
|
|
## Phase 6: Polish & Cross-Cutting Concerns
|
|
|
|
**Purpose**: Final copy alignment, formatting, and focused verification across all stories.
|
|
|
|
- [X] T026 [P] Align operator-facing copy and next-step labels in `app/Filament/Widgets/Dashboard/BaselineCompareNow.php`, `app/Filament/Widgets/Dashboard/NeedsAttention.php`, `app/Filament/Widgets/Tenant/BaselineCompareCoverageBanner.php`, and `app/Filament/Pages/BaselineCompareLanding.php`
|
|
- [X] T027 Run formatting for touched implementation files with `vendor/bin/sail bin pint --dirty --format agent` using `specs/168-tenant-governance-aggregate-contract/quickstart.md`
|
|
- [X] T028 Run the final focused verification pack from `specs/168-tenant-governance-aggregate-contract/quickstart.md` against `tests/Feature/Baselines/BaselineCompareStatsTest.php`, `tests/Feature/Baselines/BaselineCompareSummaryAssessmentTest.php`, `tests/Feature/Baselines/TenantGovernanceAggregateResolverTest.php`, `tests/Feature/Filament/BaselineCompareSummaryConsistencyTest.php`, `tests/Feature/Filament/BaselineCompareNowWidgetTest.php`, `tests/Feature/Filament/BaselineCompareCoverageBannerTest.php`, `tests/Feature/Filament/BaselineCompareLandingAdminTenantParityTest.php`, `tests/Feature/Filament/BaselineCompareLandingDuplicateNamesBannerTest.php`, `tests/Feature/Filament/BaselineCompareLandingRbacLabelsTest.php`, `tests/Feature/Filament/BaselineCompareLandingStartSurfaceTest.php`, `tests/Feature/Filament/BaselineCompareLandingWhyNoFindingsTest.php`, `tests/Feature/Filament/NeedsAttentionWidgetTest.php`, `tests/Feature/Filament/TenantGovernanceAggregateMemoizationTest.php`, and `tests/Feature/Guards/DerivedStateConsumerAdoptionGuardTest.php`
|
|
|
|
---
|
|
|
|
## Dependencies & Execution Order
|
|
|
|
### Phase Dependencies
|
|
|
|
- **Setup (Phase 1)**: Starts immediately and creates the narrow aggregate runtime and test scaffolding.
|
|
- **Foundational (Phase 2)**: Depends on Setup and blocks all user stories until the aggregate contract and request-scoped family are in place.
|
|
- **User Story 1 (Phase 3)**: Starts after Foundational and delivers the MVP shared-posture slice across three surfaces.
|
|
- **User Story 2 (Phase 4)**: Starts after User Story 1 because it refines the same summary surfaces with explicit next-action intent.
|
|
- **User Story 3 (Phase 5)**: Starts after User Story 2 because it adopts the second dashboard summary surface only after shared next-action semantics and first-slice parity are settled.
|
|
- **Polish (Phase 6)**: Starts after all desired user stories are complete and ends with focused verification.
|
|
|
|
### User Story Dependencies
|
|
|
|
- **User Story 1 (P1)**: Depends only on the aggregate contract and request-scoped family from Phase 2.
|
|
- **User Story 2 (P1)**: Depends on User Story 1 because the same summary surfaces must already read the shared aggregate before their next-action mapping can be aligned.
|
|
- **User Story 3 (P2)**: Depends on the aggregate contract from Phase 2 plus the settled shared posture and next-action semantics from User Stories 1 and 2 before the second dashboard consumer joins the shared contract.
|
|
|
|
### Within Each User Story
|
|
|
|
- Story tests should be written before or alongside the relevant implementation tasks and must fail before the story is considered complete.
|
|
- Aggregate contract changes should land before surface adoption in the same story.
|
|
- Surface refactors should land before the focused story-level regression run.
|
|
|
|
### Parallel Opportunities
|
|
|
|
- `T001` and `T002` can run in parallel during Setup.
|
|
- `T003` and `T006` can run in parallel during Foundational work.
|
|
- `T007` and `T008` can run in parallel for User Story 1.
|
|
- `T014` and `T015` can run in parallel for User Story 2.
|
|
- `T020` and `T021` can run in parallel for User Story 3.
|
|
- After `T022`, `T023` and `T024` can run in parallel because they change different files.
|
|
|
|
---
|
|
|
|
## Parallel Example: User Story 1
|
|
|
|
```bash
|
|
# User Story 1 tests in parallel:
|
|
Task: T007 tests/Feature/Baselines/TenantGovernanceAggregateResolverTest.php
|
|
Task: T008 tests/Feature/Filament/BaselineCompareSummaryConsistencyTest.php
|
|
|
|
# User Story 1 surface adoption split after aggregate semantics are fixed:
|
|
Task: T009 app/Filament/Widgets/Dashboard/BaselineCompareNow.php
|
|
Task: T010 app/Filament/Widgets/Tenant/BaselineCompareCoverageBanner.php
|
|
```
|
|
|
|
## Parallel Example: User Story 2
|
|
|
|
```bash
|
|
# User Story 2 tests in parallel:
|
|
Task: T014 tests/Feature/Filament/BaselineCompareSummaryConsistencyTest.php
|
|
Task: T015 tests/Feature/Filament/BaselineCompareNowWidgetTest.php
|
|
|
|
# User Story 2 implementation split after next-action ownership lands:
|
|
Task: T017 app/Filament/Widgets/Dashboard/BaselineCompareNow.php
|
|
Task: T018 app/Filament/Widgets/Tenant/BaselineCompareCoverageBanner.php and app/Filament/Pages/BaselineCompareLanding.php
|
|
```
|
|
|
|
## Parallel Example: User Story 3
|
|
|
|
```bash
|
|
# User Story 3 tests in parallel:
|
|
Task: T020 tests/Feature/Filament/TenantGovernanceAggregateMemoizationTest.php
|
|
Task: T021 tests/Feature/Filament/NeedsAttentionWidgetTest.php
|
|
|
|
# User Story 3 implementation split after request-scoped keying is settled:
|
|
Task: T023 app/Filament/Widgets/Dashboard/NeedsAttention.php
|
|
Task: T024 tests/Feature/Guards/DerivedStateConsumerAdoptionGuardTest.php and specs/167-derived-state-memoization/contracts/request-scoped-derived-state.logical.openapi.yaml
|
|
```
|
|
|
|
---
|
|
|
|
## Implementation Strategy
|
|
|
|
### MVP First
|
|
|
|
1. Complete Phase 1: Setup.
|
|
2. Complete Phase 2: Foundational.
|
|
3. Complete Phase 3: User Story 1.
|
|
4. Validate that the dashboard governance card, tenant banner, and landing summary now share one posture and count contract.
|
|
|
|
### Incremental Delivery
|
|
|
|
1. Add User Story 2 to align next-action guidance once shared posture parity is proven.
|
|
2. Add User Story 3 to bring the second dashboard card onto the same contract and lock in request-local stability.
|
|
3. Finish with copy alignment, formatting, and the focused verification pack.
|
|
|
|
### Parallel Team Strategy
|
|
|
|
1. One developer can complete Phase 1 and Phase 2 while another prepares the story tests.
|
|
2. After User Story 1 lands, one developer can handle User Story 2 next-action adoption while another prepares User Story 3 memoization and guard coverage.
|
|
3. Rejoin for Phase 6 to run Pint and the focused verification pack.
|
|
|
|
---
|
|
|
|
## Notes
|
|
|
|
- `[P]` tasks target different files with no direct dependency on unfinished code in the same phase.
|
|
- `[US1]`, `[US2]`, and `[US3]` labels map tasks directly to the feature specification user stories.
|
|
- The suggested MVP scope is Phase 1 through Phase 3 only.
|
|
- No task in this plan introduces new persistence, a new Graph contract, a new Filament panel/provider registration, or a new destructive action.
|