Skip to content
go-libfossil Timeline
Login

Timeline

50 ancestors of d9b18ab6196cbd09

2026-10-18
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