Skip to content
go-libfossil Timeline
Login

Timeline

50 descendants of d47958493bed6c75

2026-10-28
12:47
fix(content): classify a fossil-written store's file versions from its tables

A store this library crosslinked records each blob it found to be no artifact, and classification skips the file versions among them. A store fossil wrote has no such record, so classification read every file version raw and exceeded its byte budget: on a copy of fossil-scm.org's repository it failed on every request. A cone clone's walk then kept no base it had not reached yet, sent every in-cone version whole, and fit two or three 2-4 MB sqlite3.c texts into a 16 MB round: about 390 rounds and 30 minutes, where a dense clone takes 8 rounds.

Without the record, a version that mlink names and no table an artifact's crosslink writes claims is file content too, the proof the cone walk's knownFile already relies on; a table the store lacks claims nothing. That clone now takes 12 rounds and 9 minutes, verifying the same.

Related to #465. check-in: 4536dae44c user: [email protected] tags: main, perf/cone-clone-rounds, trunk

11:59
perf: carry a cone clone's forwarded delta chains across rounds

The server's cone walk sends an in-cone file version as a delta with the chain of newer versions ahead of it as its bases. Each round restarts the walk from the clone's cursor, so every later round that reached one of those versions at its own check-in sent it again.

The walk's cookie now names each chain a send forwarded: its head, length and an FNV-64 checksum of its rids. The next round rebuilds the chain from the store's delta table, counts its rids as sent, and drops it when the checksum no longer matches, so a store re-deltified mid-clone can never pass off a base the client was not sent. A run loses the leading rids the walk reaches, and the cookie carries at most 1,024 runs; one dropped is only sent again.

On a copy of fossil-scm.org's repository a cone clone of src now receives 72,835 blobs to hold 56,262 (main: 100,212); the clones verify identically. check-in: 9d266a0f51 user: [email protected] tags: main, perf/cone-clone-resend, trunk

11:11
seedcheck: drop a seed completed as a delta in a later round

A horizon seed stored as a delta whose base arrived only in a later round (pull, clone) or a later request (origin push) was refused by its hash but kept in the store, and a pull or clone counted the delta as received on arrival, before it could be judged (draft-fossil-horizon-00 §5.2.3, HZ-5.2-14).

On a seed verdict seedcheck now rewrites each delta built on the seed as full text, then empties the seed's row: size -1, no content, no delta link, and kept out of the phantom table so no request asks for it. The rid stays held for anything a receive pass tracks by it, and the refused hash is still recorded in store-local state.

A pull or clone counts a delta it could not read on arrival only at the end of the exchange, once readable and not dropped. A round still treats it as progress. The receive pass treats a row without content as no basis even when its cache holds the old bytes, and the push handler's same-request seed check consults the refused hash, since the dropped row no longer reads.

HZ-5.2-14 is now covered. check-in: 917bcc9830 user: [email protected] tags: fix/seed-delta-drop, main, trunk

2026-10-26
14:45
Merge pull request #513 from danmestas/test/organize-root-tests

test: move black-box tests to apitest/, consolidate root tests by source file check-in: b4ac68be08 user: [email protected] tags: main, trunk

14:36
Merge remote-tracking branch 'origin/main' into test/organize-root-tests check-in: 2bb9dc608b user: [email protected] tags: main, trunk
14:36
Merge pull request #514 from danmestas/ci/cache-release-downloads

ci: cache the pinned Fossil and zit release tarballs check-in: 38eb1f810c user: [email protected] tags: main, trunk

14:28
ci: cache the pinned Fossil and zit release tarballs

fossil-scm.org answered 503 for the Fossil release tarball, and both test jobs failed before any test ran. The checksummed tarballs are now cached by version and checksum, so fossil-scm.org and zit's server are needed only on a cache miss; a cached copy is still verified before it is installed. check-in: b65ca240f1 user: [email protected] tags: main, trunk

14:05
test: consolidate root white-box tests by source file

Merge the root package's white-box test files so each mirrors the source file it exercises (checkout, fossil, horizon, repo_checkout, repo_history, repo_merge, repo_sync, repo_ticket, repo_extras, required_content, transport), and rename single files to match their source (repo_content_cache_test.go, repo_admin_test.go, required_content_checkout_test.go). Test bodies are unchanged; only imports are consolidated. check-in: af6431af27 user: [email protected] tags: main, trunk

