Skip to content
zit Timeline
Login

Timeline

50 descendants and 50 ancestors of 5c445bb3f31f4598

2026-10-12
22:34
Version 0.3.43 and its release notes check-in: cdb78ee485 user: dmestas tags: trunk
22:14
repostate: a date tag sets a check-in's event time, as Fossil orders it; log --long prints the event time check-in: d504efc44f user: dmestas tags: trunk
20:52
sync: a reply cut inside a payload keeps the prefix and warns; clone fails on it, as Fossil's does check-in: 85fd204f34 user: dmestas tags: trunk
18:59
Six errata against the -01 drafts, applied: Julian-day form, cancel cards from the parent, date-tag event time, truncated payload, file card after a refused push, errors N check-in: 100351e26c user: dmestas tags: trunk
18:45
Fold the 23 errata into draft-fossil-{artifact-format,repo-state,sync-protocol}-01 check-in: 44685f33b1 user: dmestas tags: trunk
2026-10-11
23:51
sync: judge each card by the rights in force where it appears, validate artifact names, and answer duplicate deltas, failed logins, refused pushes and /xfer redirects as Fossil does check-in: 6f833f9335 user: dmestas tags: trunk
23:44
repostate: a singleton walks as a cancel, a skipped tag op walks nowhere, and trailing punctuation is retried as Fossil retries it check-in: 3aa3ec3861 user: dmestas tags: trunk
23:22
artifact: drop reserved F cards before they set the type, merge one level under a delta baseline, as Fossil does check-in: 5b1329eb6d user: dmestas tags: trunk
21:47
errata: sync-protocol behaviours where Fossil departs from the draft check-in: 275e884be5 user: dmestas tags: trunk
21:47
errata: repo-state singleton walks, branch creation and trailing-punctuation retry, as Fossil does them check-in: 21e3d381fe user: dmestas tags: trunk
21:47
errata: artifact-format reserved F cards and delta-of-delta baselines, as Fossil handles them check-in: df960eaa60 user: dmestas tags: trunk
20:57
erratum: sync-protocol §5.2 Fossil URL-encodes file, cfile and uvfile handler errors check-in: 9f16e2ed2c user: dmestas tags: trunk
20:57
erratum: repo-state §7.3 Fossil never makes a parentless check-in without a branch tag a leaf check-in: 81608c772f user: dmestas tags: trunk
20:57
erratum: artifact-format §4.1.2 marker is rejected by card ordering, not as leftover bytes check-in: 094d3c5f8c user: dmestas tags: trunk
20:57
rfc vectors: the A.1.2 technote is the draft's 655 bytes, checked against its published name check-in: 5b89639228 user: dmestas tags: trunk
20:49
erratum: sync-protocol §7.3 uvgimme answered only to a requester with Read check-in: 5ee2946fa2 user: dmestas tags: trunk
2026-10-09
03:36
Release 0.3.42 check-in: c2dd1794b3 user: dmestas tags: trunk, version-0.3.42
03:19
merge-tree --commit: a clean merge whose sides share no changed file is recorded check-in: 6e715c9cc3 user: dmestas tags: trunk
2026-10-08
22:10
erratum: artifact-format §4.6.4 field constraints scoped to the forms that carry the fields check-in: f0e21c6db4 user: dmestas tags: trunk
22:10
Release 0.3.41 check-in: 408e03e8d7 user: dmestas tags: trunk, version-0.3.41
21:54
merge-tree --commit: a clean merge is recorded with no answers check-in: 2243921ec4 user: dmestas tags: trunk
2026-10-07
10:45
crosslink: line counts only with --lines; a shun recounts only the check-ins it reaches check-in: da2b12bb28 user: dmestas tags: trunk
05:23
Release 0.3.40 check-in: 59bc4dded1 user: dmestas tags: trunk, version-0.3.40
05:18
crosslink: a lines line under each changed file, counted as diff --numstat counts it, kept in a cache only crosslink reads check-in: 2ef61d6628 user: dmestas tags: trunk
2026-10-06
21:17
Release 0.3.39 check-in: 938da971fb user: dmestas tags: trunk, version-0.3.39
20:44
merge-tree: test a store missing one side's content, reported unreadable and refused by --commit check-in: 8b9da419b2 user: dmestas tags: trunk
19:47
merge-tree: -F json reports a conflicting merge file by file and region by region; --commit records the merge with resolutions supplied by the caller check-in: 0a0e119374 user: dmestas tags: trunk
2026-10-05
23:38
release workflow: clear the macOS package directory before extracting into it check-in: 24836c1902 user: dmestas tags: trunk
22:16
Release 0.3.38 check-in: bda4cf23d0 user: dmestas tags: trunk, version-0.3.38
21:03
protected branches: a fronted server keeps a pushed-again refused check-in on an attempt branch; push and sync show server messages check-in: 7facdf45fa user: dmestas tags: trunk
20:12
push protection: judge pushed check-ins by where the derive places them check-in: 790343bd37 user: dmestas tags: trunk
2026-10-04
17:44
Release 0.3.37 check-in: f8fa6f4f77 user: dmestas tags: trunk, version-0.3.37
17:43
crosslink: a cherrypick line per Q card check-in: 3fee66211a user: dmestas tags: trunk
17:43
sync server: only an authorized push writes; file content without one is refused, igot from a non-pusher makes no phantom check-in: 56b513bee8 user: dmestas tags: trunk
2026-10-02
14:32
Release 0.3.36 check-in: 15936cb158 user: dmestas tags: trunk, version-0.3.36
14:04
zit uv list|pull|push|rm: a server's unversioned files, moved to and from plain files, nothing stored in .zit check-in: 34f040a3e6 user: dmestas tags: trunk
13:38
settings main-branch: read and set the repository's main line; import-fossil --submanifest keeps it check-in: 477fc5f186 user: dmestas tags: trunk
2026-09-28
23:54
Release 0.3.35 check-in: 080052acdf user: dmestas tags: trunk, version-0.3.35
23:31
zit merge-tree: write the tree a merge would produce, as files or a tar, without a checkout or store writes check-in: 5471e96902 user: dmestas tags: trunk
23:13
One store-level merge produces the merged tree, modes included; merge --probe, the chained probe and landing call it check-in: c61f1fc9ff user: dmestas tags: trunk
22:55
merge takes a mode the other side alone changed, as Fossil does; an overwrite applies the mode check-in: 8dba50836f user: dmestas tags: trunk
22:23
landing reads find forum posts through an index kept in .zit-cache, walking only what was appended since the last read check-in: 658d4a733d user: dmestas tags: trunk
20:37
commit holds the store lock only to snapshot and to publish, not through the tree scan, editor or signing check-in: 6145d7a7b8 user: dmestas tags: trunk
20:22
A writer turned away by a busy lock says so once; serve answers it 503 check-in: 5a0b10fa8d user: dmestas tags: trunk
19:37
Lock notices append to a redirected stderr instead of overwriting it check-in: d59b4a1827 user: dmestas tags: trunk
16:44
zit git export/status: a remembered Git mirror with autopush

