TenantAtlas/specs/259-compliance-evidence-mapping/data-model.md
ahmido 866875559f
Some checks failed
PR Fast Feedback / fast-feedback (pull_request) Failing after 1m4s
feat(specs/259): compliance evidence mapping (#312)
Implements platform feature branch `259-compliance-evidence-mapping`.

Target branch: `platform-dev`.

Follow-up integration path after merge:

`platform-dev` -> `dev`.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #312
2026-04-30 21:27:49 +00:00

341 lines
14 KiB
Markdown

# Data Model — Compliance Evidence Mapping v1
**Spec**: [spec.md](spec.md)
No new persisted table, report artifact family, or projection store is required for this feature. The implementation reuses current review, section, evidence, finding, accepted-risk, membership, and audit truth, then embeds one bounded interpretation contract inside the existing review payloads.
## Source Truth Reused
### Workspace / Tenant Entitlement Context
**Purpose**: Establish the active workspace boundary and entitled tenant set before any workspace row, released-review detail, or supporting evidence route is resolved.
**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 existing workspace session model
**Validation rules**:
- the actor must be a member of the current workspace or the request resolves as not found
- workspace rows and explicit tenant filters may only resolve for entitled tenants in that workspace
- out-of-scope tenant targets remain `404` and must not leak review or evidence presence
### CanonicalControlDefinition
**Purpose**: Existing provider-neutral control identity used as the anchor for every mapped customer-safe control summary.
**Carrier**: existing [../../apps/platform/config/canonical_controls.php](../../apps/platform/config/canonical_controls.php) loaded through [../../apps/platform/app/Support/Governance/Controls/CanonicalControlCatalog.php](../../apps/platform/app/Support/Governance/Controls/CanonicalControlCatalog.php)
**Relevant fields**:
- `control_key`
- `name`
- `domain_key`
- `subdomain_key`
- `summary`
- `control_class`
- `evaluation_strategy`
- `evidence_archetypes`
- `historical_status`
**Validation / usage rules**:
- canonical controls remain provider-neutral and customer-facing labels must continue to use the catalog's neutral names
- provider-specific Microsoft bindings stay internal resolution inputs only
- the interpretation overlay may add customer-safe readiness meaning, but it must not create a second control taxonomy
### Findings Summary Evidence Input
**Purpose**: Existing per-finding evidence basis that already resolves canonical control references and accepted-risk governance state.
**Persisted carriers**:
- existing `evidence_snapshots`
- existing `evidence_snapshot_items`
- existing `findings`
**Primary producer**: [../../apps/platform/app/Services/Evidence/Sources/FindingsSummarySource.php](../../apps/platform/app/Services/Evidence/Sources/FindingsSummarySource.php)
**Relevant fields / payload**:
- `EvidenceSnapshot.id`
- `EvidenceSnapshot.generated_at`
- `EvidenceSnapshot.expires_at`
- `EvidenceSnapshotItem.dimension_key = findings_summary`
- `summary_payload.entries[].id`
- `summary_payload.entries[].status`
- `summary_payload.entries[].severity`
- `summary_payload.entries[].terminal_outcome`
- `summary_payload.entries[].canonical_control_resolution`
- `summary_payload.entries[].governance_state`
- `summary_payload.entries[].governance_warning`
- `summary_payload.canonical_controls[]`
- `summary_payload.risk_acceptance`
**Validation / usage rules**:
- canonical control identity continues to come from the current upstream resolution path only
- the interpretation overlay should consume current governance-state and terminal-outcome values rather than inventing a second status source
- if the current payload is sufficient, upstream evidence collection remains unchanged
### FindingException / Accepted Risk Decision
**Purpose**: Existing accepted-risk and accountability truth that can weaken or qualify a customer-safe control interpretation.
**Persisted carrier**: existing `finding_exceptions` rows via [../../apps/platform/app/Models/FindingException.php](../../apps/platform/app/Models/FindingException.php)
**Relevant fields / relationships**:
- `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**:
- accepted-risk truth may qualify a control interpretation but must not collapse into a fully positive readiness claim
- missing owner, approver, or review-due truth must surface as explicit partial disclosure rather than fabricated certainty
- this slice remains read-only and does not introduce approval, renewal, or revocation actions
### TenantReview
**Purpose**: Existing released review artifact that anchors the shared interpretation contract for both workspace and detail surfaces.
**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`
- `operation_run_id`
- `tenant`
- `evidenceSnapshot`
- `sections`
**Planned embedded summary additions inside the existing `summary` JSON**:
- `control_interpretation.version`
- `control_interpretation.display_label`
- `control_interpretation.non_certification_disclosure`
- `control_interpretation.controls[]`
- `control_interpretation.limitations[]`
**Validation / usage rules**:
- only released reviews feed the default customer-safe workspace path
- the shared interpretation version must be carried at compose time so older released reviews preserve the meaning shown at publication time
- the workspace must read the embedded summary contract instead of recomputing the interpretation locally
### TenantReviewSection
**Purpose**: Existing detailed review section carrier used for the per-control explanation surface on the released review detail page.
**Persisted carrier**: existing `tenant_review_sections` rows via [../../apps/platform/app/Models/TenantReviewSection.php](../../apps/platform/app/Models/TenantReviewSection.php)
**Relevant fields**:
- `section_key`
- `title`
- `sort_order`
- `completeness_state`
- `summary_payload`
- `render_payload`
- `measured_at`
**Planned usage**:
- add one new v1 interpretation section inside the existing section family with the canonical `control_interpretation` section key
- keep the section near the top of the customer-workspace detail disclosure so mapped-control explanation precedes rawer supporting sections
**Planned embedded payload shape**:
- `summary_payload.version`
- `summary_payload.mapped_control_count`
- `summary_payload.follow_up_required_count`
- `summary_payload.limitation_counts`
- `render_payload.entries[]` containing detailed per-control explanations
**Validation / usage rules**:
- exactly one interpretation section should exist per review for v1
- the detail surface should read this section instead of deriving a second explanation contract in-page
- this remains part of the existing review artifact and does not create a new section table or entity family
### 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**:
- supporting proof remains optional, lower-priority, and capability-gated
- the overlay may summarize the evidence basis, but raw payloads and unrestricted diagnostics remain outside the default customer-safe path
- supporting evidence access should reuse the existing evidence route and audit action
### Audit Log Event Family
**Purpose**: Existing audit trail used to keep the displayed interpretation and access path traceable.
**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`
- `evidence_snapshot.opened`
**Planned shared metadata additions**:
- `source_surface`
- `interpretation_version`
- `review_id` when a released review is opened from the workspace
- `tenant_filter_id` when the workspace is entered with a safe prefilter
**Validation / usage rules**:
- no new audit store or audit event family is justified
- interpretation-version traceability should be added to shared metadata before introducing any new event concept
## Embedded Interpretation Contracts
### ControlInterpretationOverlayVersion
**Purpose**: The explicit version label that states which customer-safe interpretation rules produced the displayed control/readiness summaries.
**Persistence**: embedded in existing `TenantReview.summary` and the existing interpretation section payload; echoed in shared audit metadata when relevant
**Fields**:
- `version_key` (planned baseline: `compliance_evidence_mapping.v1`)
- `display_label`
- `non_certification_disclosure`
**Validation rules**:
- exactly one version key is carried for a given released review
- the version must be visible on workspace and detail surfaces whenever mapped control summaries are shown
### CustomerControlSummary
**Purpose**: Compact per-control summary reused by the workspace and as the top-level contract for the detail surface.
**Persistence**: embedded inside `TenantReview.summary['control_interpretation']['controls']`
**Fields**:
- `control_key`
- `control_name`
- `domain_key`
- `readiness_bucket`
- `limitation_flags[]`
- `customer_summary`
- `evidence_basis_summary`
- `accepted_risk_summary` (nullable)
- `recommended_next_action`
- `detail_anchor` (nullable)
- `supporting_finding_ids[]`
**Validation rules**:
- one summary exists per mapped canonical control for the released review
- the summary must stay customer-safe and must not expose provider IDs, raw JSON, or support-only diagnostics
- the same summary meaning must appear on the workspace and detail surfaces for the same released review
### CustomerControlExplanation
**Purpose**: Detailed per-control explanation rendered on the released-review detail surface.
**Persistence**: embedded inside the interpretation `TenantReviewSection.render_payload.entries[]`
**Fields**:
- `control_key`
- `control_name`
- `readiness_bucket`
- `limitation_flags[]`
- `explanation_text`
- `evidence_basis_items[]`
- `accepted_risk_context` (nullable)
- `recommended_next_action`
- `proof_access_state`
**Validation rules**:
- the detail explanation must be a denser expansion of the compact summary, not a second source of truth
- supporting evidence remains explicit drilldown, not default-visible raw detail
- the explanation must keep non-certification language visible and must not claim legal or framework attestation
### CustomerReviewWorkspaceEntry
**Purpose**: Derived row-level presentation contract for one entitled tenant with a released review on the workspace page.
**Persistence**: none; derived at request time from the latest released `TenantReview` and its embedded interpretation contract
**Fields**:
- `workspace_id`
- `tenant_id`
- `tenant_name`
- `latest_published_review_id`
- `latest_review_published_at`
- `interpretation_version`
- `control_summaries[]`
- `follow_up_summary`
**Validation rules**:
- exactly one derived entry exists per entitled tenant with a released review visible in the current workspace scope
- when no entitled tenant has a released review, the workspace falls back to a page-level empty state rather than emitting partial row contracts without a review
- the one dominant row action remains opening the released review; supporting proof stays secondary and is not a peer primary action on the row
### CustomerReviewDetailContext
**Purpose**: Derived detail-page contract for the existing released-review surface when launched from the workspace.
**Persistence**: none; derived from the released `TenantReview`, its interpretation section, and the current `customer_workspace` query flag
**Fields**:
- `review_id`
- `tenant_id`
- `customer_workspace_context` (boolean)
- `interpretation_version`
- `controls[]`
- `non_certification_disclosure`
- `operator_actions_hidden` (boolean)
- `supporting_evidence_collapsed_by_default` (boolean)
**Validation rules**:
- the detail page must stay read-only in customer-workspace context
- the same interpretation version and control meaning shown on the workspace must be visible here
- supporting evidence should remain explicit in-body drilldown rather than a new dominant header action
## Derived Disclosure States
This feature introduces no new platform-wide lifecycle family. It does require one bounded overlay-local readiness contract and explicit limitation flags.
### Primary readiness buckets
- `follow_up_required`
- `review_recommended`
- `evidence_on_record`
### Limitation flags
- `accepted_risk_influenced`
- `partial_mapping`
- `stale_evidence`
- `supporting_evidence_unavailable`
- `unmapped`
**Validation rules**:
- limitation flags qualify the customer-safe interpretation and must never be silently collapsed into `evidence_on_record`
- accepted risk remains a qualifier, not a passing state
- these values stay embedded in the interpretation contract only and do not become a broader platform taxonomy or standalone persistence family