Files
ss-tools/specs/025-clean-release-compliance/contracts/modules.md
2026-03-27 21:27:31 +03:00

21 KiB

Module Contracts: Clean Release Compliance Subsystem Redesign

Backend Domain Models Contract

[DEF:CleanReleaseDomainModule:Module]

@TIER: CRITICAL

@SEMANTICS: [clean_release, domain, lifecycle, immutability, evidence]

@PURPOSE: Define canonical clean release entities, lifecycle states and evidence invariants for candidate, manifest, run, report, approval and publication records.

@LAYER: Domain

@RELATION: DEPENDS_ON -> [DEF:TaskManagerModule]

@INVARIANT: Immutable snapshots are never mutated after creation; forbidden lifecycle transitions are rejected.

@PRE: Lifecycle commands reference existing candidate/report/publication identifiers when required.

@POST: State transitions are valid and terminal evidence remains readable.

@TEST_CONTRACT: CleanReleaseDomainModule -> {Input: lifecycle command + current aggregate, Output: updated aggregate or domain error}

@TEST_FIXTURE: candidate_state_machine -> INLINE_JSON {"candidate_id":"2026.03.09-rc1","status":"CHECK_PASSED"}

@TEST_EDGE: approve_without_passed_report -> reject transition

@TEST_EDGE: publish_without_approval -> reject transition

@TEST_EDGE: mutate_existing_manifest -> reject update

@TEST_INVARIANT: lifecycle_integrity -> VERIFIED_BY: [approve_without_passed_report, publish_without_approval, mutate_existing_manifest]

[/DEF:CleanReleaseDomainModule:Module]


Backend Clean Release Facade Contract

[DEF:CleanReleaseFacadeModule:Module]

@TIER: CRITICAL

@SEMANTICS: [clean_release, facade, orchestration, dto]

@PURPOSE: Expose one stable application facade for CLI, TUI, REST API and future Web UI over the clean release lifecycle.

@LAYER: Application

@RELATION: DEPENDS_ON -> [DEF:CandidatePreparationServiceModule]

@RELATION: DEPENDS_ON -> [DEF:ManifestServiceModule]

@RELATION: DEPENDS_ON -> [DEF:PolicyResolutionServiceModule]

@RELATION: DEPENDS_ON -> [DEF:ComplianceExecutionServiceModule]

@RELATION: DEPENDS_ON -> [DEF:ApprovalServiceModule]

@RELATION: DEPENDS_ON -> [DEF:PublicationServiceModule]

@INVARIANT: Interface adapters never bypass facade for business mutations.

@PRE: Incoming commands are validated and include actor context.

@POST: Returns DTOs with enough data for thin clients to render without local business recomputation.

@TEST_CONTRACT: CleanReleaseFacadeModule -> {Input: validated command, Output: CandidateOverviewDTO|ManifestDTO|ComplianceRunDTO|ReportDTO|ApprovalDTO|PublicationDTO}

@TEST_FIXTURE: facade_happy_path -> INLINE_JSON {"candidate_id":"2026.03.09-rc1","actor":"release-bot"}

@TEST_EDGE: missing_candidate -> returns explicit not-found error

@TEST_EDGE: illegal_transition -> returns transition error

@TEST_EDGE: missing_policy_snapshot -> returns trusted-source error

@TEST_INVARIANT: thin_client_boundary -> VERIFIED_BY: [missing_candidate, illegal_transition, missing_policy_snapshot]

[/DEF:CleanReleaseFacadeModule:Module]


Backend Candidate Preparation Service Contract

[DEF:CandidatePreparationServiceModule:Module]

@TIER: CRITICAL

@SEMANTICS: [clean_release, candidate, artifacts, preparation]

@PURPOSE: Register release candidates, import artifacts, validate artifact sets and progress candidates to PREPARED.

@LAYER: Application

@RELATION: DEPENDS_ON -> [DEF:CleanReleaseDomainModule]

