# Feature Specification: Review Pack PDF/HTML Renderer v1
**Feature Branch**: `356-review-pack-pdf-html-renderer-v1`
**Created**: 2026-06-05
**Status**: Implemented - close-ready after validation
**Type**: Productization / rendered review output / customer-safe report delivery
**Depends on**: Specs 263, 347, 349, 351, 355
**Runtime posture**: Reuse the current review-derived `ReviewPack` delivery contract. HTML rendering is required. PDF is allowed only if the repo already supports it from the same contract without adding a new package, a new `OperationRun`, or a second artifact family.
**Input**: Direct user-provided Spec 356 draft plus repo truth from the current review-pack export surfaces and Spec 355's documented follow-up queue.
## Dependencies And Repo-Truth Adjustments
- Spec 263 already introduced the current executive entrypoint (`executive-summary.md`) and delivery metadata inside the current review-derived pack. This spec must not reopen or duplicate that bundle-contract work.
- Current customer-safe detail surfaces already direct the reader to start with `executive-summary.md`, and the current review-derived pack is tenant-safe, auditable, and backed by the current signed-download seam.
- Current repo truth before this slice required a ZIP download and Markdown/JSON inspection. This branch adds the calm rendered HTML/print report while preserving the existing ZIP artifact.
- Spec 355 explicitly deferred this renderer until the operator/productization flow was browser-verified as coherent. Spec 355 is now commit-backed on `platform-dev`, so that prerequisite gate is satisfied.
- No dedicated repo-supported report PDF stack is present in the current application dependencies. PDF therefore remains deferred for this slice; the implementation stays HTML-first with browser print support and does not add a package or second rendering subsystem.
## Spec Candidate Check *(mandatory — SPEC-GATE-001)*
- **Problem**: TenantPilot can now produce customer-safe review packs and an executive-first Markdown entrypoint, but the externally deliverable output still feels like an internal ZIP artifact rather than a calm report a customer, executive, or demo stakeholder can open immediately.
- **Today's failure**: Even after Spec 263 and Spec 355, an operator still has to explain that the stakeholder should download a ZIP, open `executive-summary.md`, and ignore the structured JSON appendix unless deeper inspection is needed. That adds friction and weakens the product's demo- and handoff-quality story.
- **User-visible improvement**: An entitled user can open one rendered report from the current released review/current pack context, read the executive story first, understand evidence basis and limitations, and download a printable version when the repo can support it honestly.
- **Smallest enterprise-capable version**: Keep one released-review-bound `ReviewPack` artifact and the current export/download authority model. Add one deterministic HTML report over the existing contract, surface it through the current review/customer-workspace seams, and allow PDF only when it comes from the same render contract without new dependencies.
- **Explicit non-goals**: No new `AuditorPack` model or table, no new customer portal, no public share links, no email delivery, no AI summary generation, no branding or white-label system, no batch multi-review export, no second report engine, and no new review publication workflow.
- **Permanent complexity imported**: One bounded render layer, one or more read-only preview/download surfaces, localized copy updates, and focused Feature/Browser coverage. No new persistence family, no new queue family, no new capability family, and no second artifact taxonomy are allowed.
- **Why now**: Spec 355 explicitly named this as the next narrow follow-up once sellable-flow coherence was proven. The remaining gap is not another operator workflow foundation; it is the presentable customer/demo artifact.
- **Why not local**: A copy-only change or another Markdown file does not remove the ZIP-first friction. A customer portal or generic reporting engine overshoots the current repo truth.
- **Approval class**: Core Enterprise
- **Red flags triggered**: New rendered delivery surface and a conditional PDF branch. Defense: the slice stays derived from the current `ReviewPack` truth, forbids a new package or artifact family, and keeps PDF honest instead of forcing infrastructure.
- **Score**: Nutzen: 2 | Dringlichkeit: 2 | Scope: 2 | Komplexitaet: 1 | Produktnaehe: 2 | Wiederverwendung: 1 | **Gesamt: 10/12**
- **Decision**: approve
## Candidate Source And Completed-Spec Guardrail
- **Candidate source**:
- direct user-provided Spec 356 draft
- explicit deferred follow-up in `specs/355-platform-sellable-smoke-matrix/spec.md`
- current review-pack runtime truth in `ReviewPackService`, `GenerateReviewPackJob`, customer-review surfaces, and their tests
- **Completed-spec guardrail result**:
- `specs/263-auditor-pack-executive-export/` is treated as completed historical/runtime context because its task checklist is fully checked and its runtime/test traces are present; it must not be rewritten.
- `specs/347-*`, `349-*`, `351-*`, and `355-*` are dependency and proof context only and must not be normalized back into preparation wording.
- no `specs/1000-*` package existed before this Spec 356 run.
- **Close alternatives deferred**:
- `customer-review-workspace-v1-completion`: broader workspace productization lane; this renderer is the smaller output-first slice.
- `localization-v1-customer-facing-surfaces`: important follow-through, but it should not hide the output-format gap.
- `customer-portal-boundary-contract`: premature before the current output artifact is rendered and trustworthy.
- `decision-based-governance-inbox-v1`: separate operator-workbench lane, not delivery-format work.
- **Smallest viable implementation slice**: one current-review-bound HTML report plus truthful preview/download affordances on existing review/report surfaces; PDF only when the same render contract can produce it without new infrastructure.
## Spec Scope Fields *(mandatory)*
- **Scope**: canonical-view
- **Primary Routes**:
- existing workspace customer review registry at `/admin/reviews/workspace`
- existing environment review detail route under `EnvironmentReviewResource`
- existing review-pack detail route under `ReviewPackResource`
- existing signed review-pack download route `/admin/review-packs/{reviewPack}/download`
- one new read-only rendered-report route under the current `/admin/review-packs/{reviewPack}/...` family for preview/print delivery, while the current signed route remains ZIP-download-only
- **Data Ownership**:
- `EnvironmentReview`, `EnvironmentReviewSection`, `ReviewPack`, `EvidenceSnapshot`, `StoredReport`, `Finding`, `FindingException`, and `AuditLog` remain the only persisted truth used by this slice
- rendered HTML and any optional PDF remain derived from current review-pack/review truth; if implementation requires a new table, a new stored artifact family, or new DB columns, the scope must stop and split
- **RBAC**:
- workspace membership remains the first isolation boundary and stays `404` for non-members or out-of-scope environment/review targets
- current operator export initiation on published review detail continues to require the existing review-manage capability path used by `export_executive_pack`
- current in-scope review/review-pack view permissions remain authoritative for rendered preview/download
- this slice must not invent a new capability family for rendered delivery
For canonical-view specs, the spec MUST define:
- **Default filter behavior when tenant-context is active**: `CustomerReviewWorkspace` keeps the current managed-environment prefilter launch behavior. The rendered report remains anchored to the selected released review/current pack rather than any hidden shell/session state.
- **Explicit entitlement checks preventing cross-tenant leakage**: rendered preview/download is available only for entitled workspace and managed-environment scope through the current review/review-pack seams; inaccessible targets are omitted from aggregate lists and direct targeting resolves as not found.
## UI Surface Impact *(mandatory — UI-COV-001)*
Does this spec add, remove, rename, or materially change any reachable UI surface?
- [ ] No UI surface impact
- [x] Existing page changed
- [x] New page/route added
- [ ] Navigation changed
- [ ] Filament panel/provider surface changed
- [x] New modal/drawer/wizard/action added
- [ ] New table/form/state added
- [x] Customer-facing surface changed
- [ ] Dangerous action changed
- [x] Status/evidence/review presentation changed
- [ ] Workspace/environment context presentation changed
## UI/Productization Coverage *(mandatory when UI Surface Impact is not "No UI surface impact"; otherwise write `N/A - no reachable UI surface impact` plus rationale)*
- **Route/page/surface**:
- `CustomerReviewWorkspace` governance-package area
- `ViewEnvironmentReview` in customer-workspace mode
- `ReviewPackResource` detail/download surface
- one new read-only rendered report preview/print route under `/admin/review-packs/{reviewPack}/...`
- **Current or new page archetype**: existing customer-safe detail/report surfaces plus one rendered-report viewer route
- **Design depth**: Strategic Surface for customer-review workspace follow-through, released-review detail, review-pack detail, and rendered report preview
- **Repo-truth level**: repo-verified existing surfaces plus one new spec-backed rendered-report route in the current review-pack family
- **Existing pattern reused**: current governance-package truth, `ArtifactTruthPresenter`, current review-pack delivery contract, current customer-safe detail disclosure
- **New pattern required**: one bounded report-view pattern over the existing review-pack truth; no portal, dashboard, or second delivery family
- **Screenshot required**: yes; the rendered report and its launch path need browser-proof screenshots during implementation
- **Page audit required**: yes; the rendered report is a new reachable customer-facing surface
- **Customer-safe review required**: yes; this slice exists to improve customer/demo delivery without leaking internal detail
- **Dangerous-action review required**: no; the slice adds read-only delivery surfaces only
- **Coverage files updated or explicitly not needed**:
- [x] `docs/ui-ux-enterprise-audit/route-inventory.md`
- [x] `docs/ui-ux-enterprise-audit/design-coverage-matrix.md`
- [x] `docs/ui-ux-enterprise-audit/page-reports/...`
- [x] `docs/ui-ux-enterprise-audit/strategic-surfaces.md`
- [ ] `docs/ui-ux-enterprise-audit/grouped-follow-up-candidates.md`
- [x] `docs/ui-ux-enterprise-audit/unresolved-pages.md`
- [ ] `N/A - no reachable UI surface impact`
- **No-impact rationale when applicable**: N/A
- **Audit follow-through note**: implementation must update the Review Pack detail/page coverage so the current `UI-042` unresolved ledger entry no longer conflicts with the changed review-pack/report surfaces.
## Cross-Cutting / Shared Pattern Reuse *(mandatory when the feature touches notifications, status messaging, action links, header actions, dashboard signals/cards, alerts, navigation entry points, evidence/report viewers, or any other existing shared operator interaction family; otherwise write `N/A - no shared interaction family touched`)*
- **Cross-cutting feature?**: yes
- **Interaction class(es)**: download actions, preview/report viewers, delivery-status messaging, customer-safe disclosure, review-output guidance
- **Systems touched**: `CustomerReviewWorkspace`, `EnvironmentReviewResource`, `ViewEnvironmentReview`, `ReviewPackResource`, `ReviewPackService`, `GenerateReviewPackJob`, `ReviewPackDownloadController`, localization files, and the current review-pack/report truth presenters
- **Existing pattern(s) to extend**: current `ReviewPack` delivery contract, current `export_executive_pack` path, current signed download route, current customer-safe released-review detail block
- **Shared contract / presenter / builder / renderer to reuse**: `ReviewPackService`, `GenerateReviewPackJob`, `ReviewPackOutputReadiness`, `ArtifactTruthPresenter`, `EnvironmentReview` summary truth, current review-pack authorization/download seams
- **Why the existing shared path is sufficient or insufficient**: the existing path is sufficient for review anchoring, entitlement, export dedupe, audit continuity, and executive-summary truth. It is insufficient only because the current externally consumable output is still ZIP-first and Markdown-first.
- **Allowed deviation and why**: none. The slice must extend the current `ReviewPack` family and current review/report seams instead of creating a new report subsystem.
- **Consistency impact**: rendered copy, package-readiness wording, evidence-basis language, non-certification disclosure, and dominant next-action semantics must stay aligned across workspace rows, released-review detail, review-pack detail, and the rendered report.
- **Review focus**: reviewers must block any second artifact family, any live provider-data render path, any false PDF claim, or any duplicated summary language that competes with the current owner surfaces.
## OperationRun UX Impact *(mandatory when the feature creates, queues, deduplicates, resumes, blocks, completes, or deep-links to an `OperationRun`; otherwise write `N/A - no OperationRun start or link semantics touched`)*
- **Touches OperationRun start/completion/link UX?**: yes, reuse-only
- **Shared OperationRun UX contract/layer reused**: the existing `ReviewPackGenerate` start and completion flow reused by `export_executive_pack` remains the only run path
- **Delegated start/completion UX behaviors**: queued toast, already-available pack reuse, active-run dedupe messaging, current operation link continuity, and current terminal notification behavior remain on the shared review-pack export path
- **Local surface-owned behavior that remains**: preview/download of already-ready rendered output only; the renderer must not invent its own queued/run semantics
- **Queued DB-notification policy**: unchanged from the current review-pack export contract
- **Terminal notification path**: unchanged; the current `OperationRunCompleted` path remains authoritative
- **Exception required?**: none
## Provider Boundary / Platform Core Check *(mandatory when the feature changes shared provider/platform seams, identity scope, governed-subject taxonomy, compare strategy selection, provider connection descriptors, or operator vocabulary that may leak provider-specific semantics into platform-core truth; otherwise write `N/A - no shared provider/platform boundary touched`)*
N/A - no shared provider/platform boundary is widened. Provider-specific appendix content remains secondary and does not become the primary rendered language.
## UI / Surface Guardrail Impact *(mandatory when operator-facing surfaces are changed; otherwise write `N/A`)*
| Surface / Change | Operator-facing surface change? | Native vs Custom | Shared-Family Relevance | State Layers Touched | Exception Needed? | Low-Impact / `N/A` Note |
|---|---|---|---|---|---|---|
| Customer Review Workspace governance-package area | yes | Native Filament page plus shared review-package primitives | delivery status, launch actions, customer-safe disclosure | page, URL | no | Existing row-level `Open review` remains the list inspect model |
| Released review detail in customer-workspace mode | yes | Native Filament detail surface plus shared summary/artifact-truth primitives | package meaning, evidence basis, rendered output action hierarchy | detail, URL | no | One rendered-output action must not compete with diagnostics or proof links |
| Review Pack detail and rendered report preview/print surface | yes | Mixed native detail plus bounded custom report surface | evidence/report viewer, read-only output delivery | detail, route | no | The rendered report is read-only and derived from the current pack |
| Published review detail in operator mode | yes | Native Filament detail surface | current pack reuse, export/read-only follow-through | detail | no | Operator export remains current source-owned initiation path |
## Decision-First Surface Role *(mandatory when operator-facing surfaces are changed)*
| Surface | Decision Role | Human-in-the-loop Moment | Immediately Visible for First Decision | On-Demand Detail / Evidence | Why This Is Primary or Why Not | Workflow Alignment | Attention-load Reduction |
|---|---|---|---|---|---|---|---|
| Customer Review Workspace governance-package area | Primary Decision Surface | Decide whether the current released review is ready for stakeholder consumption | release/readiness state, limitations, dominant next step | deeper review detail and rendered report after explicit open | Primary because it remains the calm workspace handoff surface | stays on the existing review-consumption workflow | removes the need to explain ZIP mechanics first |
| Released review detail in customer-workspace mode | Secondary Context | Confirm what the rendered report will say and whether it is safe to open/download | executive-ready summary, evidence basis, current readiness, dominant output action | appendix detail, proof links, deeper governance sections | Secondary because the workspace owns the first selection decision | keeps delivery anchored to one released review | avoids duplicate workspace- and detail-level summaries |
| Review Pack detail and rendered report preview | Secondary Context | Inspect or download the current artifact in a presentable format | rendered report, limitation disclosure, appendix relationship | raw ZIP contents and technical metadata stay secondary | Secondary because the report is a delivery artifact, not the primary decision queue | stays on the current review-pack/report flow | removes unzip-plus-Markdown explanation work |
| Published review detail in operator mode | Secondary Context | Prepare or reuse the current pack before external handoff | export readiness and pack reuse status | run detail and review-pack detail after follow-up | Secondary because it is operator-only preparation, not customer-safe consumption | preserves current operator initiation flow | avoids adding a second operator export path |
## Audience-Aware Disclosure *(mandatory when operator-facing surfaces are changed)*
| Surface | Audience Modes In Scope | Decision-First Default-Visible Content | Operator Diagnostics | Support / Raw Evidence | One Dominant Next Action | Hidden / Gated By Default | Duplicate-Truth Prevention |
|---|---|---|---|---|---|---|---|
| Customer Review Workspace | operator-MSP, customer-admin, customer-read-only | release state, package readiness, rendered-report availability, next step | none beyond current review state | raw pack files, fingerprints, internal reasoning | `Open review` | raw/support detail stays off the list surface | workspace rows say whether the handoff is ready; detail owns the explanation |
| Released review detail in customer-workspace mode | operator-MSP, customer-admin, customer-read-only | rendered summary, evidence basis, limitation state, one output action | review lineage and deeper governance detail in secondary sections | raw payloads, fingerprints, platform reason family, internal reason ownership | `Open rendered report` or equivalent safe output action | appendix/raw detail stays secondary | the report intent is stated once and later sections add evidence |
| Review Pack detail and rendered report | operator-MSP, customer-admin, auditor-read-only | rendered story first, appendix relationship second, truthful availability | technical metadata and ZIP details remain secondary | raw JSON files, fingerprints, support-only interpretation | `Open rendered report` or `Download rendered report` | raw bundle detail remains lower priority | the rendered report explains the human-readable path once; ZIP metadata stays supportive only |
| Published review detail in operator mode | operator-MSP | export readiness, reuse truth, current pack availability | run detail and pack metadata after explicit follow-up | raw appendix files remain on the pack/resource seam | `Export executive pack` | customer-safe rendered copy stays off blocked/draft operator states | operator initiation does not duplicate customer-facing delivery text |
## UI/UX Surface Classification *(mandatory when operator-facing surfaces are changed)*
| Surface | Action Surface Class | Surface Type | Likely Next Operator Action | Primary Inspect/Open Model | Row Click | Secondary Actions Placement | Destructive Actions Placement | Canonical Collection Route | Canonical Detail Route | Scope Signals | Canonical Noun | Critical Truth Visible by Default | Exception Type / Justification |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Customer Review Workspace governance-package area | Dashboard / Workbench | Customer-safe workspace review hub | Open the released review that is ready for delivery | existing review-open inspect path | existing | supporting output actions stay off the list row | none | `/admin/reviews/workspace` | existing review detail route | workspace plus optional managed-environment filter | Customer review | whether the current released review is ready for a rendered handoff | none |
| Released review detail in customer-workspace mode | Detail / Report | Read-only detail report | Open the rendered report | sectioned detail with one dominant safe action | forbidden | appendix/proof links remain in-body secondary | none | `/admin/reviews/workspace` | existing review detail route | workspace, managed environment, released review | Governance package | what the rendered handoff means and whether it is available | none |
| Review Pack detail and rendered report | Detail / Report / Export Viewer | Read-only artifact viewer | Inspect or download the presentable output | detail then explicit report open | existing detail row click on pack list stays current | ZIP diagnostics and raw metadata stay secondary | none | current review-pack collection route | current review-pack detail and render route | workspace, managed environment, artifact state | Review pack / rendered report | rendered output readiness and appendix relationship | none |
| Published review detail in operator mode | Detail / Report / Export initiation | Operator export surface | Generate or reuse the current pack | existing detail/open model | existing | pack detail and run links remain secondary | none | existing review collection route | existing review detail route | managed environment, review status, pack status | Executive pack export | whether the current output can be prepared or reused now | none |
## Operator Surface Contract *(mandatory when operator-facing surfaces are changed)*
| Surface | Primary Persona | Decision / Operator Action Supported | Surface Type | Primary Operator Question | Default-visible Information | Diagnostics-only Information | Status Dimensions Used | Mutation Scope | Primary Actions | Dangerous Actions |
|---|---|---|---|---|---|---|---|---|---|---|
| Customer Review Workspace | MSP operator | Decide whether a released review is ready to hand over | Read-only workspace report | Is there a presentable current review I can share now? | release state, rendered-output availability, next step | none beyond secondary detail | release readiness, evidence sufficiency, package availability | none | Open review | none |
| Released review detail in customer-workspace mode | MSP operator or entitled customer reader | Understand and open the presentable report | Read-only detail report | What will the stakeholder read first, and what are the limitations? | executive summary, evidence basis, limitations, one output action | deeper governance detail, lineage, proof links | delivery readiness, evidence sufficiency, review status | none | Open rendered report / Download rendered report | none |
| Review Pack detail and rendered report | MSP operator or entitled reviewer | Inspect the current artifact in human-readable form | Read-only artifact viewer | Can I open a calm report from the current pack without unpacking it? | rendered report, appendix explanation, availability | ZIP metadata, fingerprints, technical context | artifact readiness, delivery status | none | Open rendered report | none |
| Published review detail in operator mode | MSP operator | Prepare or reuse the current pack | Export-initiation detail surface | Can I prepare the presentable output now, or is a current pack already available? | review status, reuse truth, pack availability | run detail and pack metadata | review status, pack availability | current `ReviewPackGenerate` only | Export executive pack | none |
## Proportionality Review *(mandatory when structural complexity is introduced)*
- **New source of truth?**: no
- **New persisted entity/table/artifact?**: no new persistence family; current `ReviewPack` remains the source artifact
- **New abstraction?**: no new cross-domain abstraction by default; any helper must stay local to current review-pack/report rendering
- **New enum/state/reason family?**: no
- **New cross-domain UI framework/taxonomy?**: no
- **Current operator problem**: the current output still requires ZIP-first explanation, which weakens customer/demo consumption even though the underlying review truth is already repo-real.
- **Existing structure is insufficient because**: the current Markdown entrypoint and JSON appendix are accurate but not directly consumable as a calm rendered report.
- **Narrowest correct implementation**: render one HTML report from current review-pack/review truth and only allow PDF when the same contract can produce it without new infrastructure.
- **Ownership cost**: maintain one bounded report view, one or more read-only routes/actions, and focused customer-safe regression coverage.
- **Alternative intentionally rejected**: a customer portal, a second report engine, or a new PDF dependency were rejected as broader than current-release truth requires.
- **Release truth**: current-release sellability follow-through, not future delivery automation.
### Compatibility posture
This feature assumes a pre-production environment.
Backward compatibility, legacy aliases, migration shims, historical fixture support, and compatibility-specific tests are out of scope unless explicitly required by this spec.
Current review-pack extension is preferred over a new delivery artifact family.
## Testing / Lane / Runtime Impact *(mandatory for runtime behavior changes)*
- **Test purpose / classification**: Feature, Browser
- **Validation lane(s)**: confidence, browser, `git diff --check`
- **Why this classification and these lanes are sufficient**: focused Feature tests can prove rendered contract truth, authorization, audit continuity, and honest PDF handling. One bounded browser smoke is justified because the rendered report is a customer-facing delivery surface.
- **New or expanded test families**: extend existing `apps/platform/tests/Feature/EnvironmentReview/`, `apps/platform/tests/Feature/ReviewPack/` including `ReviewPackResourceTest.php`, `apps/platform/tests/Feature/Reviews/`, and current customer-review browser smoke coverage
- **Fixture / helper cost impact**: low to moderate; reuse current released-review, review-pack, evidence-snapshot, and entitlement fixtures. No provider-sync, no new queue family, and no heavy-governance lane are needed.
- **Heavy-family visibility / justification**: none beyond one explicit browser smoke or an existing browser family extension
- **Special surface test profile**: shared-detail-family
- **Standard-native relief or required special coverage**: customer-workspace detail plus rendered report need explicit disclosure and action-hierarchy coverage; ordinary review-pack CRUD smoke is not sufficient
- **Reviewer handoff**: reviewers must confirm HTML is the mandatory floor, PDF is not falsely claimed, the renderer stays on the current `ReviewPack` family, and no second artifact family or new package appears
- **Budget / baseline / trend impact**: low feature-local increase only
- **Escalation needed**: `document-in-feature` if the repo cannot support PDF without a package and the slice lands HTML-only
- **Active feature PR close-out entry**: Smoke Coverage
- **Planned validation commands**:
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/EnvironmentReview/EnvironmentReviewExecutivePackTest.php tests/Feature/EnvironmentReview/EnvironmentReviewExplanationSurfaceTest.php tests/Feature/EnvironmentReview/EnvironmentReviewUiContractTest.php tests/Feature/Reviews/CustomerReviewWorkspacePackAccessTest.php tests/Feature/ReviewPack/EnvironmentReviewDerivedReviewPackTest.php tests/Feature/ReviewPack/ReviewPackDownloadTest.php tests/Feature/ReviewPack/ReviewPackResourceTest.php`
- `export PATH="/bin:/usr/bin:/usr/local/bin:$PATH" && cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Browser/Reviews/CustomerReviewWorkspaceSmokeTest.php`
## User Scenarios & Testing *(mandatory)*
### User Story 1 - Open A Calm Rendered Review Report (Priority: P1)
As an entitled operator or customer-safe reviewer, I want to open one calm rendered report from the current released review/current pack context so I do not have to unzip a package and explain Markdown/JSON files first.
**Why this priority**: This is the core productization gap. Without a rendered report, the output still feels like an internal artifact.
**Independent Test**: From the current customer-review/review-pack flow, open the rendered report and verify that executive story, evidence basis, limitations, findings, accepted risks, and non-certification disclosure are visible without raw diagnostics by default.
**Acceptance Scenarios**:
1. **Given** a released review with a ready current pack, **When** an entitled user opens the rendered output, **Then** the report shows the executive story, evidence basis, limitations, key findings, accepted risks, and appendix relationship from current stored truth.
2. **Given** a current pack whose output readiness is `partial`, `blocked`, or `expired`, **When** the user opens the owner surfaces, **Then** the product explains the limitation truthfully and does not overclaim a customer-ready rendered report.
---
### User Story 2 - Keep Printable Delivery Honest And Bounded (Priority: P1)
As an MSP operator, I want the same rendered contract to support a printable handoff path when the repo can do so honestly, but I do not want the product to promise PDF when current dependencies cannot support it safely.
**Why this priority**: A printable artifact is part of the draft's user value, but false PDF claims or a second rendering engine would create more debt than value.
**Independent Test**: Verify that the current review/review-pack flow exposes one rendered output contract, that HTML is always available, and that PDF is either supported from the same contract or truthfully unavailable without a dependency addition.
**Acceptance Scenarios**:
1. **Given** the repo can render PDF from the same contract without a new package, **When** an entitled user requests a printable version, **Then** the product serves PDF from the same underlying rendered report and does not introduce a second artifact family.
2. **Given** the repo cannot render PDF without adding a package, **When** an entitled user uses the output surfaces, **Then** the product still serves the HTML report and does not label PDF as available.
---
### User Story 3 - Keep Delivery Tenant-Safe, Auditable, And Derived (Priority: P2)
As a platform owner, I want rendered delivery to stay on the current entitlement, audit, and review-pack truth seams so the presentable report does not become a second uncontrolled export surface.
**Why this priority**: The sellability gain matters only if it stays on the current authorization and audit model.
**Independent Test**: Verify non-members receive `404`, in-scope viewers stay on the current read-only permission paths, and export/download/render actions keep the current audit and `OperationRun` boundaries.
**Acceptance Scenarios**:
1. **Given** a non-member or wrong-environment target, **When** they try to open the rendered report or current pack route, **Then** the response remains deny-as-not-found.
2. **Given** an entitled viewer, **When** they open the rendered report, **Then** the content is derived from existing review-pack/review truth and does not trigger live provider calls or a new queue/run path.
## Edge Cases
- A released review exists but no ready current pack exists yet: the owner surfaces stay truthful about unavailability and do not fabricate a rendered handoff action.
- The current pack is expired: the owner surfaces show `expired`, and the user must rely on the current operator export path rather than a stale rendered link.
- Evidence is partial or stale: the rendered report must carry the limitation state explicitly instead of reading as customer-safe ready.
- Workspace lifecycle blocks new pack generation but an existing ready pack remains readable: export stays blocked while current read-only access remains governed by existing entitlement rules.
- PDF support is absent in current repo dependencies: the feature must still ship HTML cleanly or stop at the documented HTML-only boundary without adding a package.
## Requirements *(mandatory)*
**Constitution alignment:** This feature reuses the current `ReviewPackGenerate` `OperationRun` path and current review-pack authorization/download seams. It must not introduce a second run type, a second artifact family, or live provider calls during render.
**Constitution alignment (PROP-001 / PERSIST-001 / BLOAT-001):** The rendered output must remain derived from current review/review-pack truth. If implementation requires a new table, a second persisted artifact family, or a new dependency-backed rendering engine, the scope fails and must split.
**Constitution alignment (XCUT-001):** Delivery status messaging, rendered report actions, and customer-safe disclosure must extend the current review/review-pack/report seams rather than introducing a parallel local UX language.
### Functional Requirements
- **FR-356-001**: The current review-derived `ReviewPack` remains the source artifact for this slice; no second artifact family may be introduced.
- **FR-356-002**: Operator-side export initiation for published reviews must continue to reuse the current `export_executive_pack` action and current `ReviewPackGenerate` `OperationRun` semantics.
- **FR-356-003**: The renderer must consume the current review-derived runtime truth exposed by `EnvironmentReview`, `EnvironmentReviewSection`, `ReviewPack`, current readiness semantics, and current governance-package summary truth. It must stay semantically consistent with the existing ZIP contract, including the current `executive-summary.md` and section ordering/content, without requiring archive re-parsing as the primary runtime source.
- **FR-356-004**: V1 must provide one rendered HTML report suitable for customer-safe and demo-ready consumption without requiring JSON inspection by default.
- **FR-356-005**: The HTML report must present executive story, evidence basis, limitation state, key findings, accepted risks, governance decisions requiring awareness, next actions, and explicit non-certification disclosure.
- **FR-356-006**: The rendered report must not expose raw provider payloads, fingerprints, internal reason ownership, platform reason families, or operator-only diagnostics by default.
- **FR-356-007**: The rendered output must remain anchored to one released review and one current review pack. No batch, portfolio, or multi-review delivery is allowed in v1.
- **FR-356-008**: `CustomerReviewWorkspace`, released-review detail, review-pack detail, and any render/download actions must keep readiness states truthful and must not imply rendered or PDF readiness when the current truth does not support it.
- **FR-356-009**: PDF is allowed only if the repo can generate it from the same rendered contract without a new package, a second render subsystem, or a second artifact family. Otherwise HTML remains the v1 floor and the product must stay honest about PDF unavailability.
- **FR-356-010**: Existing export/download audit events and metadata must be reused or minimally extended. A new renderer-specific audit family is out of scope.
- **FR-356-011**: This slice must not add a new panel, a new global-search surface, or a new Filament asset strategy.
- **FR-356-012**: This slice must not require live provider calls or Graph calls during render.
- **FR-356-013**: Report chrome and app actions must render outside the report canvas and must be hidden from print output so printed reports contain no operator/admin controls.
- **FR-356-014**: The rendered report must show a readiness-aware hero state at the top. Customer-safe labels may appear only when the stored review/pack readiness supports them; limited, internal, PII, blocked, or not-ready outputs must show an external-sharing warning.
- **FR-356-015**: The report must include a management-readable Executive Summary that explains overall state, reason, impact, recommended next action, and top limitations without making raw state keys the dominant copy.
- **FR-356-016**: Output limitations and evidence-basis copy must be human-readable, early in the report, and honest about shareability. Technical state fields may appear only in the supporting appendix.
- **FR-356-017**: Report localization must not leak raw `localization.*` keys in EN or DE, including the non-certification disclosure.
- **FR-356-018**: Empty or zero-heavy sections must collapse to compact empty-state copy instead of large KPI/card grids.
- **FR-356-019**: The appendix must appear after the management/readiness/risk/evidence sections, be clearly marked as supporting/auditor context, and avoid raw JSON dump presentation.
- **FR-356-020**: Accepted-risk content must use customer-safe summaries when available, must not expose internal rationale as customer-safe copy, and must honestly show expired/expiring/incomplete state without legal or approval claims.
- **FR-356-021**: Controlled MSP co-branding is limited to repo-backed existing workspace/environment names plus TenantPilot generated-by copy. No branding settings, upload UI, theme engine, or new persistence may be added.
- **FR-356-022**: Report/download labels must be readiness-aware and must not use forbidden terms such as customer-ready, certified, approved compliance report, or share-with-customer for limited/internal/blocked output.
- **FR-356-023**: The existing ZIP review-pack download/export contract must continue to work unchanged alongside the rendered HTML/print report.
## Scope Boundaries
### In Scope
- one rendered HTML report over the current review-derived `ReviewPack` contract
- truthful preview/download affordances on the current review/customer-workspace/report seams
- honest PDF handling from the same contract when current repo support exists
- localized copy required to explain rendered output, appendix relationship, and PDF availability truthfully
- focused authorization, audit, disclosure, and browser smoke follow-through for the rendered report
- bounded productization of report presentation, readiness copy, print chrome, localization, compact empty sections, supporting appendix, accepted-risk display, evidence-basis explanation, and repo-backed MSP co-branding slots
### Out Of Scope
- a customer portal
- a standalone `AuditorPack` or `RenderedReport` persistence family
- a new PDF dependency or rendering package
- email delivery, scheduled delivery, public sharing, or branding/white-label systems
- multi-review or multi-tenant bundles
- a second review composition engine
- AI-generated report narratives
- a branding admin UI, logo upload, accent/theme engine, customer-specific templates, public links, customer accounts, or customer portal
## Success Criteria
- Entitled users can open one rendered HTML report from current released-review/current-pack context without unzipping JSON first.
- The rendered output stays customer-safe, limitation-aware, and derived from current stored truth.
- PDF is either served from the same contract without new infrastructure or explicitly and honestly unavailable.
- No second artifact family, new package, new queue family, or live provider render path is introduced.
## Risks
- **Risk 1 - PDF support gap**: current repo dependencies do not provide an approved native report PDF stack for this slice. Mitigation: HTML and browser print are mandatory; native PDF remains a documented follow-up behind the hard no-new-package boundary.
- **Risk 2 - Scope creep into portal/reporting engine work**: presentable output can tempt broader document-delivery ambitions. Mitigation: stay on the current review-pack family and existing routes/surfaces only.
- **Risk 3 - Duplicate truth drift**: rendered copy could diverge from current review detail or executive-summary truth. Mitigation: keep one render contract sourced from current stored review-pack/review data.
- **Risk 4 - Customer-safe overclaim**: a rendered report can look more final than the underlying evidence state deserves. Mitigation: render limitation state and non-certification disclosure explicitly.
## Follow-Up Candidates
- PDF-only delivery hardening if HTML lands and the repo later gains an approved PDF stack
- richer customer-facing localization adoption over rendered delivery surfaces
- customer portal boundary work only after current rendered delivery is proven
## Assumptions
- Spec 355's browser-verified readiness gate is sufficient proof that the current review/output flow is coherent enough for a rendered delivery follow-up.
- Current `ReviewPack` and `EnvironmentReview` summary truth is rich enough to drive an HTML report without live provider calls.
- Implementation and productization changes are included in this branch; close readiness is based on completed validation, screenshots, and reviewer acceptance rather than additional preparation-only work.
## Open Questions
No blocking implementation questions remain.
Runtime constraint result:
- the current repo does not provide an approved native report PDF stack from the same render contract without a new dependency; the slice remains HTML-first with browser print and records native PDF as a bounded follow-up instead of widening scope