14:00
test: move black-box root tests to apitest/

Every package libfossil_test file in the root used only exported identifiers and shared no helpers with the white-box tests, so all 21 move to a test-only apitest package. Docs that name their location follow. check-in: 6956a92661 user: [email protected] tags: main, trunk

13:09
Merge pull request #512 from danmestas/feat/opt-in-ssh-verify

feat(sshverify): make in-process SSH signature verification opt-in check-in: 5e7ce934cd user: [email protected] tags: main, trunk

13:00
Merge remote-tracking branch 'origin/main' into feat/opt-in-ssh-verify

# Conflicts: # CHANGELOG.md check-in: 52d7948375 user: [email protected] tags: main, trunk

12:59
test: guard simio against linking SSH crypto too

simio is the third package an embedder links; the opt-in guard now checks it alongside the library and db. check-in: d79a35c16a user: [email protected] tags: main, trunk

12:49
Merge pull request #511 from danmestas/feat/wasm-tickets

feat: ticket writes, ticket reads and timeline-since check-in: e448e2e48d user: [email protected] tags: main, trunk

12:45
feat(sshverify): make in-process SSH signature verification opt-in

internal/clearsign keeps the SSH envelope, SSHSIG parsing, namespace, hash and SHA-1 checks, none of which need cryptography, and hands the key parse and signature check to an SSHVerifier that the new public package sshverify registers from init. The library therefore no longer links golang.org/x/crypto/ssh and the ECDSA, P-256, Ed25519 and RSA code it pulls in; html-artifact-publisher's TinyGo engine drops from 1,347,569 to 1,093,647 bytes gzipped (3,777,936 to 3,208,411 raw).

Without the verifier nothing is accepted unchecked: a well-formed SSH signature is ErrSSHVerifierUnavailable, which wraps ErrCannotVerify, so a seed under an SSH horizon-seed-key is refused, the held one is kept, and the sync or rebuild fails naming the package to import. Malformed signatures are still bad. The cli package (and so cmd/libfossil) and examples/tinygo import sshverify; a go list guard keeps x/crypto/ssh out of the root and db closures. check-in: a87790f468 user: [email protected] tags: main, trunk

12:39
Merge remote-tracking branch 'origin/main' into feat/wasm-tickets

# Conflicts: # CHANGELOG.md check-in: 1d8b2e6658 user: [email protected] tags: main, trunk

12:38
Merge pull request #510 from danmestas/fix/create-unsupported-stat

fix: let Create proceed when the filesystem cannot stat the parent check-in: b7e00e1673 user: [email protected] tags: main, trunk

12:30
fix: let Create proceed when the filesystem cannot stat the parent

Create's parent-directory check, added in #457, refused a path whenever os.Stat of its parent failed. Under TinyGo wasm a repository lives in a SQLite VFS and os.Stat is unsupported, so every create failed with "parent directory does not exist: /"; standard Go's js/wasm build hung on the same check. It now refuses only a parent the filesystem confirms is missing or is not a directory, and otherwise lets SQLite's own open report a real failure (tracked in #509). check-in: 2449bcd313 user: [email protected] tags: main, trunk

03:24
fix: timelineSince means arrived after, not stamped after

A sync handler asks what a push brought in. Filtering on timestamps missed an artifact made on a machine whose clock runs behind the given check-in's. TimelineSince now keeps entries whose artifacts were stored after the given one: a later receipt (blob.rcvid, which a phantom fill updates), then a higher rid. Any held artifact hash is accepted; an unknown one is an error.

Tracked in #504. check-in: 29b53e75d2 user: [email protected] tags: main, trunk

03:14
feat: ticket writes, ticket reads and timeline-since

Repo.TicketAdd and Repo.TicketSet write the ticket-change artifact stock `fossil ticket add` / `fossil ticket set` write (D, J incl. +append, K, U, Z), byte for byte, and crosslink it in the same transaction so the ticket, ticketchng and event rows read back at once. TicketOpts.Comment is stored as the stock ticket forms store a remark: icomment with login, username and mimetype.

Repo.TicketList, Repo.TicketChanges and Repo.TimelineSince expose the reads the html-artifact-publisher engine needs, as JSON-ready values. manifest.Timeline gains Kinds and Since to back TimelineSince.

Tracked in #503 and #504. check-in: 68f2c3d930 user: [email protected] tags: main, trunk

