# Data Model: Clean Release Compliance Subsystem Redesign

**Feature**: [`025-clean-release-compliance`](specs/025-clean-release-compliance)  
**Spec**: [`spec.md`](specs/025-clean-release-compliance/spec.md)  
**Research**: [`research.md`](specs/025-clean-release-compliance/research.md)

## 1. Entity: ReleaseCandidate

Represents the release unit that is being prepared, checked, approved and published.

### Fields

| Field | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Stable candidate identifier. |
| version | string | Yes | Release version label. |
| source_snapshot_ref | string | Yes | Reference to code/source snapshot used to create candidate. |
| build_id | string | No | Upstream build or pipeline identifier. |
| created_at | datetime | Yes | Candidate creation timestamp. |
| created_by | string | Yes | Actor that created the candidate. |
| provenance_ref | string | No | Optional provenance or attestation reference. |
| status | enum | Yes | Current lifecycle state. |

### Validation Rules

- `id`, `version`, `source_snapshot_ref`, `created_at`, `created_by`, `status` must be present.
- `status` must be one of: `DRAFT`, `PREPARED`, `MANIFEST_BUILT`, `CHECK_PENDING`, `CHECK_RUNNING`, `CHECK_PASSED`, `CHECK_BLOCKED`, `CHECK_ERROR`, `APPROVED`, `PUBLISHED`, `REVOKED`.
- Terminal publication evidence cannot exist without a valid candidate.

### Lifecycle / State Transitions

- `DRAFT -> PREPARED`
- `PREPARED -> MANIFEST_BUILT`
- `MANIFEST_BUILT -> CHECK_PENDING`
- `CHECK_PENDING -> CHECK_RUNNING`
- `CHECK_RUNNING -> CHECK_PASSED`
- `CHECK_RUNNING -> CHECK_BLOCKED`
- `CHECK_RUNNING -> CHECK_ERROR`
- `CHECK_PASSED -> APPROVED`
- `APPROVED -> PUBLISHED`
- `PUBLISHED -> REVOKED`

---

## 2. Entity: CandidateArtifact

Represents one artifact associated with a release candidate.

### Fields

| Field | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Stable artifact identifier. |
| candidate_id | string | Yes | Owning release candidate. |
| path | string | Yes | Artifact path or logical location. |
| sha256 | string | Yes | Artifact checksum. |
| size | integer | Yes | Artifact size in bytes. |
| detected_category | string | No | Category determined by system or pipeline. |
| declared_category | string | No | Category declared by external input. |
| source_uri | string | No | Artifact source URI if known. |
| source_host | string | No | Parsed source host if known. |
| metadata | object | Yes | Additional attributes. |

### Validation Rules

- `sha256` must be present and stable for the artifact content.
- `size >= 0`.
- `declared_category` and `detected_category` may differ, but the difference must remain observable.

---

## 3. Entity: DistributionManifest

Immutable snapshot describing the candidate payload selected for distribution.

### Fields

| Field | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Stable manifest identifier. |
| candidate_id | string | Yes | Owning release candidate. |
| manifest_version | integer | Yes | Monotonic manifest version per candidate. |
| manifest_digest | string | Yes | Overall digest of manifest content. |
| artifacts_digest | string | Yes | Digest over artifact selection. |
| created_at | datetime | Yes | Manifest creation time. |
| created_by | string | Yes | Actor that built the manifest. |
| source_snapshot_ref | string | Yes | Source snapshot bound to the manifest. |
| content_json | object | Yes | Serialized immutable manifest content. |
| immutable | boolean | Yes | Must be `true` after creation. |

### Validation Rules

- `manifest_version >= 1` and strictly increases for a candidate.
- Existing manifest content cannot be overwritten.
- `manifest_digest` must uniquely reflect `content_json`.

---

## 4. Entity: CleanPolicySnapshot

Immutable policy snapshot used to evaluate a run.

### Fields

| Field | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Snapshot identifier. |
| policy_id | string | Yes | Logical policy identifier in trusted store. |
| policy_version | string | Yes | Trusted policy version. |
| created_at | datetime | Yes | Snapshot creation time. |
| content_json | object | Yes | Frozen policy content. |
| registry_snapshot_id | string | Yes | Bound source registry snapshot. |
| immutable | boolean | Yes | Must be `true`. |

