# 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