# Data Model — Governance-as-a-Service Packaging v1

**Spec**: [spec.md](spec.md)

No new persisted table, artifact family, or package projection store is required for this feature. The package remains a derived management-ready view over current review, section, review-pack, evidence, stored-report, governance-decision, entitlement, and audit truth.

## Source Truth Reused

### Workspace / Tenant Entitlement Context

**Purpose**: Establish the active workspace boundary and entitled tenant set before workspace rows, released-review detail, package download, or supporting artifact links resolve.

**Persisted carriers**:
- existing workspace membership rows
- existing tenant membership pivot rows and role assignments
- existing capability registry and role-capability map

**Relevant fields / contracts**:
- `workspace_id`
- `tenant_id`
- workspace membership existence
- tenant membership role
- capability grants derived from [../../apps/platform/app/Support/Auth/Capabilities.php](../../apps/platform/app/Support/Auth/Capabilities.php)
- remembered tenant context from the current workspace session model

**Validation rules**:
- actors outside the current workspace or tenant scope resolve as not found
- package readiness is only aggregated for entitled tenants with eligible released reviews
- supporting artifact availability must not leak inaccessible tenant or review presence

### ReleasedReviewContext

**Purpose**: Existing tenant review that anchors all package content and package-access semantics.

**Persisted carrier**: existing `tenant_reviews` rows via [../../apps/platform/app/Models/TenantReview.php](../../apps/platform/app/Models/TenantReview.php)

**Relevant fields / relationships**:
- `id`
- `workspace_id`
- `tenant_id`
- `status`
- `generated_at`
- `published_at`
- `summary`
- `evidence_snapshot_id`
- `current_export_review_pack_id`
- `tenant`
- `evidenceSnapshot`
- `sections`

**Validation / usage rules**:
- only released reviews feed the management-ready package path
- the review remains the canonical package-owning context; package output must not become independent truth about review state
- existing `summary.control_interpretation`, `summary.highlights`, and related summary data remain the first reuse path for package meaning

### TenantReviewSection Family

**Purpose**: Existing released-review section set that already captures the management-relevant content needed for packaging.

**Persisted carrier**: existing `tenant_review_sections` rows via [../../apps/platform/app/Models/TenantReviewSection.php](../../apps/platform/app/Models/TenantReviewSection.php)

**Current section keys already relevant to packaging**:
- `executive_summary`
- `control_interpretation`
- `open_risks`
- `accepted_risks`
- `permission_posture`
- `baseline_drift_posture`
- `operations_health`

**Relevant fields**:
- `section_key`
- `title`
- `sort_order`
- `completeness_state`
- `summary_payload`
- `render_payload`
- `measured_at`

**Validation / usage rules**:
- package sections should be rendered from this current section family before any new payload is considered
- accepted-risk and governance-decision follow-up stays anchored to the current `accepted_risks` section and related persisted decision truth
- if implementation later needs a small additional helper field, it must stay embedded inside existing review payloads rather than creating a new package entity

### Shared Interpretation Summary

**Purpose**: Existing management-meaning layer from Spec 259 that translates technical review truth into calm customer-safe language.

**Primary producer**: [../../apps/platform/app/Support/Governance/Controls/ComplianceEvidenceMappingV1.php](../../apps/platform/app/Support/Governance/Controls/ComplianceEvidenceMappingV1.php) via [../../apps/platform/app/Services/TenantReviews/TenantReviewSectionFactory.php](../../apps/platform/app/Services/TenantReviews/TenantReviewSectionFactory.php) and [../../apps/platform/app/Services/TenantReviews/TenantReviewComposer.php](../../apps/platform/app/Services/TenantReviews/TenantReviewComposer.php)

**Current carriers**:
- `TenantReview.summary['control_interpretation']`
- `TenantReviewSection` with `section_key = control_interpretation`

**Relevant fields / payload**:
- interpretation version
- control readiness summaries
- evidence-basis summaries
- limitation and follow-up wording
- per-control entries rendered for deeper detail

**Validation / usage rules**:
- package meaning must remain dependent on this shared interpretation layer
- if the interpretation layer or version is unavailable, the package must show explicit partial or unavailable state and must not infer management meaning directly from raw findings or stored reports

### ReviewPack

**Purpose**: Existing packaged export artifact reused as the default package-delivery seam for stakeholder download.

**Persisted carrier**: existing `review_packs` rows via [../../apps/platform/app/Models/ReviewPack.php](../../apps/platform/app/Models/ReviewPack.php)