02:38
Merge pull request #508 from danmestas/release/v0.16.2

chore(release): v0.16.2 check-in: 89f09bf179 user: [email protected] tags: main, trunk, v0.16.2

01:42
chore(release): v0.16.2 leaf check-in: 0da8ac4f50 user: [email protected] tags: release/v0.16.2, trunk
01:40
Merge pull request #507 from danmestas/test/horizon-partials

test(conformance): close four partial horizon rows check-in: 94717e5803 user: [email protected] tags: main, trunk

01:19
Merge remote-tracking branch 'origin/main' into test/horizon-partials check-in: 825a901dda user: [email protected] tags: fix/conformance-subtest-t, main, trunk
01:18
test(conformance): close four partial horizon rows

HZ-5.2-2: the seed label appears on no artifact an origin or its structural clone stores, across re-seeding and writes on both sides; the minted floor survives a restart of the origin. HZ-5.2-9: a seed's missing base filled by a pull, a local check-in and a local tag leaves the seed refused, unlinked and unserved, and the transfer that filled it linked. HZ-6.1-2: path-cone and cursor pragmas beside horizon-name are answered as beside pragma horizon, and act; a named clone with path members sends them and records both. HZ-6.2-17: an event-mtime tie resolves to the lowest full hash for tip and a branch; a full-hash-shaped name no check-in has resolves as a symbolic name, and one a check-in has names that check-in first. check-in: 7a375b6d73 user: [email protected] tags: fix/conformance-subtest-t, main, trunk

01:07
Merge pull request #505 from danmestas/fix/conformance-subtest-t

test(conformance): hand each case its subtest's t; cancel stale Race runs check-in: 49bf242db8 user: [email protected] tags: main, trunk

00:59
Merge remote-tracking branch 'origin/main' into fix/conformance-subtest-t leaf check-in: e0dcd0ea23 user: [email protected] tags: fix/conformance-subtest-t, main, trunk
00:59
test(conformance): hand each case its subtest's t; cancel stale Race runs

check runs each case as a subtest, but the suites passed the case the parent's t, captured in a closure. A fixture that skips or fails, as the fossil-built R-card fixture skips when fossil(1) is absent, then called SkipNow or FailNow on the parent from inside the subtest, which Go fails as "subtest may have called FailNow on a parent test". The Race workflow installs no fossil and failed this way in TestSparseCone. check now hands conforms the subtest's t, and all 150 call sites take it, so a case's skip or failure ends that case alone. TestCheckSkipEndsOnlyTheCase guards the harness.

A Race run takes most of an hour and merges land faster, so a new run on a ref now cancels the older one. check-in: 43df2fd2c2 user: [email protected] tags: fix/conformance-subtest-t, main, trunk

00:54
Merge pull request #502 from danmestas/docs/sdk-reference-check

docs: regenerate the SDK reference and check it in CI check-in: 51d3b9cf5f user: [email protected] tags: main, trunk

00:46
docs: regenerate the SDK reference and check it in CI

The gomarkdoc SDK pages had drifted about a thousand lines from the code: make docs-gen-sdk was never part of docs-gen, so nothing regenerated them and the docs check did not compare them. ReadBlob, SetContentCache, ListFilesIn and OriginNamer were missing from the libfossil page.

scripts/gen-sdk-docs.sh now renders them, running gomarkdoc v1.1.0 through go run so CI needs no install, then adds the frontmatter. It honours OUT_DIR, gen-docs.sh calls it, and check-docs-generated.sh compares the result, so a stale SDK page fails CI like any other generated input. make docs-gen-sdk calls the same script. llms.txt and llms-full.txt are regenerated from the refreshed pages. check-in: c12b02189f user: [email protected] tags: main, trunk

00:11
Merge pull request #501 from danmestas/perf/submanifest-node-memo

perf(manifest): memoize parsed sub-manifests by hash check-in: d82fddda6a user: [email protected] tags: main, trunk

00:02
perf(manifest): memoize parsed sub-manifests by hash

draft-fossil-submanifests-00 §7.4: enumeration results SHOULD be cached keyed by artifact name, so a rebuild parses each distinct sub-manifest once. The tree walk's loader now serves a resolved node from, and keeps it in, a new byte-bounded LRU memo on content.Cache (DerivedSized), keyed by the node's hash and charged its bytes, within a quarter of the cache's budget. The existing 32-entry Derived FIFO is sized for a few parsed check-ins; a tree's working set is every distinct node, which would thrash it and evict those check-ins.

