Skip to content
zit Timeline
Login

Timeline

18 check-ins related to "release-0.1"

2026-07-19
01:58
Merge release-0.1: merge3_properties algebraic-property fuzz (P4-F7)

Lands the last of the seven 0.1.0 release blockers. merge3 — the three-way merge — had no fuzz target, and silent merge corruption is the worst failure a version-control system can have, because it produces a tree that looks right.

The merged tree was re-verified on trunk after the merge, not inherited from the branch: zig fmt --check ., zig build, and zig build test all exit 0. The merge reported no conflicts and touched four files; fossil extras is empty, so nothing referenced went unadded. The conflict-marker sequences a repo-wide grep reports in src/merge3.zig and src/e2e.zig are that module's own sentinel constants and the tests asserting on them, not merge residue.

Landed by hand rather than by the release workflow: its TigerStyle gate spent its three-round budget on this diff and halted without a confirming pass. The final round's two blockers were real — a zig fmt failure and an oracle hole where conflict spans were validated individually but never as ordered and disjoint, which would have let one widened span exempt every line from oracle 4 — and both were fixed by the round that followed. Verified here before landing: fmt clean, the ordered/closes_once checks present, and merge3_properties running clean at seed 1 over 2000 rounds. check-in: 08e7c6d6f1 user: dmestas tags: trunk

01:54
Add merge3_properties: algebraic-property fuzzing over the three-way merge

Silent merge corruption is the worst failure a version-control system can have — it produces a tree that looks right — and merge3 had no fuzz target. This adds one, driving the merger with generated base/current/other triples and asserting the properties that must hold for any input.

Oracle 4 (no invented lines) needs a carve-out, because the merger is supposed to fabricate lines inside a conflict envelope. That carve-out is only sound if the recorded spans really are envelopes, so expectNoInventedLines validates the claim before subtracting anything: each span must be in-bounds, open at a line boundary with conflict_sentinel, close with conflict_terminator, start at or after the previous span's end, and carry no second terminator inside it.

The ordering and interior-terminator checks are load-bearing, not belt-and- braces. inAnySpan matches on overlap, so an over-long span exempts every output line up to its end. End-pinning alone admits a single span stretched from the first envelope's start to the last one's end — it opens and closes correctly and overlaps nothing — which would exempt the clean lines between two envelopes from the oracle entirely. closes_once catches that case on the first envelope's terminator. merge3 asserts ordering itself, but only under runtime_safety, which a ReleaseFast sweep — the build a fuzz run uses — erases; this loop holds in every optimize mode.

merge3.zig gains one export: conflict_terminator, the closing counterpart of the existing conflict_sentinel, with a comptime tripwire pinning its shape. Additive only, no behavior change — it lets the oracle pin both envelope ends against the module that produces them instead of re-typing the literal, so the two cannot drift apart.

Battery green in the worktree: zig fmt --check ., zig build, zig build test, zig build e2e, zig build dst (6 seeds x 1000 steps). The new target runs clean at seed 1 over 2000 rounds; no bug was found, so no regression seed is pinned. closed check-in: 21ca364fb3 user: dmestas tags: release-0.1

00:17
Merge release-0.1: Add transport_frame_garbage and serve_request_garbage seeded fuzz targets

Lands P4-F6, closing the last unfuzzed attack surface in the release scope. transport.zig and serve.zig are the only two files a remote peer can reach with bytes it fully controls, and neither had a fuzz target: the sync_parsers_adversarial target covers the layer above them, so the HTTP framing itself — the first code to touch untrusted input — was exercised only by hand-written smoke cases. These two targets hit that framing directly.

The increment: src/transport_fuzz.zig (205 L) and src/serve_fuzz.zig (303 L), registered in the fuzz_tests.zig dispatch table alongside the existing 24 and pinned by that file's registration test. serve.zig's driveHttp is promoted to pub with a comment stating why — it is the receiveHead to handleHttpRequest seam the smoke tests and the fuzz target both need, and duplicating it would have meant fuzzing a copy of the request path rather than the real one. Both sides stay in-memory, so neither target binds a port and neither can flake in CI. dst.zig picks up the two targets plus fuzz_tests.zig itself, the latter so the registration pin has a test step to run in: zig build fuzz has none.

