TenantAtlas/specs/265-decision-register-approval/tasks.md
Ahmed Darrazi b5671cbf47
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 3m49s
chore: commit all local changes (automated by Copilot)
2026-05-02 21:00:28 +02:00

17 KiB

description
Task list for Decision Register & Approval Workflow v1

Tasks: Decision Register & Approval Workflow v1

Input: Design documents from specs/265-decision-register-approval/
Prerequisites: specs/265-decision-register-approval/spec.md, specs/265-decision-register-approval/plan.md, specs/265-decision-register-approval/checklists/requirements.md

Tests: REQUIRED (Pest). Keep proof bounded to Unit plus Feature coverage for the derived register contract and the existing findings detail flow. The canonical proving suite is GovernanceDecisionRegisterBuilderTest, DecisionRegisterPageTest, DecisionRegisterAuthorizationTest, FindingExceptionDecisionRegisterNavigationTest, FindingExceptionDetailDecisionSummaryTest, and FindingExceptionDecisionRegisterBoundariesTest. One narrow browser smoke on the register-to-detail path is also allowed for implementation-loop verification and is now covered by Spec265DecisionRegisterSmokeTest. Operations: No new OperationRun, queue family, or notification path is allowed. Any related run link must reuse existing OperationRunLinks only when current proof already exposes it. RBAC: Workspace non-members and out-of-scope tenant or record targets remain 404; in-scope members with no visible decisions remain 403. Register visibility reuses Capabilities::FINDING_EXCEPTION_VIEW; current decision actions remain on the detail surface and keep their existing approval capability checks such as Capabilities::FINDING_EXCEPTION_APPROVE. Shared Pattern Reuse: Reuse CanonicalNavigationContext, OperationRunLinks, BadgeRenderer, current exception decision history, current exception detail action surfaces, and current audit-trail semantics. Do not create a generic workflow engine or a second decision store. Filament / Panel Guardrails: Filament remains v5 on Livewire v4. Provider registration remains unchanged in apps/platform/bootstrap/providers.php. No new panel, no new globally searchable resource, and no new asset strategy are allowed. Organization: Tasks are grouped by user story so the derived register, detail continuity, and bounded decision-truth rules remain independently implementable and testable.

Test Governance Checklist

  • Lane assignment stays Unit plus Feature and remains the narrowest sufficient proof for the changed behavior.
  • New or changed tests stay in focused apps/platform/tests/Unit/Support/GovernanceDecisions/, apps/platform/tests/Feature/Governance/, and apps/platform/tests/Feature/Findings/ families only.
  • Shared helpers, fixtures, and context defaults stay cheap by default; do not add new provider setup, queue scaffolding, or a dedicated browser family.
  • Planned validation commands cover register assembly, authorization, and launch continuity without widening into unrelated lanes.
  • The declared surface test profile remains global-context-shell because tenant and return-context continuity are part of the contract.
  • The implementation must pass docs/product/standards/list-surface-review-checklist.md, and any deviation must be explicit instead of hidden in bespoke row markup.
  • Decision-surface proof must cover one dominant next action, diagnostics-secondary treatment, and no duplicate visible decision summary between register and detail.
  • Any drift toward a new decision table, workflow engine, cross-family register, or inline register mutation resolves as reject-or-split, not hidden implementation growth.

Phase 1: Setup (Shared Context)

