Artifact 02910f995c6690a0814863adc9a48f0b5c97345b725bd13768cbc0e74ab72c5c:
- File
docs/RELEASE-NOTES-0.3.0.md
— part of check-in
[1e2a7bbc0d]
at
2026-08-29 10:18:41
on branch trunk
— release: prepare zit 0.3.0
Fossil parity on the everyday verbs, landings and strata, protected branches behind a trusted front, Fossil's user table, and the read paths that now scale with the change rather than the store. (user: dmestas, size: 15202) [annotate] [blame] [check-ins using]
# zit 0.3.0 zit 0.3.0 is a workflow release. 0.2.0 closed the store and dialect work; 0.3.0 is what happens when a person then sits down and uses the verbs all day. Its centre is the Fossil-parity programme on everyday verbs (zit#166): a Fossil user's fingers now work, the receipts and narration Fossil prints are printed, and a differential harness runs one scripted session through both tools and pins every place they differ. Around that sit landings and strata (a branch proposed for trunk as a reviewable artifact, and stacks of them), per-request branch protection for a fronted `serve`, Fossil's user table, and a round of read-path performance work that took the common verbs from "scales with the store" to "scales with the change". Nothing in this release changes an artifact, a tag namespace, or a sync message. A stock `fossil` still clones, pushes, and pulls a 0.3.0 repository byte-for-byte. Two local records grew an optional field each (the checkout record and the undo journal); both read older records unchanged. ## Highlights - **Fossil muscle memory.** Verb prefixes and Fossil's aliases (`ci`, `co`, `rm`/`delete`, `changes`, `rename`, …), a suggester for typos, Fossil's update and merge receipts, network narration that names the peer, the commit editor when `-m` is absent, and checkout-relative names (`current`, `prev`, `next`, `trunk~2`). `zig build muscle` runs the same 27-step session through `fossil` and `zit` and fails on any divergence that is not recorded as deliberate. - **The weekly verbs, filled in.** `branch new|close|reopen|hide|unhide| current|info`; `clone URL` derives its directory and opens the tree; `mv` takes many operands and directories; `diff` takes paths and grew `--numstat`, `--invert`, `--checkin`, `--branch`, `--by`; `merge --integrate`, `--baseline`, a bare `merge` onto the one other open leaf; `stash snapshot|diff|goto` and `apply --merge`; `revert -r`; `-n` on `revert`, `undo`, `redo`, `mv`, `merge`; `settings editor`, `autosync pullonly`, `--changed`, `--value`; `grep -i -c -l -v --once`; `annotate -n -l`; `timeline -F html`. - **Landings and strata.** `zit landing` proposes a branch for trunk as a forum thread plus a tag on the check-in — a reviewable record any forge can display, accept, or reject, from a bare store. Landings stack (`strata`): a branch may target another branch with its own open landing. - **`serve` can protect branches** on a trusted front's say-so: membership changes to a named branch are refused per request, including a check-in's own singleton claim. - **Fossil's user table travels.** `import-fossil` and `config pull user` carry logins, capabilities, and password hashes; `zit users` reads them. - **Read paths scale with the change.** `diff`, `status`, `stat`, `settings`, `artifact`, and store open no longer derive the whole store per call: a stat memo skips re-hashing unchanged files, index v3 carries a sorted directory so opening builds no hash map, adopted index entries slice the blob instead of copying it, and CRC32 uses the ARMv8 instruction where present. `update` and `open` materialize large trees about twice as fast. - **`import-fossil --submanifest` is usable on real corpora.** Each check-in's tree is built from its parent's with the sub-manifest editor, SSH-signed manifests are accepted, the whole-history replay gate is gone, and the conversion also runs straight from a Fossil URL or as `submanifest convert` on a zit store. A 26-hour pkgsrc import became a matter of minutes. ## Everyday verbs (zit#156–#166) The programme's three rules held throughout: no artifact, tag namespace, or sync message changed; the exit-status contract and silent success on stdout survived; where Fossil has a spelling it was adopted exactly, with zit-only forms added beside it, never instead. ### Dispatch and names (#156, #161) - Any unambiguous prefix of a verb dispatches (`zit stat` still means `stat`; `zit timel` is `timeline`). Ambiguity is a two-line diagnostic naming the candidates. - Fossil's aliases are accepted: `ci`, `checkin`, `co`, `checkout`, `rm`, `delete`, `changes`, `rename`, `ls`/`dir`, and the rest listed under `zit help`. - The typo suggester never proposes a destructive verb for a short token. - `current`, `ckout`, `prev`/`previous`, `next` resolve relative to the checkout; `NAME~N` and `NAME^N` walk parents; `trunk^` alone is the same as `trunk` (Fossil's trailing-punctuation rule), no longer silently the tip of something else. ### Receipts and narration (#159, #160) - `update` prints Fossil's receipt: a line per changed file, an `updated-from`/`updated-to` block with dates, tags, and comment, and the `zit undo` hint. `-n`/`--dry-run` and `--latest` are accepted. - `pull`, `push`, `sync`, and `clone` name the peer (`pull from URL: …`), share one no-op phrase (`already in sync`), show per-round progress on a terminal, and `clone` prints the project code. A dead peer is named. ### Commit (#157, #158) - With no `-m`, `commit` opens `$VISUAL`/`$EDITOR` (or the new `editor` setting) on a template that lists the changes; the comment survives a failed commit in `.zit-ci-comment`. `-M FILE`, `--editor PROG`, `-n`, `--allow-empty`; `--no-warnings` is `--no-checks`. - Fossil's warn-by-default on binary and CRLF content was weighed and not adopted (#158): zit's content gate — `binary-glob`/`crlf-glob`, honoured from versioned `.fossil-settings/` too — stays opt-in, so an unset glob is "no opinion", never "refuse everything". ### Reading history (#163) - `timeline -b BRANCH | -c`, `-p PATH`, `-u LOGIN`, `-r`, `--offset N`, `-v`, `-F oneline|medium|full|html`, `*CURRENT*` and `*MERGE*` marks, `--weekday`. - `status` classifies (`--added`, `--edited`, `--missing`, `--conflict`, `--extra`, `--differ`), detects conflict markers, and prints a header with `-v`; `-R` works on `pull`, `push`, `sync`, `remote`. - Not taken, and why: `--localtime` (no tz database), a global `-U` (collides with `commit --user`), `--chdir` (no chdir in std.Io). ### The weekly verbs (#164) - `branch new NAME [BASIS]`, `current`, `close`/`reopen`/`hide`/`unhide` (control artifacts, as `tag add --raw` mints them), `info NAME`, list `-c -t -r`. - `clone URL` derives DIR from the URL and opens the working tree in it; `--no-open` keeps a bare store; the cone is carried into the open. `open URL` delegates to clone. - `mv OLD... NEW|DIR`: several files into a directory, a tracked directory as a unit, `--soft` to record without moving, `-n` to preview. The managed set now records one pending rename per moved file, so a commit carries every old name. - `revert -r VERSION` restores another check-in's content without moving the checkout; `revert -n`, `undo -n`, `redo -n` name what they would touch. `add -f` takes ignored files in a directory expansion; `clean -n`, `-f`, `--emptydirs`. - `diff` takes PATH operands; `--numstat`; `--invert`; `--checkin V` (against its parent); `--branch B` (tip against its fork point); `-Z` is `-w`; `-N` is accepted; `--by` writes a side-by-side HTML page under `$TMPDIR` and opens it from a terminal. - `merge --integrate` closes the merged leaf when the merge is committed (the checkout record carries the leaf's hash as an optional sixth field; `commit` mints the same control artifact `branch close` does); `--baseline B`; `-n` is `--probe`; a bare `merge` takes the one other open leaf and names them when there are several. - `stash snapshot` saves without touching the tree; `stash diff [ID]`; `stash goto [ID]` updates to the entry's check-in and applies; `apply|pop --merge` three-way merges into a dirty file, with markers, a conflict list, and exit 5. - Settings: `editor CMD` (executable tier, after `--editor`, before the environment; a configured editor makes `commit` editor-capable without a terminal), `autosync pullonly`, `--changed`, `--value`. Both new settings ride the keyed config block; older stores read unchanged. - `grep -i -c -l -v --once`; `annotate -n N` (look back N check-ins) and `-l` (the check-ins consulted). ### The `fossil ui` answer (#165) - `diff --by` and `timeline -F html` render the two pages people open most. - `zit ui` launches quarry's single-repository local mode (`quarry ui <checkout root> ARGS...`, binary from `ZIT_QUARRY` or `PATH`); when it cannot be started the verb says so, points at the two static renders, and exits 1. quarry RFC 0010 specifies the mode. ### Acceptance (#162) `zig build muscle` runs 27 steps through `fossil` and `zit`, comparing exit classes and speech. Every divergence is either `same`, `by_design` with a reason (the `changes` alias header, `tag list` excluding branches, the dead peer's exit class, binary content gating), or a failure. It runs in CI. ## Landings and strata (#127, #131–#134, #136, #138, #144, #149, #152) - `landing open` proposes a branch for trunk as a forum thread plus a raw tag on the check-in; `landing ls`, `show` (the check-ins being proposed, mergeability, and the thread), `comment` (`--reply-to` aims the I-card at a post), `accept`, `reject`, `update` (bring the target into the proposed branch on the store). - `accept -R` merges against a bare store in a working area it creates, refusing conflicts, so a forge can accept without a checkout. `merge --probe` answers mergeability for any pair. - Strata: a landing may target another branch with its own open landing; accepted landings close the landed leaf without propagating; cycles, unresolvable targets, already-contained branches, and rejected or already-landed bases are refused with the reason. - The record scan no longer parses every blob to find landings (#134). The first line of `-m` is the landing's title (#138); N cards follow Fossil's per-type write rule (#136). ## Serve and sync (#112, #151) - Per-request branch protection behind a trusted front: `serve` refuses membership changes to protected names, including a check-in's own singleton claim, and warms the image only after the refusal check. - The sync client's holdings are log-backed instead of a whole-store snapshot, and `serve` reads push policy from the snapshot rather than scanning the log per round — the 20-minute clone stall at ~1.1M artifacts is gone. ## Users and configuration (#117, #124, #125, #153) - A `.user` frame kind carries Fossil's user table; `import-fossil` adopts it, `config pull user` fetches it from a peer with credentials, `zit users` reads it. - `.fossil-settings/*` is honoured beside `.zit-settings/*`, Fossil's spelling winning, so a mirrored Fossil project keeps its ignore globs. - `settings` and `config` accept `-R` on a bare store. ## Performance (#107, #114, #115, #118, #120, #121, #122, #140–#143, #145, #148) - Store open: index v3 carries a sorted directory (no 255k-key hash map to answer one lookup); adopted index entries slice the blob instead of copying it; CRC32 uses the ARMv8 instruction where present. Opening the 302MB tcl store: 47ms → 20ms (#143, #145). - `diff`, `artifact`, `settings`, and the `diff`/`status` baseline read through the image path and the scan index instead of deriving the whole view per call (#141, #118); a per-file (mtime, size, hash) memo in `.zit-cache` skips re-hashing unchanged files. - `update`/`open` stage payloads once and rename them into place: about 2x on large trees. `pack` trusts profitable at-rest deltas and no-ops an unchanged log. `ls --long` per-file cost no longer scales with the store. - The first read after a sync no longer pays a multi-second cache rebuild: two quadratic scans inside the image serializer were the cost, not the maintenance model (#107). Every verb no longer pays O(store) DWARF stack unwinds; the release binary is a third of its former size (#140). - `timeline --weekday` uses Ben Joffe's branchless day-of-week. ## Sub-manifest import (#126, #129, #155, #167, #168) - Each check-in's tree is built incrementally from its parent's with the sub-manifest editor rather than from scratch; baseline manifests are read and parsed once; SSH-signed manifests are stripped and verified per pair in the mint loop. - The whole-history replay gate and `--force` are gone: the gate replayed every commit through a second converter and disagreed with the store by 10–20x on cost. - `import-fossil URL --submanifest` converts straight from a Fossil server; `submanifest convert SRC DEST [--k N]` re-mints a flat zit store. `fossil_convert` mints FLAT when the names do not partition. ## Indexer feeds (#108, #109) - `frames --structural` emits only what the crosslink links (content blobs dominated a full stream: 13.2GB on pkgsrc). - `crosslink` streams the derived per-check-in records, with the U-card user and the changed files, as a CLI contract for indexers. ## Fixes - A second checkout on a shared store (`open --store`) no longer treats the other checkout as "current" for `update` and `merge` (#116). - `update` carries uncommitted work across the move by three-way merge, recording no merge parent; `merge` merges into a dirty tree the same way. `undo` restores the uncommitted bytes either way (#135). - `update` on a never-opened clone no longer uses memory that scales with corpus size: the client sits on the same log-backed store `serve` uses (#119, #112). - `logstore` answers a byte-aligned name prefix from the sorted directory; a complete SHA-1 name resolves (#148). - RFC test vectors are kept inert on disk so Fossil's crosslinker cannot mistake one for a real artifact. - `diff -w` ignores whitespace-only changes in hunks and `--brief` (#130). ## Compatibility - Artifacts, tags, and the sync protocol are unchanged; Fossil RFC revision 00 remains the target. - The checkout record (`.zit-checkout`) gained an optional sixth field (`integrate`), written only when set; a record without it is byte-identical to the five-field form. The undo journal's format version is 4 (a sixth string); an older journal reads as damaged, which is the documented posture for transient working-tree state. - The repository config block gained two keyed entries (`editor`, `autosync_mode`); unknown keys were always skipped, so 0.2.0 reads a 0.3.0 store. - `clone URL DIR` now opens the working tree; scripts that ran `zit open` afterwards should pass `--no-open` or drop the second step. `mv` with three operands moves into a directory instead of failing; `merge` with no NAME merges instead of failing; `diff` with a bare word treats it as a PATH instead of failing; `clean -f`/`-n` are aliases now. ## Qualification Every change passed `zig build test`, `e2e` (711 scenarios), `smoke` (12 Fossil interop scenarios against a real `fossil`), `muscle` (27 differential steps), `git-import-e2e`, `git-export-e2e`, and `dst`, and the three-runner CI battery (macOS ARM64, Linux x86-64, Linux ARM64). Each published binary is built from the same checksum-pinned source and executed under low-feature CPU models before publication, as since 0.1.4.