Evidence, re-verified on the merged tree rather than on the branch, since trunk had advanced: zig fmt --check ., zig build, and zig build test each exit 0. Both new targets run clean seeded — invoking zig build fuzz with each target name and --seed 1 exits 0 for transport_frame_garbage and for serve_request_garbage — and found no crash, leak, or UB to fix, so this step carries no pinned-seed regression. The merge reported no conflicts; a repo-wide grep for conflict markers is clean, and fossil extras is empty, so both added files are tracked and nothing referenced went unadded. check-in: b8db5ecabd user: dmestas tags: trunk

00:10
Add transport_frame_garbage and serve_request_garbage seeded fuzz targets

The 24 existing fuzz targets cover the delta, artifact, sync-parser and logstore layers, but not the two CLI-layer modules that consume bytes an untrusted remote peer chose. `sync_parsers_adversarial` covers the layer above; the HTTP framing itself was unfuzzed. These are the last two wire surfaces on the release bar, and they are what a hostile peer reaches first.

What landed:

- `src/transport_fuzz.zig` — `frameGarbage`, registered as `transport_frame_garbage`. Client-side §4/§4.1 framing and redirect policy: the round-trip law (whatever `frame` produces, `unframe` returns exactly those plaintext bytes), mutation of framed containers (bit damage never survives as *different* plaintext — it either fails the container's Adler-32/zlib checks or, in the length-field range the §4.1 compression-length erratum makes a capacity bound, decodes back to the same bytes), and garbage `Location` headers through `resolveRedirect`. Totality is the asserted contract: every input yields a value whose postconditions hold or a declared member of `TransportError`.

- `src/serve_fuzz.zig` — `requestGarbage`, registered as `serve_request_garbage`. Server-side HTTP request path: raw bytes into `std.http.Server.receiveHead`, then `handleHttpRequest`'s dispatch (`classifyXfer` -> body read -> responder -> reply framing). It does not re-feed `handleXfer` in isolation — that decoding is already fuzzed twice — it reaches it only as the tail of a full-path dispatch, which is the point. Asserted contract: any `receiveHead` error is a clean rejection, `handleHttpRequest` returns void, and any produced response begins with an HTTP/1.1 status line.

- `src/serve.zig`: `driveHttp` becomes `pub`. It is the request-path seam two callers need and neither should reimplement — the §4 smoke tests and this fuzz target. In-memory reader/writer on both sides, so the target binds no port and cannot flake in CI.

- `src/fuzz_tests.zig`: both targets registered in the `targets` table, and `targets` becomes `pub` for a new structural registration pin. An unregistered target compiles, passes review, and is then never run by any invocation; the pin asserts every target the release bar names is actually reachable from the runner, so the registration cannot rot.

- `src/dst.zig`: aggregates both new files plus `fuzz_tests.zig` into `zig build test`. This root is the one that reaches serve.zig and transport.zig relatively while carrying the `zit` dep those two import; `zig build fuzz` has no test step, so it is also the only place the registration pin can run.

No bug found, so no fix and no pinned-seed regression in this commit — both surfaces held over the seeded runs below. The targets are the standing check, not a one-time sweep.

Test evidence (this worktree, after `fossil update` absorbed the sibling `zit open` commit 5ba418801d and its 8 modified files):

- `zig build fuzz -- transport_frame_garbage --seed 1 --rounds 2000` — clean, no crash/leak/UB. - `zig build fuzz -- serve_request_garbage --seed 1 --rounds 2000` — clean, no crash/leak/UB. - `zig build test` — green, including the new registration pin and the fixed-seed smoke tests at the foot of both new files. - `zig build` and `zig fmt --check .` — green.

No borrowed technique in this change. check-in: cec4afaf89 user: dmestas tags: release-0.1

2026-07-18
23:19
Merge release-0.1: zit open — the clone-to-working-tree path (P3-F3)

Lands the last of the three P3 CLI cliffs. A clone previously produced only an artifact log: there was no verb that turned one into a working tree, so clone-to-usable-checkout was unreachable and unproven by any test. `zit open` closes that path, resolving the trunk tip and materializing the check-in into the target directory.

The merged tree — not merely the branch — was re-verified on trunk after the merge: zig fmt --check ., zig build, and zig build test all exit 0. The merge reported no conflicts and touched six already-tracked files; fossil extras is empty, so nothing referenced went unadded. The conflict-marker byte sequences that a repo-wide grep reports in src/merge3.zig and src/e2e.zig are that module's own conflict sentinel and the tests asserting on it, not merge residue.

Landed separately from the sibling status increment (3b7fe2fbe1) rather than folded into one commit: the two are independent release steps and each keeps its own subject and evidence. check-in: 91c682fd06 user: dmestas tags: trunk

23:14
Merge release-0.1: status: report edited files by hashing tracked files against the current check-in

Lands release step P3-F5-status on trunk, completing the B-status-16 deferral.

The increment: `status` previously classified only `added` and `missing`, so a tracked file that was present but modified produced no line at all — the gap was documented in a comment, in `--help`, and in an e2e test that pinned the silence. Documenting a hole is not the same as not having one, and "your working copy looks clean" is the wrong thing for a version control system to say about an edited file. `status` now resolves the current check-in and compares every tracked file against it, emitting an `edited` row when the bytes or the file mode differ; a file whose contents match is still not listed.

The comparison is not a second implementation. The check-in resolution, the legacy trailing-separator F-card tolerance, the delta-manifest walk, and the merge against the sorted managed set were all machinery `diff` already had; that machinery is extracted into `CheckinBaseline` and `walkWorkingTree`, and both verbs now run through it, with each verb supplying only a sink. `diff` is a pure refactor here — same output, less code. Dirtiness remains a non-failure: every `added`/`edited`/ `missing` row exits 0 (B-status-15); only a genuine comparison failure exits 1. `--help` no longer defers edited-file detection and now narrows the deferral text to the two cases that genuinely remain out of scope.

This lands the full detection called for by P3-F5, not the fallback. The plan's fallback of record required an explicit operator decision; none was taken and none was needed.

Merge evidence: `fossil merge release-0.1` reported no conflicts, updating only src/e2e.zig and src/main.zig. The tree carries no conflict markers — the three open-marker occurrences a grep turns up in src/e2e.zig are string literals inside assertions pinning zit's own merge3 conflict sentinel, not merge residue.

Verification evidence: the merged tree — not merely the branch — was re-verified on trunk after the merge. `zig fmt --check .`, `zig build`, and `zig build test` each exit 0. Behavioral evidence rides in the branch commit's new e2e coverage, which pins each acceptance criterion: an edited tracked file is reported as edited; a rewrite with identical bytes (mtime bump, same content) is not reported; an executable-bit-only change is reported; a file deleted from the check-in but no longer tracked is still not reported; and a delta checkout with an absent B-card baseline fails cleanly rather than reporting a false clean tree. The e2e that pinned the old deferral is replaced by those tests, and the help-text e2es compare against a hand-written expected string, so the `--help` change is pinned too.

`fossil extras` is empty, so the merge adds no file it fails to track.

No performance claim is made here. No borrowed techniques in this change, so no attribution is owed. check-in: 3b7fe2fbe1 user: dmestas tags: trunk

23:11
Add zit open: clone→working-tree path, proven by e2e chain and fossil smoke scenario

`zit clone` builds a repository file and nothing else. The checkout it left behind was the same UNBORN record `init` writes (`version == ""`, branch `trunk`), with no managed set and no files, and there was no way to turn it into a usable tree: `zit update` accepts only a literal 40/64-hex check-in ID, so a freshly cloned tree could not name its own tip. Clone was a dead end.

`zit open` is the second half of fossil's own clone+open UX. It resolves the tip of the main branch out of this repository's derived state and hands materialization to the SAME `update.applyCheckin` engine every other working-tree move rides — journal-armed, transactional, rollback-safe. Tip resolution is the only work that is open's own; everything else is wiring.

What changed:

- `cli.parseOpenArgs` / `OpenArgs` / `OpenResult`: an operand-free surface. `-h`/`--help` is the only accepted token and wins over every other token; a bare `-x` is an unknown option, anything else an extra argument. The verb takes no operand by design — it derives its target from the repository. - `main.runOpen` plus the `open` entries in the `Verb` enum, the dispatch switch, and the `verb_help` table, so the verb is added in one place and the total switch stays total. `runOpen` writes NO checkout record and NO managed set of its own: `init` already wrote the unborn record, an absent managed set already reads as the empty set, and the update engine stays the single writer of the born record. A second writer of that bootstrap state would only be a second thing to keep in sync. - `main.openApplyFail`: one arm per `update.ApplyError` variant and no `else`, so a new variant fails the compile and forces a decision, mirroring `updateApplyFail`. `SymlinkUnsupported` / `InvalidPath` / `ReservedPath` are raised while planning the TARGET manifest and are reachable on a perfectly intact repository, so they get honest prose instead of a corruption claim. - `update.planUpdate`: an UNBORN record now takes the same arm as an absent one. Unborn is the normal state of every fresh repository, so without this the first `update` after a clone handed `""` to `buildPlan`, failed `artifact.validateName("")`, and reported `CurrentStateInvalid` — a clean, correct tree diagnosed as broken. A record that names no check-in but claims a merge parent or a pending special operation stays incoherent and is still `CurrentStateInvalid`. - BORN-ness, not presence, is the "already open" signal. A presence-based gate would have rejected a clone followed by an open on every clone, the primary path the verb exists to serve.

Test evidence (all run in this worktree after absorbing the sibling P3-F4 commit 281c0ed815, which arrived during this step and was merged by hand in `src/e2e.zig` — both sides had appended the identical P3-F4 block, so the duplicate was dropped):

- `zig build test` — green, including new `update_test.zig` coverage of the unborn-record arm and its incoherent-record rejections. - `zig build e2e` — green, including the P3-F3 block: clone → open → byte-identical tree → update → commit round-trip; a plain clone's unborn checkout tolerated by `update`; an untracked file in the way failing the open and materializing nothing; re-opening an already-open tree refused with no change; a repository with no check-in reported rather than failed; outside a repository failing with the not-a-repo diagnostic (exit 1); unknown option and positional as usage errors (exit 2); and the verb present in top-level help with one help text behind both `--help` and `help open`. - `zig build smoke` — green, with the new S6 scenario (§3.7/§4): `zit clone` + `zit open` against a REAL fossil server materializes the committed bytes byte-for-byte. This is the cross-implementation proof that the new path produces a working tree fossil itself agrees with. - `zig fmt --check .`, `zig build`, and `zig build dst` (6 seeds x 1000 steps) also green.

No borrowed technique in this change. No new file: the work lands entirely in existing modules. check-in: 5ba418801d user: dmestas tags: release-0.1

23:08
status: report edited files by hashing tracked files against the current check-in

Completes the B-status-16 deferral. `status` previously classified only `added` and `missing`: a tracked file that was present but modified produced no line at all, and the gap was documented in a comment, in `--help`, and in an e2e test that pinned the silence. Documenting a hole is not the same as not having one, and "your working copy looks clean" is the wrong thing for a version control system to say about an edited file.

What changed:

- `status` now resolves the current check-in and compares every tracked file against it, emitting an `edited` row naming the path when the bytes or the file mode differ. A file whose contents match is still not listed.

- The comparison is not a second implementation. `diff` already resolved the current check-in, tolerated the legacy trailing-separator F-card, walked the delta manifest, and merged that effective file set against the sorted managed set. That machinery is extracted into `CheckinBaseline` (open/resolve) and `walkWorkingTree` (the merge), and both verbs now run through it. `diff` is a pure refactor here -- same output, less code. The `diff*Fail` diagnostic mappers become `compare*Fail` and take the verb as a parameter, the shape `checkoutFail` and `managedFail` already used.

- A verb supplies only a sink with `emit(entry)`. `DiffSink` renders diff records; `StatusSink` renders human rows and drops the deleted-from-check-in class, which `status` still defers because it iterates the managed set. The sink is comptime-generic rather than an erased pointer pair: both sinks are known at compile time, so the call stays direct and type-checked.

- The whole report is buffered and written once, as `diff` already did. A comparison failure part-way through the walk now leaves stdout empty rather than a header above a truncated report. Dirtiness is still never a failure: every `added`/`edited`/`missing` row exits 0 (B-status-15). Only a genuine comparison failure -- unreadable tracked file, corrupt or unresolvable check-in -- exits 1.

- `CheckinBaseline` is self-referential (the walk borrows the resolver, which borrows the log, which reads through the file storage), so it is initialized in place and must not be moved. The open/deinit contract used to rest purely on each call site placing its `defer` correctly; an `opened` flag now makes that invariant assertable, and both `deinit` and the failure path assert it.

- `walkWorkingTree` carries a termination guard against the exact bound (one step per managed path, one per effective file), plus a per-iteration progress assertion, because correctness of the merge rests on every switch arm advancing exactly one cursor. Debug-only, alongside the existing debug-only assertion that the managed set is sorted.

- `--help` no longer defers edited-file detection. It documents the three row classes and narrows the deferral text to the two cases that genuinely remain out of scope: a file deleted from the check-in but no longer tracked, and untracked "extra" files -- pointing at `zit diff` and `zit extras`.

Test evidence: new e2e coverage pins each acceptance criterion -- an edited tracked file is reported as edited in the born state; a rewrite with identical bytes (mtime bump, same content) is not reported; an executable-bit-only change is reported as edited; a file deleted from the check-in but untracked is still not reported; and a current delta checkout with an absent B-card baseline fails cleanly rather than reporting a false clean tree. The pre-existing e2e that pinned the deferral is replaced by the tests above. The help-text e2es compare against a hand-written expected string, so the `--help` change is pinned too. `zig build` and `zig build test` pass in this worktree after absorbing the sibling add/rm recursion commit (281c0ed815), and the commit is proved against a clean `fossil open` checkout running `zig build` then `zig build test`. check-in: 02d993f860 user: dmestas tags: release-0.1

22:52
Merge release-0.1: Implement add/rm directory recursion through the shipped extras.sweep walk

Lands release step P3-F4-addrm on trunk. `zit add DIR` and `zit rm DIR` were hard errors directing the user to name individual files, which made `zit add .` and adding a source subtree dead ends. The increment makes both verbs recurse: `add DIR` expands over the already-shipped `extras.sweep` of the checkout root rather than introducing a second walker, so the exclusions, the no-follow symlink posture, and the tracked-set subtraction are the ones `addremove` and `clean` already use, with the sweep lazy and memoized so multiple directory arguments still perform one enumeration. `rm DIR` expands over the tracked keys via `ManagedSet.iterate` rather than over the disk, so an already-deleted directory remains forgettable. A single containment predicate, `pathUnderDir`, serves both verbs so the prefix-boundary case cannot diverge between them. Help text and exit-status wording now describe recursion instead of the removed directory error.

Merge evidence: `fossil merge release-0.1` reported no conflicts, updating only src/e2e.zig and src/main.zig; the tree carries no conflict markers (the open-marker occurrences that a grep turns up in src/merge3.zig and src/e2e.zig are that module's own conflict sentinel constant and the tests asserting on it, not merge residue). The merged tree — not merely the branch — was re-verified green on trunk after the merge: `zig fmt --check .`, `zig build`, and `zig build test` all exit 0. `fossil extras` is empty, so the merge adds no file it fails to track.

No borrowed techniques in this change, so no attribution is owed. check-in: fca1e073c2 user: dmestas tags: trunk

22:45
Implement add/rm directory recursion through the shipped extras.sweep walk

`zit add DIR` and `zit rm DIR` were hard errors that told the user to name individual files. That made the two most common invocations -- `zit add .` and adding a source subtree -- dead ends, and it was the last place where the CLI asked the user to do work the repository already knows how to do.

What changed:

- `add DIR` now expands to every untracked file beneath the directory. It reuses the ALREADY SHIPPED `extras.sweep` of the checkout root rather than introducing a second walker: the same walk, the same exclusions, the same no-follow symlink posture `addremove` and `clean` use. The sweep is lazy and memoized for the whole invocation, so `zit add a b c` over three directories still performs exactly one enumeration. Because the sweep already subtracts the tracked set and the depth-0 control names, neither can be re-inserted or re-reported by the directory path. - `rm DIR` expands over the TRACKED keys via `ManagedSet.iterate`, never over the disk, so a directory the user has already deleted is still forgettable. Keys are copied into the arena before the first removal, because `iterate()`'s slice and its backing bytes are invalidated by `remove` -- the same discipline `addremove` uses for its remove set. Ascending order is preserved and every expanded key still passes the per-key control-file guard (B-rm-7). - One containment predicate, `pathUnderDir`, serves both verbs, so the boundary case cannot diverge between them: `src2/c` is not under `src`, because containment requires the separator immediately after the directory's bytes. - No new diagnostic class. `zit rm .` with nothing tracked resolves to the existing not-tracked message rather than inventing an empty-expansion error; `zit add .` on a tree holding only control files adds nothing and succeeds. - The `add` and `rm` help text and exit-status wording now describe recursion instead of the removed directory error.

Test evidence: the B-add-5 and B-rm-5 contract tests were rewritten to pin the new behavior (a named symlink is still rejected; a directory now recurses; `.` at the root is never reported as outside the repository), and a new P3-F4 block of end-to-end tests covers nested trees, prefix-boundary siblings, multiple directory arguments sharing one sweep, --dry-run, --hard, and rm of a directory that no longer exists on disk. `zig build test` passes in this worktree after absorbing the sibling packaging commit (3645c03e2d), and the commit is proved against a clean `fossil open` checkout running `zig build` then `zig build test`. check-in: 281c0ed815 user: dmestas tags: release-0.1

21:11
Merge release-0.1: Narrow .paths to docs/rfcs so working docs never ship in a fetched package

Second increment of the 0.1.0 release sequence, landed on trunk as it completes rather than accumulating to a big-bang merge at the end.

The increment: build.zig.zon .paths named the whole docs directory. A Zig package is cut from the working tree, not from what fossil tracks, so the ignore-glob does not govern it -- a bare docs entry ships whatever sits under docs/ at package time, including the ignore-glob'd docs/plans/*.md working documents, which are internal and must never leave the repository. .paths now names docs/rfcs directly, which is also what the repo convention already states (0ad7fa92c6: "docs/ is for the RFCs only"); the manifest encodes that convention instead of relying on docs/ happening to stay clean.

Evidence: a new pin in src/packaging_test.zig asserts both halves -- that .paths contains "docs/rfcs", and, as negative space, that a bare "docs" entry is absent, so the ship-everything form cannot drift back unnoticed.

The merged tree was re-verified before this commit: zig fmt --check, zig build, and zig build test all green on the merge result. Green on the branch does not imply green on the merge, since trunk advances with concurrent work.

No borrowed techniques in this change, so no attribution is owed. check-in: 0c22d3a950 user: dmestas tags: trunk

20:52
Narrow .paths to docs/rfcs so working docs never ship in a package

`.paths` named the whole `docs` directory. A Zig package is cut from the working tree, not from what fossil tracks, so the ignore-glob does not govern it: a bare `docs` entry ships whatever sits under docs/ at package time — including the ignore-glob'd docs/plans/*.md working documents, which are internal and must never leave the repository.

Naming docs/rfcs directly is also what the repo convention already states (0ad7fa92c6: 'docs/ is for the RFCs only'); the manifest now encodes that convention instead of relying on docs/ happening to stay clean. A new pin in src/packaging_test.zig asserts it so the bare-docs form cannot drift back. check-in: 3645c03e2d user: dmestas tags: release-0.1

20:30
Merge trunk into release-0.1: resync after the P1 land

P1 landed on trunk (8117eab3b2) per the continuous-integration rule, so the release branch absorbs trunk to keep a single lineage. Content-identical merge — this records the ancestry so later increments do not re-traverse it. check-in: 6d229acebf user: dmestas tags: release-0.1

20:27
Merge release-0.1: BSD-2-Clause LICENSE and the packaging structural pins (P1)

First increment of the 0.1.0 release sequence, landed on trunk immediately per the plan's continuous-integration rule rather than accumulating to a big-bang merge at P6.

- LICENSE at the repo root (BSD-2-Clause, copyright Daniel Mestas 2026). zit is an independent reimplementation from the Fossil RFCs, not a derivation of Fossil source, so the choice was open; BSD-2-Clause matches the Fossil heritage and the systems-Zig ecosystem. - build.zig.zon .paths names LICENSE, so it ships inside a fetched package. - The commit-description-* scratch file is gone and the pattern is in the versioned ignore-glob. - src/packaging_test.zig pins these as executable facts, including a negative-space pin asserting every repo-root path build.zig embeds is also named in .paths — the embeds attach to the test-only module, never to the exported zit module, so a consumer never depends on a file outside .paths.

The merged tree was re-verified before this commit (fmt/build/test green): green on the branch does not imply green on the merge, since trunk advances with concurrent work. check-in: 8117eab3b2 user: dmestas tags: trunk

20:19
Remove docs/RELEASE-0.1.0-PLAN.md from tracking; working docs live under the ignored docs/plans/

The release plan is a working document, not a shipped artifact. Repo convention (0ad7fa92c6) is that docs/ carries the RFCs only, with docs/plans/* already in the versioned ignore-glob; the plan, the readiness assessment, and its earlier draft all belong there. P1 added the plan because its own scope text said to commit it — that instruction is wrong and has been removed from the plan.

The file is unchanged on disk, now at docs/plans/RELEASE-0.1.0-PLAN.md. It remains in the history of 122998a428 — fossil history is immutable and shunning it would be disproportionate for a working doc. check-in: 3179b6805a user: dmestas tags: release-0.1

20:12
Add BSD-2-Clause LICENSE, ship it in .paths, drop scratch file, ignore the pattern

A release without a license grants nobody any rights, so this is the legally gating step of the 0.1.0 sequence. zit is an independent reimplementation from the Fossil RFCs rather than a derivation of Fossil source, so the choice was open; BSD-2-Clause matches the Fossil heritage and the systems-Zig ecosystem.

What changed:

- LICENSE at the repo root, BSD 2-Clause, copyright Daniel Mestas 2026. - build.zig.zon .paths now names LICENSE, so the file actually ships inside a fetched package instead of only existing in the checkout. - The leftover commit-description-413190fb92be991f.txt scratch file is gone and .fossil-settings/ignore-glob carries commit-description-* so the class of file cannot drift back in. - src/packaging_test.zig pins the above as executable facts: LICENSE content, LICENSE named inside the manifest's brace-matched .paths block, a line-anchored ignore-glob pin, and a negative-space pin asserting every repo-root path build.zig embeds is also named in .paths. These acceptance criteria are file-structure facts, which rot silently because nothing executes them; the battery alone cannot catch a .paths regression. - build.zig grows build_unit_test_module: the pinned repository files attach as anonymous imports to a test-only compile of root.zig, never to the exported zit module. Attaching them to zit made every consumer's build depend on files outside .paths and a fetched package failed on a missing .fossil-settings/ignore-glob before compiling a line. The negative-space pin exists to catch exactly that recurrence. - docs/RELEASE-0.1.0-PLAN.md, the plan of record for the 0.1.0 release, is committed alongside the first step it describes.

Test evidence: zig build and zig build test green in the working checkout. This commit is additionally gated on a clean-checkout proof — fossil open into a fresh temp directory, then zig build and zig build test there — which is the check that catches a file referenced but never added.

No borrowed techniques in this change, so no attribution is owed. check-in: 122998a428 user: dmestas tags: release-0.1

19:29
Create new branch named "release-0.1" check-in: be86f4a5e6 user: dmestas tags: release-0.1
17:21
Remove docs/plans/bench benchmark-run JSON from tracking; ignore docs/plans

These four bench-run outputs (baseline / step2-pickbase / step3-pack-redeltify / step4-samepath) were measurement artifacts committed under docs/plans/bench — they do not belong in version control (docs/ is for the RFCs only). Remove them from the tip and add docs/plans/* to the versioned ignore-glob so the pattern cannot recur. They remain in the historical check-ins that added them (9aaf485847 and the integration merges) — Fossil history is immutable; purging them from provenance entirely would require fossil shun, deliberately not done. check-in: 0ad7fa92c6 user: dmestas tags: trunk