Expand description
The sealed, content-addressed release plan — the read-only pre-image the human approves (ADR-0002 §3).
release plan computes and seals a plan_id; release cut --plan <plan_id>
executes it and refuses on repo drift. The binary never prompts: it plans
and exits at the approval boundary.
§What plan_id hashes (the content address)
build derives a ReleasePlan from the already-normalized contract and
detected repo facts, then content-addresses it. The plan_id is the
lowercase SHA-256 hex digest of a canonical JSON pre-image (serde_json,
whose struct-field and BTreeMap ordering is deterministic) covering
exactly, in this fixed order:
- a domain separator +
SEAL_VERSION— so aplan_idcan never collide with any other ossctl digest and the canonicalization format can be evolved by a deliberateSEAL_VERSIONbump instead of silently; - the contract-document
schema_version(ADR-0002 lists it explicitly); - the full normalized contract JSON (
contract show’s canonical output — every defaulted field, so any config change is drift; hashing the whole contract is deliberately fail-closed: a cosmetic change re-requires approval rather than risk missing a substantive one); - the git
HEADsha the plan was sealed against; - the chosen release version (the human’s bump — design §3.4);
- the resolved concrete target set — each target’s ecosystem, resolved
package name, registry, and adapter identity. Resolution overlays
facts-derived package names onto the contract’s (which may be
null), so a manifest rename is detectable drift even though the contract text is unchanged; - the phase sequence (constant per ADR-0002 §2 for a
--bump-less plan, so it never causes drift within a binary, but binding it authenticates the execution shape the approver saw and makes a future phase-model change aSEAL_VERSIONevent). A--bumpplan prepends abumpphase, which this field binds; - the engine-owned bump plan (
release-rust-workspace-multicratefacet 2/3), or absent.--bump <level>computes a new version from the current manifest version + the level and seals the deterministic edit set (computed version, intra-workspace pin rewrites, CHANGELOG-finalize intent, any declaredbump_hook). Omitted from the pre-image when absent (skip_serializing_if), so a--bump-less plan hashes byte-for-byte as it did before this field existed — the additive superset that made aSEAL_VERSIONbump unnecessary.
§Coordinator seam (what the sibling consumes)
The coordinator refuses a release cut --plan <id> on drift by re-deriving
current state and calling verify. It needs to persist only two plain
fields from an approved plan — plan_id and version — into its journal;
the approved ReleasePlan is otherwise reconstructed via build from
the journalled sealed inputs. The plan DTOs are therefore Serialize-only,
matching the repo-wide convention that the wire enums (Ecosystem/Registry
/Adapter) do not derive Deserialize (they collect-all-errors on parse).
The trust boundary is the local journal: an approved plan is one ossctl
itself wrote, not untrusted caller input.
§Out of this worker’s scope (handed to the coordinator)
- Working-tree cleanliness. The seal binds
HEAD, not uncommitted changes. Enforcing a clean tree / executing from a clean checkout of the sealed commit is an execution guard the coordinator owns (it needs a new read-onlyGitRepostatus port). Until then a dirty tree can publish code that differs from the sealed commit — an accepted, documented gap.
Adapter tool versions (accepted gap). ADR-0002 §3 names “resolved
adapter identities+versions”. The adapter registry (a sibling unit) is not
landed, so no adapter tool version (e.g. a pinned cargo-dist release) is
resolvable yet; today the address binds adapter identity (the enum). When
the registry lands, fold the resolved versions into the pre-image — a
deliberate schema_version-bumping change to what the address covers, never
a silent one.
Determinism: no wall-clock, no id-gen, no ordering-unstable map enters the
pre-image — identical (contract, facts, head, version) always yield the
same plan_id (proven in tests).
Structs§
- Plan
Drift - Why a
release cut --plan <plan_id>was refused: the current repo no longer hashes to the approved plan (ADR-0002 §3,plan_stale). - Unversioned
Target - A manifest-versioned target (
VersionSource::Manifest) whose resolved package has no detected manifest version infacts— the fail-closed row forversion-source-fail-closed-nonrust. - Version
Mismatch - One publishable target’s resolved package paired with the version its tree
manifest declares — the version the ecosystem’s publish command (
cargo publishreadingCargo.toml, …) would actually upload.
Enums§
- Version
Resolve Error - Why a single release version could not be resolved from the workspace manifest —
the single source of truth for the release version.
ossctl release cutpublishes the version already in the tree; there is no--versioninput to override it (release-drop-version-flag). - Version
Source - Whether a publish target derives its release version from a package manifest
the version guard can read, or has no manifest version by design — the capability
the fail-closed guard keys on (
version-source-fail-closed-nonrust).
Functions§
- build
- Build and seal a
ReleasePlanfrom an already-normalizedcontractand detectedfacts, at githead_sha, for the chosenversion. - build_
with_ bump - Build and seal a
--bumpReleasePlan: an engine-owned version-bump plan that computes a new version from the current manifest version + a semanticleveland owns the deterministic edit set (release-rust-workspace-multicratefacet 2). - compute_
plan_ id - Compute the content-addressed
plan_idof a--bump-less plan for(contract, facts, head_sha, version)without allocating a fullReleasePlan. - resolve_
release_ version - Resolve the release version from the workspace manifest — the single source of truth.
- verify
- Check whether an
approvedplan still matches the current repo state.