Purpose: Confirm the bounded slice, the current decision truth, and the reviewer stop conditions before implementation begins.

  • T001 Review specs/265-decision-register-approval/spec.md, specs/265-decision-register-approval/plan.md, specs/265-decision-register-approval/checklists/requirements.md, specs/154-finding-risk-acceptance/spec.md, specs/250-decision-governance-inbox/spec.md, specs/257-governance-decision-convergence/spec.md, docs/product/spec-candidates.md, docs/product/roadmap.md, and docs/product/standards/list-surface-review-checklist.md together so the slice stays on current decision truth and native list-surface rules.
  • T002 [P] Confirm the current exception-decision domain seams in apps/platform/app/Models/FindingException.php, apps/platform/app/Models/FindingExceptionDecision.php, apps/platform/app/Models/FindingExceptionEvidenceReference.php, and apps/platform/app/Services/Findings/FindingExceptionService.php.
  • T003 [P] Confirm the current operator surfaces in apps/platform/app/Filament/Pages/Monitoring/FindingExceptionsQueue.php, apps/platform/app/Filament/Resources/FindingExceptionResource.php, apps/platform/app/Filament/Resources/FindingExceptionResource/Pages/ViewFindingException.php, and apps/platform/app/Filament/Pages/Governance/GovernanceInbox.php.
  • T004 [P] Confirm the current shared helper seams in apps/platform/app/Support/Navigation/CanonicalNavigationContext.php, apps/platform/app/Support/OperationRunLinks.php, and current finding-exception badge or audit helpers before adding any register-local builder logic.

Phase 2: Foundational (Blocking Prerequisites)

Purpose: Lock the bounded register contract before surface-level implementation begins.

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

  • T005 [P] Add failing unit coverage in apps/platform/tests/Unit/Support/GovernanceDecisions/GovernanceDecisionRegisterBuilderTest.php for open versus recently-closed row derivation, the 30-calendar-day terminal window, owner and due context, hidden-tenant omission, and honest proof-link availability.
  • T006 [P] Add failing feature coverage in apps/platform/tests/Feature/Governance/DecisionRegisterPageTest.php and apps/platform/tests/Feature/Governance/DecisionRegisterAuthorizationTest.php for page visibility, tenant and register-state filters, truthful filtered empty states after authorized filtering, clearing a tenant prefilter back to the workspace-wide open register, and 404 versus default-unfiltered 403 behavior.
  • T007 [P] Add failing feature coverage in apps/platform/tests/Feature/Findings/FindingExceptionDecisionRegisterNavigationTest.php and apps/platform/tests/Feature/Findings/FindingExceptionDetailDecisionSummaryTest.php for register-to-detail launch continuity, preserved tenant and return context, and the absence of inline mutation controls on the register page.
  • T008 Implement a bounded register builder in apps/platform/app/Support/GovernanceDecisions/GovernanceDecisionRegisterBuilder.php that derives rows from current FindingException, FindingExceptionDecision, finding impact, owner, due or review dates, closure reason for recently closed rows, evidence references, and existing proof links only.
  • T009 Implement the new native Filament page class apps/platform/app/Filament/Pages/Governance/DecisionRegister.php with a Filament-native table or list surface, query-backed tenant and register-state filters, capability-safe omission, and no inline approval workflow.
  • T010 [P] Implement apps/platform/resources/views/filament/pages/governance/decision-register.blade.php only as a thin host for the native Filament surface, with one dominant Open decision action per row, closure reason on recently closed rows, diagnostics-secondary treatment, no duplicate visible decision summary, truthful proof availability cues, and calm empty-state copy.

Checkpoint: The derived row contract, visibility rules, and read-only register surface are settled before user-story-specific changes widen.


Phase 3: User Story 1 - See Open Governance Decisions In One Register (Priority: P1)

Goal: Give the operator one bounded register that surfaces open and recently closed accepted-risk governance decisions from existing truth.

Independent Test: Seed visible and hidden tenants with pending, expiring, lapsed, and recently closed decisions, open the register, and verify that only visible-tenant rows appear with owner, due context, status, impact, and one dominant next action.

Tests for User Story 1

  • T011 [P] [US1] Extend apps/platform/tests/Feature/Governance/DecisionRegisterPageTest.php to cover pending approval, pending renewal, active or expiring follow-up, lapsed governance, recently closed rows inside the 30-calendar-day window with closure reason visible, rows older than that window being excluded, and hidden-tenant omission.
  • T012 [P] [US1] Extend apps/platform/tests/Feature/Governance/DecisionRegisterAuthorizationTest.php to cover 403 for in-scope members with no visible rows and 404 for explicit out-of-scope tenant filters or detail targets.