@RELATION: DEPENDS_ON -> [DEF:CandidateRepositoryModule]

@RELATION: DEPENDS_ON -> [DEF:ArtifactRepositoryModule]

@INVARIANT: Candidate preparation does not run compliance checks or synthesize manifests implicitly.

@PRE: Candidate identifiers are unique and artifact payloads are structurally valid.

@POST: Candidate and artifact records are persisted and candidate status advances only through allowed states.

@TEST_CONTRACT: CandidatePreparationServiceModule -> {Input: candidate payload + artifacts, Output: candidate aggregate}

@TEST_FIXTURE: prepared_candidate -> INLINE_JSON {"candidate_id":"2026.03.09-rc1","artifacts":[{"path":"dist/app.whl","sha256":"abc"}]}

@TEST_EDGE: duplicate_candidate_id -> reject create

@TEST_EDGE: malformed_artifact_payload -> reject import

@TEST_EDGE: empty_artifact_set -> reject mark_prepared

@TEST_INVARIANT: candidate_input_integrity -> VERIFIED_BY: [duplicate_candidate_id, malformed_artifact_payload, empty_artifact_set]

[/DEF:CandidatePreparationServiceModule:Module]


Backend Manifest Service Contract

[DEF:ManifestServiceModule:Module]

@TIER: CRITICAL

@SEMANTICS: [clean_release, manifest, digest, immutability]

@PURPOSE: Build immutable manifest snapshots and return latest manifest views for candidates.

@LAYER: Application

@RELATION: DEPENDS_ON -> [DEF:CandidateRepositoryModule]

@RELATION: DEPENDS_ON -> [DEF:ArtifactRepositoryModule]

@RELATION: DEPENDS_ON -> [DEF:ManifestRepositoryModule]

@INVARIANT: Existing manifest versions remain immutable; rebuild creates a new version.

@PRE: Candidate exists and artifact set is valid for manifest generation.

@POST: New manifest digest is deterministic for the selected artifact set.

@TEST_CONTRACT: ManifestServiceModule -> {Input: candidate_id, Output: DistributionManifest}

@TEST_FIXTURE: manifest_rebuild -> INLINE_JSON {"candidate_id":"2026.03.09-rc1","manifest_version":1}

@TEST_EDGE: build_without_candidate -> reject request

@TEST_EDGE: build_with_changed_artifacts -> create new version

@TEST_EDGE: overwrite_existing_manifest -> reject mutation

@TEST_INVARIANT: manifest_snapshot_integrity -> VERIFIED_BY: [build_without_candidate, build_with_changed_artifacts, overwrite_existing_manifest]

[/DEF:ManifestServiceModule:Module]


Backend Policy Resolution Service Contract

[DEF:PolicyResolutionServiceModule:Module]

@TIER: CRITICAL

@SEMANTICS: [clean_release, policy, registry, trust_model]

@PURPOSE: Resolve active policy and source registry from trusted read-only stores into immutable snapshots.

@LAYER: Application

@RELATION: DEPENDS_ON -> [DEF:PolicySnapshotRepositoryModule]

@RELATION: DEPENDS_ON -> [DEF:TrustedPolicyStoreModule]

@INVARIANT: No interface-provided payload may alter resolved policy or registry contents.

@PRE: Requested profile exists in trusted store.

@POST: Returns immutable policy snapshot and linked registry snapshot.

@TEST_CONTRACT: PolicyResolutionServiceModule -> {Input: profile, Output: CleanPolicySnapshot + SourceRegistrySnapshot}

@TEST_FIXTURE: trusted_default_profile -> INLINE_JSON {"profile":"default"}

@TEST_EDGE: missing_profile -> reject request

@TEST_EDGE: registry_missing -> reject request

@TEST_EDGE: ui_override_attempt -> ignore override and fail validation

@TEST_INVARIANT: trusted_input_boundary -> VERIFIED_BY: [missing_profile, registry_missing, ui_override_attempt]

[/DEF:PolicyResolutionServiceModule:Module]


