TenantAtlas/specs/357-report-profiles-disclosure-policy-v1/plan.md
ahmido b7907bd69d feat: add report profile and disclosure policy to rendered review reports (#428)
Implementing report profiles and disclosure policy as per spec 357.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #428
2026-06-06 09:41:19 +00:00

302 lines
12 KiB
Markdown

# Implementation Plan: Spec 357 - Report Profiles & Disclosure Policy v1
**Branch**: `357-report-profiles-disclosure-policy-v1` | **Date**: 2026-06-05 | **Spec**: `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/357-report-profiles-disclosure-policy-v1/spec.md`
**Input**: Feature specification from `/Users/ahmeddarrazi/Documents/projects/wt-plattform/specs/357-report-profiles-disclosure-policy-v1/spec.md`
## Summary
Add a bounded report-policy layer to the current rendered review-report flow. The implementation should keep the current `ReviewPack` artifact and rendered report route, but introduce:
1. a static report-profile registry
2. a disclosure-policy evaluator with explicit proof states
3. profile-aware rendered-report composition and section filtering
The slice must stay static and read-only. It must not create new persistence, delivery flows, public links, PDF infrastructure, or AI/runtime expansion.
## Technical Context
**Language/Version**: PHP 8.4.15
**Primary Dependencies**: Laravel 12.52, Filament 5.2.1, Livewire 4.1.4, Pest 4.3
**Storage**: Existing PostgreSQL truth plus existing `exports` disk-backed `ReviewPack` artifacts only
**Testing**: Pest Unit, Feature, Browser
**Validation Lanes**: confidence, browser
**Target Platform**: Laravel Sail local runtime and existing Filament admin panel
**Project Type**: Laravel monolith with Filament admin surfaces
**Performance Goals**: No measurable render slowdown beyond current rendered report; no new remote calls during render
**Constraints**: No Graph/provider calls during render, no new persistence, no public route contract widening, no second artifact family
**Scale/Scope**: One existing report route and its owner surfaces, one static registry, one policy evaluator, focused regressions
## Repo Truth
Current repo-real seams:
- `apps/platform/app/Http/Controllers/ReviewPackRenderedReportController.php` already builds the rendered report payload.
- `apps/platform/resources/views/review-packs/rendered-report.blade.php` already renders HTML-first output.
- `apps/platform/app/Support/ReviewPacks/ReviewPackOutputReadiness.php` and `ReviewPackOutputResolutionGuidance.php` already derive readiness and limitation semantics.
- `apps/platform/app/Services/ReviewPackService.php` and `GenerateReviewPackJob` already anchor the current `ReviewPack` delivery contract.
- `docs/ui-ux-enterprise-audit/page-reports/ui-006-customer-review-workspace.md`, `ui-042-review-pack-detail.md`, and `ui-099-rendered-review-report.md` already document the affected strategic surfaces.
Current gap:
- There is no static report-profile registry.
- There is no first-class disclosure-policy result that distinguishes `verified`, `assumed`, `missing`, `unknown`, and `not_applicable`.
- The current renderer cannot express different audience/detail policies without ad hoc branching.
## Candidate Selection Gate
**Result**: PASS
- The candidate was directly provided by the user as a concrete Spec 357 draft.
- It aligns with current runtime truth after Spec 356 rather than reopening an older or completed foundation.
- Related specs 347, 355, and 356 are treated as historical/runtime context only.
- The scope is small and reviewable: static registry + disclosure policy + existing rendered-report integration.
- Broader alternatives such as billing, localization, customer portal, or AI remain explicitly deferred.
## UI / Surface Guardrail Plan
- **Guardrail scope**: changed existing customer/report surfaces
- **Affected routes/pages/actions/states/navigation/panel/provider surfaces**:
- `/admin/reviews/workspace`
- `/admin/workspaces/{workspace}/environments/{environment}/environment-reviews/{record}`
- `/admin/workspaces/{workspace}/environments/{environment}/review-packs/{record}`
- `/admin/review-packs/{reviewPack}/report`
- **No-impact class, if applicable**: N/A
- **Native vs custom classification summary**: mixed; existing native Filament owner surfaces plus the existing custom rendered-report Blade surface
- **Shared-family relevance**: report viewer, status messaging, artifact truth, customer-safe disclosure
- **State layers in scope**: detail route payload and existing owner-page derived payload; no shell or navigation contract change
- **Audience modes in scope**: customer/read-only, operator-MSP, controlled auditor, support/internal
- **Decision-first contract**: the rendered report must identify its audience, readiness, and limitations immediately before showing deeper section detail
- **Required tests or manual smoke**:
- explicit Unit tests for policy
- explicit Feature coverage for rendered report
- one bounded Browser smoke for profile variants and disclosure hierarchy
- **Active feature PR close-out entry**: `Guardrail / Exception / Smoke Coverage`
## Technical Approach
### 1. Keep everything inside the existing ReviewPack report family
Do not create:
- a new report persistence model
- a separate rendered artifact family
- a profile CRUD resource
- a delivery workflow
The current rendered report stays the single report route. The new logic should live inside `App\Support\ReviewPacks` and be consumed by the existing controller and owner surfaces.
### 2. Introduce a static report-profile registry
Preferred repo-aligned shape:
- `apps/platform/app/Support/ReviewPacks/ReportProfileRegistry.php`
- one static array-based contract or readonly value structure
- no database/config mutation path
Required implemented profiles:
- `customer_executive`
- `customer_technical`
- `internal_msp_review`
- `auditor_appendix`
Required placeholder:
- `framework_readiness` marked not implemented and not selectable for an implemented report
The registry must remain narrow and typed enough for tests, but must not become a generalized framework.
### 3. Introduce a disclosure-policy evaluator
Preferred repo-aligned shape:
- `apps/platform/app/Support/ReviewPacks/ReportDisclosurePolicy.php`
Inputs:
- selected effective profile
- current readiness / limitation truth
- evidence completeness state
- PII/internal-only state
- available source/disclosure metadata
Outputs:
- mandatory disclosures
- warnings
- blocking reasons
- proof states (`verified`, `assumed`, `not_applicable`, `missing`, `unknown`)
The evaluator must use stored truth only. No render-time provider or Graph calls.
### 4. Add one local rendered-report profile composition layer if needed
The current controller already builds a large report payload. If profile/disclosure integration makes that method unreviewable, introduce one local support layer under `App\Support\ReviewPacks` to compose:
- effective profile metadata
- filtered section list
- disclosure result
- appendix policy
- audience labels
This must stay local to the current rendered report. No cross-domain reusable viewer framework.
### 5. Keep profile selection bounded and authenticated
V1 defaults:
- default effective profile: `internal_msp_review`
- customer-facing or auditor-oriented variants remain authenticated and capability-gated
Preferred surface policy:
- the existing report route may accept a bounded authenticated profile selector only when the parameter is carried through the existing signed URL builders (`ReviewPackService::generateRenderedReportUrl()` and current owner-surface helper/action seams)
- existing owner surfaces may add at most one small group of safe "view report as ..." actions if that remains reviewable
- if action-surface growth is too large, keep selection route-local via those existing signed URL seams and test it directly
No unsigned query contract or share link may be introduced.
### 6. Mandatory truth overrides profile presentation
Profiles may influence:
- section inclusion
- appendix visibility
- detail level
- audience label
Profiles may not hide:
- readiness state
- evidence completeness / limitation state
- internal-only or PII warning
- non-certification disclosure
- generated/source metadata
### 7. Preserve current owner-surface boundaries
- `CustomerReviewWorkspace` remains the handoff surface
- `EnvironmentReviewResource` remains the released-review detail seam
- `ReviewPackResource` remains the artifact truth seam
- the rendered report remains read-only delivery output
Do not turn any of these into a profile management surface.
## Domain / Model Implications
- No new table, column, enum, or persisted artifact family is expected.
- `ReviewPack`, `EnvironmentReview`, `EnvironmentReviewSection`, and `EvidenceSnapshot` remain the only persisted truth used here.
- Disclosure proof states remain derived-only and request-scoped.
## Filament / Livewire Implications
- Livewire v4.1.4 compliance is required; no Livewire v3 APIs.
- Filament panel provider registration remains unchanged in `apps/platform/bootstrap/providers.php`.
- No global-search changes are expected. `ReviewPackResource` and related review surfaces keep their current search posture.
- Any new action affordances on owner surfaces must remain read-only and subordinate to the existing primary inspect/open model.
## OperationRun / Observability Implications
- No new `OperationRun` type is introduced.
- Existing review-pack generation/run-link behavior remains authoritative.
- Any profile or disclosure result should remain derivable from existing stored artifact truth and not require a new run or audit path.
## Authorization / Security Implications
- Existing workspace/environment entitlement and `Capabilities::REVIEW_PACK_VIEW` remain authoritative.
- Customer-facing profiles must not bypass internal-only or current-export guards.
- Invalid profile keys must fail closed.
- Non-members and out-of-scope records remain 404, missing capability remains 403.
## Data / Persistence Implications
- No migrations
- No new settings rows
- No new config-write path
- No new stored report or rendered artifact record
If implementation proves persistence is required, stop and split the scope.
## Test Strategy
### Unit
- registry shape and implemented/placeholder behavior
- disclosure proof-state evaluation
- invalid-profile fail-closed behavior
### Feature
- rendered report profile selection and profile metadata
- mandatory disclosures cannot be hidden
- customer profiles remain visibly limited on limited/internal output
- internal profile remains clearly internal when appropriate
### Browser
One bounded smoke file covering:
- internal MSP profile with limitations
- customer executive profile on limited output
- customer-safe profile on ready output
- auditor appendix profile
- invalid or placeholder profile behavior
### Regression
Keep existing rendered-report and review-pack tests green, especially Spec 347 and Spec 356 coverage.
## Rollout / Deployment
- No env vars
- No migrations
- No queue changes
- No scheduler changes
- No storage contract changes
- No `filament:assets` impact expected
## Risks And Controls
- **Risk**: profile system drifts into delivery or portal work
- **Control**: static registry only; explicit non-goals in tasks and checklist
- **Risk**: proof-state modeling becomes a fake certainty layer
- **Control**: explicit `assumed`/`verified` distinction and tests
- **Risk**: customer-facing profile hides limitations
- **Control**: mandatory disclosure override plus feature/browser assertions
- **Risk**: controller complexity grows too far
- **Control**: allow one local report-profile payload layer only if needed
## Implementation Phases
1. Repo-truth recheck and failing tests first
2. Static report-profile registry
3. Disclosure-policy evaluator with proof states
4. Rendered-report payload integration and section filtering
5. Owner-surface handoff and localization updates
6. UI-audit follow-through
7. Focused validation, browser smoke, and screenshots
## Spec Readiness Gate
**Result**: PASS
- `spec.md`, `plan.md`, and `tasks.md` are present.
- Scope is bounded to the current rendered report family.
- No open question blocks safe implementation.
- RBAC, isolation, disclosure truth, and customer-safe behavior are explicit.
- No new persistence or delivery workflow is required.
- Required checklist artifact is included in this spec package.
## Assumptions
- The current rendered report route remains the correct owner for profile-aware output.
- A bounded authenticated selection mechanism is sufficient for v1.
- Existing report/resource page reports can absorb the UI audit updates without inventing new page identities.
## Open Questions
- Whether owner-surface actions are necessary or whether the signed-URL-local profile selector is enough for v1
- Whether `auditor_appendix` should render as internal-only by default until a later delivery workflow spec
These are safe implementation decisions, not product blockers.