Core store file
version.toml
The version and release ledger, at .working/toml/version.toml:
numbers, dates, spans, and digests, never prose.
About
One of three deliberately separated release artifacts: this ledger anchors the versioning,
the worklog holds every fact, and CHANGELOG.md tells the public story. The
ledger is the single source for the project's version; the root VERSION file is
deterministically generated from its latest release, as exact bytes, so the version can never
live in two hand-maintained places.
Why
When the version anchor, the detailed record, and the public story share a file, they tangle: editing the story risks the facts, and cutting a release risks the prose. Splitting them means each can be gated on what it actually is. The ledger's rows are append-only and immutable, so a release, once cut, is a fixed point everything else reconciles against.
Description
Two arrays of rows. Each [[release]] row records the SemVer version
(unique in the ledger), the RFC 3339 UTC date read from the clock at the release
event, the worklog_span (the inclusive, contiguous span of worklog entry IDs the
release covers), and a coverage_digest over the covered entries, computed at
release cut. Spans must tile: contiguous, non-overlapping, in ID order, so the unreleased
tail is everything after the last span. Each [[summary]] row backs one public
changelog entry: covers (a version, a range like 1.0.0..1.2.3, or
unreleased), status (working, published, or superseded), the freeze
digest once published, and superseded_by when a range rollup
replaced it. Summary rows hold digests and ranges only; prose lives in exactly one place, the
root CHANGELOG.md.
schema = 1 [[release]] version = "1.3.0" date = "2026-08-30T00:00:00Z" worklog_span = ["WL-89", "WL-131"] coverage_digest = "sha256:..." [[summary]] covers = "1.2.3..1.3.0" status = "published" digest = "sha256:..."
How it works
A release cut appends a row and freezes the covered worklog span; from then on any change to
those entries breaks the recorded digest and fails the gate. Publishing a changelog summary
records its freeze digest here; editing a published entry is therefore never silent, because
the changed bytes break the digest and the edit is structurally a re-publication. A fresh
store scaffolds an empty ledger (release = [], summary = []).
Generated view
Two deterministic renders: the root VERSION file (the latest release's version
as exact bytes, the one generated file that carries no header) and the optional human view
VERSION.md. Both are byte-drift-gated. The reference scaffold's pinned initial
view set declares VERSION.md; the root VERSION view row joins the
manifest where the adopter's release flow requires it (see the site note on tooling
status).
Value
One ledger, one version, everywhere: the drift gate makes a stale VERSION file a
reported failure, and the span-tiling rule means late attribution to a published release cannot
pass the gate, rather than being forbidden by policy.
Usage
- Created by:
opf init, empty. - Updated by: the release cut (a new append-only release row) and the changelog publish and rollup flow (summary rows and their digests).
- Read by:
opf render(the VERSION and VERSION.md renders); the changelog range-coverage and freeze gates;opf doctor(span tiling, frozen coverage digests, append-only history); release-delta tooling in the AIQT reference suite, as a consumer of the ledger.