git export exports into MIRROR and remembers it, with an autopush URL, push branch and email domain, in repository config; a bare re-run does the round trip. Authors' addresses come from their user-table contact, set with the new users contact. Autopush URLs carrying a password are refused. The config payload bound is now sized from its key count. Release 0.3.34. check-in: 5fce7e867d user: dmestas tags: trunk, version-0.3.34

12:53
pack, shun --force: fsync the directory after the rename; model it in DST

The rename that installs a new generation was never made durable, so a power loss after a reported success could bring the old store back, and with it content a shun had removed. The fault layer now reverts creates, renames and deletes no directory fsync made durable, and the shun sweep requires a rewrite that succeeded to survive a power cut. check-in: 3873759cfa user: dmestas tags: trunk

12:35
landing accept: read the target once; --expect-target refuses a moved one

accept merged onto the target resolved by name at merge time, so a landing accepted meanwhile put an untested target under the merge. It now reads the target once and merges onto that check-in by hash. --expect-target HASH refuses with exit 7 and nothing written when the target is no longer at HASH. check-in: 676068f793 user: dmestas tags: trunk

11:59
Lock the store with exclusive-create lock files instead of flock

Writers create .zit.lock with O_CREAT|O_EXCL before opening the store. A waiter names the holder and gives up after a minute; a dead holder's lock is broken; pack and shun --force hold the writer lock across their final check and rename. Release 0.3.33. check-in: d6cf7bf59c user: dmestas tags: trunk, version-0.3.33