Backend Compliance Execution Service Contract

[DEF:ComplianceExecutionServiceModule:Module]

@TIER: CRITICAL

@SEMANTICS: [clean_release, compliance, task_manager, stages, report]

@PURPOSE: Create compliance runs, bind them to TaskManager, execute stage pipeline, persist stage results, violations and final reports.

@LAYER: Application

@RELATION: DEPENDS_ON -> [DEF:PolicyResolutionServiceModule]

@RELATION: DEPENDS_ON -> [DEF:StagePipelineModule]

@RELATION: DEPENDS_ON -> [DEF:ComplianceRepositoryModule]

@RELATION: DEPENDS_ON -> [DEF:ReportRepositoryModule]

@RELATION: DEPENDS_ON -> [DEF:AuditServiceModule]

@RELATION: DEPENDS_ON -> [DEF:TaskManagerModule]

@INVARIANT: A compliance request becomes exactly one run and at most one final immutable report.

@PRE: Candidate and manifest exist; trusted snapshots are resolvable.

@POST: Run state, stage records, violations and report are mutually consistent.

@POST: API-facing request method is non-blocking and returns run/task identifiers before stage completion.

@TEST_CONTRACT: ComplianceExecutionServiceModule -> {Input: candidate_id + manifest_id + actor, Output: ComplianceRunDTO or ComplianceReport}

@TEST_FIXTURE: blocking_run -> INLINE_JSON {"candidate_id":"2026.03.09-rc1","manifest_id":"man-001"}

@TEST_EDGE: run_without_manifest -> reject request

@TEST_EDGE: task_crash_mid_run -> final_status ERROR with preserved partial evidence

@TEST_EDGE: blocked_violation_without_report -> reject finalization

@TEST_INVARIANT: run_report_consistency -> VERIFIED_BY: [run_without_manifest, task_crash_mid_run, blocked_violation_without_report]

[/DEF:ComplianceExecutionServiceModule:Module]


Backend Stage Pipeline Contract

[DEF:StagePipelineModule:Module]

@TIER: STANDARD

@SEMANTICS: [clean_release, stages, pluggable_pipeline]

@PURPOSE: Provide pluggable compliance stages with deterministic ordering and structured results.

@LAYER: Domain

@RELATION: CALLED_BY -> [DEF:ComplianceExecutionServiceModule]

@INVARIANT: Mandatory stages execute in stable order unless run stops on terminal error policy.

@PRE: Compliance context contains candidate, manifest, policy snapshot and registry snapshot.

@POST: Each stage returns decision, violations and details without mutating trusted snapshots.

[/DEF:StagePipelineModule:Module]


Backend Approval Service Contract

[DEF:ApprovalServiceModule:Module]

@TIER: CRITICAL

@SEMANTICS: [clean_release, approval, gate]

@PURPOSE: Approve or reject candidates based on completed compliance reports.

@LAYER: Application

@RELATION: DEPENDS_ON -> [DEF:ReportRepositoryModule]

@RELATION: DEPENDS_ON -> [DEF:ApprovalRepositoryModule]

@RELATION: DEPENDS_ON -> [DEF:AuditServiceModule]

@INVARIANT: Approval is impossible without a valid PASSED report; latest approval decision governs publication gate.

@PRE: Candidate exists and referenced report belongs to the candidate.

@POST: Approval or rejection decision is persisted immutably; rejection blocks publication gate without mutating compliance evidence.

@TEST_CONTRACT: ApprovalServiceModule -> {Input: candidate_id + report_id + actor, Output: ApprovalDecision}

@TEST_FIXTURE: passed_report -> INLINE_JSON {"candidate_id":"2026.03.09-rc1","report_id":"rpt-001","final_status":"PASSED"}

@TEST_EDGE: approve_blocked_report -> reject request

@TEST_EDGE: approve_foreign_report -> reject request

@TEST_EDGE: duplicate_approve_terminal_state -> reject or preserve existing state deterministically

