# Versioning & drift

Two kinds of change exist on this surface and they never share a
channel. **Surface drift** is the toolkit evolving — new verbs, new
doors, better prose. **Normative drift** is the standard's own bytes
moving — a new official schema, a revised context document. The first
rides npm semver; the second rides sha256 pins that change only by
journaled human ruling. An agent audits both with commands, not diffs
of prose.

## The version, from the thing itself

```
$ npx epcis.dev version --json
{
  "package": "epcis.dev",
  "version": "0.1.0",
  "epcis": "2.0.1",
  "cbv": "2.0.1",
  "suite": "0.4.0"
}
```

Four version axes, deliberately separate: the npm package, the EPCIS
standard pinned, the CBV standard pinned, and the conformance suite.
The public registry agrees:

```
$ npm view epcis.dev@0.1.0 version dist.tarball
version = '0.1.0'
dist.tarball =
  'https://registry.npmjs.org/epcis.dev/-/epcis.dev-0.1.0.tgz'
```

## What is stable across releases

- **Exit codes** — `0` ok · `1` fail · `2` usage · `3` not-found ·
  `4` internal. A release that changed a meaning would be a breaking
  change under semver.
- **Error `code` strings** on stderr and `epcisException:*` types on
  every door. **Match on code, never on prose** — `title` and `detail`
  are worded for humans and may be rephrased in any release.
- **The verb set is closed.** A new verb is a minor release; a removed
  or reshaped verb is a major one.
- **`--json` output shapes.** Fields are added, never repurposed.

## What moves only by ruling

The five official GS1 artifacts are vendored bytes with sha256 pins —
[the pins page](/docs/conformance/pins/) lists them. The shipped
`vendor/gs1/PINS.json` states the law in its own first sentence:
*"Pins change only by journaled human ruling."* To detect normative
drift between two installs, diff the pins, not the prose:

```
$ npx epcis.dev pins --json | \
    node -e "let s='';process.stdin.on('data',d=>s+=d)
      .on('end',()=>{const p=JSON.parse(s).artefacts;
      for(const k in p)console.log(p[k].sha256,k)})"
3d33792c… openapi.json
0f46ff69… epcis-json-schema.json
5056c65f… epcis-context.jsonld
4b5583c9… query-schema.json
7db2547a… epcis-shacl.ttl
```

(Digests truncated for width; the full 64-hex values are on
[the pins page](/docs/conformance/pins/) and in the run's output.)

Two installs whose pin sets match produce byte-identical verdicts.
That is why the [CI page](/docs/conformance/ci/) says to pin the
package version: `npx -y epcis.dev@0.1.0` freezes both drift axes at
once.

## The journal is append-only about itself

The [launch journal](/journal/) follows the same law as the event
record it documents: **entries are never edited after their date — a
correction is a new entry** that names what it corrects. What you
cite from a dated entry stays citable; the fix arrives beside it, not
over it. The dated build-state ledger at
[/what-ships-today/](/what-ships-today/) is the authoritative
structured fact for what answers on this origin today — treat its
open column as open, not live.

Pin `epcis.dev@0.1.0`, match on codes, diff the pins, cite dated
entries. That is the whole drift contract.

---

**Proof, not adjectives.** This build could not verify the gateway's test suite green, so no sentence on this page claims a passing run — the last verified run is recorded in the repository's own CI, not here. Live on this origin, no key: POST /translate, /validate, /hash. No conformance attestation has ever been issued. The dated ledger is /what-ships-today/.