02:59
import-git: record a project code; verify notes a store without one

import-git wrote no project code, so every sync peer and forge refused the store it made. It now derives one from the destination's absolute path, as init does, and the import request requires it. verify notes a repository with no project code without counting it as damage. check-in: add51a12d2 user: dmestas tags: trunk

02:39
Take the writer lock inside LogStore.open and test the lock class

LogStore.open now takes the exclusive lock before it reads the file's length and scans for the end, and a read-only handle refuses to append. purge undo opens the store through the shared writer path.

A new DST sweep runs two to four writers interleaved against one log through a file that models the lock. It flags unlocked or misplaced appends as they happen, checks each writer sees everything committed before it locked and reads back its own writes, including deltas. A source check fails on any write-mode open of the store outside openStoreAppend. An e2e test races commits, tags and user-table writes on one store and counts what landed. check-in: 5c445bb3f3 user: dmestas tags: trunk, version-0.3.32

2026-09-27
20:37
purge undo: take the store's append lock before restoring

It appended without the lock every other writer takes, so a concurrent commit, pull or push could overwrite its frames or have its own overwritten with valid frames nothing could detect. It now opens through openStoreAppend, which also resolves a detached worktree's store. Release 0.3.32. check-in: 2249f19056 user: dmestas tags: trunk

2026-09-26
18:22
soak: print its log into the job, and let the artifact upload fail alone

The artifact quota is shared with every repository on the account; a full one failed the log upload on two nights the soak passed. The log is now printed into the job output, which is kept 90 days outside the quota, and the upload no longer decides the run. check-in: 96b430bb17 user: dmestas tags: trunk

17:56
landing accept: merge the tip it read once; --expect-tip refuses a moved branch

accept read the branch tip up to three times and merged it by name, so a push mid-accept could be merged unprobed. It now reads the tip once and merges that hash on both paths. --expect-tip HASH refuses with exit 6 and nothing written when the branch is no longer at HASH. Release 0.3.31. check-in: 60890d6661 user: dmestas tags: trunk, version-0.3.31

2026-09-25
21:14
release workflow: keep its artifacts three days, not thirty

Every artifact it uploads is transit, published to the uv store and a GitHub release the day it is built. Thirty days kept ~40 MB per release against the 500 MB storage quota, and a full quota failed the soak's log upload. check-in: 29f07577ae user: dmestas tags: trunk

2026-09-24
16:44
transport: refuse Basic over plain http to another host; drop it on a cross-host redirect

A Basic challenge was answered whatever the scheme, so over http the password crossed readable and the saved remote repeated it. It is now refused to non-loopback hosts, naming the https URL; a redirect to another host drops the credential; plain http to another host notes it on stderr. Release 0.3.30. check-in: b637cbd37c user: dmestas tags: trunk, version-0.3.30

01:02
soak: record a finding and keep sweeping; CI: cap the runners' zig cache

A failing fuzz target is abandoned and the sweep moves on, so one recurring crash no longer hides the targets after it; the exit lists every finding. Each workflow clears its zig-local cache whole at job start once it passes 8 GB, since Zig never prunes it. check-in: 8ebc3e4dd8 user: dmestas tags: trunk

2026-09-23
18:33
inflate: a truncated dynamic-block header is the end of the stream, not a crash

tossBitsShort added the consumed bits where it must subtract them, so a header ending one byte short tossed past the end of the input and the next peek read a wrapped length off the stack. Found by the nightly soak four nights running. Release 0.3.29. check-in: 362f18d357 user: dmestas tags: trunk, version-0.3.29

13:47
config export, and merge --probe over a stack

config export AREA [FILE] writes fossil's configuration export format, so an area can be backed up before import replaces it; import and merge now apply /shun cards, add-only in both modes. merge --probe with several NAMEs answers each against TARGET with the ones before it landed, holding merged files in memory and moving the merge base with the landing. Release 0.3.28. check-in: c5243e961f user: dmestas tags: trunk, version-0.3.28

