# zit 0.3.14

zit 0.3.14 makes a file's history cheap to ask for. `zit log CHECKIN PATH`
reconstructed a check-in manifest for every check-in it walked, so one file's
history on a mirror of SQLite took over two minutes and the cost grew with how
much unrelated history sat behind it. It now answers from an index the derive
was already computing and discarding.

No artifact, tag namespace, sync message, or on-disk format changed. The index
is a `.zit-cache` member: advisory, rebuilt from the log if deleted, and
answering nothing the log cannot.

## `log PATH` and `timeline -p`

Two defects, fixed in that order.

**The predicate asked twice.** It computed a check-in's effective content for
PATH once as the check-in and once as the primary parent of the check-in below
it, and each call re-read, re-verified and re-parsed the manifest because
`fileAt` took neither the walk's plaintext memo nor a baseline memo. Threading
both — and the answer itself, memoised by rid — took reconstructions per walk
from `2N-1` to exactly `N`. `timeline -p PATH` shared the defect and is fixed
with it.

**The predicate should not have been reconstructing at all.** zit already
computes each check-in's change set against its primary parent during the
derive (`ChangedFile` is Fossil's `mlink` row) and streams it to the
`crosslink` feed without keeping it. That fact, inverted by path, is now
persisted as `.zit-cache/finfo`, keyed to the log tail and the shun
fingerprint exactly like the cluster and disposition maps. The PATH walk
traverses the derived adjacency — as the unfiltered walk already does — and
the index narrows it.

| `log --long -n 50`, SQLite mirror (131,558 artifacts) | before | after |
|---|---|---|
| README.md | 72.20s | **1.58s** |
| src/btree.c | 24.88s | **1.11s** |
| manifest reconstructions (README.md) | 25,106 | **141** |

Output is byte-identical, checked per path rather than inferred.

**The index narrows; it does not decide.** `captureFileFacts` diffs at F-card
level, so a delta manifest that restates a path with the hash it already had
reads as a change there while the path's effective content did not move — one
check-in in 2,113 on btree.c's full history, an over-report and never an
omission. Every candidate the index names is therefore still confirmed by the
change predicate, which is what keeps the answer exact. `ZIT_NO_FILE_INDEX=1`
answers by reconstruction alone; an end-to-end test compares the two for every
tracked path so a regression cannot silently drop a file's history.

Building the index is a one-time pass over the check-ins (about 164s and
882 KB on the SQLite mirror) and happens on the first PATH query.

**What this does not fix.** About 0.7s of each figure above is opening the
repository, which is unchanged here and is now tracked on its own. A warm
process pays it once; a single CLI invocation pays it every time.

## `zig build cross`

A new gate step compiles the CLI for `x86_64-linux` and `aarch64-linux` and
runs nothing. This project links no libc and macOS links libc unconditionally,
so a call that demands libc builds on a developer's mac, passes every local
lane, and refuses on both Linux runners. That happened during this release's
development. `gate` depends on the new step; CI does not run it, because CI
compiles the real thing on all three targets it ships for.

## Compatibility

- No on-disk or wire format changed; Fossil RFC revision 00 remains the target.
- `.zit-cache/finfo` is a new cache member. Older zit ignores it, and deleting
  it costs one rebuild.
- No command or flag changed. `ZIT_NO_FILE_INDEX` is a diagnostic seam, not a
  supported interface.

## Qualification

`zig build test`, `e2e`, `smoke` (Fossil interop against a real `fossil`),
`muscle` (41 differential steps), `git-import-e2e`, `git-export-e2e`, `dst`,
and `cross`, plus the three-runner CI battery. The timings above are release
builds against the flat SQLite mirror; the before figures come from the
preceding binary run on the same store.