Implementation for User Story 1

  • T013 [US1] Register the new page inside the existing governance navigation in apps/platform/app/Filament/Pages/Governance/DecisionRegister.php so it becomes one bounded workspace decision surface without becoming a new searchable resource or a second inbox.
  • T014 [US1] Reuse current badge and vocabulary semantics in apps/platform/app/Filament/Pages/Governance/DecisionRegister.php, apps/platform/resources/views/filament/pages/governance/decision-register.blade.php, and localization files only as needed so row state, due context, closure reason, and next-action wording stay aligned with current exception surfaces.

Checkpoint: User Story 1 is independently functional when the register truthfully surfaces the current decisions that need follow-through and keeps hidden tenants silent.


Phase 4: User Story 2 - Open The Existing Approval Surface With Context (Priority: P1)

Goal: Preserve tenant and register context when the operator opens the current exception detail and action surface from the new register.

Independent Test: Open a decision row from the register, land on the current exception detail page, verify the existing approval or closure actions remain there, and return to the same register scope.

Tests for User Story 2

  • T015 [P] [US2] Extend apps/platform/tests/Feature/Findings/FindingExceptionDecisionRegisterNavigationTest.php for register-to-detail launch continuity, preserved tenant scope, truthful return-path handling, and tenant-filter reset back to the workspace-wide open register when the actor clears the prefilter.
  • T016 [P] [US2] Extend apps/platform/tests/Feature/Findings/FindingExceptionDetailDecisionSummaryTest.php to cover register-aware decision summary context on the detail page and confirm that current approve, reject, renew, or revoke actions remain the only mutation path.

Implementation for User Story 2

  • T017 [US2] Wire CanonicalNavigationContext through apps/platform/app/Filament/Pages/Governance/DecisionRegister.php and apps/platform/app/Filament/Resources/FindingExceptionResource/Pages/ViewFindingException.php so the detail page can return to the correct register scope and clearing a tenant prefilter restores the workspace-wide open register.
  • T018 [US2] Add any bounded detail-summary or back-link affordance needed in apps/platform/app/Filament/Resources/FindingExceptionResource/Pages/ViewFindingException.php and its supporting view or infolist seams so the detail page deepens the chosen decision, keeps diagnostics secondary, and avoids duplicating the workspace summary.

Checkpoint: User Story 2 is independently functional when the register chooses the current record and the current detail surface remains the only action owner.


Phase 5: User Story 3 - Keep Decision Truth Audit-Safe And Bounded (Priority: P2)

Goal: Ensure the register stays derived from the current decision history, audit trail, and evidence references without creating a second workflow state.

Independent Test: Verify that register rows derive from current decision history, recently closed rows remain bounded and show closure reason, and missing proof stays truthful without generating anything new.

Tests for User Story 3

  • T019 [P] [US3] Extend apps/platform/tests/Unit/Support/GovernanceDecisions/GovernanceDecisionRegisterBuilderTest.php to assert that current row state, the 30-calendar-day terminal-window eligibility, closure reason, and next action remain derived from append-only decision history only.
  • T020 [P] [US3] Add or extend apps/platform/tests/Feature/Findings/FindingExceptionDecisionRegisterBoundariesTest.php to prove that missing review or run proof does not trigger generation, hidden proof stays omitted, the 30-calendar-day recently-closed boundary is enforced, and no second register mutation path appears.