2026-09-22
17:34
protected branches: admit a cancel on a check-in the server does not hold

The pusher's recovery from a refused push, amend --branch, was refused too. A cancel on an unheld target removes it from nothing held, so the check-in is judged where it joins, with a same-round branch move counted. A held check-in re-offered in a push is no longer judged as joining. The e2e raw-push fixture compared raw digests to hex and excluded nothing. Release 0.3.27. check-in: d4571a4b1a user: dmestas tags: trunk, version-0.3.27

2026-09-20
22:07
tarball and zip: consume the end-of-options marker

The marker branch fell through to the operand slots, so it took VERSION's place and OUTPUTFILE was refused. A value option's argument is now also taken before the marker is considered. Release 0.3.26. check-in: 28cd7f506a user: dmestas tags: trunk, version-0.3.26

13:25
Release 0.3.25

A bare -- ends the options in every verb; zip names are flagged UTF-8. check-in: 726efdca6b user: dmestas tags: trunk, version-0.3.25

13:03
cli: honour a bare -- as end of options in every verb

A file whose name begins with '-' could not be named at all: passed bare it parses as a flag, and './-x.txt' parses and then matches nothing, because a path is compared literally against the check-in's file list. A forge serving such a repository answered 500 for every content route on that file. Twenty parsers already honoured the marker, including the shared flag scanner behind add, rm, commit and mv; the twenty-five with hand-written loops did not, cat among them. Each now gates its flag branches behind the marker, so operands fall through to the positional handling untouched and '-n' after '--' is a name rather than a limit. Documented as its own help topic rather than an options row in thirty-nine verbs: '--' is not a verb's option, it is the rule every verb parses by. check-in: 85a1d4bf3f user: dmestas tags: trunk

11:49
zip: flag member names as UTF-8 in both headers

The name bytes were always correct UTF-8 and general-purpose bit 11 was never set, so a conforming reader must decode them as CP437 and a committed 'café.txt' extracted as 'caf├⌐.txt'. Both headers now take the flag from one constant: a reader trusts the central directory for metadata, so setting it on the local header alone would still ship the bug. Set unconditionally, since ASCII is a subset of UTF-8 and one value cannot disagree with itself. Content and the data-descriptor bit are unchanged. check-in: 3caf366005 user: dmestas tags: trunk

2026-09-19
14:45
Release 0.3.24

Closing a protected branch is a protected move; a damaged sync container is an error, not a crash. check-in: 3bcbc1c903 user: dmestas tags: trunk, version-0.3.24

14:40
container: a damaged container is an error, never a crash or wrong bytes

The first nightly soak flipped one bit in a valid container and brought the process down inside the standard inflate: an integer underflow in its end-of-input bit peek that a truncated stream can arrange, reachable from any peer through every sync body. The decoder is now the tree's own copy of the standard one (Zig 0.16.0, MIT) with the comparison reordered so the stream ends, and its origin noted. With the crash gone the same bytes decoded to 58 bytes reported as good: the flip made a block final, and the zlib footer's Adler-32 was read but never checked, by the decoder or by us. The codec now requires a finished stream and verifies the footer against the output. The exact bytes are a fixed test. check-in: 46fcd75fc3 user: dmestas tags: trunk

14:40
sync: a closed tag on a protected branch is refused

The push gate judged tags by the branch they named, so sym-B and branch=B were refused under any sign while a closed tag, which names a check-in, was admitted: an account that could not push onto trunk could close its tip, and the owners' next commit was refused against a closed leaf with no cause named. A closed tag aimed at a held check-in now resolves that check-in's branch and is refused when the branch is protected, under any sign, saying close or reopen. A release name on the leaf, a close off the branch, and a close of an unheld target stay admitted; a resolver fault still fails closed. check-in: ff30ba16e8 user: dmestas tags: trunk

2026-09-18
16:31
dst: a bitflip inside a config frame owes a repair, as one in a content frame does