@TEST_EDGE: reject_then_publish -> publish remains blocked until a later valid approve

@TEST_INVARIANT: approval_gate_integrity -> VERIFIED_BY: [approve_blocked_report, approve_foreign_report, duplicate_approve_terminal_state, reject_then_publish]

[/DEF:ApprovalServiceModule:Module]


Backend Publication Service Contract

[DEF:PublicationServiceModule:Module]

@TIER: CRITICAL

@SEMANTICS: [clean_release, publication, revoke]

@PURPOSE: Publish approved candidates to target channels and revoke publications without deleting historical evidence.

@LAYER: Application

@RELATION: DEPENDS_ON -> [DEF:ApprovalServiceModule]

@RELATION: DEPENDS_ON -> [DEF:PublicationRepositoryModule]

@RELATION: DEPENDS_ON -> [DEF:AuditServiceModule]

@INVARIANT: Publication is impossible without candidate approval; revoke does not erase original publication record.

@PRE: Candidate is approved and report is the approved basis for publication.

@POST: Publication or revocation record is persisted immutably with channel and actor context.

@TEST_CONTRACT: PublicationServiceModule -> {Input: candidate_id + report_id + channel + actor, Output: PublicationRecord}

@TEST_FIXTURE: approved_candidate -> INLINE_JSON {"candidate_id":"2026.03.09-rc1","status":"APPROVED"}

@TEST_EDGE: publish_without_approval -> reject request

@TEST_EDGE: revoke_unknown_publication -> reject request

@TEST_EDGE: republish_after_revoke -> deterministic policy required

@TEST_INVARIANT: publication_gate_integrity -> VERIFIED_BY: [publish_without_approval, revoke_unknown_publication, republish_after_revoke]

[/DEF:PublicationServiceModule:Module]


Backend Audit Service Contract

[DEF:AuditServiceModule:Module]

@TIER: STANDARD

@SEMANTICS: [clean_release, audit, append_only]

@PURPOSE: Persist append-only audit events for release lifecycle and compliance execution.

@LAYER: Infra

@RELATION: CALLED_BY -> [DEF:CandidatePreparationServiceModule]

@RELATION: CALLED_BY -> [DEF:ManifestServiceModule]

@RELATION: CALLED_BY -> [DEF:ComplianceExecutionServiceModule]

@RELATION: CALLED_BY -> [DEF:ApprovalServiceModule]

@RELATION: CALLED_BY -> [DEF:PublicationServiceModule]

@INVARIANT: Audit records are append-only in real mode.

@PRE: Event context contains actor and operation identifiers.

@POST: One structured audit event is persisted per critical lifecycle mutation.

[/DEF:AuditServiceModule:Module]


Backend Repository Contracts

[DEF:CandidateRepositoryModule:Module]

@TIER: STANDARD

@SEMANTICS: [clean_release, repository, candidate]

@PURPOSE: Persist and query release candidates and candidate overview projections.

@LAYER: Infra

@INVARIANT: Candidate writes honor lifecycle guards defined in the domain module.

[/DEF:CandidateRepositoryModule:Module]

[DEF:ArtifactRepositoryModule:Module]

@TIER: STANDARD

@SEMANTICS: [clean_release, repository, artifacts]

@PURPOSE: Persist and query candidate artifacts with checksum metadata.

@LAYER: Infra

@INVARIANT: Artifact checksum/path records remain stable after import.

[/DEF:ArtifactRepositoryModule:Module]

[DEF:ManifestRepositoryModule:Module]

@TIER: STANDARD

@SEMANTICS: [clean_release, repository, manifest]

@PURPOSE: Persist immutable manifests and provide latest-version lookup.

@LAYER: Infra

@INVARIANT: Existing manifest versions are read-only.

[/DEF:ManifestRepositoryModule:Module]

[DEF:PolicySnapshotRepositoryModule:Module]

@TIER: STANDARD

@SEMANTICS: [clean_release, repository, policy_snapshot]

