Skip to content
zit Check-in [861b223e3c]
Login

Check-in [861b223e3c]

Overview
Comment:CI: fuzz sweep at 100 rounds per target, not 2000

The sweep could not finish inside its own 10-minute step timeout. Per-target cost varies by roughly 276x across the corpus: artifact_parse_garbage runs 100 rounds in 0.18s, while logstore_pack_same_path_round_trip takes 49s because it performs a full store pack every round. At 2000 rounds that single target needs about 16 minutes on its own.

The original figure was extrapolated from one cheap target on the assumption that per-round cost was roughly uniform. It is not, and the assumption was never measured. 100 rounds is measured: the full 27-target sweep takes about 76s.

This makes CI fuzzing a regression check — every target still runs clean on every push — rather than a bug hunt. Finding new defects needs depth, and depth belongs in an out-of-band run with its own budget, where a long sweep costs nobody a merge.

Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 861b223e3c8e1f1986d1718d7f73d76e794f1d8656dff70f30fcceb9623d9f1e
User & Date: dmestas on 2026-07-19 15:25:14.437
Other Links: manifest | tags
Context
2026-07-19
15:31
Merge blockers: refuse symlinks consistently across add/addremove/commit (B3)

Lands the B3 increment (1aeb531cac) on trunk. The fix itself is unchanged from that commit and its reasoning is recorded there; this message covers the landing, because the merge was not a formality.

WHAT B3 FIXES

A symlink anywhere in the checkout permanently wedged `commit`. `extras.zig` classified a symlink as an extra, and the recursive `add DIR` / `addremove` paths reused that sweep as their add set without re-applying the kind test that explicit `zit add sym.txt` and `commit` both apply. The recursive path tracked exactly what the direct path refused, so after `zit add .` every subsequent `zit commit` died with "cannot commit 'sym.txt': not a regular file" and the only way out (`zit rm sym.txt`) was named nowhere. Consistent refusal is the contract: 0.1.0 does not version symlinks on any path.

WHY IT LANDED SEPARATELY

B3 was committed to `blockers` off the old branch tip and never reached trunk; trunk meanwhile took B1, B5 and a CI change. The sibling B6 commit (d8e5e811) had already absorbed B3 into its own tree, so B3 would eventually have arrived on trunk bundled inside B6. Landing it on its own keeps each increment gated and merged on its own evidence rather than riding in on another's, and it shrinks the diff B6 still has to land.

CONFLICT RESOLUTION, STATED

One conflict, src/e2e.zig, positional rather than semantic: trunk's B5 block and B3's block are both appended at the end of the file, over an empty common ancestor. Both blocks are kept, one copy each.

Worth recording because it is a trap: fossil emitted a five-part conflict, not the usual four. Between the local copy and the ancestor section it inserted a "####### SUGGESTED CONFLICT RESOLUTION follows" section carrying its own proposed merge. Splitting only on the four familiar markers silently swallows that separator line into the kept text, which then compiles as garbage — it surfaced here as `zig fmt` and the compiler both failing at that exact line, not as anything that looked like a merge problem. The resolution keeps the local copy plus fossil's suggested section (B5 then B3) and drops the duplicate merged-in copy, which was verified to be a strict substring of what was kept. Post-resolution the file holds 13 tests in that region with no duplicated test name and no residual marker of any of the five kinds.

TEST EVIDENCE ON THE MERGED TREE

Re-verified on trunk after absorbing the latest sibling (861b223e3c), not inherited from the branch: `zig fmt --check .`, `zig build`, `zig build test`, `zig build e2e`, `zig build dst` (6 seeds x 1000 steps) and `zig build smoke` (S1-S6) each exit 0. Full battery, no filtering. `fossil extras --dotfiles` is empty.

The B3 repro was also driven by hand against the rebuilt binary: `zit add .` skips sym.txt and says so on stderr, `zit commit` succeeds, `zit status` reports nothing, `zit extras` lists sym.txt, explicit `zit add sym.txt` refuses with the symlink wording at exit 1, and `addremove` withholds it silently.

No borrowed technique. No performance claim is made. check-in: 01dc9f8e8a user: dmestas tags: trunk

15:25
CI: fuzz sweep at 100 rounds per target, not 2000

The sweep could not finish inside its own 10-minute step timeout. Per-target cost varies by roughly 276x across the corpus: artifact_parse_garbage runs 100 rounds in 0.18s, while logstore_pack_same_path_round_trip takes 49s because it performs a full store pack every round. At 2000 rounds that single target needs about 16 minutes on its own.

The original figure was extrapolated from one cheap target on the assumption that per-round cost was roughly uniform. It is not, and the assumption was never measured. 100 rounds is measured: the full 27-target sweep takes about 76s.

This makes CI fuzzing a regression check — every target still runs clean on every push — rather than a bug hunt. Finding new defects needs depth, and depth belongs in an out-of-band run with its own budget, where a long sweep costs nobody a merge. check-in: 861b223e3c user: dmestas tags: trunk

15:13
Merge blockers: an add-only merge registers its file and commits (B5)

A merge whose only effect was an ADDED file was silently lost: the file landed on disk but never in .zit-managed, so status said "nothing to report", extras listed it as junk, and commit refused "nothing to commit (no changes)" while dropping the merge parent. The branch existed on one disk and undo was the only escape.

No new state was needed — CheckoutState.merge_parent already carried the pending merge and commit already consumed it as a two-token P card. The gap was the managed set and two refusals that did not know about it. applyMerge now derives the membership mutation from the same entry stream that drives the filesystem effects, which also fixes the symmetric bug for free (a merge-deleted file used to stay managed and invent a phantom "missing") and covers cherrypick/backout, which share the seam. status names a pending merge/cherrypick/backout. commit's no-op refusal no longer fires over a pending merge, so a convergent-content merge can no longer wedge the tree.

One test expectation changed: the new add-idempotence case asserted the "already tracked" notice on stdout; it has always been a stderr diagnostic (three shipped e2e cases assert it there). The test had the stream wrong, not the product.

Merged tree re-verified on trunk rather than inherited from the branch: zig fmt --check ., zig build, zig build test, full zig build e2e (420 tests, all eight REGRESSION B5 cases green including the contract-partner undo guard) and smoke S1-S6 all exit 0. fossil extras --dotfiles is empty. The blocker repro was also driven by hand against the rebuilt binary end to end.

Landed alongside, not merged here: another session committed B3 (1aeb531cac) to blockers off the OLD blockers tip, leaving that branch with two leaves. This increment branched off trunk, so the two do not interact and B3 remains that session's to land. check-in: 99f4895c04 user: dmestas tags: trunk

Changes