TenantAtlas/specs/255-enforce-finding-creation-invariants/tasks.md
ahmido 51ea80ca05
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 1m5s
Automatische PR: 255-enforce-finding-creation-invariants → platform-dev (#298)
Automatisch erstellt: Commit & Push aus Workspace (WIP)

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #298
2026-04-29 12:26:21 +00:00

24 KiB

Tasks: Enforce Creation-Time Finding Invariants

Input: Design documents from /specs/255-enforce-finding-creation-invariants/ Prerequisites: plan.md, spec.md, research.md, data-model.md, quickstart.md, contracts/finding-creation-invariants.contract.yaml, checklists/requirements.md

Tests (TEST-GOV-001): REQUIRED (Pest). Keep proof in the targeted fast-feedback and confidence lanes named in specs/255-enforce-finding-creation-invariants/plan.md and specs/255-enforce-finding-creation-invariants/quickstart.md. Keep the three writer suites as the primary proof in apps/platform/tests/Feature/Baselines/BaselineCompareFindingsTest.php, apps/platform/tests/Feature/EntraAdminRoles/EntraAdminRolesFindingGeneratorTest.php, and apps/platform/tests/Feature/PermissionPosture/PermissionPostureFindingGeneratorTest.php. Use only bounded adjacent regression in apps/platform/tests/Feature/Findings/FindingRecurrenceTest.php, apps/platform/tests/Feature/Findings/FindingAutomationWorkflowTest.php, apps/platform/tests/Feature/Findings/FindingWorkflowServiceTest.php, apps/platform/tests/Feature/Findings/MyWorkInboxTest.php, apps/platform/tests/Feature/Findings/FindingsIntakeQueueTest.php, apps/platform/tests/Feature/Rbac/BaselineCompareMatrixAuthorizationTest.php, and apps/platform/tests/Feature/EntraAdminRoles/AdminRolesSummaryWidgetTest.php where they prove shared recurrence, consumer honesty, or unchanged trigger authorization without inflating the implementation scope into direct UI rewrites. Operations: This slice does not add or change an OperationRun start family, does not add a new audit action ID, and must not introduce migrations, DB constraints, repair tooling, deploy hooks, or external integrations. Existing current_operation_run_id correlations stay contextual only where the current writers already set them, and any report-emission assertions remain bounded to the writer suites that already own them. RBAC: Preserve current tenant/workspace isolation, current 404 versus 403 behavior on the baseline compare matrix and admin-roles scan trigger surfaces, and the existing tenant-scoped background/system reopen semantics. Do not add a new capability, bypass, or customer-facing workflow branch. UI / Surface Guardrails: This is a review-mandatory write-time truth hardening slice with standard-native-filament relief. apps/platform/app/Filament/Resources/FindingResource.php, apps/platform/app/Filament/Pages/Findings/MyFindingsInbox.php, and apps/platform/app/Filament/Pages/Findings/FindingsIntakeQueue.php stay regression consumers only unless existing tests prove a shared-truth fix is insufficient. Filament UI Action Surfaces: No new Filament Resource, Page, RelationManager, panel, provider, or asset work is introduced. FindingResource already has a view page, so global-search compliance stays satisfied without new tasking. No new destructive action is introduced or changed. Organization: Tasks are grouped by user story so each slice stays independently verifiable. Recommended delivery order is Phase 1 -> Phase 2 -> US1 -> US2 -> US3 -> final validation, because creation-readiness must be explicit before reopen and recurrence proofs are tightened.

Implementation note: If creation-time invariants converge through the three writer paths plus FindingWorkflowService and FindingSlaPolicy, keep downstream findings surfaces untouched and make proof responsibility explicit in their existing test files rather than planning direct edits to every listed consumer file.

Test Governance Checklist

  • Lane assignment stays fast-feedback plus confidence and remains the narrowest sufficient proof for write-time lifecycle hardening.
  • New or changed tests stay in focused Feature files only; no browser or new heavy-governance family is added.
  • Shared helpers, factories, fixtures, and context defaults stay cheap by default; any broader setup is isolated to the findings suites that already need it.
  • Planned validation commands stay limited to the quickstart command set, allowing the three writer-suite commands to be combined into one equivalent Sail invocation plus the shared recurrence, consumer, and trigger-authorization checks below.
  • The declared surface test profile stays standard-native-filament; downstream findings surfaces remain proof consumers only.
  • Any material residue or follow-up note resolves as document-in-feature, follow-up-spec, or reject-or-split, not as implicit scope drift.

Phase 1: Setup (Shared Invariant Anchors)

Purpose: Lock the bounded writer inventory, shared lifecycle seams, and proving commands before implementation starts.

  • T001 [P] Verify the bounded feature package, stop conditions, and non-goals across specs/255-enforce-finding-creation-invariants/spec.md, specs/255-enforce-finding-creation-invariants/plan.md, specs/255-enforce-finding-creation-invariants/research.md, specs/255-enforce-finding-creation-invariants/data-model.md, specs/255-enforce-finding-creation-invariants/quickstart.md, and specs/255-enforce-finding-creation-invariants/contracts/finding-creation-invariants.contract.yaml
  • T002 [P] Verify the active finding-writer and shared seam inventory across apps/platform/app/Jobs/CompareBaselineToTenantJob.php, apps/platform/app/Services/EntraAdminRoles/EntraAdminRolesFindingGenerator.php, apps/platform/app/Services/PermissionPosture/PermissionPostureFindingGenerator.php, apps/platform/app/Services/Findings/FindingWorkflowService.php, apps/platform/app/Services/Findings/FindingSlaPolicy.php, and apps/platform/app/Models/Finding.php
  • T003 [P] Verify the narrow Sail validation commands and manual smoke expectations in specs/255-enforce-finding-creation-invariants/plan.md and specs/255-enforce-finding-creation-invariants/quickstart.md
  • T004 [P] Verify downstream proof-only consumers across apps/platform/tests/Feature/Findings/FindingRecurrenceTest.php, apps/platform/tests/Feature/Findings/FindingAutomationWorkflowTest.php, apps/platform/tests/Feature/Findings/MyWorkInboxTest.php, and apps/platform/tests/Feature/Findings/FindingsIntakeQueueTest.php

Checkpoint: The bounded invariant target, shared seams, and validation entry points are explicit before any runtime file changes begin.


Phase 2: Foundational (Blocking Proof Surfaces)

Purpose: Make the intended proof surfaces and adjacent cleanup guardrails explicit before the write paths are changed.

CRITICAL: No user story work should begin until this phase is complete.

  • T005 [P] Lock the per-family lifecycle-ready and inline-repair proof plan in apps/platform/tests/Feature/Baselines/BaselineCompareFindingsTest.php, apps/platform/tests/Feature/EntraAdminRoles/EntraAdminRolesFindingGeneratorTest.php, and apps/platform/tests/Feature/PermissionPosture/PermissionPostureFindingGeneratorTest.php
  • T006 [P] Lock the shared recurrence and reopen proof plan in apps/platform/tests/Feature/Findings/FindingRecurrenceTest.php, apps/platform/tests/Feature/Findings/FindingAutomationWorkflowTest.php, and apps/platform/tests/Feature/Findings/FindingWorkflowServiceTest.php
  • T007 [P] Audit incomplete-lifecycle fixture and helper anchors across apps/platform/database/factories/FindingFactory.php, apps/platform/tests/Feature/Baselines/BaselineCompareFindingsTest.php, apps/platform/tests/Feature/EntraAdminRoles/EntraAdminRolesFindingGeneratorTest.php, and apps/platform/tests/Feature/PermissionPosture/PermissionPostureFindingGeneratorTest.php
  • T008 [P] Audit adjacent cleanup guardrails in apps/platform/tests/Feature/Findings/RemoveFindingsLifecycleBackfillActionTest.php and apps/platform/tests/Feature/Findings/RemoveAcknowledgedCompatibilityWorkflowTest.php so this slice does not reintroduce repair tooling or acknowledged compatibility

Checkpoint: Writer-level proof, shared reopen proof, and adjacent no-regression guardrails are explicit and ready for bounded implementation work.


Phase 3: User Story 1 - See Ready Findings Immediately (Priority: P1)

Goal: Newly detected findings arrive lifecycle-ready on first persistence across the three active writer families.

Independent Test: Trigger one new finding per writer family and verify the first persisted record already carries canonical open status, seen history, ownership anchors, and due or SLA truth without any repair or second-pass workflow.

Tests for User Story 1

  • T009 [P] [US1] Extend baseline compare create-readiness and incomplete-field inline-repair coverage in apps/platform/tests/Feature/Baselines/BaselineCompareFindingsTest.php
  • T010 [P] [US1] Extend Entra admin roles create-readiness and incomplete-field inline-repair coverage in apps/platform/tests/Feature/EntraAdminRoles/EntraAdminRolesFindingGeneratorTest.php
  • T011 [P] [US1] Extend permission posture create-readiness and incomplete-field inline-repair coverage in apps/platform/tests/Feature/PermissionPosture/PermissionPostureFindingGeneratorTest.php

Implementation for User Story 1

  • T012 [US1] Align baseline compare finding creation and active-record refresh with the lifecycle-ready contract in apps/platform/app/Jobs/CompareBaselineToTenantJob.php
  • T013 [US1] Align Entra admin roles finding creation and active-record refresh with the lifecycle-ready contract in apps/platform/app/Services/EntraAdminRoles/EntraAdminRolesFindingGenerator.php
  • T014 [US1] Align permission posture finding creation and active-record refresh with the lifecycle-ready contract in apps/platform/app/Services/PermissionPosture/PermissionPostureFindingGenerator.php
  • T015 [US1] Keep ownership anchors plus due or SLA initialization explicit without introducing a migration or repair surface in apps/platform/app/Models/Finding.php, apps/platform/app/Services/Findings/FindingSlaPolicy.php, and the three story tests from T009 through T011

Checkpoint: User Story 1 is independently functional and all three active writers create lifecycle-ready findings in the same write path.


Phase 4: User Story 2 - Reopen the Same Finding When the Risk Returns (Priority: P1)

Goal: Resolved findings reopen through the existing shared workflow path with refreshed lifecycle truth and preserved canonical identity.

Independent Test: Resolve an in-scope finding, re-observe the same issue through each writer family, and verify the same record reopens with cleared terminal markers and refreshed due or SLA truth.

Tests for User Story 2

  • T016 [P] [US2] Add baseline compare resolved-to-reopened regression and current_operation_run_id continuity coverage in apps/platform/tests/Feature/Baselines/BaselineCompareFindingsTest.php
  • T017 [P] [US2] Add Entra admin roles resolved-to-reopened regression and current_operation_run_id continuity coverage in apps/platform/tests/Feature/EntraAdminRoles/EntraAdminRolesFindingGeneratorTest.php
  • T018 [P] [US2] Add permission posture resolved-to-reopened regression plus existing current_operation_run_id and stored-report emission continuity coverage in apps/platform/tests/Feature/PermissionPosture/PermissionPostureFindingGeneratorTest.php
  • T019 [P] [US2] Tighten shared reopen-service proof for reopenBySystem() due or SLA recalculation, audit continuity, and terminal eligibility in apps/platform/tests/Feature/Findings/FindingWorkflowServiceTest.php

Implementation for User Story 2

  • T020 [US2] Keep reopened-state mutation on FindingWorkflowService::reopenBySystem() and reconcile baseline compare call sites in apps/platform/app/Services/Findings/FindingWorkflowService.php and apps/platform/app/Jobs/CompareBaselineToTenantJob.php
  • T021 [US2] Preserve same-finding reopen identity and family-specific evidence refresh in apps/platform/app/Services/EntraAdminRoles/EntraAdminRolesFindingGenerator.php and apps/platform/app/Services/PermissionPosture/PermissionPostureFindingGenerator.php
  • T022 [US2] Reconcile reopened due-date, SLA, and resolved-marker expectations without adding new workflow states or audit dialects in apps/platform/app/Services/Findings/FindingSlaPolicy.php, apps/platform/app/Services/Findings/FindingWorkflowService.php, and apps/platform/tests/Feature/Findings/FindingWorkflowServiceTest.php

Checkpoint: User Story 2 is independently functional and resolved findings reopen through the existing shared workflow semantics rather than duplicating records or adding a second reopen path.


Phase 5: User Story 3 - Keep One Canonical Finding Identity Through Repeated Detection (Priority: P2)

Goal: Repeated observation strengthens the same finding record, respects each family's observation boundary, and keeps downstream surfaces truthful without widening the feature into UI redesign.

Independent Test: Re-run the same observation and then a later valid observation across the in-scope families and verify that one canonical finding identity remains in place, same-observation retries do not double count, and downstream findings surfaces still read honest lifecycle truth.

Tests for User Story 3

  • T023 [P] [US3] Extend same-observation idempotence and canonical-identity reuse coverage in apps/platform/tests/Feature/Baselines/BaselineCompareFindingsTest.php and apps/platform/tests/Feature/Baselines/BaselineCompareFindingRecurrenceKeyTest.php
  • T024 [P] [US3] Extend cross-family recurrence and observation-boundary coverage in apps/platform/tests/Feature/Findings/FindingRecurrenceTest.php and apps/platform/tests/Feature/Findings/FindingAutomationWorkflowTest.php
  • T025 [P] [US3] Tighten downstream consumer and trigger-authorization proof that shared lifecycle truth still renders honestly and that non-members remain 404 while in-scope capability failures remain 403 in apps/platform/tests/Feature/Findings/MyWorkInboxTest.php, apps/platform/tests/Feature/Findings/FindingsIntakeQueueTest.php, apps/platform/tests/Feature/Rbac/BaselineCompareMatrixAuthorizationTest.php, and apps/platform/tests/Feature/EntraAdminRoles/AdminRolesSummaryWidgetTest.php

Implementation for User Story 3

  • T026 [US3] Preserve family-owned recurrence keys, fingerprints, and observation boundaries while preventing duplicate canonical findings in apps/platform/app/Jobs/CompareBaselineToTenantJob.php, apps/platform/app/Services/EntraAdminRoles/EntraAdminRolesFindingGenerator.php, and apps/platform/app/Services/PermissionPosture/PermissionPostureFindingGenerator.php
  • T027 [US3] Keep any shared lifecycle normalization bounded to apps/platform/app/Services/Findings/ only when it replaces real duplication across all three writers, with proof confined to apps/platform/tests/Feature/Baselines/BaselineCompareFindingsTest.php, apps/platform/tests/Feature/EntraAdminRoles/EntraAdminRolesFindingGeneratorTest.php, apps/platform/tests/Feature/PermissionPosture/PermissionPostureFindingGeneratorTest.php, and apps/platform/tests/Feature/Findings/FindingRecurrenceTest.php rather than widening into new workflow or UI files

Checkpoint: User Story 3 is independently functional and recurrence keeps one canonical finding identity without double-counting or forcing direct downstream surface rewrites.


Phase 6: Polish & Cross-Cutting Concerns

Purpose: Keep the slice bounded, run the narrow validation workflow, and check for out-of-scope residue.

  • T028 [P] Run formatting for touched PHP files with export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent
  • T029 [P] Run the focused writer-suite Sail command export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Baselines/BaselineCompareFindingsTest.php tests/Feature/EntraAdminRoles/EntraAdminRolesFindingGeneratorTest.php tests/Feature/PermissionPosture/PermissionPostureFindingGeneratorTest.php
  • T030 [P] Run the focused shared-recurrence Sail command export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Findings/FindingRecurrenceTest.php tests/Feature/Findings/FindingAutomationWorkflowTest.php tests/Feature/Findings/FindingWorkflowServiceTest.php
  • T031 [P] Run the downstream-consumer and trigger-RBAC Sail command export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Findings/MyWorkInboxTest.php tests/Feature/Findings/FindingsIntakeQueueTest.php tests/Feature/Rbac/BaselineCompareMatrixAuthorizationTest.php tests/Feature/EntraAdminRoles/AdminRolesSummaryWidgetTest.php
  • T032 [P] Execute quickstart manual smoke steps 1 through 4 from specs/255-enforce-finding-creation-invariants/quickstart.md against /admin/t/{tenant}/findings, MyFindingsInbox, and FindingsIntakeQueue, then leave diff/scope review to T034
  • T033 [P] Run residue searches for backfill, repair, constraint, migration, and any new Finding::STATUS_ additions across apps/platform/app/, apps/platform/tests/, apps/platform/database/, and specs/255-enforce-finding-creation-invariants/, then classify each remaining match as allowed shared-consumer proof, in-scope cleanup to delete now, or reject-or-split
  • T034 Verify that no file under apps/platform/database/migrations/ changed, no new repair or rollout entry point appeared under apps/platform/app/Console/Commands/ or apps/platform/app/Services/Runbooks/, and no direct workflow expansion landed in apps/platform/app/Filament/Resources/FindingResource.php, apps/platform/app/Filament/Pages/Findings/MyFindingsInbox.php, or apps/platform/app/Filament/Pages/Findings/FindingsIntakeQueue.php; if truth-consumer proof from T025 and T031 suggests a direct UI edit is necessary, stop and record that as document-in-feature or reject-or-split instead of treating it as default in-scope work

Dependencies & Execution Order

Phase Dependencies

  • Setup (Phase 1): Starts immediately and locks the exact scope, writer inventory, and proving commands.
  • Foundational (Phase 2): Depends on Setup and blocks all story work until proof files, fixtures, and adjacent cleanup guardrails are explicit.
  • User Story 1 (Phase 3): Depends on Foundational and establishes the lifecycle-ready create contract.
  • User Story 2 (Phase 4): Depends on User Story 1 because reopen semantics should refresh the same lifecycle-ready contract established at creation time.
  • User Story 3 (Phase 5): Depends on User Story 1 and User Story 2 because recurrence and consumer proof only mean the right thing after create and reopen behavior are aligned.
  • Polish (Phase 6): Depends on all desired user stories being complete so final validation and residue checks run on the finished slice.

User Story Dependencies

  • US1: No dependencies beyond Foundational.
  • US2: Depends on US1.
  • US3: Depends on US1 and US2.

Within Each User Story

  • Add or update the story tests first and confirm they fail before implementation edits are considered complete.
  • Keep recurrence identity family-owned instead of introducing a generic invariant framework.
  • Keep downstream findings surfaces as proof consumers unless shared-truth tests prove a concrete need for direct edits.
  • Keep migrations, DB constraints, repair tooling, acknowledged cleanup, external support-desk or PSA work, customer-facing workflow changes, and broad findings redesign out of scope.

Parallel Opportunities

  • T001, T002, T003, and T004 can run in parallel during Setup.
  • T005, T006, T007, and T008 can run in parallel during Foundational work.
  • T009, T010, and T011 can run in parallel for User Story 1 before T012, T013, T014, and T015.
  • T016, T017, T018, and T019 can run in parallel for User Story 2 before T020, T021, and T022.
  • T023, T024, and T025 can run in parallel for User Story 3 before T026 and T027.
  • T029, T030, T031, T032, and T033 can run in parallel during final validation after T028, followed by T034 as the final scope-boundary check.

Parallel Example: User Story 1

# User Story 1 tests in parallel
T009 apps/platform/tests/Feature/Baselines/BaselineCompareFindingsTest.php
T010 apps/platform/tests/Feature/EntraAdminRoles/EntraAdminRolesFindingGeneratorTest.php
T011 apps/platform/tests/Feature/PermissionPosture/PermissionPostureFindingGeneratorTest.php

# User Story 1 implementation after the tests are in place
T012 apps/platform/app/Jobs/CompareBaselineToTenantJob.php
T013 apps/platform/app/Services/EntraAdminRoles/EntraAdminRolesFindingGenerator.php
T014 apps/platform/app/Services/PermissionPosture/PermissionPostureFindingGenerator.php

Parallel Example: User Story 2

# User Story 2 tests in parallel
T016 apps/platform/tests/Feature/Baselines/BaselineCompareFindingsTest.php
T017 apps/platform/tests/Feature/EntraAdminRoles/EntraAdminRolesFindingGeneratorTest.php
T018 apps/platform/tests/Feature/PermissionPosture/PermissionPostureFindingGeneratorTest.php
T019 apps/platform/tests/Feature/Findings/FindingWorkflowServiceTest.php

# User Story 2 implementation after the tests are in place
T020 apps/platform/app/Services/Findings/FindingWorkflowService.php + apps/platform/app/Jobs/CompareBaselineToTenantJob.php
T021 apps/platform/app/Services/EntraAdminRoles/EntraAdminRolesFindingGenerator.php + apps/platform/app/Services/PermissionPosture/PermissionPostureFindingGenerator.php

Parallel Example: User Story 3

# User Story 3 tests in parallel
T023 apps/platform/tests/Feature/Baselines/BaselineCompareFindingsTest.php + apps/platform/tests/Feature/Baselines/BaselineCompareFindingRecurrenceKeyTest.php
T024 apps/platform/tests/Feature/Findings/FindingRecurrenceTest.php + apps/platform/tests/Feature/Findings/FindingAutomationWorkflowTest.php
T025 apps/platform/tests/Feature/Findings/MyWorkInboxTest.php + apps/platform/tests/Feature/Findings/FindingsIntakeQueueTest.php

# User Story 3 implementation after the tests are in place
T026 apps/platform/app/Jobs/CompareBaselineToTenantJob.php + apps/platform/app/Services/EntraAdminRoles/EntraAdminRolesFindingGenerator.php + apps/platform/app/Services/PermissionPosture/PermissionPostureFindingGenerator.php
T027 apps/platform/app/Services/Findings/

Implementation Strategy

MVP First (User Stories 1 and 2)

  1. Complete Phase 1: Setup.
  2. Complete Phase 2: Foundational.
  3. Complete Phase 3: User Story 1.
  4. Complete Phase 4: User Story 2.
  5. Run T028, T029, and T030 before widening into recurrence and consumer-proof cleanup.

Incremental Delivery

  1. Lock the bounded writer inventory, proof files, and stop conditions.
  2. Make create-time lifecycle readiness explicit for baseline compare, Entra admin roles, and permission posture.
  3. Preserve the shared reopen path and refresh lifecycle truth when resolved findings return.
  4. Tighten recurrence, idempotence, and downstream proof without widening into UI redesign or repair tooling.
  5. Finish with focused Sail validation, manual smoke, and residue checks.

Parallel Team Strategy

  1. One contributor can own the three writer-family tests while another confirms shared recurrence and downstream consumer proof after Phase 2.
  2. After User Story 1 lands, one contributor can align the reopen path while another prepares the recurrence and consumer proof for User Story 3.
  3. Finish with one bounded pass for formatting, focused Sail validation, and residue or scope-boundary review.

Notes

  • Suggested MVP scope: Phase 1 through Phase 4. Creation readiness without reopen reuse is not sufficient for this feature.
  • Explicit non-goals remain: runtime backfill surfaces, acknowledged cleanup, new workflow states, broad findings redesign, migrations or DB constraints, repair tooling, external support-desk or PSA work, and customer-facing workflow expansion.
  • Filament remains on Livewire v4.0+; no panel/provider or asset strategy changes are needed, and apps/platform/bootstrap/providers.php remains the relevant provider-registration location if later Filament work is ever required.
  • All tasks above follow the required checklist format with task ID, optional parallel marker, story label where applicable, and concrete file paths.