Implementation for User Story 3

  • T021 [US3] Reuse current FindingExceptionDecision, AuditLog, and evidence-reference truth in apps/platform/app/Support/GovernanceDecisions/GovernanceDecisionRegisterBuilder.php and any supporting detail-surface code instead of adding a second decision summary store.
  • T022 [US3] Expose related evidence and optional OperationRun links through existing helpers only when current proof exists, and render truthful absence when it does not.
  • T023 [US3] Review the implementation to confirm it introduces no new decision table, no generic workflow engine, no inline register mutation lane, no new run type, no new global search contract, no new panel or asset strategy, one dominant next action per row, diagnostics-secondary treatment, and no duplicate visible decision summary.

Checkpoint: User Story 3 is independently functional when the register remains derived, auditable, and bounded.


Phase 6: Polish & Cross-Cutting Validation

Purpose: Validate the bounded slice and stop before wider workflow growth appears.

  • T024 [P] Run export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Support/GovernanceDecisions/GovernanceDecisionRegisterBuilderTest.php.
  • T025 [P] Run export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Governance/DecisionRegisterPageTest.php tests/Feature/Governance/DecisionRegisterAuthorizationTest.php tests/Feature/Findings/FindingExceptionDecisionRegisterNavigationTest.php tests/Feature/Findings/FindingExceptionDetailDecisionSummaryTest.php tests/Feature/Findings/FindingExceptionDecisionRegisterBoundariesTest.php.
  • T026 [P] Perform one narrow browser or manual smoke on the register flow: open /admin/governance/decisions, apply a tenant filter, open a decision, confirm the existing detail actions, and return to the same register scope.
  • T027 [P] Run export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent for touched platform files.
  • T028 [P] Review touched code against docs/product/standards/list-surface-review-checklist.md and confirm Filament stays on Livewire v4, provider registration remains unchanged in apps/platform/bootstrap/providers.php, the register remains a native table or list surface, no globally searchable resource is added, and no new asset strategy appears.
  • T029 [P] Review touched code to confirm normal decision actions remain DB-backed and audit-tracked, no new OperationRun start path or queued notification family is introduced, and the slice does not widen into alerts, operations, or customer-facing decision workflows.

Dependencies & Execution Order

Phase Dependencies

  • Phase 1 (Setup): no dependencies; start immediately.
  • Phase 2 (Foundational): depends on Phase 1 and blocks all user stories.
  • Phase 3 (US1): depends on Phase 2 and establishes the register itself.
  • Phase 4 (US2): depends on Phase 2 and should ship with US1 so the new register is not a dead-end summary.
  • Phase 5 (US3): depends on Phase 2 and hardens the bounded-truth rules after the register contract exists.
  • Phase 6 (Polish): depends on all desired user stories being complete.

User Story Dependencies

  • US1 (P1): independently testable after Phase 2 and delivers the core register value.
  • US2 (P1): independently testable after Phase 2 and should ship with US1 so the register remains a truthful decision hub.
  • US3 (P2): independently testable after Phase 2 and protects the bounded architecture.

Within Each User Story

  • Write the listed Pest coverage first and make it fail for the intended gap.
  • Land the shared builder and page contract before widening navigation or detail-surface changes.
  • Re-run the narrowest affected validation command after each story checkpoint before moving on.

Implementation Strategy

Suggested MVP Scope

  • MVP = US1 + US2 together. The slice becomes meaningful only when the register exists and can open the current action-owning detail surface with preserved context.

Incremental Delivery

  1. Complete Phase 1 and Phase 2.
  2. Deliver US1 and US2 together.
  3. Add US3 boundary hardening.
  4. Finish with the focused validation and smoke path in Phase 6.

Team Strategy

  1. Settle the derived register builder and page contract first.
  2. Parallelize unit and feature coverage inside each story before runtime edits widen.
  3. Serialize merges around DecisionRegister, ViewFindingException, and any shared navigation helper so the launch and return language stays coherent.

Deferred Follow-Ups / Non-Goals

  • governance inbox launch integration
  • alerts, operations, and review follow-up as additional decision families
  • customer-facing decision awareness or delivery-pack follow-through
  • generic escalation hooks, assignment engines, or autonomous routing