50 descendants and 50 ancestors of 6d791304180d1e15
|
2026-10-19
| ||
| 22:48 |
test(checkout): a renamed symlink is not merged, and the rename drops the old name
Covers the rename and dry-run paths of Update's symlink conflict: the link is listed in Unmerged, nothing is written through it, and only a real run deletes the old name, as fossil's update does. check-in: ef49615d6c user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 21:50 |
fix(sync): gate sub-manifest trees on the send-submanifests pragma
draft-fossil-submanifests-00 §7.2 no longer gates S-bearing artifacts on the peer's announced version: fossil 2.29 announces 22900 and reads no tree. A peer that reads trees now says so with pragma send-submanifests, which go-libfossil sends in every request right after client-version and in every reply, clone replies included, right after server-version, whatever the sub-manifest settings. The version threshold and the 22900 reader marker are gone; client-version and server-version announce 22800, the fossil release whose protocol this library speaks. A tree manifest or sub-manifest is refused to a peer that has not sent the pragma with "Peer does not accept sub-manifests.", never converted or omitted. A server decides from the whole request it answers, a client from the replies it has received in the exchange. avoid-submanifests moves from the ci-lock answer into the same leading run of every reply. Enabling emission over a stored submanifest-k outside 1 to 12 without an explicit k is refused, naming the stored value (§8.1). The conformance suite pins the draft with the 2026-10-19 errata applied: SM-7.2-1 and SM-6.3-3 are met rather than deviations, SM-7.2-2, SM-7.2-3, SM-6.3-1/2/7 and SM-8.1-3 follow the corrected text, and SM-7.2-4 covers the pragma's placement. The zit interop pushes a tree go-libfossil wrote to zit and checks both sides refuse trees when the pragma is stripped. Tracked in #452. check-in: 05a53c393d user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 20:09 |
fix(checkout): revert renames onto taken names, saving undo first
Checkout.Revert refused to undo a rename when another file held the old name: a swap, a chain, a new add or an untracked file there. Like fossil's revert it now saves each file it writes or deletes for undo, then reverts in one transaction, so Undo or fossil undo brings back what it overwrote, and a failed revert puts the files back. Undoing a rename takes back the old name from whatever row holds it: a row renamed onto it is reverted to its own old name, and any other row is dropped, as fossil's UPDATE OR REPLACE drops it. Every committed file ends under its committed name; fossil's own revert leaves a swap renamed and stops tracking the second file of a chain. Tracked in #248. check-in: 80764da743 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 18:49 |
fix(checkout): Update decides the cone before renames, and never merges symlinks
A file outside a sparse checkout's cone is never on disk, so it read as missing, hence changed, and followed the target's rename; any upstream rename outside the cone then refused the update. It is now classified before renames are followed and matched by name: a rename outside the cone moves only the record, one into the cone writes the file under its new name, and an unedited file renamed out of it leaves the disk. A symlink edited locally and changed by the target was merged through the link, writing conflict markers into the file it points at. As fossil's update does, it is now a conflict with nothing written, listed in UpdateResult.Unmerged; a rename still removes the old name. check-in: f373c9a8ae user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 18:34 |
fix(checkout): materialize a symlink entering the cone as a symlink
The cones merge called extractSingleFile without the islink argument the symlink fix added, so it did not build. SetCone now passes the row's islink, and a file entering the cone is written as Extract writes it: a symlink with allow-symlinks on. check-in: 36fccc1f87 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 18:29 | Merge branch 'feat/cones' into feat/submanifest-reader check-in: 1a17a3defe user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 18:29 |
Merge branch 'fix/scan-symlink-extract' into feat/submanifest-reader
# Conflicts: # internal/checkout/update.go check-in: 6708292b55 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 18:27 | Merge branch 'fix/receipt-followups' into feat/submanifest-reader check-in: 41ff5d315a user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 18:27 | Merge branch 'fix/stash-undo-followups' into feat/submanifest-reader check-in: 22101b521f user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 18:27 |
fix(checkout): write symlink entries as fossil does, so a fresh checkout extracts
Since the scan began recording islink and chnged 7/9, Create followed by Extract without Force failed on any repository with an "l" file: the file was missing, the scan read it as UNLINK, and the missing-file skip only covered plain edits. Extract and Update now write a symlink entry as fossil's vfile_to_disk does: as a symlink to the blob content while allow-symlinks is on and the storage can make links, otherwise as a plain file holding the target. A symlink is deleted before a file is written over it, and setMergedMode leaves symlinks and directories alone, as file_setexe does. Extract's missing-file skip covers mode changes too, so the first Extract after Create plays fossil's open whatever the entry. With allow-symlinks off, fossil itself reports such a file UNLINK and its checkout refuses without --force; Extract keeps that behavior, and an interop test pins it against fossil's open in both modes. ScanENotFile no longer refuses a directory at a pending add or removal recorded with chnged=0, matching the else-if in vfile_check_signature. Tracked in #449 check-in: 8cad365e82 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 16:51 |
Merge branch 'feat/submanifest-reader' into feat/cones
Update now follows the target's renames and saves undo state. A file outside the cone stays a record-only step: never written, chmodded, backed up or read for undo. A local edit that a rename would carry out of the cone is refused, naming the cone. check-in: 74aa290eda user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 16:29 |
Merge branch 'feat/submanifest-reader' into fix/stash-undo-followups
# Conflicts: # internal/undo/undo.go check-in: d6ac19e580 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 16:26 |
fix(stash,undo): scan before stashing; return undo changes, print nothing
Stash save now scans the checkout first, as fossil's stash_create does (vfile_check_signature), so an edit no scan had recorded is stashed too. Save takes the scanner, a *checkout.Checkout, as its first argument. Undo and redo no longer print to standard output: they return the files they changed, as []undo.Change, in the undo table's row order, the order fossil undoes them in. Tracked in #448 check-in: 2dfae63b63 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 16:25 | Merge branch 'fix/update-undo' into feat/submanifest-reader check-in: da7c8a19cd user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 16:10 |
fix(checkout): save undo state in Update, as fossil does
Update saved no undo state, so nothing could reverse it. It now reads the file of every step that writes or removes one before writing, as fossil's update calls undo_save, and saves those files with copies of vfile and vmerge and the checked-out version in the same transaction that moves the checkout to the target. If a write fails partway the files are put back, as fossil's undo_rollback does. Checkout.Undo and Checkout.Redo (internal and public) swap that state back and forth and keep checkout-hash naming the restored version. The undo package gains ReadFile, SaveTx and RestoreFiles, and its undo table now has fossil's schema (isExe, unique pathname, rowid order, the executable bit read from disk), so fossil undo reverses a go-libfossil update and Checkout.Undo reverses fossil update; fossil 2.28 interop tests check both. Under js/wasm, which has no undo package, Update saves nothing. Tracked in #446 check-in: 294a537880 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 15:59 |
Merge branch 'fix/update-renames' into feat/submanifest-reader
# Conflicts: # CHANGELOG.md check-in: 5d0a52d706 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 15:45 |
docs(manifest): CheckinOpts.User is the U card, fossil's --user-override
It is never checked against the user table; the check-in's rcvfrom row credits that login's uid when the table holds it and the local setup user otherwise, as fossil credits g.userUid whatever the U card says. A test pins that an unknown name commits under that name. check-in: 54c9e56786 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 14:52 |
fix(db): forget a receipt's row when its transaction rolls back
Receipt.ID took (rcvid, mtime) to identify its own row and checked it with a SELECT on every use. After a rollback the rcvid can be reused by another receipt's insert, and under a frozen clock the mtime matches too, so the receipt attached to the wrong row. Fossil holds g.rcvid for its process and never re-reads the row (content_rcvid_init); a rollback ends the process with it. A Receipt outlives transactions, so the transaction or savepoint that makes its row now records that, forgets the id if it rolls back, and hands it to the enclosing level when released. A kept id costs no query, which takes one SELECT per stored blob off the clone path. Also checks that a tree check-in's sub-manifests share the commit's receipt. check-in: 0269bd9461 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 14:41 |
Merge branch 'feat/submanifest-reader' into feat/cones
Update's rewrite meets the sparse worktree: a file outside the cone is a record-only step, counted in OutOfCone, and never planned, scanned, checked, written, backed up as NAME-original or chmodded; reloading vfile moves its record to the target. SetCone records the mtime of each file it materializes, as Extract now does. check-in: 47f89f0798 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 14:40 |
docs: state where text Julian times are checked and how sweep errors read
Only macOS arm64 and linux-x64 fossil have been compared bit for bit, so the rebuild test no longer claims Windows is exact. julian.go says which long doubles fall back to 53 bits wrongly, and ExpandAll's doc says its errors match Cache.Expand's in kind, not always in wording. check-in: e4c84f20f9 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 14:38 |
test(fsltype): check macOS fossil's event times at its own long double
TestTextJulianDayMatchesFossil compared macOS arm64 fossil's stored values with the text form at the running platform's long double, so it failed on linux-x64, where fossil itself stores different last digits. TestTextJulianDayPerLongDouble already checks those values at 53 bits and linux-x64 fossil's at 64, so the platform-blind test goes. check-in: e499428d3b user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 12:56 |
fix(verify): count a tree gap found in the one-pass check-in sweep
checkCheckins now gathers into a staging report and copied only its issues back, so the MissingRefs count treeGap adds was lost: Verify reported a missing sub-manifest as an issue but counted zero missing references. check-in: 39b524c37c user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 12:47 |
fix(verify): give treeGap a cache after the one-pass blob walk
The rebuild speed-up hands checkOneCheckin each check-in's expanded bytes and drops the pass-wide expansion cache. treeGap, from the sub-manifest reader, still lists a check-in's files to find a missing sub-manifest, and it needs a cache: without one every delta manifest re-expands its baseline. checkCheckins now keeps a small cache for those manifest reads only. check-in: 1a45812566 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 12:47 |
Merge branch 'perf/rebuild-blob-check' into feat/submanifest-reader
# Conflicts: # CHANGELOG.md check-in: e3c81fb936 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 12:47 |
Merge branch 'fix/stash-undo-storage' into feat/submanifest-reader
# Conflicts: # CHANGELOG.md # internal/checkout/vfile.go check-in: 189088f46c user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 12:46 |
Merge branch 'fix/merge3-markers' into feat/submanifest-reader
# Conflicts: # CHANGELOG.md check-in: 2a0701c7d3 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 12:46 | Merge branch 'fix/tag-events' into feat/submanifest-reader check-in: e9e08cbb58 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 02:08 | Merge branch 'fix/private-blob-public-checkin' into feat/submanifest-reader check-in: 52ca05c6c4 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 02:08 |
fix(manifest): make every file blob a public check-in names public
A public check-in could reuse content first stored privately, say by syncing a private branch, and leave it in the private table. Sync never sends private blobs to a peer without private access, so that peer got a check-in whose file stayed a phantom and could not be checked out. storeFileBlobs now calls content.MakePublic on each file blob inside the check-in's transaction, as fossil's commit calls content_make_public for each F card (checkin.c). The blob is already queued in unsent, so the next push carries it. The sub-manifest writer already does this for trees. Tracked in #439. check-in: 6d239246d0 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 02:00 | Merge branch 'fix/scan-missing-perms' into feat/submanifest-reader check-in: ef787892fe user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 02:00 |
Merge branch 'fix/tag-events' into feat/submanifest-reader
# Conflicts: # CHANGELOG.md check-in: 2e1d1e6fb7 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 02:00 |
Merge branch 'fix/rcvfrom-receipts' into feat/submanifest-reader
# Conflicts: # CHANGELOG.md # internal/manifest/manifest.go # internal/sync/handler.go check-in: 6651024b58 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 00:43 | feat(cli): repo status reports within a sparse checkout's cone; changelog check-in: 0f52dfecb9 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 00:33 |
Merge remote-tracking branch 'origin/main' into feat/submanifest-reader
# Conflicts: # CHANGELOG.md check-in: c851990f41 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
|
2026-10-18
| ||
| 18:46 |
Merge remote-tracking branch 'origin/main' into feat/submanifest-reader
# Conflicts: # CHANGELOG.md check-in: 92936436e5 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 18:46 |
refactor(checkout): keep the functions the cone touched within 70 lines
The unchanged-file pass of a commit, the on-disk half of a rename, the tracked-row lookup of Manage and Create's local records become helpers; Update's content precheck moves into buildUpdateMaps. The fossil interop test isolates fossil's home itself. check-in: 857b86be94 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 18:41 | test: fossil opening a sparse checkout cannot commit its uncovered files away check-in: f7c86ac519 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 18:40 |
test(conformance): pin the sparse-cone and horizon drafts, with zit as the cone oracle
The two drafts from zit's horizon-rfc branch at 86d4b67372, their requirements tables (later phases recorded as not yet implemented), the sparsecone suite over the cone specification and the sparse worktree, and the horizon suite's one case. zit's serialized cones, the files its sparse worktrees materialize over flat and tree histories, and a commit from a zit sparse worktree are recorded under testdata/zit-cones and replayed without zit. check-in: d9b18ab619 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 18:29 |
feat: sparse checkouts in the public API and the CLI
Cone, NewCone, CheckoutCreateOpts.Cone, Checkout.Cone and SetCone, UpdateResult.OutOfCone and ErrOutsideCone; repo open --cone/--cone-not and repo cone (show, add, remove, set, dense, test). check-in: 94304a520c user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 18:26 |
feat(checkout): the sparse worktree of draft-fossil-sparse-cone-00 §4
A checkout created with a cone materializes, scans and tracks only the files it covers; vfile stays the full record, so fossil still reads the checkout. Commits carry uncovered files from the baseline by hash, update applies uncovered changes to the record only, and tracking, renaming, reverting or merging across the cone is refused naming it. SetCone widens and narrows. check-in: 3672f3d4fb user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 18:26 |
feat(manifest): a cone predicate at the enumeration seam, and carried files
ListFilesFiltered narrows a check-in's file set to a filter's coverage; on a tree manifest the walk skips every sub-manifest whose key range the filter cannot cover. File.UUID carries an artifact the repository holds into a check-in by its name, verbatim. check-in: 337dde8a34 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 18:26 |
feat(cone): the cone specification of draft-fossil-sparse-cone-00 §3
Inclusion and exclusion members as literal path prefixes, normalized through tracked-path validation, longest member deciding, dead exclusions and contradictions refused, and zit's canonical serialized form (version 1, and version 2 for exclusions) with its SHA3-256 digest. check-in: 027fc6c741 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 17:33 |
fix(manifest): re-read settings before auto-retune; queue republished leaves
The post-commit re-tune re-reads the settings in its own transaction and does nothing unless the pin is still the commit's k and submanifest-auto-retune is still on, so a manual re-tune or the automatic one switched off since the commit is never overwritten. A sub-manifest a public commit makes public is queued for the next push, since it was never sent while private. The CLI states the k range from the manifest constants, and buildCheckinDeck's R-card computation moves to checkinRCard. check-in: c907b009c7 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 17:26 |
fix: select over the newest check-in off trunk; honest submanifests status
Repo.EnableSubmanifests(0) analyzes the main-branch tip, and when no check-in is on the main branch (a repository whose history sits on another branch name) the newest check-in by time, the highest rid breaking a tie, rather than refusing; an empty repository still refuses. The godoc names the check-in in each case, and DisableSubmanifests' says existing trees remain and keep being served and that no note is returned. `repo submanifests status` fails when a setting cannot be read instead of printing defaults, and shows a stored k outside 1..12 as invalid, with commits falling back to flat manifests. check-in: a659919be4 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 17:19 |
fix(cli): refuse an explicit --k 0, and restore the SDK source links
`repo submanifests enable --k 0` ran automatic selection; §8.1 refuses an explicit k outside 1..12, so only an absent --k selects now. The SDK pages are rebuilt with gomarkdoc's repository flags, which a worktree cannot detect, so their source links match the published pages again. SM-7.2-3's note says the pragma is not reachable from the public API. check-in: 7a2f6dbe7a user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 17:19 |
fix(manifest): tree storage, privacy and post-commit work per review
- A public check-in makes every sub-manifest it names public, so a leaf a private check-in stored first is sent with the tree. - Sub-manifests are named by the hash policy alone (StoreUnderPolicy), in sha1, sha3 and auto repositories alike, and only those the commit wrote are queued for sync. - A sub-manifest that fills a phantom links the check-ins waiting on it once the commit is durable (§7.1, §7.3), not at the next sweep. - The automatic re-tune runs after the commit is durable, as zit runs it; its failure is logged and never fails the commit. - Enabling selects outside any write transaction, replaying one check-in at a time, then re-reads the settings in a short write; a pin that appeared meanwhile takes §8.1's precedence. - Checkin's transaction body moves to checkinTx, so neither function exceeds 70 lines. check-in: 0f543785e1 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 17:19 |
feat(blob): store under the policy's name alone, reporting the outcome
StoreUnderPolicy names content by the repository's hash-policy algorithm and never reuses a copy held under the other algorithm's name, as draft-fossil-submanifests-00 §6.2 requires of an S card's hash. It reports whether the row was found, inserted, or filled a phantom, so a caller can queue only what it wrote and retry what waited on a phantom. Store shares its write-and-verify tail. check-in: 315b5021fc user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 17:04 |
feat: select over the main-branch tip, and add submanifests status
Repo.EnableSubmanifests(k) now analyzes the current trunk, the check-in the next commit most plausibly descends from, instead of the newest check-in; with no trunk check-in only an explicit k succeeds. A test puts a newer one-file check-in on another branch to show which one is read. Repo.DisableSubmanifests returns only an error and documents that existing trees stay. `libfossil repo submanifests status` prints the three settings and whether the repository holds a tree; `retune` requires --k, and `disable` prints zit's note when trees exist. The SDK pages are rebuilt with make docs-gen-sdk. check-in: 5377023003 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 16:58 |
test(conformance): check enable-time selection against zit
On four flat two-commit histories zit wrote, go-libfossil reproduces every manifest byte for byte and then enables at the k zit pinned; in each the replay moves the pin off the snapshot's value, so the replay port is what is being checked. The pins are recorded for CI under testdata/zit-writer, and SM-6.3-7 states the refinement. The changelog describes the API and CLI. check-in: aea1e207f4 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 16:58 |
feat: sub-manifest settings in the Repo API and the CLI
Repo.EnableSubmanifests(k) now selects over the newest check-in itself, so callers pass only k (0 to select); Repo.DisableSubmanifests joins RetuneSubmanifests. `libfossil repo submanifests enable [--k N]`, `retune --k N` and `disable` drive them, printing the pin and the operator warning. The libfossil and cli SDK reference pages are regenerated. check-in: 0ebee94560 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 16:58 |
feat(manifest): select k on enable as zit does, and add disabling
The draft's automatic selection is advisory, and zit lets history outrank the snapshot: on enable it replays the newest 200 check-ins through the tree builder at the snapshot's k and its two neighbours and pins the value whose steady-state commits materialize the fewest bytes, the lowest on a tie, keeping the snapshot when fewer than two check-ins replay or every candidate stays flat. replayK ports that step by step, so two writers enabling on one history pin alike. DisableSubmanifests turns emission off and keeps the pin, returning zit's note when trees already exist. The out-of-range fallback logs zit's report. check-in: 6d79130418 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 16:44 | docs(changelog): sub-manifest writer check-in: 8d3962592c user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 16:44 |
test(conformance): cover the sub-manifest writer, with zit as oracle
The submanifest table gains the writer's requirements: the §6.1 predicate, §6.2's construction, limits, merge, stops, canonical encoding and storage order, §6.3's pinning, out-of-range fallback and selection, §6.4's manual and automatic re-tune, §8.1's enable rules and disabling, and the writer vectors of A.5. The writer reproduces every Appendix A tree, the A.5 three-level vector at k = 2 and the height-0 merge and encoding vectors at k = 3. 71 requirements: 66 covered, 3 partial, 2 deviations, 0 failing. TestZitWriterInterop, with zit present, has zit commit ten scenarios (the A.1 set; 40 files at k = 1, 2 and 12; 3,000 files at k = 1, 3 and 5; deep paths; names with spaces, tabs, newlines and non-ASCII, executables and a rename) and requires go-libfossil's check-ins byte-identical. zit then clones, verifies and lists go-libfossil's trees, and verifies a tree go-libfossil commits on top of zit's; the §6.3 selection matches zit's analysis on five file sets. TestZitWriterBundle replays the recorded zit manifests in CI. zitRun now returns stdout only and sets FOSSIL_HOME, and zitListing reads names holding spaces, tabs or newlines. check-in: b77d8b119e user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 16:44 |
feat(manifest): write tree check-ins behind enable-submanifests
Checkin now honours draft-fossil-submanifests-00 §8.1: with enable-submanifests on and a pinned submanifest-k it stores the canonical tree first, marks each sub-manifest unsent, records the seen-submanifest indicator that arms the §7.2 gate, and writes a manifest of S cards with no F card and never a B card. The setting is off by default, so every commit is byte-identical to before. A stored k outside 1..12 falls back to a flat manifest and logs it (§6.3); unchanged sub-manifests are shared by content addressing. EnableSubmanifests is §8.1's local request: a valid pin wins and a different explicit k is refused as a re-tune; with no valid pin an explicit k is pinned, or §6.3's selection runs over the current check-in; a request that cannot be met changes neither setting. RetuneSubmanifests is the manual §6.4 re-tune. After a tree commit the §6.4 gate re-pins k while submanifest-auto-retune is on, and only advises otherwise. A sync run reports avoid-submanifests in SyncResult, and CheckinOpts.AvoidSubmanifests keeps a commit made in that sync flat (§7.2). The settings' names and parsers move to internal/manifest, which sync now uses. Repo.EnableSubmanifests and Repo.RetuneSubmanifests expose the two requests, the first returning the operator warning. A test shows fossil 2.28 never receives a tree this writer made. check-in: 14f17e675e user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 16:44 |
feat(manifest): build canonical sub-manifest trees
BuildTree is the construction of draft-fossil-submanifests-00 §6.2 over a check-in's sorted file entries at partition parameter k: the §6.1 predicate (leading zero bits of SHA3-256 of the name), the one-pass scan with its MIN and MAX limits and final-group merge at every height, the non-reducing and single-group stops, and the height-16 cap. Sub-manifests come back in storage order, children before parents, named by a caller function so the commit path can store as it names. partitionCosts is §6.3's C(k), computed with zit's arithmetic so the two writers select alike; SelectPartitionK picks the least cost and the lowest k on a tie, and retuneTarget is §6.4's gate with zit's 15% margin. Tests reproduce Appendix A.2, A.3 and A.4 by name and pin the scan's limits on synthetic counts. check-in: 47cb5afcd7 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 16:44 |
feat(deck): canonical encoding and sub-manifest serializers
draft-fossil-submanifests-00 §6.2 fixes minimal escaping for every filename a tree construction emits: exactly space, newline and backslash are escaped, every other byte raw. CanonicalEncode is that encoding; S cards and a sub-manifest's F cards now marshal with it, while a flat manifest keeps §4.3's, so no existing artifact changes name. MarshalLeaf and MarshalInterior serialize the two sub-manifest shapes, and LeafCard gives one leaf F card's bytes for the §6.3 cost. A test reproduces the Appendix A.2 leaf byte for byte. check-in: e9ec7390c7 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
|
2026-10-17
| ||
| 23:26 |
docs(submanifest): point the version-gate and config deviations at zit
Fossil has no plans to read sub-manifests, so the 22900 threshold is not only fossil 2.29's announcement: every later release clears it too. The fix is a version no fossil announces, agreed with zit and the draft; SM-7.2-1 now cites danmestas/zit#239, and SM-6.3-3's draft wording is tracked in danmestas/zit#240. check-in: 7408c02304 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 21:54 |
fix(sync): close the review's sub-manifest transfer findings
- A clone to a client the 7.2 gate refuses could name a withheld tree as a delta source: walkCloneChain never asked the gate, and a refused artifact was still recorded as sent. A flat check-in stored as a delta of a tree manifest -- the normal flat-to-tree transition -- then reached a 2.28 client as a cfile it could never apply. A withheld source is now unforwardable, so its dependent goes out whole, and a refused artifact is not recorded as sent. Gimme answers and pushes already send full content, and igot only announces, so the clone was the one path. - The gate armed only once a crosslink set the seen-submanifest indicator, so a tree a sync had stored but not yet linked went out ungated. Every receive path now sets it as the artifact is stored -- checkDelta hands back the content it rebuilt, so a verified delta costs no second expansion -- and a repository an earlier version swept, which may hold trees that version filed as unparseable, arms the gate until the next sweep re-examines them. - The three sub-manifest settings are written inside one savepoint, so a database error partway leaves none of them applied. - The 22900 threshold is zit's and is also what an unreleased fossil 2.29 announces without reading trees. The constant says so, and the conformance suite records SM-7.2-1 as a deviation with a case that shows such a peer being sent a tree. check-in: 4deb9d870f user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 21:29 |
perf(manifest): parse a delta's baseline once per sweep for the tree check
A sweep asked every delta manifest whether its baseline is a tree by expanding and parsing the baseline again, after missingBaseline had just done so. Record tree-ness where the baseline is first verified, and walk only a tree baseline. check-in: edefbcd26f user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 21:13 |
test(testutil): exempt the zit interop test from the fossil-home check
It runs zit, not fossil, each time under a HOME of its own. check-in: 6b694f0419 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 21:10 | docs(changelog): sub-manifest reader, transfer gate and version announcement check-in: 3232f3b158 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 21:10 |
test(conformance): read zit's sub-manifest trees end to end
TestZitInterop, with zit on PATH or in ZIT_BIN, builds a flat history in go-libfossil (edits, a delete, a rename, a merge), serves it for zit to re-mint as sub-manifest trees at k = 1, which gives interior sub-manifests, and clones zit's trees over HTTP. Every check-in's file set must equal zit's own `ls --long`, the clone must verify and every R card check. go-libfossil then serves the clone to a zit clone, which verifies and lists the tip the same; pulls a tree check-in zit commits to its own server; and, as a server, receives and links a tree check-in zit pushes to it. REQUIRE_ZIT_BIN=1 makes a missing zit a failure. CI has no zit, so TestZitTreeBundle reads a recorded copy of what zit wrote (testdata/zit-trees: 81 artifacts and the per-check-in listings, rewritten by ZIT_REGENERATE=1), storing every manifest before any sub-manifest so the deferral and retry run on real zit output. check-in: 3e7b98e18d user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 21:05 |
test(conformance): add the submanifest suite (draft-fossil-submanifests-00)
Pin draft-fossil-submanifests-00 from zit check-in 3f86ff4261 and write its reader-scope requirements table, 55 rows, from the draft text. The writer sections, the informative 5.6, the operator rule of 8.2 and the 7.4 SHOULD are listed as skipped, with reasons, in the table's header. 84 cases: card-level cases through deck.Parse; tree cases that store artifacts and read them back through ListFiles, LookupFile, Crosslink, VerifyRCard, Verify, Rebuild, Checkin and the sync handler; and the Appendix A vectors, as zit's byte vectors (vendored under testdata/submanifest), checked for their recorded names, walked enumerations and R cards, the A.5 delta-over-tree vector included. Result: 50 COVERED, 4 PARTIAL, 1 DEVIATION. SM-6.3-3 deviates by following zit: the configuration request is reqconfig /config, the scalar marker zit's server answers, sent once in the clone's cleanup round and never on pull. The PARTIAL rows: a reference cycle cannot be built from content-addressed artifacts (SM-5.1-5); go-libfossil writes no tree, so the emission rules hold vacuously (SM-7.2-3, SM-8.1-1); and the visit bound is not reached by a case (SM-10-1). check-in: 6ccebaeab5 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 20:57 |
feat(sync): carry sub-manifest trees safely (draft-fossil-submanifests-00)
Gate, announce and configure sub-manifest transfer the way zit does, so the two implementations interoperate and no fossil release is handed a tree it cannot read. - 7.2 gate: once the repository has stored an S-bearing artifact, a tree manifest or sub-manifest is withheld from a peer announcing a release below 2.29.0, zit's threshold, with one explicit error card per reply and never by omission. The server applies it to gimme answers and clone batches; the client to gimmes on push, recording each withheld artifact in the result. - This library reads trees, so it announces 22900 in client-version and server-version; a peer holding trees refuses them to anything lower. No fossil release gates any behaviour between 22800 and 22900. - A ci-lock reply carries pragma avoid-submanifests, where avoid-delta-manifests goes, while enable-submanifests is off. - 6.3: the three settings are /project members on the server, which also answers zit's reqconfig /config with them. Clone asks for them as zit's clone does, once, in its cleanup round with zit's scalar marker; fossil answers that with nothing. A reply's settings are staged and applied all or none. The examined-blob table's old revision is dropped only when present, so a sweep pays no extra write. check-in: 707ffd05a2 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 20:50 |
fix(verify): report a tree waiting on a sub-manifest as a missing reference
A tree check-in whose sub-manifest has not arrived is deferred with no derived rows (draft-fossil-submanifests-00 5.2, 7.3). Verify reported that as a missing event row and missing plink rows, which reads as damage. Report it once as a missing reference naming the sub-manifest, and count it in MissingRefs. check-in: ffdf538656 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 20:49 |
feat(manifest): read sub-manifest trees (draft-fossil-submanifests-00)
Parse the S card and the SUBMANIFEST artifact type, and read tree manifests through one enumeration seam. deck: the S card (exact arity, decoded filename, raw 40/64-hex hash, strictly ascending run between R and T), type Submanifest reached only by reassigning a D-less manifest, its F S Z legality row, and the 4.4 checks: no B with S, no F with S in a manifest, F xor S in a sub-manifest. manifest: checkinFileCards, ownFileCards and lookupFileCard are the one place a check-in's file set is assembled (9.3). A tree manifest is walked depth first with an explicit stack, a depth bound of 16, the repeated-artifact check and the least-filename and ordering checks of 5.1; lookup binary-searches one sub-manifest per level (5.3); a delta may name a tree as its baseline (5.4). A tree that cannot be walked is an error, never a partial file set (5.2). mlink derivation, R-card verification and the delta-manifest builder read through the seam, and a commit on a tree parent is written flat. Crosslink defers a check-in whose tree cannot be walked, recording the blocking sub-manifest in orphan so the phantom-fill cascade links it on arrival (7.3, 9.4). Storing an S-bearing artifact reserves phantoms for its absent references with the referrer's privacy (7.1) and sets the seen-submanifest indicator (8.1). A sub-manifest is filed as examined so the sweep never reselects it (9.2). The examined-blob table is versioned, so verdicts a parser without S cards reached are dropped. check-in: f51becc770 user: [email protected] tags: feat/submanifest-reader, main, trunk | |
| 20:27 |
test(conformance): re-pin the -01 drafts with the 2026-10-14/16 errata (#436)
zit check-in 3f86ff4261 applies six more errata to the -01 drafts. Copy the three drafts and the five new -01 errata files, re-pin their SHA-256 in the requirements tables, and record the check-in in the README. The draft text changes add six requirements and reword two: - AF-4.7.3-2: a named delta's delete markers are filtered out of a delta-of-delta's file set and lookups. - AF-4.7.8-1: an absent and a present empty J value decode alike. - AF-6.2-7: the Z verification state is read from the bytes at n-35 and n-34, not from card lines. - RS-5.3-3: a cancel keeps its card's value on the row it writes. - RS-5.3-6: the event table and propagation treat that value as null. - RS-5.3-7: an artifact's tag cards apply in card order. - RS-6.2-4: a branch root carrying *sym-NAME and -sym-NAME keeps the tag. - SP-6.6-4: a client recognizes a refusal by its leading text. go-libfossil already behaves this way. Each row has a case, checked against fossil 2.28 where the harness does: 421 requirements, 420 covered, 1 partial (SP-9.5-7, as before). The repo-state §5.3 step 3 change is filed in zit as a -00 erratum and is not pinned, like the other -00 errata; the -01 draft carries its text. check-in: f61c8174a8 user: [email protected] tags: main, trunk | |
|
2026-10-13
| ||
| 17:32 | chore(release): v0.12.0 changelog (#435) check-in: 7a25e35893 user: [email protected] tags: main, trunk, v0.12.0 | |
| 16:51 |
fix(manifest): maintain the leaf table incrementally (RS-7.3-3) (#434)
* fix(manifest): maintain the leaf table incrementally (RS-7.3-3) The leaf table was recomputed from scratch at the end of every crosslink batch, so a check-in lost its leaf verdict whenever a later batch linked an untagged child to it. repo-state-01 Section 7.3, as corrected, and fossil keep that verdict: a check-in and its plink parents are rechecked only when a branch tag is written to it or propagation updates or deletes its branch row (src/tag.c:195, :100-102), and the checks run when the batch ends (src/leaf.c leaf_do_pending_checks). The rule now lives in a new internal/leaf package: Check (leaf_check), Rebuild (the explicit full rebuild) and Pending (the deferred schedule). internal/tag schedules a recheck at exactly the branch-row writes; the crosslink sweep, receive linker and repair gate apply a batch's schedule at the gate, each phantom-fill cascade transaction and each commit or tag transaction apply their own before commit, and verify.Rebuild keeps the whole-table recompute. Reparenting schedules nothing, as in fossil, so the reparent case is split into a one-batch case and a per-artifact case. Tracked in #426. * fix(manifest): recheck leaves a cancel reaches; drop rechecks of a failed receive tx check-in: 628f932301 user: [email protected] tags: main, trunk | |
| 16:10 |
test(conformance): refresh the corrected sync §9.4 erratum (#431)
zit check-in 00e1711e802e corrects the erratum's account of Fossil 2.28: forbid-delta-manifests defaults on only since 2.29, and 2.28 defaults it off. The draft text is unchanged. Re-pin the erratum copy and its SHA-256 in the sync requirements table, and record the check-in in the README. check-in: caa2797892 user: [email protected] tags: main, trunk | |
| 15:55 |
test(conformance): re-pin the -01 drafts with the 2026-10-13 errata (#430)
* test(conformance): re-pin the -01 drafts with the 2026-10-13 errata Re-pin the repo-state and sync-protocol drafts to zit check-in 5a1b741b25d8, which applies five more -01 errata: repo-state §5.3, §7.3 and §8.3, sync-protocol §9.4/§9.5 and §10.1. zit now keeps each -01 text under the -00 file name; the copies keep their -01 names and conformance/rfcs/README.md records the zit path and check-in. The new errata are pinned, and the requirement tables are re-read against every changed hunk. The §7.3 and §8.3 cases that were deviations now pass as written, and new cases cover a date tag's arrival order (§5.3), untagged leaves and a merge parent's recheck (§7.3). The sync server answers each guard-passing ci-lock with pragma avoid-delta-manifests while forbid-delta-manifests is on, defaulting to on as the draft and fossil 2.29 do (fossil 2.28 defaults it off). The client leaves its transfer unchanged on that pragma. A file or cfile whose content does not match its hash now fails the client's round, in a pull and a clone: the reply rolls back, prefix included, and no further round starts. The leaf table is still recomputed per crosslink batch, so a parent whose untagged child arrives in a later batch loses the verdict §7.3 keeps; that case is marked as a gap, tracked in #426. * fix(sync): continue after a uvfile content error; renumber the avoid-delta-manifests row A uvfile whose content does not match its HASH is a handler-reported content error: warn, commit the prefix and follow ordinary continuation (sync-protocol-01 10.1). The avoid-delta-manifests client row is SP-9.5-7 now that share-links took SP-9.5-5 and SP-9.5-6. Older unreleased changelog entries drop the pending-erratum wording. check-in: 600861484f user: [email protected] tags: main, trunk | |
| 15:33 |
chore: ignore .agent-config at any depth; drop a stray tool trace (#429)
.gitignore anchored .agent-config/* to the repository root, so a local tool's trace written under conformance/ was committed with the suite in #264. Remove it and ignore .agent-config directories wherever they are. check-in: fd0add2110 user: [email protected] tags: main, trunk | |
| 15:25 |
feat(sync): add share-links mode for pragma req-links and link (#428)
* feat(sync): add share-links mode for pragma req-links and link sync-protocol-01 Section 9.5 makes share-links mode OPTIONAL. With SyncOpts.ShareLinks a pulling session sends pragma req-links in its first request, as fossil's --share-links does, unless SyncOpts.ProjectCode names another project. It keeps each pragma link URL ARG MTIME as config link:URL = ARG, defossilized and otherwise verbatim, replacing an existing link only with a strictly newer MTIME. A wrong token count, a URL that is not HTTP(S) or an MTIME that is not a positive decimal drops the link. Where fossil 2.28 differs the draft is followed: fossil fails fatally on a link URL its parser rejects and reads MTIME with strtoll base 0. New sync.9.5 client cases run against fossil sync --share-links as well. SP-9.5-4 loses its scope note and is covered; SP-9.5-5 and SP-9.5-6 are new rows for which links a client keeps and when it sends req-links. Tracked in #425. * test(sync): cover links in later rounds and push+pull req-links; match project code case-insensitively check-in: 5473c06942 user: [email protected] tags: main, trunk | |
| 15:15 |
fix(sync): answer a client clone_seqno with bad command; make Clone's phantom pull opt-in (#427)
* fix(sync): answer a client clone_seqno with bad command; make Clone's phantom pull opt-in Two deliberate #255 deviations from sync-protocol-01 move to conformance. SP-5.2-6: the server now answers a client-sent clone_seqno with "error bad command" and processes the cards after it, as Section 5.2 requires for a reply-only card and as fossil's page_xfer does. SP-8.2-5: Clone now sends nothing after clone_seqno 0 and its cleanup round, so by default it leaves the phantoms a clone produces in place, as fossil(1)'s clone does. The follow-up pull that fetched them is now opt-in through CloneOpts.PullPhantoms, whose doc comment says enabling it departs from Section 8.2. Both cases leave the sync deviations map. Tracked in #424. * fix(sync): quote a client clone_seqno as received in bad command; keep DST coverage of the opt-in pull Tracked in #424. check-in: d3fb5397c8 user: [email protected] tags: main, trunk | |
| 14:23 |
test(conformance): report deviations marked on repo-state API cases (#423)
rsAPICases copied each case's gap mark but never its deviation mark, so repostate.8.3.ckout-inclusive-whole-name, listed in repostateDeviations by #420, ran as an ordinary pass and the coverage report showed RS-8.3-4 as COVERED. Copy the deviation mark too, and state that case the way the other deviation cases are written: it holds go-libfossil to the draft's answer (Section 8.3 retries "ckout." under ci, where ckout is a keyword, so it names the working files), checks fossil(1) against its own answer (the ckout tag's check-in), and is skipped as a deviation while go-libfossil follows fossil. RS-8.3-4 now reports DEVIATION until the 8.3 erratum is applied. check-in: e71b5c241f user: [email protected] tags: main, trunk | |
| 14:09 |
fix(sync): run each request, reply and clone round in one transaction (#422)
A received delta found wrong when its basis arrives later in the pass fails sync-protocol-01 Section 7.7's commit check, which now rolls back everything the pass stored, as fossil's page_xfer and client_sync transactions do, instead of undoing the delta by hand and keeping the rest. The phantom-fill cascades and the server's closing leaf and tag repair run inside that transaction. Any other card error still commits the prefix before it (Section 10.1); on the client that prefix now includes the reply's buffered igot phantoms and visibility changes. db.DB.WithBoundTx binds a DB to one write transaction so code written against *DB, nested WithTx included, joins it as savepoints instead of contending for the write lock from a second connection. SP-7.7-4 is covered; the new SP-10.1-6 has sync.10.1.integrity-error-prefix. Tracked in #418. check-in: c5f5838169 user: [email protected] tags: main, trunk | |
| 13:36 |
feat(resolve): checkout-inclusive request where ckout names the working files (#420)
* feat(resolve): checkout-inclusive request where ckout names the working files Checkout.ResolveWorking is fossil's "ci+" request (repo-state-01 8.3): while the checkout has a version, "ckout" answers the working files, reported as WorkingVersion.Working rather than as a pseudo-RID. Every other name goes through the same resolver as Checkout.ResolveVersion, restricted to check-ins as fossil's ci+ is. The draft also makes ckout a keyword in a plain "ci" request; this follows fossil, where only ci+ has it. New repostate.8.3 cases run the request against fossil test-name-to-id --type ci+, and RS-8.3-4 loses its scope note. Tracked in #419. * fix(resolve): record the ckout retry as a fossil deviation; tighten tests check-in: 0889d8b777 user: [email protected] tags: main, trunk | |
| 12:56 |
fix(sync): verify a dangling delta when its basis arrives in the same pass (#417)
Tracked in #412. check-in: 056f36e0bc user: [email protected] tags: main, trunk | |
| 12:27 |
fix(sync): repair leaves and tags for check-ins the cascade links (#414) (#416)
* fix(sync): repair leaves and tags for check-ins the cascade links (#414) A pulled check-in arrives as an announced phantom filled the next round, so the phantom-fill cascade links it. The session's closing sweep then found nothing left to link and skipped the leaf and tag-propagation repair, which gated on the sweep's own count: the check-in had an event row and no leaf row, and its parent stayed a leaf. The server handler had the same gap for a pushed artifact that fills a phantom. AfterDephantomize and AfterDephantomizeBatch now return how many artifacts they linked. The sync client and the handler add that up over the session and close it with the new CrosslinkAfterCascades, which runs the repair once when the sweep or the cascades linked anything (repo-state-01 Section 7.3, RS-7.3-4), not once per file. The receive linker's cancellation paths gate on the same flag. The repo-state harness gains a pull load: the first artifacts of a script are held and crosslinked locally, the rest pulled in process from a go-libfossil server holding them all. New cases repostate.7.3.pulled-child and repostate.7.6.pulled-retag, checked against fossil per artifact, each run as a .pull case too. Tracked in #414. * fix(sync): repair leaves of cascade links when a session fails (#414) check-in: 0035af8ac5 user: [email protected] tags: main, trunk | |
| 11:59 |
fix(manifest): link check-ins with absent files; refuse absent baselines (#415)
* fix(manifest): link check-ins with absent files; refuse absent baselines The crosslink sweep held a check-in back until every file it names was stored. A root check-in, or one on a present parent, whose files never arrived got no event, plink, mlink, leaf or tag rows. fossil links it against phantom files (add_one_mlink, uuid_to_rid(..., 1)), and repo-state-01 Section 4.2 makes an unresolved reference a phantom, not an error. The sweep -- Crosslink, the close of every sync and clone, and verify.Rebuild -- now waits only on a delta manifest's baseline. The receive-time cascade and receive linker still wait for files while blobs are still arriving; the closing sweep bounds that wait. verify.Rebuild linked a delta manifest whose baseline was absent, with no baseline id. fossil refuses it (fetch_baseline) and files it in orphan under a phantom for the baseline; artifact-format-01 Section 8.3 calls this a soft failure retried when the baseline arrives. Every path now does the same, so a sync requests the baseline and the phantom-fill cascade links the manifest when it lands. Rebuild clears and rederives orphan. The gap case repostate.4.2.root-absent-file passes and is unmarked; new cases cover a present parent with an absent file and an absent or late baseline, each also through verify.Rebuild where fossil rebuild agrees. Tracked in #406. * fix(manifest): refuse a non-manifest baseline and drop the orphan row on link Tracked in #406. check-in: 67fc6ced4b user: [email protected] tags: main, trunk | |
| 11:38 |
test(sync): mark dangling deltas whose basis arrives in the same pass (#413)
* test(sync): mark a dangling delta whose basis arrives in the same pass SP-7.7-4 requires every artifact stored in a pass whose bytes are available in that pass to be checked against its HASH. A delta stored dangling is not rechecked when its basis arrives later in the same reply or request; fossil's commit hook catches it and rolls the round back. Add client, clone and server cases for it, marked as gaps. Tracked in #412. * test(sync): note how the server late-basis case must tighten when its gap closes check-in: 8f03734a23 user: [email protected] tags: main, trunk | |
| 11:14 |
fix(sync): verify a received delta against HASH before storing it (#410)
sync-protocol-01 Section 7.7 verifies a reconstructable non-clone file before storage, and SP-7.7-4 has every newly stored artifact whose bytes are available hashed before commit. The client and a clone stored a delta against a held basis as given, and the server checked only a file delta, so a delta that did not give HASH stayed stored under that name until something expanded it. The check moves to storeReceived, the one choke point every receive path shares, so the client, the server (file and cfile) and a clone refuse a delta whose result is not HASH, or that does not apply. An unheld basis still leaves the delta stored dangling. Tracked in #405. check-in: b3914d95b3 user: [email protected] tags: main, trunk | |
| 11:14 |
feat(repo): name the current trunk and a branch's open leaf (#411)
* feat(repo): name the current trunk and a branch's open leaf Repo.CurrentTrunk resolves the main-branch setting's name the way ResolveVersion does, as fossil does for update outside a checkout and open with no version (repo-state-01 Section 9). Repo.BranchOpenLeaf names the open leaf of a branch with the greatest mtime, or reports the branch not open; fossil's branch info takes whichever open leaf its query meets first, and this follows the draft. checkout.BranchLeaves and the new checkout.BranchOpenLeaf share one open-leaf query. RS-9-1 and RS-9-4 lose their scope notes and gain cases. * fix(repo): resolve the current trunk as a check-in, reject an empty branch name Tracked in the stacked work on repo-state-01 Section 9. check-in: c2795c4f48 user: [email protected] tags: main, trunk | |
| 11:05 |
feat(resolve): resolve checkout-relative names and branch-type requests (#409)
* feat(resolve): resolve checkout-relative names and branch-type requests Checkout.ResolveVersion resolves current, prev/previous and next relative to the open checkout, after tip and before the other forms, as fossil's symbolic_name_to_rid does; a keyword that names nothing falls through. Repo.ResolveBranchStart is the branch-type request: it resolves a name and walks back to the first check-in of its branch. Section 8.3 walks back from every result; fossil only from tag:NAME and plain names, and this follows the draft. The repostate.8.3 checkout and branch-type cases run against the new entry points, with new cases for a keyword shadowing a tag, prev at a root, an untyped ckout, root:current and a branch-type hash. Tracked in #386. * fix(resolve): match check-ins only for branch-type requests, merge via checkout A branch-type request is rewritten to a check-in request (repo-state-01 Section 8.3), so a technote tagged with the branch name cannot answer it. A checkout with no recorded version resolves the ordinary forms, and merge resolves its version through the open checkout. Tracked in #386. * fix(resolve): wrap a long test line check-in: cba2d0c823 user: [email protected] tags: main, trunk | |
| 10:59 |
feat(repo): set the hash policy by name (#408)
artifact-format-01 7.1 (AF-7.1-2) matches policy value strings case-sensitively and exactly and makes an unrecognized value fatal. No surface took a value string, so the row stayed partial. Repo.SetHashPolicy takes sha1, auto, sha3, sha3-only or shun-sha1, as fossil's hash-policy command does with fossil_strcmp, stores the ordinal, and refuses any other string without touching the stored policy. Auto in a repository that already holds a SHA3 artifact stores sha3 (7.3). New conformance cases drive every name, wrong-case names, unknown names and the empty name through it, and the AF-7.1-2 scope note is dropped. check-in: feea6a1614 user: [email protected] tags: main, trunk | |
| 10:52 |
fix(manifest): link a check-in atop an absent parent despite absent files (#407)
* fix(manifest): link a check-in atop an absent parent despite absent files The crosslink deferral held back a check-in until every F-card blob was stored. When the primary parent's manifest is itself absent, no mlink row depends on those files (fossil's add_mlink returns before reading one, and the parent's crosslink derives the transition once it arrives), so the wait could never complete for files the repository will not receive. The libfossil repository holds one such check-in, a fossil-scm commit imported without its history; the sweep lost its event and plink rows that fossil rebuild writes (RS-4.2-2). missingCheckinRefs now skips the F-cards when the primary parent is unavailable; the baseline is still required. Adds conformance case repostate.4.2.phantom-parent-absent-file and a unit test that also checks the child's mlink is derived once the parent arrives. Tracked in #398. * fix(manifest): record the remaining crosslink deferral gaps Adds gap case repostate.4.2.root-absent-file, a receive-linker ordering test for the child-before-parent path, and notes the narrowed exemption. Tracked in #398 and #406. check-in: 15762adeb6 user: [email protected] tags: main, trunk | |
| 07:32 |
fix(sync): stop the client reply loop at a card with no artifact name (#404)
* fix(sync): stop the client reply loop at a gimme or igot with no artifact name fossil's client reads gimme and igot only with blob_is_hname; any other line is an unknown command that ends the reply-card loop, as sync-protocol-01 Section 5.2 requires of a malformed defined card. A server case pins the existing bad-command answer to such a gimme. Tracked in #397. * fix(sync): stop the client reply loop at a file or cfile with no artifact name Tracked in #397. * test(conformance): split the case tables this round grew past 70 lines Tracked in #397. Each half keeps its cases in order; only the table functions move. check-in: 636e873e6a user: [email protected] tags: main, trunk | |
| 07:19 |
fix(sync): reclassify held artifacts and phantoms from igot (#403)
sync-protocol-01 Section 7.5 has a pushed igot reclassify what the server holds: public igot makes it public, igot HASH 1 private, the latter from a requester without x too, where it still makes no phantom. This matches page_xfer's content_make_public and content_make_private. Tracked in #391. check-in: 5004d66398 user: [email protected] tags: main, trunk | |
| 07:12 |
fix(sync): end card processing when a pushed file fails its handler (#402)
* fix(sync): end card processing when a pushed file fails its handler sync-protocol-01 Section 5.2 has a file or cfile handler failure reset the reply, send the error and stop parsing, as fossil's xfer_accept_file path does. A wrong hash, a bad HASH or DELTASRC and a storage failure now break the card loop; a file delta with a held basis is verified before it is stored (Section 7.5). Tracked in #390. * fix(sync): model a bad file name in the clone-fatal probe Tracked in #390. check-in: c36a69e366 user: [email protected] tags: main, trunk | |
| 06:42 |
fix(sync): send the clone reply and cluster igots in place (#401)
page_xfer writes the clone batch, its catalog, clone_seqno and push card at the clone card and the req-clusters igots at the pragma, so any later reset discards them (sync-protocol-01 Section 10.1). They were sent after the card loop and survived a bad command or refused push. The clone snapshot cookie is now read ahead of the loop. Tracked in #389. check-in: 65783dbd3e user: [email protected] tags: main, trunk | |
| 06:34 |
fix(sync): apply ci-lock and ci-unlock for any requester (#400)
sync-protocol-01 Section 9.4 applies both pragmas with no Write test, as fossil's page_xfer does. The leaf sweep before each lock write bounds the lock table. nobody's lock row stores a null login; ci-lock-fail fossilizes LOGIN and names a login-less holder nobody. lock-timeout is read as db_get_int reads it. Tracked in #392. check-in: e44a484403 user: [email protected] tags: main, trunk | |
| 06:14 | fix(checkout): pick the no-target update target as fossil does; read untagged check-ins as the default branch (#399) check-in: 425dd36e13 user: [email protected] tags: main, trunk | |
| 05:59 |
fix(manifest,hash): verify the R card at commit; reject an unrecognized hash-policy (#396)
* fix(manifest,hash): verify the R card at commit; reject an unrecognized hash-policy A check-in reads its manifest back and requires the R card to equal the digest recomputed over the resolved tree, byte for byte (artifact-format-01 6.3.4, AF-6.3-5). A hash-policy setting outside the ordinals 0 through 4 is now an error instead of a fall back to the default (7.1, AF-7.1-2). Tracked in #387. * fix(manifest,repo): drive the commit R check from conformance; refuse a bad hash-policy on write check-in: c42a2b90c6 user: [email protected] tags: main, trunk | |
| 05:32 | test(conformance): cover the repo-state GAP and PARTIAL rows (#395) check-in: 3c3b12fdf2 user: [email protected] tags: main, trunk | |
| 05:26 |
fix(sync): cover the sync-protocol-01 coverage rows (#394)
Check the remaining partial and uncovered sync rows, and fix the client private-gimme answer, the unversioned-file NAME encoding, the check-in lock table, the uv-hash name form and the uvgimme round limit they exposed. Tracked in #392. check-in: 161d6ab68f user: [email protected] tags: main, trunk | |
| 05:17 |
fix(sync): handle server cards in request order, phantom gimme after push, clone bad cards (#393)
Tracked in #385. The server verified the login card first and handled every control card before any data card. A file card ahead of its push card was stored, and cards ahead of a successful login got the login's capabilities. Cards are now handled in one in-order loop, as fossil's page_xfer reads them. A request holding an invalid clone sequence is first walked without side effects, which stands in for fossil's whole-request rollback. A refused push without an earlier pull now resets and answers "not authorized to write"; a refused pull resets, answers "not authorized to read" and ends card processing (sync-protocol-01 Section 6.6). An accepted push now asks for the server's phantoms after the card loop, at most 500, skipping what the client asked for, shunned names and private ones outside a private sync, as request_phantoms does. A pushed igot makes a phantom instead of drawing a gimme on the spot. A clone reply card the client cannot read ends the reply-card loop instead of aborting: the session goes on, the second clone round is still made, and the clone then fails naming the card. The conformance matchers that accepted "push denied" and "pull denied" are narrowed to the draft's text, and new cases put output ahead of a refusal and cards ahead of the push or login they depend on. check-in: 3beb6eeb15 user: [email protected] tags: main, trunk | |
| 04:51 |
test(conformance): cover artifact K, delta-lookup and delta-size requirements (#388)
* test(conformance): cover artifact K, delta-lookup and delta-size requirements Single-name lookup in a delta manifest now follows artifact-format-01 8.4 (manifest.LookupFile), Marshal writes the K ticket ID lowercase (4.7.9), and new cases cover 3.1 size limits, 3.4 checksum mismatches and date-only timestamps. AF-6.3-5 and AF-7.1-2 stay uncovered with a reason in their rows. * test(conformance): cover artifact K, delta-lookup and delta-size requirements (review fixes) check-in: 22b3a0f06d user: [email protected] tags: main, trunk | |
| 04:13 |
fix(sync): withhold SHA3 unversioned files from a pre-SHA3 server (#303) (#384)
sync-protocol-01 Section 7.6 (SP-7.6-1): a sender replaces a uvfile whose HASH is a SHA3 name with the error "Fossil version 2.0 or later required." when the peer's recorded VERSION is below 20000. The client gated artifacts this way already but sent unversioned files to such a server regardless. buildUVFileCards now sends the refusal in place of the card, with or without content, and drops the file from the send list, as fossil's send_unversioned_file does. A deletion tombstone names no hash and is still sent. check-in: 6bde4f3729 user: [email protected] tags: main, trunk | |
| 04:08 |
fix(sync): answer a private gimme with igot HASH 1 for a recent peer (#375) (#383)
sync-protocol-01 Section 8.6: outside a private sync, a gimme for content held as private is answered with igot HASH 1 when the peer's date is 2020-04-13 or later, and with nothing for an earlier or unknown date. fossil's send_file decides it on remoteDate, which page_xfer reads from a client-version pragma carrying DATE and TIME. The handler now records the peer's date from client-version and sends the private igot in place of the skipped file. check-in: 13e5e9d229 user: [email protected] tags: main, trunk | |
| 03:56 |
fix(sync): end card processing on refused writes and logins, count errors as fossil (#374) (#382)
Three server refusal paths now follow sync-protocol-01: - Section 6.6 (erratum s6.6-file-card-after-refused-push): a file or cfile card without an accepted push resets the reply, sends "not authorized to write" and ends card processing, as page_xfer does. The pull's igot inventory still follows. - Section 6.4: a refused login ends card processing at its own position rather than ending the request. Cards before it keep their effect, the end-of-request inventory runs, and the reply carries the closing timestamp comment. - Section 5.3 (erratum s5.3-errors-count): errors N counts errors raised, including those a reset discarded, and skips the bad-command error, the private-content refusal and the SHA3 refusal. check-in: 5f4424320b user: [email protected] tags: main, trunk | |
| 03:51 |
fix(xfer): treat a payload cut short as its card's handler failure (#373) (#381)
sync-protocol-01 Section 5.1 (erratum s5.1-truncated-payload-receiver) makes a file, cfile or uvfile payload that the body ends inside a validation failure of the card's handler, never a stored artifact. The decoder failed the whole message instead, so a server answered HTTP 400 and a client dropped every card of the reply. The decoder now yields such a card as a BadFileCard carrying the handler's malformed-line text and stops, as it already does for a line it cannot frame. The server answers 200 with that error and keeps the cards before it; the client keeps the prefix it processed. fossil 2.28 stores the bytes present; -01 is followed here. check-in: 648f5d4479 user: [email protected] tags: main, trunk | |