ADR 0014: Release and contract versioning

Status: accepted, 2026-10-07

Context

Keep Shipping has three contracts that people other than us bind to. The first is the ship.ks file format: a workflow someone wrote last month has to load in a binary released this week. The second is the StepKind trait plus the port traits a third-party step or adapter is written against (ADR 0002, ADR 0100) — a step compiled against one harness must refuse to run against a harness whose ports moved. The third is the TypeScript script-host protocol: an escape hatch step written in TypeScript talks to the host over a JSON contract (ADR 0013). None of the three was versioned as a public surface, so nothing told a step author which one they had written against and nothing stopped us changing one silently.

Cratefield — the harness Keep Shipping is modelled on (ADR 0200) — versions its module contract as a constant and generates a compatibility table from it. That is the model here.

STEP_API was not the gap: it already exists at crates/core/src/step.rs, and HarnessBuilder::build already refuses a step whose step_api() differs. What was missing is the other two constants, a written record of which port trait version is which, and any enforcement that a change to a port trait comes with a STEP_API bump. The pull-request template and CONTRIBUTING.md have both asked for "port contract changes have a changelog entry" since early on, with nothing behind the ask: the changelog had nowhere to live and no test would fail if it were skipped.

The release side has the same shape. There is no tag-triggered build, so "install Keep Shipping" means "build it from a commit", and there is no artifact whose origin a user can check.

Decision

Consequences