Skip to main content

Module plan

Module plan 

Source
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:

  1. a domain separator + SEAL_VERSION — so a plan_id can never collide with any other ossctl digest and the canonicalization format can be evolved by a deliberate SEAL_VERSION bump instead of silently;
  2. the contract-document schema_version (ADR-0002 lists it explicitly);
  3. 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);
  4. the git HEAD sha the plan was sealed against;
  5. the chosen release version (the human’s bump — design §3.4);
  6. 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;
  7. the phase sequence (constant per ADR-0002 §2, 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 a SEAL_VERSION event).

§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-only GitRepo status 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§

PlanDrift
Why a release cut --plan <plan_id> was refused: the current repo no longer hashes to the approved plan (ADR-0002 §3, plan_stale).

Functions§

build
Build and seal a ReleasePlan from an already-normalized contract and detected facts, at git head_sha, for the chosen version.
compute_plan_id
Compute the content-addressed plan_id for (contract, facts, head_sha, version) without allocating a full ReleasePlan.
verify
Check whether an approved plan still matches the current repo state.