50 descendants and 50 ancestors of aa54d6f6512f7fdc
|
2026-08-16
| ||
| 19:28 | Create new branch named "project-code" check-in: e77f1e196a user: dmestas tags: project-code | |
| 18:57 |
settings: keep-glob, manifest, before-commit consent, config pull (#82, #83)
keep-glob protects files clean must never delete while extras still lists them; manifest becomes a project setting driving build stamps. Both resolve across the tier chain, so a tracked .zit-settings file clones with the code. before-commit splits declaration from consent (#82): the project ships the check as a tracked file, zit trust records the SHA-256 this checkout agreed to run. Cloning executes nothing, and an edit revokes consent by itself because the record pins content, not a flag. Non-zero exit aborts before anything is minted. zit config pull shun is fossil's explicit request side; carriage stays clone-time otherwise so no peer can suppress content here on its own say-so. Storage gains one keyed-string block: unknown keys are skipped by length, so the next string setting needs a key rather than another shape tag. Existing frames are unchanged. clean-glob is deliberately absent: it means never-prompt and no-undo, which zit clean already is. check-in: 998dbf9d43 user: dmestas tags: trunk | |
| 18:45 | merge empty-trailing-token: C and J accept an empty trailing token (#86) check-in: b4893b3fee user: dmestas tags: trunk | |
| 18:30 |
C and J accept an empty trailing token (#86)
Fossil distinguishes an absent token from an empty one positionally: `C` LF has none and is rejected, `C` SP LF has one empty token and is a present, empty comment. zit implemented §4.2's `token = 1*tchar` literally and rejected the empty form on C and J, which drops the whole artifact — every ticket change with an empty field, every check-in with an empty comment. T and U were already right. Two tests asserted the old behaviour and now assert the corrected one; a third pins the writer, since --submanifest re-mints every manifest. The RFC text is unchanged; docs/rfcs/erratum/ carries the correction. closed check-in: 5ccb138e6d user: dmestas tags: empty-trailing-token | |
| 18:04 | settings: hazard-tiered model with a global tier and provenance (#83) check-in: 6677853a3d user: dmestas tags: trunk | |
| 17:44 |
smoke S9: require the carried shun row, not a phantom (#73)
Carrying the /shun config group means a fossil clone records the artifact as suppressed instead of holding a phantom for it. That is the better end state: a phantom is something fossil goes looking for, so the next sync with any third party would undo the takedown. S9 asked for the phantom specifically and so went red. It now asks fossil's own shun table and REQUIRES the row — tolerating the phantom would leave the scenario unable to notice the carriage regressing. The phantom probe stays as a diagnostic that tells a lost row apart from a served artifact. check-in: 7c656e4718 user: dmestas tags: trunk | |
| 17:33 | merge frames-parallel: verify a batch across workers (#84) check-in: c36e9952c2 user: dmestas tags: trunk | |
| 17:28 |
frames verifies a batch across workers (#84)
Profiling the post-memo stream put 59% in artifact.verify and 38% in reconstruction, so the parallel target is verification, not reconstruction: reconstruction is what the plaintext memo made sequential-friendly, and fanning it out would contend on that cache. Reconstruction stays single-threaded; a bounded batch is hashed by workers walking disjoint strides, then emitted in order. Workers touch no store, no cache and no allocator, so there is no queue, lock or atomic — join supplies the ordering. libfossil 2.35s -> 1.37s wall, byte-identical output. closed check-in: 4b2fceeacd user: dmestas tags: frames-parallel | |
| 16:30 |
local signing settings, and the shun table over the /shun config group (#72, #73, #83)
clearsign and pgp-command join zit settings as repo-local values fossil never propagates: pgp-command is a command line this machine executes, which fossil classifies sensitive for that reason. Config frame gains shape v4 for the command string; clearsign rides the existing flags byte. Precedence is ZIT_PGP_COMMAND, then the setting, then fossil's default. zit serve now answers reqconfig for a named group, and clone requests and adopts /shun. A clone that dropped the table would re-accept content its origin was ordered to remove on the next sync with any peer; the #73 scale run also traced 12 spurious phantoms to the same loss. Verified both directions against stock fossil 2.28. scripts/roundtrip-fossil.sh is the fossil -> zit -> fossil differential, run in CI on a built corpus: zig build e2e can only spawn zit, so nothing in the Zig suite can assert a stock fossil accepts what zit served. check-in: 57a9e0fc6b user: dmestas tags: trunk | |
| 16:00 | merge frames-memo: stream through the plaintext memo (#84) check-in: 6759506ea8 user: dmestas tags: trunk | |
| 16:00 |
frames streams through the plaintext memo (#84)
frames was the one bulk reader still calling the uncached content(), so a delta base was reconstructed once per referencing delta rather than once per run — superlinear work against a linear stream, on corpora that are ~90% deltas after a fossil import. libfossil (17,449 artifacts): 12.4s -> 2.34s real, 12.0s -> 2.25s user. Output byte-identical, peak RSS down 362MB -> 314MB. memoize_undeltaed stays off: the sweep reads each artifact once, and bases are memoized regardless of their own frame kind, which is the win. closed check-in: 2e3bb0b9db user: dmestas tags: frames-memo | |
| 15:04 | merge record-cards: technote C/T cards and forum N card (#77) check-in: 5bea261864 user: dmestas tags: trunk | |
| 14:46 |
technote and forum verbs write the cards the format allows (#77)
technote add gains --comment (the C card a timeline renders as the note's title, unattachable by any later verb) and repeatable --tag, minting T +sym-NAME * sorted ascending as fossil writes it. forum post and reply gain --mimetype, matching wiki commit's spelling. Empty titles, repeated tags, and whitespace tag names are refused. First CLI-level coverage for either verb: #76 shipped them tested only at the artifact layer. closed check-in: 21f6efdd1c user: dmestas tags: record-cards | |
| 13:52 | merge tag-cards: raw-namespace tags, values, and cancel (#80) check-in: 6b4ac926e6 user: dmestas tags: trunk | |
| 13:26 |
tag: raw-namespace tags, values, and cancel (#80)
tag add could mint only T +sym-NAME, so a verdict like ci-pass became a symbolic check-in name and the second check-in carrying it made that name ambiguous. add and cancel now take fossil's --raw namespace choice, an optional VALUE, and --propagate; list --raw reads raw tags back, since they are deliberately outside the name space. Names under wiki-, tkt-, or event- are refused, as fossil refuses them. The composer's arguments moved into a TagCardSpec, which hides its two precondition asserts from the release-assert scanner (a struct field is not slice-shaped), so its baseline entry goes; the asserts stay. closed check-in: 3fa532af3a user: dmestas tags: tag-cards | |
| 12:49 |
commit --sign: clearsigned manifests, fossil's contract (#72)
The signed text is the stored artifact, so readers strip the wrapper to reach the cards and the signature travels wherever the check-in syncs. Signer invocation matches fossil's clearsign.c: COMMAND OUTFILE INFILE, default 'gpg --clearsign -o ', ssh* basenames take the detached path with assembled armor, 'off' disables. A signer that fails or alters the manifest refuses the commit rather than storing it unsigned. artifact reports signature presence; carry is pinned through pack, verify, and the sync wire. check-in: eb2f1adeda user: dmestas tags: trunk | |
| 05:35 | wiki and ticket leave the top-level command list: the four authoring verbs are machine verbs by the #76 posture (another process is their audience), each still fully documented by its own help check-in: d18a3b5589 user: dmestas tags: trunk | |
| 05:17 | merge worktree-registry: the store-side worktree list and the worktrees verb (#70); verb-set union with forum/technote (#76) check-in: d88bdc5e67 user: dmestas tags: trunk | |
| 05:01 | worktree registry (#70): every open and update stamps the tree's absolute path into the store's .zit-cache/worktrees (advisory tier, best-effort, self-healing — the store-cone discipline); 'zit worktrees' lists the registered trees with branch and check-in, verifies membership by the store file's inode, lazily prunes dead or re-pointed entries, and answers bare via -R closed check-in: 9d079f3009 user: dmestas tags: worktree-registry | |
| 05:01 |
forum and technote authoring verbs (#76)
zit forum post/reply and zit technote add record forum-thread and event artifacts under the #71 machine-verb contract: bare store via -R, hash-only stdout, exact exit codes, unlisted in the human help. A reply resolves its thread root transitively; a technote edit reuses its event id. check-in: 4317c47ed5 user: dmestas tags: trunk | |
| 04:27 |
D cards carry milliseconds (#75)
Every artifact-minting path writes the .SSS writer form fossil itself emits, so same-second writes keep a real-time order for latest-wins consumers. SOURCE_DATE_EPOCH pins .000; display surfaces unchanged. check-in: 0ff8e58ce8 user: dmestas tags: trunk | |
| 04:05 | e2e: the import-fossil residue scans iterate a dedicated .iterate handle scoped to the scan — Linux dirRead re-seeks the fd per batch, so iterating a handle owned elsewhere is BADF there (macOS tolerates it) check-in: 68506d0e3e user: dmestas tags: trunk | |
| 02:37 |
sync: per-round credentials over the cookie channel (#74)
An authenticated exchange now carries a fresh credential on every round: body login until the peer's gate is known, then an x-f-l-c cookie whose nonce covers that round's own body. The transport attaches it; serve now verifies it (and refuses tampered, replayed, and duplicate logins) instead of ignoring the header its own announced version solicits. check-in: 1fd84b4327 user: dmestas tags: trunk | |
| 02:21 | zig fmt check-in: f7b57a5869 user: dmestas tags: trunk | |
| 01:51 | merge import-fossil: fossil history import with the compatibility consequence chosen at import time (#61) — --compatible preserves the corpus byte-exact in the origin's sync world; --submanifest re-mints history as sub-manifest trees under a new project code, gated by whole-history replay, proven file-set-equivalent pair by pair, published atomically, with the old->new provenance map shipped as a technote. Merge resolution unions the verb set with wiki/ticket (#71) and completes their top-help listing check-in: 3f1f2a257d user: dmestas tags: trunk | |
|
2026-08-15
| ||
| 23:20 | conversion under the staged-publication discipline plus the provenance technote (#61): the bundle's atomic rename is the only commit point (a failed run leaves a sweepable .zit-tmp-*, never a half-repo), and the old->new map ships as a deterministic event artifact inside the converted repository — sorted pairs, source-tip timestamp, project-code-derived id — so external hash citations resolve by lookup closed check-in: cbbc910841 user: dmestas tags: import-fossil | |
| 23:20 |
wiki and ticket authoring verbs (#71)
zit wiki commit and zit ticket new/set record wiki and ticket-change artifacts on a bare store via -R, under the store write lock. Machine verbs: hash-only stdout, exact exit codes, unlisted in the human help but fully documented via their own --help. check-in: fe8d14d754 user: dmestas tags: trunk | |
| 22:49 | import-fossil --submanifest converts (#61): topo-ordered re-mint of every check-in as an S-tree (text-level card rewrite — F run out, S run in sorted position, B dropped, P/Q/T chased through the old->new map, PGP stripped and counted, Z resealed), control artifacts remapped, blobs and non-referencing chains verbatim, clusters dropped; every (old,new) pair proven file-set-equivalent through the destination flattener before anything survives, counts reconciled against the census, failed runs roll back to nothing. --compatible byte-exactness is a pinned invariant: the frames census of an imported corpus equals the origin's stream, and the import still pulls from it (#73's prerequisite) check-in: 5d61c0da47 user: dmestas tags: import-fossil | |
| 20:52 | fossil_convert: the corpus census and the re-mint cascade rule (#61) — classify every artifact, count the remap surface (check-ins re-mint; wiki/forum/ticket/attachment chains carry verbatim under kept content names), state the casualties (PGP signatures strip, clusters drop), and refuse an incomplete corpus; --submanifest prints the census as the conversion's reconciliation baseline check-in: ce57c94b6d user: dmestas tags: import-fossil | |
| 18:46 | import-fossil verb (#61): the compatibility consequence is chosen at import time — --compatible preserves the corpus verbatim through the clone machinery and stays in the origin's sync world; --submanifest runs the whole-history replay gate (static k sweep at the tip, winner±1 replayed, refuse-if-worse without --force) ahead of the conversion pass, which lands next; fossil support lives in src/fossil/ beside src/git/ check-in: 4c24d037b7 user: dmestas tags: import-fossil | |
| 18:08 | add src/ignore.zig, dropped from the #64 commit check-in: 2d981d8f85 user: dmestas tags: trunk | |
| 18:07 |
ignore mechanism: ignore-glob setting, .zit-settings/ignore-glob, .zitignore (#64)
extras, addremove, clean, and add's directory expansion share one exclusion point; explicitly named files still add. Fossil glob dialect for the setting and versioned file, gitignore dialect for a root .zitignore, unioned when both exist. check-in: 5c68eb4688 user: dmestas tags: trunk | |
| 17:39 | the submanifest -R pin follows the analyze-mode grant check-in: dab7ec41f3 user: dmestas tags: import-fossil | |
| 17:19 | submanifest analyze: -R over a bare store (tip file set, no checkout) and --replay-all for whole-history replay (#61 step 2) — the conversion gate's evidence pass and before/after table in one read-only command; settings actions refuse -R in-verb check-in: 70b7e2f06e user: dmestas tags: import-fossil | |
| 16:37 | extract the staged-publication pipeline into src/publication.zig (#61 step 1): PublicationBundle's one-way stage transaction, PublicationHooks, generation names, and the atomic-rename extern move verbatim; git_import_cli re-exports the same names, so import-git behavior, tests, and callers are unchanged — history converters share one publication discipline check-in: 7eff935454 user: dmestas tags: import-fossil | |
| 16:24 | gate: check zig fmt check-in: ad900494fb user: dmestas tags: trunk | |
| 16:16 | zig fmt check-in: 54cdfbbfaa user: dmestas tags: trunk | |
| 16:08 | mirror-export: prune closed-branch refs on every export check-in: b0fde46c32 user: dmestas tags: trunk | |
| 15:58 | merge worktrees: detached checkouts, store lock, open --store re-point (#59) check-in: bcbf29d017 user: dmestas tags: trunk | |
| 15:30 | merge diff-repo-override: bare-store diff --from/--to via -R (#69) check-in: 8066a7c21d user: dmestas tags: trunk | |
| 15:16 | diff --from/--to honors -R (#69): the check-in pair touches no working tree, so a bare store serves it; the worktree comparison refuses -R in-verb with the works-in-a-checkout diagnostic closed check-in: 4002513eeb user: dmestas tags: diff-repo-override | |
| 15:06 |
open --store re-points an already-open tree (#59)
A moved store strands its satellites, and a stranded tree can hold uncommitted work. Re-open repairs the pointer in place, gated on the new store containing the tree's current check-in. closed check-in: 7ac1ec2255 user: dmestas tags: worktrees | |
| 13:39 |
worktrees: detached checkouts of one store (#59)
Every store writer serializes on an exclusive flock held open-to-commit (released before autosync and the drift advisory). A checkout's store_location section is resolved in one place; open --store PATH creates a detached working tree, and probeRoot accepts a checkout whose pointer resolves. Store-scoped verbs (pack, shun, serve) follow the pointer end to end. check-in: 94d4659a53 user: dmestas tags: worktrees | |
| 13:04 | merge help-topics: help topics, single-source option fragments, exit-status blocks everywhere, mechanical usage-line audit (#68) check-in: 9a5ae9774b user: dmestas tags: trunk | |
| 12:50 | help topics (#68): 'zit help names/sparse/repo/exit-codes'; verbs point at the names topic instead of restating the resolution litany (timestamp forms were documented in one help of six); unknown help topics refuse with exit 2; the -R/--no-cache prose and the conventional exit-status block become single spliced consts (28 helps gain the block); a unit test asserts every options-table flag reaches its usage line — it caught commit --no-sync, merge --no-sync, and the cone flags on open/update/clone closed check-in: 21fa16cc4b user: dmestas tags: help-topics | |
| 12:10 |
import-git: O(changes) per-commit cost and live progress (#65)
Tree edits adopt untouched sibling leaves, the tree witness digest is structural over the root S-run (flat digests unchanged), and log reads go through a primed plaintext cache. Ingest reports strided progress with pack/verify phase markers. check-in: db4b2573e7 user: dmestas tags: trunk | |
| 04:01 | merge read-verbs: frames incremental artifact stream and annotate VERSION/--full (#66, #67) check-in: b41272c88c user: dmestas tags: trunk | |
| 02:52 | read verbs for external consumers (#66, #67): frames streams whole raw artifacts since an opaque cursor in persisted order, with LogKey prefix validation (appends keep a cursor alive, a pack/shun rewrite fails it with exit 4; exit 3 = current) and per-artifact hash verification; annotate gains a VERSION operand resolved like cat's (bare-repo -R works) and --full for full artifact IDs closed check-in: 68eba6cd49 user: dmestas tags: read-verbs | |
| 01:03 | merge sparse-cone: sparse checkouts and sparse stores per draft-fossil-sparse-cone-00 — worktree cones with exclusions, cone-scoped clone/open/update, cone/cone-not wire pragmas with graceful degradation, demand fetch, pack --drop-elided, cross-cone record merges, and the sparse-origin clone refusal check-in: 2ad75a9bea user: dmestas tags: trunk | |
| 00:39 | sparse origin refuses clones it does not cover (spec 5.3): dense and uncovered-cone clone requests answer one error card and no content; the client treats a progress-free error round-0 reply as fatal (spec amended — the sync 11.1 discard tolerance is for cosmetic cards on progressing replies) and quotes the peer's refusal closed check-in: 6e064b7301 user: dmestas tags: sparse-cone | |
|
2026-08-14
| ||
| 22:48 | import: sub-manifest memo progress line every 25k commits, and an adaptive trim target tracking each walk's touched bytes (#63 investigation — preventive; the pkgsrc slowdown reframed, see issue) check-in: aa54d6f651 user: dmestas tags: trunk | |
| 19:39 | sync: unversioned cards tolerate-and-report (#58) — validated, counted, never an abort; sessions report N not transferred; NotImplemented retired; uv-only replies are the clean §3.7 terminal check-in: 3cf76b982e user: dmestas tags: trunk | |
| 18:27 | import-git: refuse git older than 2.45 by name before any work — first preflight query, without --no-lazy-fetch; CI verifies the minimum beside fossil (#62) check-in: 43efce758a user: dmestas tags: trunk | |
| 16:57 | commit: fork guard — parent must still be its branch's leaf (--allow-fork to fork); autosync — settings verb, pull before commit/update/merge, push after commit, warn-and-continue (#57) check-in: 7a4dff5d5f user: dmestas tags: trunk | |
| 15:37 | linux: iterate/fsync need real fds — reopen O_PATH dir handles with iterate rights (7 sites + test helpers); runScripted captures into caller-owned storage, ending a use-after-return the Linux stack exposed check-in: a60df1f752 user: dmestas tags: trunk | |
| 14:37 | import-git: drop std.c — child environ threads from Init via Ambient, dir fsync goes through Io; Linux builds no longer demand libc check-in: 951b654c5b user: dmestas tags: trunk | |
| 13:43 | export-git: DEST preflight must name DEST's own git dir — upward discovery adopted the enclosing repo and aimed fast-import at its refs check-in: f451567485 user: dmestas tags: trunk | |
| 12:21 | merge sub-manifest: delta-manifest dialect, R cards, diff hunks, server identity, stash, open/log resolution, clone remote+progress, timestamp names; e2e expectations updated check-in: 8a45a021f9 user: dmestas tags: trunk | |
| 10:11 | clone: save the URL as the remote (canonical, password-free, --once opts out); live per-round progress on a TTY stderr (#55 #56) closed check-in: 69c14cd747 user: dmestas tags: sub-manifest | |
| 10:11 | resolve: §8.3 portable T/Z timestamp form and the NAME:TIMESTAMP compound (#60) check-in: f2691f0a23 user: dmestas tags: sub-manifest | |
| 01:57 | open: optional CHECKIN — resolve like info and materialize it directly; no-arg tip behavior unchanged (#54) check-in: 8573f4f57d user: dmestas tags: sub-manifest | |
| 01:33 | log: CHECKIN resolves like info — branch, tag, prefix, reserved forms; full hex IDs keep the stateless fast path check-in: b77d2898ad user: dmestas tags: sub-manifest | |
| 00:11 | stash: save/list/show/apply/pop/drop over a durable .zit-stash sidecar — fail-closed apply (clean targets, same check-in), corruption refuses loudly; the no-stash reflex retires; README rows updated check-in: ba3d1e705b user: dmestas tags: sub-manifest | |
|
2026-08-13
| ||
| 22:12 | commit: keep the delta-manifest dialect — once a repo stores a B-card manifest (durable seen_delta config, ingest-detected), commits emit deltas against the parent's baseline with delete markers, byte-cost guarded; commit also resolves a delta parent's true effective set check-in: 60b3557200 user: dmestas tags: sub-manifest | |
| 20:14 | diff: textual hunks by default — patience alignment, git-compatible unified output (patch -p1 round-trips), -c N context, --brief keeps name-status check-in: ca0f3df379 user: dmestas tags: sub-manifest | |
| 20:13 | sync §9.1: real per-instance servercode — derived from the checkout's absolute path (deriveServerCode, domain-separated from the project code), emitted by serve and all four client verbs; placeholder retired to test fixtures check-in: 59e8660999 user: dmestas tags: sub-manifest | |
| 19:22 | README: five-RFC table, capability overview, and the compatibility framing — what Fossil has, what zit has, and the one break (sub-manifests) check-in: 0f8b901650 user: dmestas tags: sub-manifest | |
| 19:22 | commit: emit the R aggregate checksum on every check-in; update/open verify it fail-closed (Fossil's default repo-cksum posture); diff: rev-to-rev name-status via --from/--to check-in: ad8012ec78 user: dmestas tags: sub-manifest | |
| 18:43 | docs: carry the three errata the code implements ahead of the RFC text (repo-state §5.4 cancel-halt, artifact-format §4.1.2 sterilizer, sync §3.3 content-received OPTION B) — provenance for the divergence until the canon applies them check-in: 062e9a5512 user: dmestas tags: sub-manifest | |
| 18:31 | repostate: cancel-tag propagation halts at a rowless node, matching fossil tag.c (#16); erratum filed for the divergent §5.4 draft text check-in: e286beebd3 user: dmestas tags: sub-manifest | |
| 16:09 | export-git: mirror canonical history into git check-in: ae7c26a1a3 user: dmestas tags: sub-manifest | |
| 16:09 | bench: qualify incremental git export scaling — memo parse bound pinned; althttpd/wapp export clean (fsck 0), phantom-parent lineage refuses naming both hashes check-in: 75fb61025d user: dmestas tags: sub-manifest | |
| 15:18 | e2e: verify git export commit by commit check-in: 08ca21c63c user: dmestas tags: sub-manifest | |
| 15:14 | cli: export git mirrors incrementally check-in: 5b2c6139d5 user: dmestas tags: sub-manifest | |
| 15:03 | export-git: publish mirrors without partial state check-in: 41dfef63b2 user: dmestas tags: sub-manifest | |
| 14:32 | export-git: translate check-ins refs and failures precisely check-in: 74c5c8aba0 user: dmestas tags: sub-manifest | |
| 13:52 | export-git: plan topologically and enumerate through the seam check-in: 491cbc50c5 user: dmestas tags: sub-manifest | |
| 13:35 | export-git: persist a disposable local mark map check-in: 17c02d8950 user: dmestas tags: sub-manifest | |
| 13:23 | export-git: serialize bounded fast-import streams (the writer files the previous commit's message described) check-in: bb1cc4a01b user: dmestas tags: sub-manifest | |
| 13:23 | export-git: serialize bounded fast-import streams check-in: 2450e4f142 user: dmestas tags: sub-manifest | |
| 13:08 | git: gather every interop root into src/git/ — cli.zig joins the zit module (nine importers rerouted), moved roots take parent deps through the module; ~986 duplicate test executions eliminated check-in: 49c08bb191 user: dmestas tags: sub-manifest | |
| 11:41 | submanifest: replay history to pick k (#41) — analyze replays last 200 commits through the real builder+delta encoder (both cost axes, bootstrap split, baseline-charged materialization); enable pins the replayed argmin, snapshot objective as fallback. Advisory only. check-in: b9ceda433f user: dmestas tags: sub-manifest | |
| 03:06 | clone: stop inflating served/received delta containers for their header — prefix-inflate 16B, base frame read header-only; server CPU per 1M-artifact clone 300s+ -> 22s, clone verifies 0 faults check-in: f5eafc6a2f user: dmestas tags: sub-manifest | |
| 01:25 | serve: notice a --force shun/pack generation swap — stat the path beside the held handle, reopen between rounds; shunned bytes stop serving with no restart. Closes #17 check-in: faa8befc3b user: dmestas tags: sub-manifest | |
| 00:16 | serve: scale the write deadline with the reply — 4MB clone batches at the flat 5s cut healthy slow peers mid-write (#22 shape); slow-drain e2e proves it check-in: fa230db9e8 user: dmestas tags: sub-manifest | |
|
2026-08-12
| ||
| 23:21 | timeline: order tied runs by generation, not per-pair ancestry walks — 305k-commit CVS import renders in 5s vs CPU-hours; B1 descendant-first preserved exactly check-in: d823a2811d user: dmestas tags: sub-manifest | |
| 21:47 | clone: byte-budgeted batches (4MB) — 159 rounds vs ~1000 for a 1M-artifact store; warm clones plant the checkpoint (first command 0.06s); print transfer/derive phases. Closes #53 check-in: c32414008b user: dmestas tags: sub-manifest | |
| 19:56 | checkpoint: accept delta manifests; anchor at newest check-in (mainline fold collapsed on real repos); sync: index the pending-delta queue (O(1) hasTarget, O(deps) completeFor) — zit now clones 2GB pkgsrc-2012 from real fossil in 10min, resumes opens in 9s vs 4min derive check-in: c70f48f825 user: dmestas tags: sub-manifest | |
| 09:04 |
checkpoint: retire the tree shape — sidecar only, structurally
The tree shape minted permanent SUBMANIFEST artifacts for benefits already had elsewhere: the rebuild win lives in the prefix record, verify's §6.2 oracle runs buildTree in memory, and the subtree-sharing bytes re-materialize at the first real S-emitting commit at identical cost. Minting early only created unreferenced permanent artifacts and the allow-tree/demotion/gate apparatus needed to keep automation from doing it by accident — all deleted with it. build no longer opens the log for writing or reads the emission settings at all; sidecar layout v3 (old sidecars miss and rebuild in seconds). Proven at scale: SHA-256 of pkgsrc's 593MB store is byte-identical across a full build; cold 4:12, rebuild 3.4s. check-in: 2a8fdcff60 user: dmestas tags: sub-manifest | |
|
2026-08-11
| ||
| 22:45 |
checkpoint: one-pass build, incremental advance, opportunistic refresh
Build paid a bypass derive, a whole-prefix delta scan, and a capture re-derive; a view-free captureRecords (byte-identical to the deriving walk, pinned at every boundary) now does capture and delta detection in one pass, and an existing sidecar's body plus its delta-free attestation reduce a rebuild to the unscanned tail. pkgsrc: cold build 17:58 -> 4:21; rebuild or anchor advance -> 5.1s. Repository.open's healing paths keep an existing checkpoint fresh: witness shape forced (the automatic path can never mint an artifact, whatever §8.1 says — a tree pin advances by demotion and is re-pinned deliberately), gated on 4MB growth AND anchor progress so blob-only growth never churns the sidecar. No checkpoint, no auto-creation: building once is the opt-in. check-in: adae602908 user: dmestas tags: sub-manifest | |
| 20:04 |
repostate: carry the C-card comment in the crosslink record
An unlimited timeline re-read and re-parsed every manifest just to print its comment first-line — 163k inflate+parse cycles on pkgsrc. The comment now rides the crosslink record into the derived state (commentOf; image backing falls back to the manifest read), so the render loop is a lookup per row: full timeline 12.3s -> 1.06s. Record-format consumers bumped so old bodies miss instead of misparsing (repocache v3, checkpoint v2 — one re-derive per repo, then warm). zit log's pinned B-log-1 walk untouched. check-in: 57d8de4120 user: dmestas tags: sub-manifest | |
| 19:07 |
repocache: persist the content log's scan index
The lazy content channel re-walked every frame header on each open — O(store) before the first byte of any comment, cat, or annotate. The scan's product (entries, hash index, shun rows, config cursor, tail key) now persists as .zit-cache/index, self-validating and LogKey-keyed: an exact tail adopts whole, a grown log resumes the walk over the tail alone, and anything else falls back to the authoritative scan (--no-cache never consults it). pkgsrc: info 1.7s -> 0.44s, timeline -n 5 4.3s -> 0.96s. check-in: f2bfd36e74 user: dmestas tags: sub-manifest | |
| 18:17 |
logstore: O(1) LRU eviction in PlaintextCache
Replace the pick-the-minimum-stamp linear scan with an intrusive doubly linked recency list; get/put/evict are all constant-time. The scan was invisible at small occupancy and dominant at full: a pkgsrc clone kept the cache pinned at max_entries and spent over half its client CPU sweeping the map once per stored artifact. Measured: clone 12:38 -> 8:39 wall, client CPU 694s -> 463s; cloned store verifies with 0 faults. check-in: 0df83f350a user: dmestas tags: sub-manifest | |
|
2026-08-10
| ||
| 23:48 |
Move the git-interop implementation into src/git/
Seven files relocate with unchanged basenames: git_fast_export(+test), git_import, git_import_impl, git_import_cli, git_import_verify, git_import_benchmark_support. The six standalone module roots (test, refs_test, cli_test, e2e, benchmark, pipe_helper) stay flat because a Zig module cannot import above its root file's directory — the same rule that keeps main/e2e/dst/smoke at src/. Future export-git files follow the same split: roots flat, implementation in src/git/. Path-string edits only; build.zig unchanged. check-in: ce3c87e25c user: dmestas tags: sub-manifest | |
| 23:12 |
Add zit checkpoint: durable prefix resume for hybrid history
.zit-cache/checkpoint pairs a validated log-prefix key with the prefix's crosslink record body; Repository.open resumes past the flat segment on a cache miss instead of re-parsing it. Witness shape under a closed emission gate creates zero artifacts; tree shape pins the anchor's file set as the canonical S-tree (batch-oracle byte-identical, one interior root node). verify re-derives every claim from real history; --no-cache bypasses both sidecars. New verb: zit checkpoint [show|build|verify|drop]. pkgsrc (163k commits, 60k files): cold open 8.4s vs 352s full derive; verify passes; 366/367 tree nodes deduplicated against the imported tree. check-in: e4026acd7b user: dmestas tags: sub-manifest | |
| 20:17 |
Delete the legacy reserved-name tier (consolidation Task 7)
The policy is three names and a prefix: .zit, .zit-checkout, .zit-cache, .zit-tmp-*. Removed: the absorbed sibling reservations (.zit-managed/-undo/ -bisect), the pre-directory cache/vstat spellings and their read tolerance, the retired scratch spellings, and the import-provenance names (refs, .zit-import-map.jsonl). Behavior shift: in never-re-opened old checkouts these leftovers are now visible to extras and deletable by clean. The container's byte-1 fold stays, so a legacy authoritative sibling still migrates losslessly on first contact (e2e: every-leftover checkout converges to the clean root with membership intact). check-in: c0a116d458 user: dmestas tags: sub-manifest | |
| 19:31 |
Fold managed/undo/bisect into the .zit-checkout container v2 (consolidation Task 6)
Sectioned container (ZITCKOT, tagged table, whole-file CRC); payloads are the existing formats unchanged. Byte-1 dispatch migrates legacy checkouts on first write; siblings dead once a container exists. Undo/redo restore and the commit/merge record+membership writes each collapse to one atomic splice. DST gains a legacy-seeded migration sweep (full-legacy or full-container at every crash cut). Registry: the three names move to the legacy tier. Perf on pkgsrc: adjacent update 6.50s (was 6.8), no-op 5.14s (was 7.69); migration of a 66k-file checkout invisible inside one update. check-in: efa29d234f user: dmestas tags: sub-manifest | |
| 17:25 |
control files: registry, provenance opt-in, one scratch prefix, advisory dir
Tasks 1-5 of the control-file consolidation plan. The checkout root goes from twelve zit-owned names to six live ones; the authoritative-tier container (task 6) and legacy removal (task 7) are deliberately not in this change. Registry: control_paths now carries every reserved root name with its tier -- authoritative, advisory, scratch, legacy -- and is the single authority the case table, the extras exclusions and the ignore-glob coverage pin all derive from or test against. A name added without its glob line or case coverage is a test failure, proven by mutation. The pin caught two live gaps on arrival: a crashed update's transaction directory had no ignore-glob line, and a crashed import's staging directory was never reserved at all. import-git --provenance: the per-object map and the source ref manifest are now instrumentation, published only on request. The default destination is the repository and its checkout record -- fossil's own shape. Both files are still written and verified in staging every run; without the flag they leave with the raw generation, and the staging manifest check enforces whichever set was chosen. Scratch: one prefix. .zit-tmp-txn- (update transactions), .zit-tmp-import- (import staging), .zit-tmp-pack (pack scratch; name only, the truncate-reuse and rewrite-exclusion lock protocol are untouched). One registry prefix row and one glob line cover the tier including names that do not exist yet. Advisory: .zit-cache is a directory -- repo (derived-state cache) and vstat (materialization plan), with the tree-checkpoint's member reserved. A legacy cache FILE is served through a read fallback and migrated by the first write via rename through a scratch name: the derivation survives with no bytes copied and no re-derive. Verified on a 66k-file pkgsrc checkout: identical SHA-256 across migration of a 35.8MB cache, fallback reads at parity, no-op update 7.69s vs 7.74s. Legacy spellings of every renamed or relocated name stay reserved and ignore-globbed until the removal release. check-in: f1ac625093 user: dmestas tags: sub-manifest | |
| 13:41 |
update: cost tracks the diff, not the width
Three fixes, each found by measuring the previous one's residue. markUnchanged: a path byte-identical between baseline and target -- same digest, same mode, with requireClean having already proven the on-disk file matches -- is skipped by every mutation phase: staging both directions, the undo journal, deletion and rewrite. An update used to delete and rewrite the entire tree regardless of how little changed. .zit-vstat: the stat sidecar written at materialization is now the BASELINE PLAN -- version-bound, CRC'd, carrying mode and plan order -- so requireClean rebuilds the baseline with zero tree flattens when it describes the current check-in, and proves most files clean by inode/size/mtime instead of reconstructing their content out of the log. Advisory throughout: any mismatch, staleness or corruption falls back to the flatten and the content compare, which stay authoritative. ManagedSet.fromSortedPaths: building the 66k-entry managed set through insert was quadratic -- an O(n) sorted-position memmove plus the LIVE sortedUnique assert per call -- and measured at 23.9 SECONDS of a pkgsrc update, larger than every real phase combined. The plan's own order is already sorted and unique, so the set is now built in one pass, order enforced per adjacent pair, invariant asserted once. Measured, same store and targets as #52's gate: sqlite (2.2k files): 117.8s flat -> 0.6s adjacent / 1.2s distant pkgsrc (66k files): 42.2s flat -> 6.8s adjacent / 8.9s distant pkgsrc user CPU: ~25s -> 1.3s Residue is stat I/O (two ~66k-file sweeps), not computation. The lockstep flatten prune #52 proposed was never built: the flatten measured 178ms at 66k files once the real costs fell. Tests: dirty AND delete of a skipped-diff file both refuse with the tree untouched; sidecar intact/absent/rebound-to-wrong-check-in all produce identical trees; an unchanged file provably keeps its inode; an updated tree equals a from-scratch materialization. Closes #52. check-in: 8797f53546 user: dmestas tags: sub-manifest | |
| 01:23 |
repocache: extend across appends; import warms at completion
The derived-state cache was all-or-nothing: any log append was a total miss, and the next read re-derived the whole store. On a real 1M-artifact pkgsrc store that was 352s per cold read, re-paid after every commit. Repository.open's miss path now distinguishes growth from rewrite. On growth it replays the cached record body (parse-free), folds only the tail frames through the same crosslink fold a cold derive uses, and rewrites the cache: every append healed by the next read at O(tail). Measured on pkgsrc: 352.31s cold, 2.40s after a commit, output byte-identical to a forced full re-derive. Sound because extension refuses whenever the fold could be wrong rather than stale: validatePrefix proves the old tail frame still verifies at its offset (a rewritten log cannot extend), and a shun fingerprint in the cache header forces the full derive on any shun-table change, since the body was distilled under the old mask. Cache format v2; a v1 cache misses once and rebuilds. import-git now warms the cache at completion, after the atomic rename, against the published store -- clone has done this since warmCacheFromLog existed, so an import-built store no longer defers the whole derive onto its first reader. Tests: extension equals cold derive with a fork and control tag in the tail; a forged-cache canary proving the fold starts from the stored body; shun change takes the full derive with the mask applied. Also backs out 1a4b74f2d5 (parallel staging): measured ~3% on a corpus where staging is ~5s of 149s -- threading complexity the number never justified. Closes #51. check-in: 84d3fe8f32 user: dmestas tags: sub-manifest | |
|
2026-08-09
| ||
| 16:32 |
update: stage plan entries in parallel
Staging reconstructs and writes every file in a plan -- one decompress, delta-chain application and hash verification each -- and on a wide repository that is tens of thousands of files for a single open or update. The work is per-file independent, and the store's read path is offset-addressed pread over an index immutable for the duration, so it parallelises without coordination. The one thing that cannot be written concurrently is last_stage_fault, a module global. Workers keep their own and the winner is chosen by ENTRY INDEX, which is exactly the fault sequential order would have raised, so this is observationally identical to the loop it replaces including which failure gets reported. Below 64 entries it stays sequential, and a thread that fails to spawn is not an error -- its share drains off the same cursor. Measured 2:33.5 to 2:28.8 on a 299 MB sqlite store, about 3%, with CPU never leaving 101%. So staging is NOT the dominant term there: the flatten's per-node reconstruction is, which this does not touch. Committed so it can be measured at pkgsrc scale, where the file count is 27x higher and the size distribution is different. If it does not move that number either, revert it -- it buys complexity for 3%. check-in: 1a4b74f2d5 user: dmestas tags: sub-manifest | |