Only a node that resolved is kept, so a phantom is looked up afresh and fails the walk as before. Depth, cycle and node-count bounds stay per walk. The memo is dropped with Derived on Invalidate and Clear, and the Repo's cache is replaced at every write.

Listing a tree that differs from one already read in one leaf now parses its manifest and that leaf; listing every check-in of zit's recorded tree history parses 48 sub-manifests instead of 109. SM-7.4-1 is covered.

Tracked in #493. check-in: 94f61db228 user: [email protected] tags: main, trunk

00:01
Merge pull request #500 from danmestas/feat/list-files-in-cone

feat: list a check-in's files in a cone check-in: e90c972c40 user: [email protected] tags: main, trunk

2026-10-25
23:53
feat: list a check-in's files narrowed to a cone

Repo.ListFilesIn passes the public Cone to the enumeration seam as the range predicate (draft-fossil-sparse-cone-00 §4.1). On a tree manifest the walk skips sub-manifests the cone cannot reach (§4.5), so over a sparse store it succeeds where ListFiles fails on an elided node. It reads through the attached content cache, via a new internal manifest.ListFilesFilteredCached.

Tracked in #491. check-in: 7156492179 user: [email protected] tags: main, trunk

23:44
Merge pull request #499 from danmestas/ci/race

ci: run the unit suite under -race; give packages 10m check-in: 612977a2d6 user: [email protected] tags: main, trunk

23:37
ci: run the unit suite under -race; give packages 10m

A Race workflow runs every unit package under the race detector after each merge to main, nightly, and on demand. The full suite passes under -race with no data race reported; it takes several times as long as without, so it does not gate pull requests, which already must be up to date with main to merge. Fossil and zit are not installed there; their interop tests skip, and the Tests workflow runs them.

The unit steps' -timeout is per package binary, and conformance alone takes 130-255s on a hosted runner, so 300s failed it on runner variance. It is now 10m. The dst steps keep 300s. check-in: fdd361b5a9 user: [email protected] tags: main, trunk

23:36
Merge pull request #498 from danmestas/fix/horizon-cursor-embedder-transport

fix(sync): export OriginNamer so an embedder's transport keeps a horizon cursor check-in: a52911df25 user: [email protected] tags: main, trunk

23:29
fix(sync): export OriginNamer so an embedder's transport keeps a horizon cursor

Sync and Clone keyed the horizon cursor (draft-fossil-horizon-00 §6.2.6) on an unexported syncOrigin method, which only the HTTP transport could satisfy. Any other Transport kept no cursor and announced its whole holding with igot on every pull.

OriginNamer is an optional interface, discovered by type assertion like FramedTransport, with SyncOrigin() string. The HTTP transport implements it in place of the unexported method, so one assertion serves both. The name must identify the peer stably and carry no credential.

Tracked in #488. check-in: 8d16b7289c user: [email protected] tags: main, trunk

23:28
Merge pull request #496 from danmestas/feat/read-blob-content-cache

feat: read an artifact by hash and cache content on Repo check-in: 5e882bf1f1 user: [email protected] tags: main, trunk

23:10
feat: read an artifact by hash and cache content on Repo

Repo.ReadBlob expands one artifact by its full hash after the availability check ReadFile applies, and names an unknown hash with ErrArtifactNotFound.

Repo.SetContentCache attaches a byte-bounded content.Cache that ReadFile, ReadFileAt, ReadBlob, ListFiles, Diff and Annotate share; check-in parses are kept in its derived memo, so reads at one check-in parse the manifest once. Default off. A read that finds the DB's finished-write count moved swaps in an empty cache, so a purged, compacted or elided artifact, and a rid SQLite reuses after a purge, is never served from it. Writes by another process are not seen; the method's doc says so.

Tracked in #492. leaf check-in: d367012009 user: [email protected] tags: feat/read-blob-content-cache, trunk

23:10
feat(db): count finished writes

DB.Writes counts pool Exec calls that returned and WithTx transactions that ended. Counting at the end is what lets a reader holding state across calls treat an unchanged count as no write having landed in between. check-in: 51be37dc1a user: [email protected] tags: feat/read-blob-content-cache, trunk

23:10
Merge pull request #497 from danmestas/ci/gofmt

