Skip to content
zit Artifact [503dd30dfc]
Login

Artifact [503dd30dfc]

Artifact 503dd30dfc3f609dee6d0b851d273aff393659f2751c5616567fcad3d4657cd0:


# zit 0.7.2

zit 0.7.2 closes the limit 0.7.1 named: a store no longer keeps a seed
that a peer sends it outside a seed announcement, so it can never serve
one on. The horizon draft states the rule. It fixes a seed date that
could move backwards and make a structural clone refuse a legitimate
re-seed. `zit info` also shows a horizon clone's horizon and the
origin's history URL, and `import-git` names branches that were merged
and deleted before it ran.

This release is from trunk. Stores are unchanged from 0.7.1.

## A received seed is never stored

A seed is private to the clone that holds it, and an origin sends one
only under a `horizon-seed` announcement, which a clone keeps outside
its artifact store. 0.7.1 refused a pushed seed, but an artifact of the
same shape arriving on a clone, pull or sync was stored as an ordinary
control artifact. zit never derived tags from it, but it could serve it
to other peers.

Now every receive path drops an artifact that carries the store's seed
label (`zit-seed`) or a `horizon-seed` binding card. The test is made on
the artifact's verified content when it is written, whether it arrived
in full or as a delta completed in a later round. A dropped artifact is
not counted among those received. An artifact sent as a delta against a
dropped one is stored in full. A control artifact under another label
and with no binding card is kept as before.

A zit origin writes pushed artifacts through the same path. It already
refuses a pushed seed before writing anything, and it drops a pushed
delta whose base it lacks, so a seed completed by a later push never
reaches it. The check stands behind both.

zit remembers what it dropped, in `.zit-cache/dropped-seeds`, and
never asks a peer for one of those again. The record is local and is
never synchronized; deleting it costs one re-fetch and a second drop.

## A seed's date never moves backwards

A clone refuses a seed dated earlier than the one it holds, since an
earlier one is a replay. 0.7.1 dated a seed at the latest of the tags it
records, so cancelling the newest of them, or reopening a closed
branch, produced a legitimate seed with an earlier date. The clone
refused it and fell back to the content horizon.

A seed is now dated at the latest tag event anywhere in the repository,
cancellations included. A tag event only replaces an older one, so that
time can only move forward. The seed's date now changes whenever any
tag in the repository changes, and the next pull or sync carries the
new seed, a few hundred bytes.

## `zit info` names the horizon

In a horizon clone, `zit info` now shows the horizon, and the history
URL when the origin gave one with `zit serve --horizon-url`:

```
horizon:      <full hash of C> (descendants, structural)
horizon-url:  https://forge.example/api/v1/r/x/history
```

The clone records the URL from the last reply that said which horizon
level it served, so it follows the origin if the URL changes.

## `import-git` names merged branches whose refs are gone

A Git branch merged and deleted before an import left its commits with
no ref to name them, so they read as the branch they forked from. A
mirror of a repository whose pull requests are merged and deleted within
minutes showed most of its work on trunk.

Now a run of commits that a merge brought in through a later parent, and
that no ref reaches, takes the branch the merge's message names. The
message must be GitHub's `Merge pull request #N from OWNER/BRANCH` or
git's `Merge branch 'BRANCH'`; with any other, the run stays where it
was. When no ref carries the branch any more, its tip is closed, so
`zit leaves` does not list it as live work.

A branch whose ref the source deletes between two `--into` imports keeps
its check-ins and loses its name, as before, and its last tip is now
closed when that check-in is on the branch. A name that only pointed at
another branch's check-in closes nothing.

Branches are recorded by control artifacts, never inside check-ins, so
check-in hashes do not change. Re-importing an existing mirror from its
Git source repairs its branch names and keeps every check-in hash.

## The horizon draft

`docs/rfcs/draft-fossil-horizon-00.txt` states the receive rule in
Section 5.2.3. It also states that a store which keeps a delta whose
base it lacks must not announce or serve that delta while it cannot be
expanded. Appendix C records the change.

## Test harness

The Fossil round-trip script stopped the subshell that started `zit
serve`, not the server, so each run left a server listening. It now
stops the server. Smoke scenarios that start a server on a fresh
loopback port try another port when the first is taken before the
server binds.

## Compatibility

Stores are unchanged from 0.7.1, in both directions. The derived cache
beside a store gains a column, so the first open under 0.7.2 rebuilds
it once; an older release rebuilds its own in turn.

A 0.7.2 origin's seeds are dated later than a 0.7.1 origin's for the
same state, so a 0.7.1 clone accepts them. A 0.7.1 origin keeps its old
dating, and a 0.7.2 clone of it still refuses a re-seed after a cancel,
falling back to the content horizon as 0.7.1 does. A store written by
an earlier release may hold a seed-shaped artifact. zit still skips it
when deriving, and a peer running 0.7.2 drops it on receipt.

On the wire 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](RELEASE-NOTES-0.1.0.md).