**Relevant fields / relationships**:
- `id`
- `workspace_id`
- `tenant_id`
- `tenant_review_id`
- `status`
- `expires_at`
- `summary`
- `options`
- `tenantReview`
- `evidenceSnapshot`

**Validation / usage rules**:
- the package path should prefer reusing `currentExportReviewPack` and its signed download route
- management-ready package access must not create a new review-pack generation run or a new package artifact family
- review-pack readiness, expiry, missing-input, and blocked states remain review-pack truth, not new package lifecycle state

### EvidenceSnapshot

**Purpose**: Existing supporting proof artifact that informs evidence-basis summaries and explicit deeper drilldown.

**Persisted carrier**: existing `evidence_snapshots` rows via [../../apps/platform/app/Models/EvidenceSnapshot.php](../../apps/platform/app/Models/EvidenceSnapshot.php)

**Relevant fields / relationships**:
- `id`
- `workspace_id`
- `tenant_id`
- `status`
- `completeness_state`
- `generated_at`
- `expires_at`
- `summary`
- `items`

**Validation / usage rules**:
- evidence remains supporting truth and must stay distinct from package summary truth
- default-visible package content may summarize the evidence basis, but raw evidence payloads remain secondary and capability-gated
- supporting proof access should reuse existing evidence routes and audit events

### StoredReport-backed Evidence Inputs

**Purpose**: Existing report artifacts that feed evidence dimensions and therefore indirectly support the package evidence basis.

**Persisted carriers**:
- existing `stored_reports` rows via [../../apps/platform/app/Models/StoredReport.php](../../apps/platform/app/Models/StoredReport.php)
- existing evidence-source seams such as [../../apps/platform/app/Services/Evidence/Sources/PermissionPostureSource.php](../../apps/platform/app/Services/Evidence/Sources/PermissionPostureSource.php) and [../../apps/platform/app/Services/Evidence/Sources/EntraAdminRolesSource.php](../../apps/platform/app/Services/Evidence/Sources/EntraAdminRolesSource.php)

**Relevant fields / contracts**:
- `StoredReport.id`
- `workspace_id`
- `tenant_id`
- `report_type`
- `fingerprint`
- current evidence-source `source_kind = stored_report`
- current evidence-source `source_record_id`

**Validation / usage rules**:
- stored reports remain subordinate source artifacts behind evidence and review truth
- the package may mention stored-report-backed evidence basis, but it must not default to raw report payloads or invent a new viewer shell in v1
- if no current entitled viewer seam exists, the package should prefer explicit unavailable or secondary context messaging over a new route

### GovernanceDecisionTruth

**Purpose**: Existing accepted-risk and exception decision truth that qualifies management-ready package claims and powers the narrowed `open decisions` meaning.

**Persisted carriers**:
- existing `finding_exceptions` rows via [../../apps/platform/app/Models/FindingException.php](../../apps/platform/app/Models/FindingException.php)
- existing `finding_exception_decisions` truth referenced by the current exception relationships

**Relevant fields / relationships**:
- exception `status`
- `current_validity_state`
- `owner_user_id`
- `approved_by_user_id`
- `request_reason`
- `review_due_at`
- `effective_from`
- `expires_at`
- `owner`
- `approver`
- `currentDecision`

**Validation / usage rules**:
- `open decisions` remains narrowed to this existing accepted-risk / exception decision truth only
- package wording may summarize accountable role or person, decision reason, follow-up, and validity timing where current product truth exists
- missing owner, approval, or timing truth must surface as explicit partial disclosure instead of invented certainty

### Audit Log Event Family

**Purpose**: Existing audit trail used to keep package access and supporting artifact consumption attributable.

**Persisted carrier**: existing `audit_logs` rows via [../../apps/platform/app/Services/Audit/WorkspaceAuditLogger.php](../../apps/platform/app/Services/Audit/WorkspaceAuditLogger.php)

**Relevant current action IDs**:
- `customer_review_workspace.opened`
- `tenant_review.opened`
- `review_pack.downloaded`
- `evidence_snapshot.opened`

**Validation / usage rules**:
- no new audit store or audit family is justified by default
- package access and supporting artifact access should reuse these events with shared metadata before introducing a new event concept

## Derived Contracts

### GovernancePackageSummaryProjection

**Purpose**: Conceptual derived package contract rendered from the released review and supporting artifacts.

**Persistence**: not persisted independently; derived from `TenantReview.summary`, existing section payloads, current review-pack truth, evidence truth, and governance-decision truth

**Fields**:
- `review_id`
- `tenant_id`
- `interpretation_version`
- `delivery_artifact_family = review_pack`
- `package_availability`
- `executive_summary`
- `top_findings[]`
- `accepted_risks[]`
- `governance_decisions[]`
- `evidence_basis_summary`
- `supporting_artifact_links[]`
- `calm_disclosure`

