sigelo — versioning
Two things carry version numbers and they move independently: the wire (v inside every
signed object, SPEC §3.1) and the packages (npm, the Go module). An agent that adopts a
format that then changes under it does not come back, so the wire moves rarely and loudly.
1. The wire: sigelo/0
v is "sigelo/0". Verifiers reject any other value (invariant 7; SPEC §9 step 2). There is
no minor version and no negotiation: a bundle is sigelo/0 or it is not sigelo.
Before the freeze (today): the wire may change. Every change gets a CHANGELOG line
starting wire:, the commit hash, and at least one vector that fails on the old behaviour.
Frozen at tag v0.2. From then on, sigelo/0 means exactly SPEC.md and
test-vectors.json as they stand at that tag. The freeze needs 30 consecutive days with no
wire change first (ROADMAP R6); any wire change restarts the count. After it, a wire change
is sigelo/1 or it does not happen.
A breaking change is any of:
- a vector's expected output changes: a canonical string, a DID, a signature, a §9.1 result, or a negative's stated reason or outcome;
- a new mandatory field, or a field removed, retyped or made optional (SPEC §3.1 table);
- any change to what is rejected, or to which outcome a failure gets (SPEC §7.4: "not a candidate" versus REJECT; §9: fatal versus per-item discard);
- the signing input, the suite (invariant 2), an encoding (SPEC §2), or the precedence rule.
Not breaking, allowed after the freeze: spec prose that changes no outcome; a new vector for a rule the spec already states, provided both shipped implementations pass it unchanged (if one fails, the rule was ambiguous and fixing it is breaking); anything below the wire (keys, ceremony, keeper, adapters, MONERO.md) — those follow package semver.
2. Introducing sigelo/1
- A verifier accepts a set of wire versions and each bundle carries one. A bundle that mixes versions across its objects is malformed. No object carries a list.
sigelo/1gets its own SPEC and its own vector file;sigelo/0keeps its frozen ones.- A
sigelo/1verifier SHOULD also acceptsigelo/0for at least 12 months aftersigelo/1ships, and MUST report which version it verified (a §9.1 field insigelo/1). - Identities carry over by rotation: a
sigelo/0chain rotates into asigelo/1genesis. How, and whether asigelo/0recovery commitment governs it, is part of thesigelo/1spec and must be decided before anything else in it.
3. Test vectors
test-vectors.json is versioned with the wire, not the packages. Its spec field names the
wire ("sigelo v0.1 (wire sigelo/0)"). Every release records its SHA-256 in SHA256SUMS
(ROADMAP §5.5). After the freeze the file only grows, under §1's rule; nothing in it is edited.
It is regenerated from documented seeds by ts/src/gen_vectors.ts, and CI diffs the result.
4. Packages
Semver, per package: sigelo (ts), sigelo-spend, sigelo-agent, the Go module. Each
package states the wire versions it speaks. Until 1.0.0, a minor bump may break the package
API; it may never change the wire. A package that starts speaking sigelo/1 gets a new major.
The Go module's path is github.com/csigelo/sigelo/go in the public repository
(release/publish.sh rewrites the private tree's bare sigelo at export, T4). The module sits in
the repository's go/ directory, so Go resolves go install
github.com/csigelo/sigelo/go/cmd/sigelo-verify@v0.1.0 through the tag go/v0.1.0, not
v0.1.0: every release pushes both tags on the same commit. sigelo-verify releases carry
static binaries and a signed release object (ROADMAP §5.5).
5. Deprecation
A wire version is deprecated by a CHANGELOG entry and a date, never by code alone. Minimum
12 months from deprecation to removal from the reference verifier. The keeper's HTTP surface
and the sigelo-wallet lines (spend/README.md) are package API: a removed route, verb or
exit code is a major bump with one minor release of overlap that warns.
6. Dependency pinning
- Exact versions in every
package.json(no^, no~) and ingo.mod;go.sumcommitted; Go builds withGOFLAGS=-mod=readonlyand atoolchainline. - Lockfiles committed; CI installs with
npm ci --ignore-scripts, nevernpm install. - GitHub Actions pinned by commit SHA, with the tag in a comment.
- Renovate and Dependabot are off. Updates are manual: one dependency per commit, its
changelog read, the full vector run in both implementations before and after. Security
advisories are read by hand (GitHub advisory feed,
npm audit,govulncheck). - Runtime dependencies stay as CLAUDE.md lists them:
@noble/ed25519and@noble/hashesfor ts,filippo.io/edwards25519for Go.monero-wallet-rpcis pinned too (0.18.5.0, RPC 1.30) by the canary inspend/canary.ts.