### Validation Rules

- Snapshot must reference a valid registry snapshot.
- UI/env input cannot mutate `content_json` after creation.

---

## 5. Entity: SourceRegistrySnapshot

Immutable registry snapshot for allowed sources and schemes.

### Fields

| Field | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Snapshot identifier. |
| registry_id | string | Yes | Logical trusted registry identifier. |
| registry_version | string | Yes | Trusted registry version. |
| created_at | datetime | Yes | Snapshot creation time. |
| allowed_hosts | array[string] | Yes | Allowed hosts or host patterns. |
| allowed_schemes | array[string] | Yes | Allowed URL schemes. |
| allowed_source_types | array[string] | Yes | Allowed source type labels. |
| immutable | boolean | Yes | Must be `true`. |

---

## 6. Entity: ComplianceRun

Operational record for one compliance execution request.

### Fields

| Field | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Run identifier. |
| candidate_id | string | Yes | Candidate being checked. |
| manifest_id | string | Yes | Manifest used for the run. |
| manifest_digest | string | Yes | Manifest digest copied at request time. |
| policy_snapshot_id | string | Yes | Policy snapshot used. |
| registry_snapshot_id | string | Yes | Registry snapshot used. |
| requested_by | string | Yes | Actor that requested the run. |
| requested_at | datetime | Yes | Request time. |
| started_at | datetime | No | Execution start time. |
| finished_at | datetime | No | Execution finish time. |
| status | enum | Yes | Execution status. |
| final_status | enum | No | Final compliance result. |
| failure_reason | string | No | System or validation failure summary. |
| task_id | string | No | Linked async task identifier. |

### Validation Rules

- `status` must be one of `PENDING`, `RUNNING`, `SUCCEEDED`, `FAILED`, `CANCELLED`.
- `final_status`, when present, must be one of `PASSED`, `BLOCKED`, `ERROR`.
- `task_id` is mutable only until execution binding is established.

---

## 7. Entity: ComplianceStageRun

Stage-level execution record inside one run.

### Fields

| Field | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Stage run identifier. |
| run_id | string | Yes | Owning compliance run. |
| stage_name | string | Yes | Canonical stage name. |
| status | string | Yes | Stage execution status. |
| started_at | datetime | No | Stage start time. |
| finished_at | datetime | No | Stage finish time. |
| decision | string | No | `PASSED`, `BLOCKED`, or `ERROR`. |
| details_json | object | Yes | Structured stage details. |

---

## 8. Entity: ComplianceViolation

Violation produced by one stage within one run.

### Fields

| Field | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Violation identifier. |
| run_id | string | Yes | Owning compliance run. |
| stage_name | string | Yes | Stage that detected the issue. |
| code | string | Yes | Canonical violation code. |
| severity | string | Yes | Severity label. |
| artifact_path | string | No | Related artifact path. |
| artifact_sha256 | string | No | Related artifact checksum. |
| message | string | Yes | Human-readable explanation. |
| evidence_json | object | Yes | Structured evidence. |

### Validation Rules

- Violations cannot be deleted in real mode.
- `code`, `severity`, `message` must be present.

---

## 9. Entity: ComplianceReport

Immutable result derived from a completed run.

### Fields

| Field | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Report identifier. |
| run_id | string | Yes | Source compliance run. |
| candidate_id | string | Yes | Candidate checked by this run. |
| final_status | string | Yes | Final outcome. |
| summary_json | object | Yes | Structured summary of stages and violations. |
| generated_at | datetime | Yes | Report generation time. |
| immutable | boolean | Yes | Must be `true`. |

---

## 10. Entity: ApprovalDecision

Approval or rejection bound to a candidate and report.

### Fields

| Field | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Decision identifier. |
| candidate_id | string | Yes | Candidate being decided. |
| report_id | string | Yes | Report used as approval basis. |
| decision | string | Yes | `APPROVED` or `REJECTED`. |
| decided_by | string | Yes | Actor making the decision. |
| decided_at | datetime | Yes | Decision timestamp. |
| comment | string | No | Optional operator note. |

