Implementing report profiles and disclosure policy as per spec 357. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #428
302 lines
12 KiB
Markdown
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.
|