@PURPOSE: Persist immutable policy and registry snapshots used by runs.

@LAYER: Infra

@INVARIANT: Snapshot content cannot be mutated after persistence.

[/DEF:PolicySnapshotRepositoryModule:Module]

[DEF:ComplianceRepositoryModule:Module]

@TIER: STANDARD

@SEMANTICS: [clean_release, repository, run, stage, violation]

@PURPOSE: Persist compliance runs, stage records and violations.

@LAYER: Infra

@INVARIANT: Historical run evidence is append-only in real mode.

[/DEF:ComplianceRepositoryModule:Module]

[DEF:ReportRepositoryModule:Module]

@TIER: STANDARD

@SEMANTICS: [clean_release, repository, report]

@PURPOSE: Persist immutable compliance reports and support report lookup by run and candidate.

@LAYER: Infra

@INVARIANT: Completed reports remain immutable.

[/DEF:ReportRepositoryModule:Module]

[DEF:ApprovalRepositoryModule:Module]

@TIER: STANDARD

@SEMANTICS: [clean_release, repository, approval]

@PURPOSE: Persist immutable approval decisions and query latest decision state.

@LAYER: Infra

@INVARIANT: Approval decisions are historical facts, not mutable flags.

[/DEF:ApprovalRepositoryModule:Module]

[DEF:PublicationRepositoryModule:Module]

@TIER: STANDARD

@SEMANTICS: [clean_release, repository, publication]

@PURPOSE: Persist publication and revocation records.

@LAYER: Infra

@INVARIANT: Publication history is append-only.

[/DEF:PublicationRepositoryModule:Module]

[DEF:TrustedPolicyStoreModule:Module]

@TIER: STANDARD

@SEMANTICS: [clean_release, trusted_store, policy]

@PURPOSE: Abstract the trusted read-only source of policies and source registries.

@LAYER: Infra

@INVARIANT: Store reads are side-effect free for clean release operations.

[/DEF:TrustedPolicyStoreModule:Module]


Backend REST API Contract

[DEF:CleanReleaseApiContract:Module]

@TIER: CRITICAL

@SEMANTICS: [api, clean_release, async, dto]

@PURPOSE: Define HTTP contract for candidate lifecycle, manifests, compliance runs, approvals and publications.

@LAYER: Interface

@RELATION: DEPENDS_ON -> [DEF:CleanReleaseFacadeModule]

@RELATION: IMPLEMENTS -> [DEF:Std:API_FastAPI]

@INVARIANT: Long-running compliance execution endpoints are non-blocking and machine-readable.

@PRE: Request is authenticated and actor context is available.

@POST: Mutation endpoints return canonical DTOs or explicit validation/system errors.

@POST: Compliance run creation returns run_id and task_id without waiting for final completion; latest manifest may be resolved server-side when not explicitly provided.

@TEST_CONTRACT: CleanReleaseApiContract -> {Input: HTTP request, Output: JSON DTO or machine-readable error}

@TEST_FIXTURE: api_candidate_create -> INLINE_JSON {"candidate_id":"2026.03.09-rc1","version":"1.2.0"}

@TEST_EDGE: invalid_transition_http -> 409 conflict

@TEST_EDGE: missing_candidate_http -> 404 not found

@TEST_EDGE: invalid_input_http -> 422 validation error

@TEST_EDGE: reject_without_passed_report_http -> 409 conflict

@TEST_INVARIANT: api_contract_stability -> VERIFIED_BY: [invalid_transition_http, missing_candidate_http, invalid_input_http, reject_without_passed_report_http]

[/DEF:CleanReleaseApiContract:Module]


Backend CLI Contract

[DEF:CleanReleaseCliContract:Module]

@TIER: CRITICAL

@SEMANTICS: [cli, clean_release, headless]

@PURPOSE: Provide headless command-line access to candidate lifecycle, compliance, approval, publication and demo seed/reset flows.

@LAYER: Interface

