Files
ss-tools/specs/025-clean-release-compliance/research.md
2026-03-09 16:52:46 +03:00

126 lines
6.5 KiB
Markdown

# Phase 0 Research: Clean Release Compliance Subsystem Redesign
## Decision 1: The subsystem becomes API/CLI-first and TUI becomes a thin client
**Decision**
Primary release operations are owned by application services and exposed through CLI and HTTP API first. TUI is retained only as a thin operator interface that reads state and triggers actions through the same facade.
**Rationale**
The current implementation mixes UI state with preparation, manifest creation and compliance execution. This blocks automation and makes behavior depend on the interface used.
**Alternatives considered**
- Keep TUI as primary orchestrator and add wrappers around it: rejected because it preserves hidden business logic inside the interface.
- Remove TUI entirely: rejected because operators still need an interactive console flow in enterprise environments.
---
## Decision 2: Policy and registry are trusted snapshots, never runtime UI/env payloads
**Decision**
Policy and source registry are resolved by a dedicated read-only resolution service from trusted stores, then frozen into immutable snapshots for each compliance run.
**Rationale**
The redesign explicitly separates trusted and untrusted inputs. Candidate input, artifacts JSON and operator choices are not allowed to define policy contents or final report outcomes.
**Alternatives considered**
- Continue using `.clean-release.yaml` and env bootstrap as policy source: rejected because it violates the new trust model.
- Let TUI construct policy in demo and real mode differently: rejected because it breaks evidence integrity and reproducibility.
---
## Decision 3: Manifest, report and snapshots are immutable; run history is append-only
**Decision**
`DistributionManifest`, `CleanPolicySnapshot`, `SourceRegistrySnapshot`, `ComplianceReport`, `ApprovalDecision` and `PublicationRecord` are immutable. `ComplianceRun`, `ComplianceStageRun`, `ComplianceViolation` and audit log are append-only once created; only non-terminal run fields may progress during execution.
**Rationale**
The main value of the subsystem is evidence integrity. Mutable manifest/report records make audit and publication safety unverifiable.
**Alternatives considered**
- Update manifest/report in place: rejected because historical evidence would be lost.
- Allow deleting old runs to keep storage small: rejected because real mode must preserve evidence.
---
## Decision 4: Release lifecycle is modeled as an explicit state machine
**Decision**
The candidate lifecycle is formalized as `DRAFT -> PREPARED -> MANIFEST_BUILT -> CHECK_PENDING -> CHECK_RUNNING -> CHECK_PASSED|CHECK_BLOCKED|CHECK_ERROR -> APPROVED -> PUBLISHED -> REVOKED`, with hard guards on forbidden transitions.
**Rationale**
Current logic spreads status changes across TUI and orchestration code. A formal state machine makes approval/publication gating deterministic and testable.
**Alternatives considered**
- Keep loose status updates per module: rejected because it produces hidden invalid states.
- Collapse all states into a smaller set: rejected because manifest, check and approval stages need separate audit visibility.
---
## Decision 5: Compliance execution is a pluggable stage pipeline integrated with TaskManager
**Decision**
Each compliance run becomes a `TaskManager` task. The run stores lifecycle metadata while stage logs are emitted as task logs or structured sub-events. The pipeline remains pluggable with stage-specific decisions and violations.
**Rationale**
The repository already has a mature async task lifecycle and reporting patterns. Reusing it reduces duplicated orchestration infrastructure and aligns with repository constitution.
**Alternatives considered**
- Keep synchronous orchestrator execution: rejected due to non-blocking API requirements.
- Build a second custom task subsystem inside clean release: rejected as redundant and harder to observe.
---
## Decision 6: Interfaces are split into CLI, REST API and thin TUI over one facade
**Decision**
A single `CleanReleaseFacade` exposes use cases for candidate overview, manifest build, compliance run, approval and publication. CLI, API and TUI all call the facade. Headless mode belongs to CLI/API only.
**Rationale**
A facade keeps interface code thin and prevents re-implementing business rules per entrypoint.
**Alternatives considered**
- Let each interface call lower-level services directly: rejected because state validation and DTO assembly would drift.
- Keep a headless branch inside TUI: rejected because headless is not a UI concern.
---
## Decision 7: Repositories are decomposed by responsibility, even if exposed through one internal facade
**Decision**
Persistence is split by bounded responsibility: candidate, artifacts, manifest, policy, compliance run, report, approval, publication and audit. A convenience facade may exist, but ownership remains explicit.
**Rationale**
The current `CleanReleaseRepository` is too broad for the redesigned evidence model. Explicit repository boundaries make append-only and immutable behavior easier to enforce.
**Alternatives considered**
- Keep one universal repository class: rejected because contracts stay ambiguous.
- Persist everything only through TaskManager: rejected because domain entities need direct retrieval independently of task history.
---
## Decision 8: Demo mode is preserved but isolated by namespace
**Decision**
Demo mode is handled by a dedicated demo service and isolated storage namespace. Demo runs, policies, candidates and reports never share identifiers or history with real mode.
**Rationale**
Demo mode remains useful for operator training, but it must not contaminate real compliance evidence.
**Alternatives considered**
- Simulate demo behavior inside real storage: rejected because it risks false evidence and operator confusion.
- Drop demo mode entirely: rejected because it removes a safe training path.
---
## Decision 9: Migration proceeds incrementally, starting by extracting services out of TUI
**Decision**
Migration starts by extracting build/run logic into new services/facade, then removes env-driven policy injection, then introduces immutable snapshots, then adds CLI/API contracts, and only after that thins the TUI.
**Rationale**
The current codebase already has working routes, models and tests. A big-bang rewrite would create unnecessary integration risk.
**Alternatives considered**
- Rewrite the whole subsystem at once: rejected because it is harder to validate incrementally.
- Patch TUI only: rejected because it does not solve the architectural problem.