Artifact 436cd12dd922e287f259a86510c20c25549398ae15adf2197c8aa9f4ea999618:
- File docs/RELEASE-NOTES-0.7.1.md — part of check-in [236b7b4285] at 2026-10-24 04:12:10 on branch trunk — Horizons by name and depth; a labelled, bound seed an origin refuses on push; serve --horizon-url; 0.7.1 notes (user: dmestas, size: 6214) [annotate] [blame] [check-ins using]
zit 0.7.1
zit 0.7.1 lets a horizon clone name its horizon by branch, tag or tip
and step back from it, labels and binds the seed so it can be told
apart from any other control artifact and checked against the clone
that holds it, and lets a server advertise where history below a
horizon can be queried. The horizon draft carries each change.
This release is from trunk. Stores are unchanged from 0.7.0.
Named horizons and depth
zit clone URL [DIR] --horizon=NAME [--depth=N] [--horizon-rule=RULE] [--structural]
--horizon now also takes a branch name, a tag name, or tip for the
newest check-in. --depth=N moves the horizon N check-ins back along
first parents from the check-in the hash or name gives. When the chain
ends sooner, the horizon is the root, and the clone says so.
The origin resolves the name, and the clone records only the hash it answers, so later pulls stay pinned to that check-in even when the branch moves. The clone prints what the name resolved to. A name the origin cannot resolve ends the clone with nothing on disk:
zit clone: horizon name not found: feature-x; nothing was cloned
A name resolves to a full hash first, then to the most recent check-in carrying that branch or tag. A hash prefix is not a name. An origin that does not resolve names, such as stock Fossil or zit 0.7.0, serves the whole repository. The clone then resolves the name itself from what arrived, with the same rules, and keeps what the horizon keeps:
zit clone: the origin did not resolve --horizon=trunk; resolving it here from the transfer
CI that has the commit's hash should still pass the hash, so the clone is the commit being built even if the branch has moved since.
The seed is labelled and bound
A seed's U card is now zit-seed. Control artifacts the origin writes
for sharing, such as a divert's move, keep zit-serve, so the label
identifies a seed and nothing else. Every seed also carries a
horizon-seed T card naming the C and rule it was minted for. The card
is not applied as a tag.
A clone checks both before it holds a seed: the binding must name its own horizon and rule, and the seed's D card must not be earlier than that of the seed it holds. A seed that fails either check is refused, and the clone keeps the content horizon and says so:
zit pull: the origin's seed is not bound to this store's horizon check-in and rule; refusing it
A deepen discards the held seed, so the date floor starts again at the new horizon.
An origin refuses a pushed control artifact that carries its seed label
or a horizon-seed card. The test is made on the expanded artifact,
including a delta whose base arrives later in the same push. The whole
push is refused, with one error card:
seed refused: a seed is private to the clone that holds it; it is never pushed
zit itself never pushes its seed, and it never derives tags from an artifact that carries the seed label, whatever path brought it into the store.
zit serve --horizon-url
zit serve [--port N] [--fronted] [--horizon-url URL]
--horizon-url URL names where history below a horizon can be queried.
Every horizon-served pragma the server sends then carries URL, so a
horizon clone learns where to ask about what it does not hold. URL is
one token, and whitespace or a control character in it is a usage
error.
Updating a horizon clone
zit update to a check-in whose content lies outside the store's path
cone widens the cone under the same horizon from the saved remote. One
whose content lies below the horizon deepens to it. Both say what they
fetch. A requested cone that cannot be combined with the store's horizon
is refused and changes nothing.
When merge needs a branch below the horizon, it now suggests either
re-cloning with --horizon-rule=leaves or with an earlier --horizon.
Wire capabilities
A clone that names its horizon sends pragma horizon-name NAME RULE
DEPTH, in the first request only. Every later request carries pragma
horizon HASH RULE. An origin that implements it answers
pragma horizon-resolved HASH STEPS before any file card, where STEPS
is how far back the depth reached. A name it cannot resolve gets
error horizon\sname\snot\sfound:\sNAME. A malformed pragma gets
error malformed\shorizon-name\spragma. Authorization errors come
before either. horizon-served takes an optional URL after its level.
All of these are pragmas or replies to pragmas, which Fossil and zit 0.7.0 ignore or never see.
The horizon draft
docs/rfcs/draft-fossil-horizon-00.txt gains a section on named
horizons and depth, the seed label, the binding card and date floor,
the seed-signing namespace fossil-horizon-seed, and the origin's
refusal of a pushed seed. It also gains a requirement that an origin
judge a pushed delta once it becomes expandable, by whatever path.
Known limits
A store may keep a seed-shaped control artifact that a peer sends it on pull or clone. zit never derives its tags, but could serve it on to other peers. The fix is planned for the next release.
Compatibility
Stores are unchanged from 0.7.0, in both directions.
A 0.7.1 clone against a 0.7.0 origin works as before, with one
difference: the 0.7.0 origin's seeds carry no binding card, so a 0.7.1
structural clone refuses them and keeps the content horizon. A seed a
store already holds from 0.7.0 is still applied at open. A name passed
to --horizon against a 0.7.0 origin is resolved locally after a full
transfer.
A 0.7.0 structural clone of a 0.7.1 origin does not know the binding
card, so it applies it as a tag named horizon-seed on C. 0.7.1 skips
the card when it applies a seed.
On the wire to stock Fossil, nothing changes.
Qualification
The release manifest records native qualification against the exact tagged source archive on macOS ARM64, Linux x86-64 and Linux ARM64, using the pinned Zig 0.17.0 toolchain. Publication is gated on unit and end-to-end tests, Git differentials, deterministic simulation, seeded fuzzing, and Fossil interoperability checks on every distributed target.
For the basis of the conformance claim, see the 0.1.0 release notes.