The first full nightly soak found seed 22 at 10000 steps: the crash sweep flipped a bit inside a committed config frame, the store's checksum refused to serve it, and the harness reported a config mismatch because only its content-frame path knew that refusal as detection. The config check now routes rot inside the surviving config frame to the repair, and the repair's cut keeps every frame of either kind that ended before the rot, since config frames interleave with content. check-in: 79059346bc user: dmestas tags: trunk

15:49
soak: sweep the DST on the production build too

ReleaseSafe keeps every assert as a detector; the build that ships is ReleaseFast, where only the simulation's own state-replay oracle can catch a bug that appears when the checks are gone. The nightly now runs the same DST sweep on both builds. DST_FAST=0 skips the second. check-in: 4df2fad0e6 user: dmestas tags: trunk

12:48
soak: find the harness binary in the configured cache, never in the repo root

The runners keep Zig's cache outside the workspace, so the find under .zig-cache came up empty and xargs handed ls no arguments: ls listed the repo root and the newest entry, src, was run as the harness. The lookup honours ZIG_LOCAL_CACHE_DIR and an empty find is a build failure. check-in: b56ed097fd user: dmestas tags: trunk

12:31
soak: a nightly deep DST and fuzz run

scripts/soak.sh passed the optimize flag this Zig rejects, so it has been unrunnable since the toolchain moved; it takes --release=safe now. A scheduled workflow runs it at 03:00 UTC on the x64 runner with the script's nightly budgets, overridable from the dispatch form, keeps the log and any reproduce line as an artifact, and is pinned to the ci toolchain by ci_test like the other workflows. check-in: fa78377389 user: dmestas tags: trunk

12:31
fuzz: reach the igot accept arm again, and sweep at the floor in ci

The adversarial token generator capped fields at 24 bytes, and the igot parser has required a 40- or 64-byte name since the shun work, so the parser's accept arm was unreachable and the harness's own reachability floor said so at 256 rounds. CI swept 100 rounds, below the floor, and never saw it; the first bounded soak did. One field in four is now hash-shaped, and ci sweeps every target at the floor's round count. check-in: af292c3091 user: dmestas tags: trunk

11:37
Release 0.3.23

The transport answers an HTTP Basic challenge; a gated first round is no longer fatal. check-in: 2a3106fcaf user: dmestas tags: trunk, version-0.3.23

11:31
transport: answer an HTTP Basic challenge

A forge that gates a read answers a clone's first request with 401. The login card cannot answer that round, since its secret needs the project code the first reply teaches, and the status was fatal, so the credential never reached the wire. When a verb holds a plaintext password the transport keeps a Basic credential ready, sends nothing until a 401 names the Basic scheme, then repeats the round with the Authorization header and carries it on every later round, as fossil's --httpauth does. A 401 now says what the peer wanted. Proven by an e2e with an authenticating gate in front of zit serve. check-in: 5f541eccc7 user: dmestas tags: trunk

01:52
Release 0.3.22

clone and pull authenticate; a private repository is readable. check-in: d75c7a741d user: dmestas tags: trunk, version-0.3.22

01:45
sync: clone and pull send a login card

Only push and sync signed a login, so a private repository on a forge that gates reads was unreadable by the account that owned it, and a stored login sat unused while pull read anonymously. All four verbs now resolve the login the same way: --user, the URL's user@, then the stored login. A clone holds name and password until the round-0 reply teaches the project code, then signs every later round; a refused round 0 that taught the code is retried with the login, as fossil's client does. The accepted login is stored in the clone. A URL user with no password source is a hint and goes anonymous with a note; --user without a password is an error. Smoke S17 drives a read-gated fossil. check-in: 1d5a6c8fa7 user: dmestas tags: trunk

2026-09-17
19:12
Release 0.3.21

A multi-check-in fossil push lands; --httptrace reaches a zit server. check-in: 575cd3fcdd user: dmestas tags: trunk, version-0.3.21

19:06
serve: accept application/x-fossil-debug

fossil --httptrace sends its cards uncompressed under this type, and the server refused it with a bare 415 on the premise that the reference client never sends it. The exchange now tells handleXfer whether the body is a zlib container or plain cards; the reply is framed as before, and fossil reads the reply's framing off the reply's own content type. x-fossil-uncompressed stays reply-only. check-in: cc96464a51 user: dmestas tags: trunk

