50 descendants of 9c071c7c22808caa
|
2026-10-13
| ||
| 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): reclassify held artifacts and phantoms from igot
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. leaf check-in: e245232360 user: [email protected] tags: trunk, fix/391-igot-reclassify | |
| 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:56 |
fix(sync): handle server cards in request order, phantom gimme after push, clone bad cards
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. leaf check-in: 479df656d3 user: [email protected] tags: trunk, fix/sync-server-order | |
| 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 | |
| 03:36 |
fix(tag): derive the check-in event time from direct date tags only (#372) (#380)
* fix(tag): derive the check-in event time from direct date tags only (#372) Section 4.2, step 6 of repo-state-01 makes a date tag applied directly to a check-in set its event time, whatever order the tag and the check-in arrive in. Crosslinking read the date tagxref row whatever its source, so re-crosslinking after a propagating date tag retimed the descendants that inherited it, and a cancel, an unparsable value or 0 left no time or a time of 0, as fossil 2.28 does. tag.RefreshEventTime now holds the rule, and both tag application and crosslinking call it: a direct, non-cancel date row whose value parses to 0 < r < 5373484.5 sets mtime; anything else restores the D-card time kept in omtime. The date-tag cancel, unparsable and zero cases are no longer deviations, and new before-checkin cases cover the other arrival order. Tracked in #372. * fix(tag): word the date-tag parse rule as step 6 does (#372) * docs(changelog): tidy the entry spacing (#372) check-in: 30b9d65021 user: [email protected] tags: main, trunk | |
| 03:23 |
fix(manifest): resolve a delta manifest's baseline one level (artifact-format-01 4.7.3) (#379)
* fix(manifest): resolve a delta manifest's baseline one level (#371) A B card may name another delta manifest (artifact-format-01 4.7.3). Drop the #275 refusal in loadBaseline, which ListFiles and crosslink share, and use the named manifest's own F cards. Tracked in #371. * fix(manifest): drop baseline delete markers and never write delta-of-delta (#371) * docs(changelog): note delete markers and the writer rule for delta baselines (#371) check-in: 62396a79e5 user: [email protected] tags: main, trunk | |
| 03:13 |
fix(deck): accept the full Julian-day grammar of artifact-format-01 4.6.4 (#378)
* fix(deck): accept every Julian-day spelling of artifact-format-01 4.6.4 (#370) Sign, exponent, leading and trailing point are now read, hex/inf/nan stay rejected, and the bound is checked after millisecond rounding as fossil does. Tracked in #370. * fix(deck): test the millisecond rounding bound and drop the stale gap marker (#370) check-in: 288594db14 user: [email protected] tags: main, trunk | |
| 02:28 |
test(conformance): check the -01 drafts of artifact, repo-state and sync (#377)
Re-pin the conformance suite to draft-fossil-artifact-format-01, draft-fossil-repo-state-01 and draft-fossil-sync-protocol-01, copied byte for byte from zit check-in 100351e26c. The delta format has no -01 and stays on -00. The -00 errata are folded into -01 and are no longer pinned; the six -01 errata are pinned for the fossil 2.28 behavior they record. conformance/rfcs/README.md records where each copy came from. The requirement tables are re-read against -01, and new cases cover the date tag's event time (repo-state §4.2 step 6), the Julian-day grammar, a delta manifest naming a delta, dropped reserved F cards, the trailing-punctuation retry, truncated payloads, errors N, a file card after a refused push, the end of a request after a failed login, and the answer to a gimme for private content. No library behavior changes. Where -01 departs from fossil 2.28 and go-libfossil follows fossil (a cancelled, unparsable or 0 date tag), the cases are marked as deviations. The non-conformances the re-pin exposes are marked as gaps, tracked in #370, #371, #372, #373, #374 and #375. check-in: e49527edd2 user: [email protected] tags: main, trunk | |
| 02:23 |
test(conformance): check the -01 drafts of artifact, repo-state and sync
Re-pin the conformance suite to draft-fossil-artifact-format-01, draft-fossil-repo-state-01 and draft-fossil-sync-protocol-01, copied byte for byte from zit check-in 100351e26c. The delta format has no -01 and stays on -00. The -00 errata are folded into -01 and are no longer pinned; the six -01 errata are pinned for the fossil 2.28 behavior they record. conformance/rfcs/README.md records where each copy came from. The requirement tables are re-read against -01, and new cases cover the date tag's event time (repo-state §4.2 step 6), the Julian-day grammar, a delta manifest naming a delta, dropped reserved F cards, the trailing-punctuation retry, truncated payloads, errors N, a file card after a refused push, the end of a request after a failed login, and the answer to a gimme for private content. No library behavior changes. Where -01 departs from fossil 2.28 and go-libfossil follows fossil (a cancelled, unparsable or 0 date tag), the cases are marked as deviations. The non-conformances the re-pin exposes are marked as gaps, tracked in #370, #371, #372, #373, #374 and #375. leaf check-in: 8cc3d7c5e4 user: [email protected] tags: test/conformance-01-drafts, trunk | |
| 01:52 | fix(sync): gate xtable-hash on a direction card (#351) (#369) check-in: b2d5659397 user: [email protected] tags: main, trunk | |
| 01:46 | fix(sync): keep the client's gimme limit as fossil's mxPhantomReq (#350) (#368) check-in: 46fa73b523 user: [email protected] tags: main, trunk | |
| 01:40 | fix(sync): server igot handling skips shunned hashes (#349) (#367) check-in: 1724e7ec32 user: [email protected] tags: main, trunk | |
| 01:10 |
fix(testutil): isolate fossil's global config in tests (#284) (#366)
* test: isolate fossil's global config in tests that run the fossil binary (#284) Tracked in #284. * test(testutil): document the file-level scope of the fossil home guard (#284) * test(testutil): allow StartServer in the fossil home guard (#284) check-in: 8d3f18265e user: [email protected] tags: main, trunk | |
| 00:48 |
fix(test): kill fossil server's process group before cleanup (#352) (#365)
Start fossil server in its own process group through a shared testutil.StartServer helper and SIGKILL the whole group before Wait, so forked per-connection children cannot write into t.TempDir() during cleanup. Tracked in #352. check-in: bb864e6c58 user: [email protected] tags: main, trunk | |
| 00:38 |
fix(tag): apply bgcolor, user and comment tags to event as fossil does (#343) (#364)
* fix(tag): apply bgcolor, user and comment tags to event as fossil does (#343) tag.ApplyTagWithTx now sets event.bgcolor, euser and ecomment from the bgcolor, user and comment tags for every tag type, NULL on a cancel, as tag_insert does. Crosslinking a check-in reads the three values back from tagxref, as manifest_crosslink does, so a tag that arrived while the check-in was a phantom takes effect. Tracked in #343. * fix(tag): store empty event override values as NULL (#343) check-in: 66cd641642 user: [email protected] tags: main, trunk | |
| 00:17 |
fix(sync): let Clone imply Read at the server's read gates (#312) (#363)
fossil's trunk page_xfer sets g.perm.Read for a requester with Clone, and the section 7.3 erratum states it for uvgimme. The handler treated only o, i and Admin as Read, so a Clone-only requester got no unversioned files, no xtable-hash inventory and no read-gated configuration. This is an access change. handler.canRead, CanRead or a Clone held before any login (as page_xfer derives Read ahead of its card loop), now owns every read gate: the unversioned catalog for uv-hash and for a clone, uvigot and uvgimme answers, xtable-hash, and reqconfig. auth.CanRead is unchanged, and pull still needs o. The reqconfig interop test compares a Clone-only requester with fossil 2.28 given Read too, since the 2.28 binary predates the trunk change. Pull still needs o although fossil trunk's derived Read lets a Clone-only nobody pull; that difference is deliberate. check-in: a67fe49556 user: [email protected] tags: main, trunk | |
| 00:12 |
fix(sync): log in through the x-f-l-c cookie and accept cleartext passwords (#304) (#362)
fossil's client moves its login card from the body into the x-f-l-c cookie once the server's server-version passes xfer_xflc_check (2.27, 2025-07-27 11:05 or later), and fossil's check_login, when a stored password is not 40 characters, tries the signature again against the shared secret that cleartext password derives (sections 6.4, 6.5). The client always logged in in the body, and the server checked only the stored value. A request marks itself LoginCookieOK once the gate passes; Message.SplitLoginCookie moves its login card out of the body, and the HTTP transports (sync.HTTPTransport and the public NewHTTPTransport through the adapter) send it as the cookie, on every redirect too. The nonce is unchanged: it already covers what follows the login line, which in cookie form is the whole body. Transports that cannot set a cookie send the login in the body as before. The server side of the cookie landed with the server-version exchange. HandleOpts gains LoginCookie, so an embedder serving HandleSyncWithOpts over its own HTTP handler can pass the cookie through; XferHandler and ServeHTTP read it themselves. check-in: 9d35c01fb3 user: [email protected] tags: main, trunk | |
|
2026-10-12
| ||
| 23:24 |
fix(sync): apply received unversioned files as fossil does (#308) (#361)
fossil's xfer_accept_unversioned_file stores a received file under the HASH its card gave, takes only the mtime when the content is the same and newer (status 2), and stores an omitted payload as NULL with size 0; send_unversioned_file sends nothing for a name it does not hold; and the client seeds uv_tosend from rows whose hash is not NULL (sections 7.3, 8.5.1). Both sides stored a received file under a hash computed by local policy and dropped status 2 and omitted-content cards; the server answered an absent name with a tombstone; the client queued its tombstones. uv.Receive now owns the acceptance rule, which the server and the client share instead of each re-deriving it from uv.Read, uv.Status and uv.Write. check-in: d33a37fffd user: [email protected] tags: main, trunk | |
| 23:20 |
fix(sync): send clone replies as fossil's page_xfer does (#306) (#360)
fossil's send_compressed_file sends a cfile as the blob table stores it and pads a payload that does not end in LF; page_xfer sends a version 3 clone's reply as application/x-fossil-uncompressed, sends the unversioned catalog with a clone when uv-sync is on, and refuses a clone with a reset, the push card and "error not authorized to clone". The server recompressed each cfile, never padded, compressed the reply, sent no catalog, appended its refusal to the reply, and restarted a clone whose SEQNO was negative. CFileCard's StoredBlob, set by the clone path from the blob table, is now what the encoder sends; xfer.Message.Uncompressed tells the HTTP server to send a reply as card text. The catalog goes to a requester with Read, as for uv-hash: fossil lets Clone imply Read there, which this server does not. A negative SEQNO, which section 8.1 exempts from its fatal, now ends the clone with clone_seqno 0, and the unit test that expected a restart expects that. check-in: 6c69fc1231 user: [email protected] tags: main, trunk | |
| 23:14 |
fix(sync): answer pushed config, ci-unlock and req-clusters (#305) (#359)
fossil's page_xfer refuses a pushed config card from a requester without Admin with a reset, "error not authorized to push configuration" and a break (section 9.3); drops a client's check-in locks on pragma ci-unlock (section 9.4); and answers pragma req-clusters with send_all_clusters, the cluster igots between "# sending-clusters" and "# end-of-clusters" (section 5.3). The server ignored the first two and recorded the third without answering it. An Admin's config push is refused too, naming that this server does not apply pushed configuration, rather than dropped while the push appears to succeed. ci-unlock is honored for writers only, as ci-lock already is, and the cluster igots go to any requester, as in fossil: they name public artifacts and carry no content. check-in: 85c48f38eb user: [email protected] tags: main, trunk | |
| 23:10 |
fix(sync): exchange server-version and gate SHA3 content by peer release (#303) (#358)
fossil's page_xfer answers a client-version that carries DATE and TIME with pragma server-version, and both sides record the peer's release; send_file, send_compressed_file and send_unversioned_file then append "error Fossil version 2.0 or later required." in place of SHA3-named content for a peer older than 2.0, with a server treating a client that announced no release as one (sections 7.6, 9.1). The server sent no server-version and neither side kept or gated on the peer's release. The server gates gimme, clone and uvgimme; the client gates its answer to a gimme. Because a server-version from a current release turns fossil's client to logging in through the x-f-l-c cookie (section 6.5), the HTTP server now reads that cookie: xfer.DecodeRequest puts its login card first with the nonce bound to the whole body, as page_xfer does. Without it a real fossil client's later rounds arrived as nobody. That moves sync.6.5.server-cookie-login, marked for #304, here. check-in: 6963b0a9dc user: [email protected] tags: main, trunk | |
| 23:06 |
fix(sync): end client sessions by section 3.7 and keep igot phantoms (#301) (#357)
fossil's client_sync continues a round when stored content or a new phantom leaves the phantom table non-empty, or when files are queued for the next request (section 3.7). The client instead continued on any received file and on any phantom until it had aged three rounds, kept a gimme it could not answer queued forever, and kept an igot's phantom only in the session's map. After a clone's first round it aborted on a server error, where the draft ends the reply-card loop and goes on. converged now applies 3.7 (a) and (b). A gimme is queued only for content the client holds and may send. An igot's phantom is written to the phantom table, batched once per reply as content_new would write it, and the after-dephantomize cascades of a reply run as one batch (manifest.AfterDephantomizeBatch), so a pull no longer begins a crosslink transaction per artifact. A clone records a later round's server error, stops reading that reply, continues by 3.7, and fails at the end naming the error. Four unit tests that encoded the old continuation now expect fossil's. check-in: 62683d1d0f user: [email protected] tags: main, trunk | |
| 23:01 |
fix(sync): send pragma send-private first and keep a private basis private (#307) (#356)
fossil's client_sync emits pragma send-private ahead of client-version in its first request and right after it in later ones (section 3.2); the client put it after its igot, file and gimme cards. And fossil's content_new makes the missing basis of a private card's delta a private phantom (section 7.4), where the client made it public. buildRequest is split into header, content and extra card builders so the header can carry send-private in fossil's place; the cards it sends are otherwise unchanged. check-in: 9d3644134d user: [email protected] tags: main, trunk | |
| 22:57 |
fix(sync): drop shunned artifacts and never ask for a shunned phantom (#302) (#355)
* fix(sync): drop shunned artifacts and never ask for a shunned phantom (#302) fossil's xfer_accept_file and xfer_accept_compressed_file drop a received artifact whose hash is on the shun list, and its request_phantoms and content_new leave shunned names out of what a client asks for (sections 3.3 and 7.7). The server, the sync client and clone stored a shunned artifact, and the client asked for shunned phantoms. storeReceivedFile, which every receive path shares, now drops a shunned artifact; the server checks first so a dropped file is not reported as missing after store. The client's phantom scan and its igot handling skip shunned names, so a delta whose basis is shunned is kept as a delta and the basis is never requested. * refactor(sync): split the client's reply handling into per-card helpers processResponse had grown to 232 lines: one switch over every reply card followed by the convergence check. It is now a loop over handleReplyCard, which hands each card to a focused helper, and converged, which keeps the termination rules apart from card handling. Behavior is unchanged. check-in: aea957939f user: [email protected] tags: main, trunk | |
| 22:52 |
fix(sync): take a uvfile on y alone, without a push card (#296) (#354)
fossil's page_xfer accepts a uvfile on the unversioned-write capability (WrUnver, y) alone; `fossil uv sync` sends uvfile cards with no push card. The handler refused each with "rejected: no push card", so pushing unversioned files from fossil to a go-libfossil server stored nothing. This is an access change: a requester with y and no Write may now store unversioned files, as in fossil. A refusal (no y, or a HASH that does not match the content) now resets the reply, answers the error and breaks out of the card loop, as xfer_accept_unversioned_file's caller does. Tests pin both sides of the gate, and an interop test pushes with fossil uv sync. The real-fossil test helper now points HOME and XDG_CONFIG_HOME, not only FOSSIL_HOME, at the test's directory. check-in: b45ccf4351 user: [email protected] tags: main, trunk | |
| 22:48 |
fix(sync): refuse push and pull cards naming another project (#309) (#353)
fossil's page_xfer compares a push or pull card's PROJECTCODE with the repository's project-code before any capability check and, on a mismatch, resets the reply, answers "error wrong project" and breaks out of the card loop (section 8.5). The handler accepted either card whatever its project code. The refusal goes through a new breakLoop, which the undecodable file card path now shares: the reply is reset to the one error, no later card is processed, and the post-loop work and timestamp still follow. Tests that synced repositories created with different project codes now create them with a shared one, and the DST simulator gives its leaves the upstream's. check-in: 821cf115ce user: [email protected] tags: main, trunk | |
| 20:17 |
fix(checkout): make WouldFork fossil's commit-time fork check (#347) (#348)
Since #291 WouldFork was fossil's leaf_ambiguity, which answers no at once for a version that is not a leaf. That is the case a commit forks in: when a pull brings in a child of the checked-out version, the version stops being a leaf, WouldFork said false, and the commit became a second child. EdgeSync's autosync relies on WouldFork to refuse that commit. WouldFork is now fossil's commit refusal (src/checkin.c "Would fork", taken when !is_a_leaf(vid)): true when the version has a child on its own branch, read from plink as is_a_leaf does, merge children included. Another open leaf elsewhere on the branch no longer counts; fossil commits there, extending the checkout's leaf, and only warns afterwards. The repo-state draft's Section 7.5 ambiguity test moves to checkout.LeafAmbiguous, and the repostate.7.5.ambiguity-* conformance cases call it. The superseded #291 changelog text and the WouldFork API doc are corrected. check-in: cd4a11828f user: [email protected] tags: main, trunk | |
| 19:37 |
fix(branch): check the open branch name in the check-in transaction (#316) (#346)
branch.Create refused a name an open leaf carries (fossil's branch_is_open), but checked before manifest.Checkin opened its transaction, and Checkin applied the branch tags, parent propagation and leaf state in later transactions. Concurrent creates of one name could all pass the check and all commit. Checkin now derives its tags and leaf state inside its own transaction and runs an optional Precheck first in it. Create checks the name there, so check and write are one transaction: with BEGIN IMMEDIATE the second writer sees the first's open leaf and is refused. Create's redundant second tag pass after the check-in goes away. check-in: 9c071c7c22 user: [email protected] tags: main, trunk | |