Implementing report profiles and disclosure policy as per spec 357. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #428
12 KiB
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:
- a static report-profile registry
- a disclosure-policy evaluator with explicit proof states
- 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.phpalready builds the rendered report payload.apps/platform/resources/views/review-packs/rendered-report.blade.phpalready renders HTML-first output.apps/platform/app/Support/ReviewPacks/ReviewPackOutputReadiness.phpandReviewPackOutputResolutionGuidance.phpalready derive readiness and limitation semantics.apps/platform/app/Services/ReviewPackService.phpandGenerateReviewPackJobalready anchor the currentReviewPackdelivery contract.docs/ui-ux-enterprise-audit/page-reports/ui-006-customer-review-workspace.md,ui-042-review-pack-detail.md, andui-099-rendered-review-report.mdalready 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, andnot_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_executivecustomer_technicalinternal_msp_reviewauditor_appendix
Required placeholder:
framework_readinessmarked 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
CustomerReviewWorkspaceremains the handoff surfaceEnvironmentReviewResourceremains the released-review detail seamReviewPackResourceremains 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, andEvidenceSnapshotremain 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.
ReviewPackResourceand 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
OperationRuntype 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_VIEWremain 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:assetsimpact 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/verifieddistinction and tests
- Control: explicit
- 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
- Repo-truth recheck and failing tests first
- Static report-profile registry
- Disclosure-policy evaluator with proof states
- Rendered-report payload integration and section filtering
- Owner-surface handoff and localization updates
- UI-audit follow-through
- Focused validation, browser smoke, and screenshots
Spec Readiness Gate
Result: PASS
spec.md,plan.md, andtasks.mdare 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_appendixshould render as internal-only by default until a later delivery workflow spec
These are safe implementation decisions, not product blockers.