machine .toml source > generated view > drift gate

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.