---

## 11. Entity: PublicationRecord

Publication or revocation record bound to a candidate.

### Fields

| Field | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Publication identifier. |
| candidate_id | string | Yes | Published candidate. |
| report_id | string | Yes | Approved report used as basis. |
| published_by | string | Yes | Publishing actor. |
| published_at | datetime | Yes | Publish time. |
| target_channel | string | Yes | Target release channel. |
| publication_ref | string | No | External publish reference. |
| status | string | Yes | Publication status label. |

---

## 12. Entity: CandidateOverviewDTO

Read model used by CLI, TUI and API to show current candidate state.

### Fields

| Field | Type | Required | Description |
|---|---|---|---|
| candidate_id | string | Yes | Candidate identifier. |
| version | string | Yes | Candidate version. |
| source_snapshot_ref | string | Yes | Source snapshot ref. |
| status | string | Yes | Current lifecycle status. |
| latest_manifest_id | string | No | Latest manifest identifier. |
| latest_manifest_digest | string | No | Latest manifest digest. |
| latest_run_id | string | No | Latest run identifier. |
| latest_run_status | string | No | Latest run execution status. |
| latest_report_id | string | No | Latest report identifier. |
| latest_report_final_status | string | No | Latest report final status. |
| latest_policy_snapshot_id | string | No | Latest policy snapshot identifier. |
| latest_policy_version | string | No | Latest policy version used for latest run. |
| latest_registry_snapshot_id | string | No | Latest registry snapshot identifier. |
| latest_registry_version | string | No | Latest registry version used for latest run. |
| latest_approval_decision | string | No | Latest approval decision affecting publication gate. |
| latest_publication_id | string | No | Latest publication identifier. |
| latest_publication_status | string | No | Latest publication status. |

---

## 13. Entity: ComplianceRunDTO

Read model for run status tracking.

### Fields

| Field | Type | Required | Description |
|---|---|---|---|
| run_id | string | Yes | Run identifier. |
| candidate_id | string | Yes | Candidate identifier. |
| status | string | Yes | Run execution status. |
| final_status | string | No | Final compliance result. |
| report_id | string | No | Final report identifier. |
| task_id | string | Yes | Linked task identifier. |

---

## 14. Entity: ReportDTO

Compact report view used by interfaces.

### Fields

| Field | Type | Required | Description |
|---|---|---|---|
| report_id | string | Yes | Report identifier. |
| candidate_id | string | Yes | Candidate identifier. |
| final_status | string | Yes | Final report result. |
| policy_version | string | Yes | Policy version used for the report. |
| manifest_digest | string | Yes | Manifest digest used for the run. |
| violation_count | integer | Yes | Number of violations. |
| generated_at | datetime | Yes | Report generation time. |

---

## 15. Relationships

- `ReleaseCandidate 1 -> N CandidateArtifact`
- `ReleaseCandidate 1 -> N DistributionManifest`
- `ReleaseCandidate 1 -> N ComplianceRun`
- `ComplianceRun 1 -> N ComplianceStageRun`
- `ComplianceRun 1 -> N ComplianceViolation`
- `ComplianceRun 1 -> 1 ComplianceReport` (for terminal runs that produce a report)
- `ComplianceReport 1 -> N ApprovalDecision` (history allowed, latest valid decision governs)
- `ReleaseCandidate 1 -> N PublicationRecord`
- `CleanPolicySnapshot 1 -> 1 SourceRegistrySnapshot`

## 16. Invariants

- Policy, registry, manifest, report, approval and publication snapshots are immutable after creation.
- Real mode compliance evidence is append-only and not user-deletable.
- `APPROVED` requires a valid `PASSED` report.
- `PUBLISHED` requires a valid approval.
- `REJECTED` is modeled as an immutable latest approval decision, not as a separate candidate lifecycle state.
- Demo namespace never shares identifiers or historical storage with real mode.

## 17. Scale Assumptions

- Candidate histories may accumulate multiple manifests and multiple compliance runs per release.
- A single run may produce many violations and stage details, so read models should not require loading all artifacts for each overview request.
- Most interface reads use latest-only summary views, while audit and compliance screens require full history retrieval.