@RELATION: DEPENDS_ON -> [DEF:CleanReleaseFacadeModule]

@INVARIANT: CLI exit codes distinguish passed, blocked, invalid input and system error outcomes.

@PRE: User provides explicit command arguments for business actions.

@POST: CLI emits human-readable output by default and JSON output when requested.

@TEST_CONTRACT: CleanReleaseCliContract -> {Input: argv, Output: stdout/stderr + exit code}

@TEST_FIXTURE: cli_run_json -> INLINE_JSON {"argv":["clean-release","compliance","run","--candidate-id","2026.03.09-rc1","--json"]}

@TEST_EDGE: cli_missing_manifest -> exit code 2

@TEST_EDGE: cli_blocked_run -> exit code 1

@TEST_EDGE: cli_system_error -> exit code 3

@TEST_INVARIANT: cli_headless_integrity -> VERIFIED_BY: [cli_missing_manifest, cli_blocked_run, cli_system_error]

[/DEF:CleanReleaseCliContract:Module]


TUI Thin Client Contract

/**

  • @TIER: CRITICAL
  • @SEMANTICS: [tui, thin_client, operator, live_status]
  • @PURPOSE: Render current clean release overview and trigger facade actions without owning business logic.
  • @LAYER: UI
  • @RELATION: DEPENDS_ON -> [DEF:CleanReleaseFacadeModule]
  • @INVARIANT: TUI never constructs policy, registry, manifest or fake run state locally.
  • @PRE: Running terminal has a valid TTY; candidate context is resolvable.
  • @POST: Operator can build manifest, run compliance, approve and publish only when transitions are valid.
  • @UX_STATE: Loading -> Candidate overview is refreshing and action keys are temporarily disabled.
  • @UX_STATE: Ready -> Candidate summary, latest manifest, latest run and latest report are visible.
  • @UX_STATE: Running -> Current stage and task/run progress are visible from real task events.
  • @UX_STATE: Blocked -> Violations list and blocking reason are visually dominant; approve/publish disabled.
  • @UX_STATE: Error -> Failure reason is explicit and no hidden retry occurs.
  • @UX_FEEDBACK: F5/F6/F8/F9 actions show immediate command acknowledgment and then refresh from persisted DTOs.
  • @UX_RECOVERY: Operator can refresh, inspect violations, rebuild manifest or rerun compliance after fixing candidate inputs.
  • @TEST_CONTRACT: CleanReleaseTuiApp -> {Input: keypress + facade DTOs, Output: rendered state + triggered facade action}
  • @TEST_FIXTURE: tui_ready_candidate -> INLINE_JSON {"candidate_id":"2026.03.09-rc1","status":"MANIFEST_BUILT"}
  • @TEST_EDGE: no_tty_environment -> refuse startup and redirect to CLI
  • @TEST_EDGE: missing_manifest_on_F5 -> inline blocking message
  • @TEST_EDGE: blocked_report_on_F8 -> approve action disabled
  • @TEST_INVARIANT: tui_thin_client_boundary -> VERIFIED_BY: [no_tty_environment, missing_manifest_on_F5, blocked_report_on_F8] */

Contract Usage Simulation (Key Scenario)

Scenario traced: operator runs compliance from TUI after building a manifest.

  1. CleanReleaseTuiApp requests CandidateOverviewDTO from CleanReleaseFacadeModule.
  2. Operator presses F5.
  3. CleanReleaseFacadeModule calls ComplianceExecutionServiceModule.request_run(...).
  4. PolicyResolutionServiceModule resolves trusted snapshots.
  5. ComplianceExecutionServiceModule creates a run, binds it to TaskManagerModule, returns run_id and task_id immediately.
  6. StagePipelineModule emits ordered stage results and violations.
  7. AuditServiceModule persists append-only events.
  8. ReportRepositoryModule persists immutable final report on terminal completion.
  9. TUI refreshes and renders persisted DTOs without local recomputation.

Continuity check: no interface mismatch found across facade, services and thin-client rendering path.