# zit 0.3.3
zit 0.3.3 finishes what 0.3.2 started: no read verb walks the store for what
the derived state already knows. A full `zit timeline` of SQLite's history
went from 66.5 seconds to 0.37; `zit annotate`, which did not finish at all
on that history, answers in about a second for most files. Around the fixes
sits the thing that keeps them fixed: every manifest read is now counted,
and a regression test requires the count to stay flat as history grows.
No artifact, tag namespace, or sync message changed.
## timeline (zit#172)
The default-format timeline read and parsed a manifest per row. The fetch
condition still said "unless the format is oneline" from when oneline was
the default; 0.3.0 made `medium` the default for Fossil parity, and from
that day every row inflated a manifest for two strings — comment and login —
that the state carries. Nothing failed; the verb just grew with the store.
Full timeline of SQLite (131,558 artifacts, 44,581 lines, 4.7MB): 66.5s to
**0.37s**, byte-identical output, level with `fossil timeline`'s 0.34s.
A manifest is read only where its file cards are needed: `full`, `-v`, and
a path filter.
## annotate (zit#172)
Worse still: annotate materialized PATH's content for **every ancestor of
the tip** — a manifest read and a blob read each, then a full-file line
diff per ancestor — ~36,000 of everything on SQLite where ~400 check-ins
touched a typical file. Killed after four minutes without an answer.
Three changes, each preserving the one house line-diff core:
- The cache's records already say which check-ins changed PATH (each
record's file list is the diff against its primary parent, so "not
listed" means byte-equal there). One sequential scan builds the set;
untouched ancestors inherit the parent's content pointer outright.
- A node whose content IS its parent's slice resolves to the parent's
origins without a diff.
- The LCS matches the common prefix and suffix directly and runs its
O(n×m) table on what remains — two adjacent 15k-line versions were 225
million cells for a three-line change.
| `annotate`, full SQLite history | 0.3.2 | 0.3.3 | fossil |
|---|---|---|---|
| VERSION | killed, >4min | 1.2s | 0.04s |
| README.md | — | 0.5s | 0.03s |
| src/shell.c.in (15k lines, heavily edited) | — | 57s | 2.3s |
The honest residue: a version that edits lines near both ends of a large
file still pays a quadratic middle, which is the whole remaining gap on
shell.c.in. The remedy is a real diff core (Myers or anchor-recursion),
which touches merge conflict resolution and gets its own careful change
rather than a ride-along. One visible delta now: when a repeated line
(usually a blank one) could equally have come from two origins, the
attribution may pick the other equally-valid one than 0.3.2 did — the
inherent tiebreak of any line diff.
## The regression net (zit#172)
Every manifest read through the repository facade is counted, and any
invocation reports it on exit under `ZIT_MANIFEST_READS=1`. An e2e runs
eleven listings — `timeline` in four formats, `leaves`, `branch -v`,
`tag list`, `status`, `info`, `ls`, and `annotate` of a file committed
once — over two histories of different lengths and requires the counts to
be IDENTICAL. A verb that reads per row fails by construction: no timing,
no tolerances, no constants to maintain. Wall clock was measured at ±29%
on a shared machine in the course of this work; an integer does not vary.
## Compatibility
- Artifacts, tags, and the sync protocol are unchanged; Fossil RFC
revision 00 remains the target. A stock `fossil` clones, pushes, and
pulls a 0.3.3 repository byte-for-byte.
- No on-disk format changed (the image schema stays at 0.3.2's version 6).
- No command or flag changed. Output is byte-identical except the annotate
tiebreak noted above.
## Qualification
`zig build test`, `e2e`, `smoke` (Fossil interop against a real `fossil`),
`muscle` (41 differential steps), `git-import-e2e`, `git-export-e2e`, and
`dst`, plus the three-runner CI battery (macOS ARM64, Linux x86-64, Linux
ARM64). The invariance test is mutation-verified: reintroducing the
timeline defect turns it red with the read counts in the message.