19:06
sync: resolve a pushed delta against a basis delivered in the same round

fossil sends a batch of check-ins as one round with each manifest a delta against the previous one, and the scan reconstructed every pushed delta against the committed store, so the basis was never there and the round was refused as a malformed file card. Every multi-check-in push from a stock fossil failed. The scan now parks a delta whose basis is not held and settles it once the whole round is seen, to a fixpoint, so order within the round does not matter. A basis absent from both the store and the round is refused by name: error delta basis not held: TARGET against BASIS. Smoke S16 pushes three fossil check-ins in one round and checks all three landed. check-in: df556319a8 user: dmestas tags: trunk

17:04
Remove issue-tracker numbers from source and documents

The tracker is disposable and does not live with the source, so a number is a dangling pointer. Every zit#NN and #NN reference in code comments, test names, help text, smoke labels, identifiers, release notes and errata is replaced by enough context to stand alone, or by a short plain statement of the problem. No behaviour changed. check-in: 9033c13f21 user: dmestas tags: trunk

16:27
erratum: sync §5.2 spells the bad-command text as bare words

The ABNF and §10.1 already make every error card one fossilized TEXT; the unknown-operator prose writes "error bad command: LINE" and reads as four tokens. Records the wire form and the two-token client rule. check-in: ec7d3fc9f7 user: dmestas tags: trunk

15:29
cli: format the remote URL check check-in: ae396d9bac user: dmestas tags: trunk, version-0.3.20
15:27
Release 0.3.20

Server error cards are encoded so a fossil client reads a refusal; remote refuses a non-URL. check-in: d11082197c user: dmestas tags: trunk

15:21
remote: refuse an argument that is not an http(s) URL

zit remote list saved the word list as the remote and reported success; the loss surfaced at the next push. The help already defines the argument as an http:// or https:// address, and the parser now holds it to that with a usage error that says there are no subcommands. A valid URL is still stored verbatim. check-in: c280025388 user: dmestas tags: trunk

15:21
sync: encode every server error card

The bad-command and malformed-card refusals were written with raw spaces, so on the wire they were four tokens. A stock fossil client reads an error card as two, reported the rest as unknown commands, dropped the refusal and printed its success summary; a refused push looked landed and re-sent the same artifacts on every autosync. Every error card is now assembled at one point with its text encoded, as fossil's own server writes it. A test drives each refusal through the emitter and fails on a raw space after the operator. check-in: 8f5dff81b0 user: dmestas tags: trunk

13:46
Release 0.3.19

log opens once, on the zero-parse image; the open mode is declared, never defaulted. check-in: 61ae22616f user: dmestas tags: trunk, version-0.3.19

13:39
log: open once, on the zero-parse image

log reached past the open funnel and called Repository.open with the default options, which is the full record replay meant for write verbs, and did so twice for a symbolic name. On pkgsrc that was 0.94s before the first row; on the image path it is 0.05-0.10s, output byte-identical on every route. The open mode has no default any more: every direct caller declares it, so the next verb written past the funnel cannot inherit the expensive one silently. An e2e runs every log route under the derive-footprint seam and fails if any of them replays a record. check-in: 0910bc00f5 user: dmestas tags: trunk

00:08
ci: run on every branch push, still never on a tag

A push trigger naming only a tag filter runs for tag pushes alone, so the tags-ignore alone ran nothing for two commits. branches: ['**'] restores every branch; the pin now allows exactly that form. check-in: c004c81e03 user: dmestas tags: trunk

2026-09-16
23:09
ci: keep the Zig cache and toolchain across runs

The runners are self-hosted but checkout cleaned the workspace, so every step recompiled the same sources into its own binary from nothing; unit tests and e2e were 6 and 4 minutes on the ARM64 critical path, mostly compile. Zig's cache is content-addressed, so it now lives outside the workspace and warms across runs, in both workflows. The toolchain tarball is kept the same way and still verified against the pinned digest every run. Also pins the tag-ignore trigger the previous commit introduced, which the workflow pin test had rejected. check-in: 3106100d42 user: dmestas tags: trunk

22:58
ci: do not run the battery a second time on a tag push