ci: check gofmt; format the tree check-in: 969c8f1fe4 user: [email protected] tags: main, trunk

23:02
ci: check gofmt; format the tree

Sixteen files had drifted from gofmt: struct and comment alignment, one-line if bodies in auth_test.go, trailing blank lines, and a blank comment line gofmt now puts before an indented block in two delta.go doc comments. The test job now fails on any tracked .go file gofmt would change, and lists it. check-in: b2dcbb7130 user: [email protected] tags: main, trunk

22:36
Merge pull request #495 from danmestas/ci/zit-0.7.3

ci: pin zit interop to 0.7.3 check-in: 95610ffc23 user: [email protected] tags: main, trunk

22:27
ci: pin zit interop to 0.7.3

zit 0.7.3 (version-0.7.3, check-in f18e3cc041) carries draft check-in 39546186f4, the minted seed floor of horizon §5.2.2 that go-libfossil implements since #485, so the pinned interop zit and the pinned draft copy agree again. Every zit interop test passes against it, none skipped, with REQUIRE_ZIT_BIN and REQUIRE_ZIT_SEED_DATE set. check-in: 10737ceaec user: [email protected] tags: main, trunk

22:23
Merge pull request #494 from danmestas/feat/carried-uuid-default-login

feat(commit): carry files by UUID; fix Create's default login check-in: d0abc1b3fa user: [email protected] tags: main, trunk

21:08
fix: validate carried hashes and check FOSSIL_USER first

A carried file outside a sparse store's cone skips the held check, so any caller text of 40 bytes or more reached the F card verbatim, including a newline that writes a card of its own into the check-in. checkCarried now refuses a UUID that is not a lowercase SHA1 or SHA3-256 hash, which covers FileToCommit.UUID and the sparse checkout path alike (tracked in #486).

The default login follows fossil's db_create_default_users, which checks FOSSIL_USER before USER, LOGNAME and USERNAME (tracked in #487). leaf check-in: 2237a3781a user: [email protected] tags: feat/carried-uuid-default-login, main, trunk

21:05
fix(create): seed fossil's fallback login when no user is configured

Create with an empty CreateOpts.User read only $USER and then panicked in db.SeedUser on the empty login whenever that variable was unset, as it is in many containers and CI runners. The default login is now chosen as fossil(1)'s db_initial_setup chooses it: the first of USER, LOGNAME and USERNAME that is set, else "root". check-in: c15a6c60e9 user: [email protected] tags: feat/carried-uuid-default-login, main, trunk

21:05
feat(commit): carry a file into a check-in by UUID without its content

FileToCommit gains a UUID field. When set, the F card names that artifact verbatim and nothing is read or stored, reaching the internal manifest.File.UUID path that sparse checkouts already use. A caller that lists a parent's files can now commit with PartialManifest, dropping files, by naming the unchanged part of the tree instead of re-reading and resubmitting every byte of it. Both UUID and Content on one file is refused; so is a UUID the store does not hold outside an eliding cone. check-in: 37bba3f7b9 user: [email protected] tags: feat/carried-uuid-default-login, main, trunk

21:04
fix(create): seed fossil's fallback login when no user is configured

Create with an empty CreateOpts.User read only $USER and then panicked in db.SeedUser on the empty login whenever that variable was unset, as it is in many containers and CI runners. The default login is now chosen as fossil(1)'s db_initial_setup chooses it: the first of USER, LOGNAME and USERNAME that is set, else "root". leaf check-in: 229c02160d user: [email protected] tags: fix/create-default-login, main, trunk

21:00
feat(commit): carry a file into a check-in by UUID without its content

FileToCommit gains a UUID field. When set, the F card names that artifact verbatim and nothing is read or stored, reaching the internal manifest.File.UUID path that sparse checkouts already use. A caller that lists a parent's files can now commit with PartialManifest, dropping files, by naming the unchanged part of the tree instead of re-reading and resubmitting every byte of it. Both UUID and Content on one file is refused; so is a UUID the store does not hold outside an eliding cone. leaf check-in: 481ac23eaf user: [email protected] tags: feat/commit-carried-by-uuid, main, trunk

2026-10-24
19:19
Merge pull request #485 from danmestas/feat/horizon-seed-floor

fix(horizon): date a seed no earlier than the origin's minted floor check-in: d47958493b user: [email protected] tags: main, trunk