**Field boundary rules**:
- `accepted_risks[]` contains currently valid tolerated-risk positions that explain why a material issue is presently accepted and does not need immediate stakeholder follow-up beyond awareness.
- `governance_decisions[]` contains accepted-risk or exception decision entries that still require stakeholder awareness because they are expiring, expired, revoked, missing basis, or otherwise need follow-up.
- the same underlying accepted-risk or exception decision must not appear in both arrays for the same released review; if an entry qualifies for both, prefer `governance_decisions[]`.

**Validation rules**:
- the projection must not become independent product truth about review, evidence, pack, or governance state
- the downloadable artifact for v1 remains the current export review pack for the released review; the governance package summary is derived framing over that existing artifact, not a second export family
- package meaning must stay consistent between workspace summary, released-review detail, and package delivery for the same released review
- if implementation later needs a tiny helper shape, it must stay embedded inside current review/resource helpers rather than new persistence

### PackageAvailabilityState

**Purpose**: Derived explanation of whether the current released review can deliver the management-ready package now.

**Persistence**: derived from current review-pack truth, evidence basis completeness, interpretation availability, and entitlement state

**Planned values**:
- `available`
- `partial`
- `unavailable`
- `expired`
- `blocked`

**Validation rules**:
- these are presentation semantics only and must not become a new persisted lifecycle family
- stale or incomplete basis resolves through `partial` or `unavailable` reasons such as `stale_basis` or `evidence_basis_partial`, not a separate top-level state
- entitlement-restricted package access resolves through `blocked` or per-artifact `forbidden` semantics, not a separate top-level availability state
- reasons should remain attributable to the underlying review-pack, evidence, entitlement, or interpretation truth

**Canonical mapping from current artifact-truth seam**:

| Current repo truth | Package state | Reason-code guidance | Notes |
|---|---|---|---|
| `publicationReadiness = publishable` and current pack truth | `available` | `null` unless a secondary artifact has its own issue | The current export review pack is ready for stakeholder delivery. |
| `publicationReadiness = internal_only` or freshness `stale` while the summary is still readable | `partial` | `stale_basis` or `evidence_basis_partial` | Keep the management summary readable, but be explicit that the delivery basis is incomplete or stale. |
| `publicationReadiness = blocked`, `artifactExistence = not_created`, `contentState = missing_input`, or interpretation/source truth is not publishable | `unavailable` | `current_review_pack_missing`, `interpretation_missing`, or `source_not_publishable` | The package cannot be truthfully delivered now, so do not imply download readiness. |
| `artifactExistence = historical_only` or current pack expiry is the governing truth | `expired` | `current_review_pack_expired` | Historical exports stay attributable, but they are not the current stakeholder package. |
| In-scope actor lacks package entitlement to the released-review package path | `blocked` | `entitlement_restricted` | The package path itself is gated and must not render as deliverable. |
| Package summary is readable, but one supporting proof or artifact link is restricted | package state stays `available` or `partial` according to review-pack truth; affected secondary link becomes `forbidden` or `unavailable` | `supporting_access_limited` belongs on the supporting link message, not on the top-level package state | Keep package-level access and per-artifact access distinct. |

**Additional mapping notes**:
- repo directions such as `usable` stay inside `SupportingArtifactLink.state` and do not create a sixth package state
- repo directions such as `follow_up_needed` affect governance-follow-up wording and calm disclosure, not top-level package availability on their own

### GovernanceDecisionFollowUp

**Purpose**: Derived management-readable summary of accepted-risk / exception decisions that still need stakeholder awareness.

**Persistence**: derived from current exception and decision truth only

**Fields**:
- `decision_source`
- `decision_state`
- `decision_summary`
- `accountable_label` (nullable)
- `review_due_at` (nullable)
- `expires_at` (nullable)
- `follow_up_message`

**Validation rules**:
- follow-up entries must not imply a broader queue or workflow board
- only currently valid accepted-risk / exception decision truth may feed this projection

### SupportingArtifactLink

**Purpose**: Derived representation of optional proof and artifact drilldowns from the package.

**Persistence**: derived from current evidence, review-pack, and existing viewer availability

**Fields**:
- `artifact_family`
- `state`
- `label`
- `message`
- `url` (nullable)

**Validation rules**:
- links must point only to existing entitled surfaces
- if no current viewer seam exists for a stored-report-backed detail, the link stays unavailable rather than introducing a new route
- the package must not duplicate raw payloads when a secondary artifact link is unavailable