A release tag lands on a commit whose branch push already ran ci, and the tag push ran it again on the same three single-slot runners the release workflow was queueing for. Every branch push still runs; the release workflow, triggered by the tag, gates what it ships. check-in: e9e2ba4431 user: dmestas tags: trunk

22:11
Release 0.3.18

The file-history index is built by the derive at ingest, fossil's way. check-in: 09d191e634 user: dmestas tags: trunk, version-0.3.18

22:11
file index: built by the derive, at ingest

fossil fills mlink as each check-in arrives and answers finfo by lookup. zit's derive computed the same row per check-in and dropped it; the index was rebuilt by a separate pass on the first PATH query, 6.8 min on pkgsrc and not resumable. The derive now hands each change set to an index builder as it links, stores it beside the checkpoint, and extends it over the tail on append; a cache hit computes nothing. The on-query build is the fallback and checkpoints every 8192 entries. Index format 4 records completeness so a partial checkpoint is never adopted whole. crosslink reports a tree's files instead of unknown. pkgsrc, fresh clone to first answer: 11.7 min -> 7.1 min + 1s. check-in: df99743ca4 user: dmestas tags: trunk

13:44
Release 0.3.17

A push with no URL keeps its credential; the tree-manifest index build is proportional to what changed. check-in: dbfe2adebc user: dmestas tags: trunk, version-0.3.17

13:43
file index: diff tree manifests by S card

Two tree check-ins were diffed by flattening both to full file lists, files-per-check-in per check-in: 34 minutes once on a pkgsrc mirror. The S-card runs are now walked side by side, skipping every sub-manifest whose hash did not move and resolving only where it did. Deletes are held to the end so a moved partition key cannot make a live file look deleted. Trees flatten on demand only for the root and flat/tree pairings; the derive feed never flattens. pkgsrc: 34.3 min -> 6.8 min. check-in: ea4abe48fd user: dmestas tags: trunk

13:43
push: keep the credential when the URL is omitted

push --user U --password P with no URL parsed to a payload-less no_url, which the verb rebuilt as a bare empty URL, dropping the credential; the push went out anonymous and a peer requiring a login refused it. The parser now mirrors sync: an omitted URL is an empty one, resolved to the saved remote at run time, and the credential comes through. S12 asserts an authenticated no-URL push and a stored-login push both land on fossil. check-in: 4dba18d355 user: dmestas tags: trunk

07:42
Release 0.3.16

File index works on submanifest stores; artifact shows S cards; a saved login authenticates a push that names no user. check-in: 8cfa57ecd3 user: dmestas tags: trunk, version-0.3.16

07:28
push: a saved login authenticates a push that names no user

push --user saved the derived secret, but the resolver returned anonymous the instant --user was absent, so autosync (which pushes with no arguments) always went anonymous and a peer requiring a login refused it. With --user absent the saved login now stands in, never prompting; --user "" still forces anonymous. push, sync and config pull share the resolver. Whether such a push lands on a fossil peer is zit#196, a separate pre-existing matter. check-in: e37768d073 user: dmestas tags: trunk

07:28
log PATH: diff tree manifests in the file index

On a submanifest store every check-in is a tree manifest, which the change-set capture refused as unknown, so the index recorded the whole log as unknown and a PATH query reconstructed per check-in anyway -- 39 minutes on a pkgsrc mirror. Trees now flatten inside the diff memo through the Repository seam, so the untouched diff sees a flat list; a tree that cannot be flattened stays unknown. Index format 2 -> 3 so a stale all-unknown blob is rebuilt once. check-in: 001c73defa user: dmestas tags: trunk

06:05
artifact: render S cards

A tree check-in carries its file set entirely by S cards and the card renderer had no S lane, so it printed as a manifest with no files while ls on the same hash listed thousands. One lane, in card order, checked against --raw. check-in: da2598d1ca user: dmestas tags: trunk

2026-09-15
01:30
Add Submanifest Guide check-in: e88e3d88ed user: dmestas tags: trunk
2026-09-14
16:27
Release 0.3.15

Makes the file-history index durable across commits. check-in: 37e2519ac5 user: dmestas tags: trunk, version-0.3.15