Skip to content

Conformance

go-libfossil is checked against the Internet-Drafts that specify Fossil’s formats and protocol, and the drafts for the extensions it shares with zit. The drafts are pinned in conformance/rfcs/. Each has a table of requirements in conformance/requirements/, written from the draft text, and test cases that name the requirement they exercise.

TestCoverage derives each requirement’s status from its cases; nothing is recorded by hand:

  • covered: every case conforms.
  • partial: the cases conform, and the table row says what they leave out (shown under the requirement).
  • deviation: a case documents a deliberate difference, with its reason.
  • failing: a case is known to fail and names the issue tracking the fix. It is skipped, and fails once it passes until the mark is removed.
  • gap: no case exercises the requirement.

What counts as correct, in order: the draft text; then fossil itself, run on the same input, where the draft is silent. The suites of zit and libfossil inform which cases to write. The tables below are generated from a run of the suite (make docs-gen), and CI fails when they are out of date. To reproduce them:

CONFORMANCE_REPORT=report.md go test ./conformance -run '^TestCoverage$' -count=1
DraftRequirementsCoveredPartialDeviationFailingGapCases
Artifact format1151150000529
Delta format4040000093
Repository state97970000236
Sync protocol1691690000350
Sub-manifests76760000143
Sparse cones63630000121
Horizons76760000161
All drafts6366360

Artifact format

draft-fossil-artifact-format-00: 115 requirements, 115 covered; 529 cases.

Requirement§TextStatusCases
AF-3.1-13.1An artifact's name is the hash of its exact stored bytes, with nothing added, removed or transformed; a signed artifact's name covers its wrapper.covered1
AF-3.2-13.2A 40-digit name is the SHA-1, and a 64-digit name the SHA3-256 (FIPS 202, not Keccak), of the raw bytes.covered3
AF-3.2-23.2A candidate name of any length other than 40 or 64 is invalid.covered1
AF-3.3-13.3Every name an implementation computes or emits is lowercase hexadecimal.covered1
AF-3.3-23.3A parser that accepts an uppercase-hex name does not case-normalize it.covered1
AF-3.4-13.4Verification compares a name byte for byte with the lowercase digest its length selects; any other length, an uppercase digit or a mismatch never verifies.covered4
AF-4.1-14.1The raw input is non-empty and its last byte is LF, checked before any signature wrapper is removed.covered3
AF-4.1-24.1The stripped content is at least 10 bytes, starts with a letter A-Z, and has a space as its second byte.covered7
AF-4.1-34.1Bytes left unconsumed after the card loop cause rejection.covered1
AF-4.1.1-14.1.1A PGP clearsign wrapper is removed before parsing.covered1
AF-4.1.1-24.1.1An SSH signed-message wrapper is removed before parsing.covered1
AF-4.1.1-34.1.1A wrapper is removed only when the first 34 bytes of the input are exactly one of the two header lines.covered2
AF-4.1.1-44.1.1The body starts after the first blank line (LF LF or LF CR LF); with no blank line nothing is stripped.covered2
AF-4.1.1-54.1.1The content is cut after the LF that starts the last signature-armor line, and runs to the end of input when there is none.covered2
AF-4.1.1-64.1.1Only the first 29 bytes of the 30-byte signature-armor literal are compared.covered2
AF-4.1.2-14.1.2A sterilized artifact, its marker line after the final card or before a signature block, is rejected by the card-ordering rule.covered2
AF-4.2-14.2The byte after a card letter is exactly a space or LF; any other byte, tab included, makes the card invalid.covered2
AF-4.2-24.2Tokens are split on space and LF only; tab and CR are ordinary token bytes.covered5
AF-4.2-34.2A card's final token may be empty (the line ends in a space), giving a present, empty value distinct from an omitted token; an empty token anywhere else is malformed.covered4
AF-4.2.1-14.2.1A card with more tokens than its grammar defines is rejected.covered20
AF-4.2.2-14.2.2A card letter outside A-Z is rejected.covered3
AF-4.2.2-24.2.2The undefined letters O, S, V, X and Y are rejected.covered5
AF-4.3-14.3The eight escapes \n \s \t \r \v \f \0 and \\ decode to LF, space, tab, CR, VT, FF, NUL and backslash.covered1
AF-4.3-24.3A backslash before any other byte decodes to that byte, and a token's final backslash is kept; neither is an error.covered2
AF-4.3.1-14.3.1Tokens are decoded at the A filename and target, C comment, F filename and old-name, H title, J value, L title, N mimetype, T name and value, and U login.covered12
AF-4.3.1-24.3.1No other token is decoded: hashes, checksums, timestamps, the J field name, and the W size and body stay raw.covered4
AF-4.3.1-34.3.1The A target is decoded before it is validated, so an escaped token that decodes to hex digits is checked as a hash.covered1
AF-4.4-14.4Each card's letter is greater than or equal to the previous card's letter.covered1
AF-4.4-24.4An N card directly after a P card is accepted once an E card has been seen, and rejected otherwise.covered2
AF-4.5.1-14.5.1A second A, B, C, D, E, G, H, I, K, L, N, R, U or W card is rejected.covered14
AF-4.5.1-24.5.1F, J, M, T, P and Q cards may repeat, each adding to its list.covered1
AF-4.5.1-34.5.1The Z card has no duplicate guard: an earlier Z line is content covered by the final checksum.covered1
AF-4.5.2-14.5.2F cards are strictly ascending by decoded filename.covered5
AF-4.5.2-24.5.2J cards are strictly ascending by field name.covered3
AF-4.5.2-34.5.2M cards are strictly ascending by hash.covered3
AF-4.5.2-44.5.2T cards ascend by the full name token, sign included, and strictly by target among equal names.covered5
AF-4.5.2-54.5.2P tokens keep their order and are not deduplicated.covered1
AF-4.5.2-64.5.2Q cards are neither ordered nor checked for duplicates.covered2
AF-4.5.3-14.5.3The canonical comparator compares unsigned bytes with no case folding or normalization; a prefix sorts first and '/' is not special.covered1
AF-4.6.1-14.6.1A decoded A filename, F filename or F old-name is rejected when empty, starting with '/', '.' or '..' alone, starting with './' or '../', containing '//', ending in '/', or with a '.' or '..' element.covered15
AF-4.6.1-24.6.1The pathname predicate rejects nothing else: backslashes, spaces, control bytes and invalid UTF-8 pass.covered8
AF-4.6.1-34.6.1A writer does not create a filename containing a backslash or outside the UTF-8 profile.covered3
AF-4.6.2-14.6.2A decoded wiki name is rejected when its first byte is 0x20 or below, a later byte is below 0x20, it has two adjacent spaces, it ends in a space, or it is not 1 to 100 bytes long.covered7
AF-4.6.2-24.6.2A wiki name is otherwise unconstrained: 0x7F, bytes 0x80 and above, and invalid UTF-8 pass.covered4
AF-4.6.3-14.6.3An F card whose decoded filename is reserved (_FOSSIL_ or .fslckout, whole or after '/', or followed by -wal, -shm or -journal) is dropped, not rejected.covered7
AF-4.6.3-24.6.3A reserved tail that is neither whole, after '/', nor followed by a sidecar suffix is not reserved, and the old-name is never tested.covered4
AF-4.6.3-34.6.3The F sort check runs before the drop, and a dropped card never becomes the anchor for the next comparison.covered2
AF-4.6.3-44.6.3A dropped F card assigns no artifact type and records no file entry.covered1
AF-4.6.4-14.6.4A writer emits D and E timestamps as YYYY-MM-DDTHH:MM:SS with an optional fraction.covered1
AF-4.6.4-24.6.4A parser accepts a date-time with T or whitespace separators, HH:MM with optional seconds and a fraction of any length, and an optional +HH:MM, -HH:MM, Z or z zone.covered14
AF-4.6.4-34.6.4A lowercase t separator is rejected.covered2
AF-4.6.4-44.6.4In the date-time, date-only and time-only forms, the year is 4 digits, month 01-12, day 01-31 with no calendar check, hour 00-24, minute and second 00-59.covered13
AF-4.6.4-54.6.4A date on or before -4713-11-24 is rejected.covered2
AF-4.6.4-64.6.4A Julian day number is an optional sign, digits with an optional fraction (at least one digit), and an optional E or e exponent with an optional sign; no other numeric spelling is recognized.covered9
AF-4.6.4-74.6.4A Julian day number that is zero, negative, or 5373484.5 or more, after rounding to the nearest millisecond, is rejected.covered5
AF-4.7.1-14.7.1Every hash position (A target as a hash, A source, B, E ID, F hash, G, I, M, P, both Q tokens, T target) holds exactly 40 or 64 hexadecimal digits.covered34
AF-4.7.1-24.7.1The K ticket ID is exactly 40 hexadecimal digits; 64 is invalid.covered4
AF-4.7.2-14.7.2Only the final path component of the A filename is kept as the attachment name.covered1
AF-4.7.2-24.7.2The A target is a valid hash or a well-formed wiki name.covered2
AF-4.7.2-34.7.2The A source is optional and none is recorded when absent; a present but empty source fails hash validation and is rejected.covered2
AF-4.7.3-14.7.3A delta manifest whose baseline is itself a delta manifest is accepted, and its file set is computed from that baseline's own F cards only.covered1
AF-4.7.3-24.7.3The named delta's delete markers enter the one-level walk on the baseline side and add no file: every merged entry without a hash is filtered out of the file set and of a lookup.covered2
AF-4.7.4-14.7.4A C card with no token at all (a bare C line) is rejected.covered1
AF-4.7.4-24.7.4A C card whose single token is empty is a present, empty comment and is accepted.covered1
AF-4.7.5-14.7.5An E card carries a timestamp and a technote ID.covered1
AF-4.7.6-14.7.6In a baseline manifest every F card carries a hash; a hashless F card needs a B card.covered2
AF-4.7.6-24.7.6The third F token is the raw permission, accepted without validation; only the fourth is the old-name.covered2
AF-4.7.6-34.7.6A producer that writes an old-name also writes an explicit permission token.covered1
AF-4.7.8-14.7.8An absent J value and a present empty one (J, SP, name, SP, LF) both decode to the empty string, and a reader does not distinguish them.covered2
AF-4.7.9-14.7.9A writer emits the K ticket ID in lowercase.covered1
AF-4.7.13-14.7.13An empty P card is accepted.covered1
AF-4.7.14-14.7.14The first Q token is + or - followed by a hash; the optional second is a plain hash, empty when absent.covered3
AF-4.7.16-14.7.16A T name starts with +, - or *.covered1
AF-4.7.16-24.7.16A T name is not entirely hexadecimal after its sign, at any length and in either case.covered3
AF-4.7.16-34.7.16A T target is a hash or exactly '*'.covered1
AF-4.7.16-44.7.16An absent T value is distinct from a present, empty one (4.2).covered1
AF-4.7.17-14.7.17A U card with an empty or omitted login yields the login "anonymous".covered2
AF-4.7.18-14.7.18The W body is exactly size bytes, may hold any byte including LF, and is not scanned for card boundaries.covered3
AF-4.7.18-24.7.18The byte after the W body is LF.covered1
AF-4.7.18-34.7.18A reader takes only the leading digits of the W size token, so 4x is 4 and abc is 0.covered4
AF-4.7.18-44.7.18A W size beyond the rest of the artifact, or one that overflows, is rejected.covered5
AF-5.1-15.1Every structural artifact is classified as exactly one of the eight types.covered8
AF-5.2-15.2An artifact with a card outside its type's allowed set is rejected.covered109
AF-5.2-25.2An artifact missing a card of its type's required set is rejected.covered19
AF-5.3-15.3When several type-setting cards appear, the last one processed sets the type.covered1
AF-5.3-25.3With no type-setting card, an artifact with a C or P card is a manifest, and any other a control artifact.covered4
AF-5.3-35.3An artifact whose every F card was dropped for a reserved filename, with no C or P card, is a control artifact and is rejected for its F card.covered1
AF-5.4-15.4A control artifact has no self-referential T card.covered1
AF-5.4-25.4Every T card in a technote is self-referential and has the + sign.covered3
AF-5.4-35.4A forum post does not have both an H card and an I card.covered1
AF-5.4-45.4A forum post's P card lists at most one parent.covered1
AF-6.1-16.1The R and Z tokens are exactly 32 hexadecimal digits.covered4
AF-6.2-16.2An artifact whose Z card does not match is rejected.covered1
AF-6.2-26.2The Z value is compared, byte for byte, with the lowercase MD5 of the stripped content before its last 35 bytes, so an uppercase digit fails.covered3
AF-6.2-36.2An artifact without a Z card is rejected.covered1
AF-6.2-46.2A producer writes the Z card as Z, a space, 32 lowercase digits and LF.covered1
AF-6.2-56.2The Z verification stage does not itself reject an artifact for lacking a Z card, or for being too short to hold one.covered2
AF-6.2-66.2The Z verifier neither reads nor requires any value at the artifact's last byte.covered1
AF-6.2-76.2The Z verification state is decided by the bytes at offsets n-35 and n-34, not by where card lines begin: an artifact with no Z card whose last line ends in Z, a space and 32 further bytes before its LF is verified, and fails on a mismatch.covered2
AF-6.3-16.3.1A parser does not check the R value against file content.covered1
AF-6.3-26.3.2The R value is the MD5 of, for each file in comparator order, its name, a space, its decimal size, LF and its content, written as 32 lowercase digits.covered4
AF-6.3-36.3.3A delta manifest's R value covers the merged file set, not its own F cards.covered1
AF-6.3-46.3.4A writer emits the R card as R, a space, 32 lowercase digits and LF.covered1
AF-6.3-56.3.4At commit time the R card is checked byte for byte against the lowercase digest recomputed from the checkout.covered3
AF-7.1-17.1New content is named SHA-1 under sha1 and auto, and SHA3-256 under sha3, sha3-only and shun-sha1.covered5
AF-7.1-27.1Policy value strings match case-sensitively and exactly; an unrecognized value is a fatal error.covered15
AF-7.2-17.2With no policy set, a repository holding a SHA3 name or no SHA-1 name, including an empty one, defaults to sha3, and otherwise to auto.covered3
AF-7.4-17.4Under auto, storing an artifact under a name longer than 40 digits promotes the repository to sha3 and persists the change.covered2
AF-7.5-17.5Under sha1, auto and sha3, content already stored under the other algorithm's name keeps that name and is not stored again.covered2
AF-7.5-27.5Under sha3-only and shun-sha1, content is named SHA3-256 even when it is already stored under a SHA-1 name.covered2
AF-7.6-17.6Changing the policy never renames a stored artifact.covered1
AF-8-18A manifest is a delta manifest exactly when it has a B card, and its file set is the merge with its baseline.covered2
AF-8.2-18.2In the merge, a delta entry with a hash replaces or adds a file, a hashless entry deletes it, other baseline files carry forward, and an unmatched deletion adds nothing.covered4
AF-8.3-18.3Enumerating a delta manifest's files fails when its baseline is missing or is not a manifest.covered2
AF-8.4-18.4Looking up one name in a delta manifest searches the delta first, and a delete marker answers not-found without reading the baseline.covered7

Delta format

draft-fossil-delta-format-00: 40 requirements, 40 covered; 93 cases.

Requirement§TextStatusCases
DF-3-13A delta is a header, zero or more segments and a trailer, concatenated with nothing between them (delta = header *segment trailer); a decoder accepts every such delta whose bounds hold.covered4
DF-3-23Applying a delta a producer emitted for a source and target to that source yields the target exactly.covered4
DF-3.1-13.1A producer writes every integer in canonical form: base 64, most significant digit first, no leading zeros, and zero as the single digit 0.covered1
DF-3.1-23.1Digits 0-9 have values 0-9, A-Z 10-35, _ 36, a-z 37-62 and ~ 63, and a multi-digit integer is read most significant digit first.covered2
DF-3.1-33.1Reading an integer stops at the first byte that is not a digit; that byte is the opcode or separator that follows the integer.covered1
DF-3.1-43.1A decoder that accepts an integer field with no digits treats it as zero; it may reject such a delta instead.covered5
DF-3.1-53.1A decoder that accepts an integer field with leading zeros uses its decoded value; it may reject such a delta instead.covered4
DF-3.1-63.1A producer emits only integer values below 2^32.covered2
DF-3.2-13.2A decoder rejects a delta whose header integer is not immediately followed by 0x0a.covered3
DF-3.3.1-13.3.1A copy segment (count @ offset ,) appends count bytes of the source starting at zero-based byte position offset.covered3
DF-3.3.1-23.3.1A decoder rejects a copy segment whose offset is not followed by a comma (0x2c).covered1
DF-3.3.1-33.3.1A copy segment with count zero copies zero bytes, not the rest of the source (Appendix A).covered2
DF-3.3.1-43.3.1A producer never emits a copy segment with count zero.covered1
DF-3.3.2-13.3.2A literal segment (count : payload) appends the count bytes that follow the colon.covered2
DF-3.3.2-23.3.2A reader consumes exactly count payload bytes without scanning them for a separator; any byte in a payload, 0x0a included, is data.covered3
DF-3.4-13.4A producer always ends a delta with a trailer (checksum ;) carrying the checksum of the target, including when the target is empty.covered2
DF-3.4-23.4The checksum is the sum modulo 2^32 of the target's big-endian 32-bit words, plus any 1 to 3 trailing bytes added as z[0]<<24, z[1]<<16 and z[2]<<8.covered3
DF-3.4-33.4A decoder that verifies the checksum rejects a delta whose trailer does not match the reconstructed target.covered4
DF-3.4-43.4A decoder treats the delta as complete at the trailer opcode; bytes after it are not read as segments.covered2
DF-4-14A decoder rejects a zero-length delta before attempting any read (also section 6).covered1
DF-4-24A decoder rejects a delta that ends inside an integer field.covered3
DF-4-34A decoder rejects a copy segment that would take the output past the declared target length.covered1
DF-4-44A decoder rejects a copy segment whose offset plus count exceeds the source length.covered3
DF-4-54The offset-plus-count check is made with arithmetic that cannot overflow, so large offsets or counts cannot wrap past it.covered1
DF-4-64A decoder rejects a literal segment that would take the output past the declared target length.covered1
DF-4-74A decoder rejects a literal segment whose count exceeds the bytes remaining in the delta.covered1
DF-4-84A decoder rejects a delta whose output length at the trailer differs from the declared target length.covered1
DF-4-94A decoder rejects a segment whose opcode byte is not @, : or ;.covered4
DF-4-104A decoder rejects a delta that ends without a ; trailer.covered2
DF-4-114A decoder that accepts an empty, leading-zero or 2^32-or-larger integer still applies every structural and bounds check to the value it uses.covered4
DF-4-124A decoder does not require, or reject a delta for, a particular segmentation or copy strategy.covered3
DF-4.1-14.1A target-size query returns the header integer after reading only it and the following 0x0a; it needs no later bytes and does not validate them.covered3
DF-4.1-24.1A target-size query fails on an empty buffer.covered1
DF-4.1-34.1A target-size query fails when the header integer is not immediately followed by 0x0a.covered3
DF-4.2-14.2The caller supplies the complete source before invoking the decoder; a delta whose source is not held is not applied.covered1
DF-6-16A parser never reads past the end of the delta buffer it was given; integer accumulation stops at that boundary.covered3
DF-6-26A failed delta application is never reported as success.covered1
DF-6-36A caller discards the output buffer when application fails.covered2
DF-6-46Bytes 0x80 through 0xFF in integer position terminate the integer; they are never decoded as digits (no high-bit masking).covered4
DF-6-56A decoder treats the header's declared target length as untrusted: it does not allocate in proportion to it before the delta supplies that much output (SHOULD).covered1

Repository state

draft-fossil-repo-state-00: 97 requirements, 97 covered; 236 cases.

Requirement§TextStatusCases
RS-2-12An operation that tags a check-in with a user-supplied symbolic name stores it as "sym-" + name unless the caller asks for the raw name.covered1
RS-2-22Tags whose names begin with "wiki-", "tkt-" or "event-" are never created by a user tagging operation.covered1
RS-3.1-13.1Each parent named on a check-in's P card yields a linkage row (parent, child) carrying the primary-parent flag, the check-in's mtime and the baseline id.covered2
RS-3.1-23.1A parent named more than once on one P card yields a single linkage row for that (parent, child) pair.covered2
RS-3.1-33.1A delta manifest whose baseline is absent or is not a manifest is not linked: it gets no event or linkage row, and the gap is recorded against the baseline (artifact-format-00 Section 8.3) so it links when the baseline arrives.covered5
RS-3.2-13.2The first parent on the P card is the primary parent (flag set); every other parent is a merge parent (flag unset).covered2
RS-3.2-23.2A repeated parent keeps the primary flag chosen by its first occurrence.covered2
RS-3.2-33.2Linear-history operations (first-parent traversal, the prev keyword) follow only the primary-parent row.covered1
RS-3.2-43.2Full-ancestry operations (merge base, ancestor tests) include merge-parent rows.covered6
RS-4.1-14.1A manifest with a T-card whose name lacks a -, + or * prefix is rejected.covered2
RS-4.1-24.1A manifest with a T-card whose name after the prefix is all hexadecimal digits is rejected.covered2
RS-4.1-34.1A manifest whose T-cards are not strictly ascending by (name, uuid) is rejected.covered2
RS-4.1-44.1A rejected manifest contributes no tag state at all, not even from its valid T-cards.covered2
RS-4.2-14.2A T-card naming an artifact not yet stored resolves to a phantom rid; the tag is recorded against it and is in effect once the artifact arrives and is crosslinked.covered4
RS-4.2-24.2A P-card parent not yet stored yields a phantom rid and a linkage row to it, not an error.covered8
RS-4.2-34.2T-cards are applied only from control, check-in and technote (event) artifacts.covered2
RS-4.2-44.2Crosslinking a cluster applies an implicit singleton "cluster" tag to the cluster itself.covered2
RS-4.2-54.2After a check-in with a resolved primary parent is crosslinked, the parent's tags are re-propagated, so the new check-in inherits them.covered2
RS-4.2-64.2A T-card of any type applied to a resolved target runs the propagation walk from that target; a singleton enters it as a cancel, removing the same-named tag the descendants inherited.covered4
RS-4.2-74.2Crosslinking an artifact again creates no additional linkage or event rows and leaves derived state unchanged.covered1
RS-4.2-84.2Singleton reparent operations recorded during a crosslink batch are re-applied when the batch ends.covered4
RS-4.2-94.2A date tag applied to a crosslinked check-in sets its stored event time to the tag's value, which otherwise is the D-card time.covered2
RS-4.2-104.2A date tag that arrives before its check-in sets the event time when the check-in is crosslinked.covered2
RS-4.2-114.2A newer date tag replaces an older one, so the newest date tag's value orders the check-in.covered2
RS-4.2-124.2A date tag of any type sets the time of its target only; a propagating date tag does not retime descendants.covered3
RS-4.2-134.2Cancelling the date tag restores the D-card time.covered3
RS-4.2-144.2A date tag whose value does not parse, or parses to a time that is not positive, is ignored, leaving the D-card time.covered6
RS-4.2-154.2The D-card timestamp is retained separately as the original time.covered2
RS-4.3-14.3No tag, propagation or linkage effect is applied on behalf of a manifest that fails the T-card checks.covered2
RS-4.4-14.4An artifact that hashes to its name but is not classifiable does not make state assembly fail.covered2
RS-4.4-24.4An unclassifiable artifact contributes no linkage, tag or branch effect.covered2
RS-4.4-34.4An artifact whose bytes do not hash to its stored name is rejected.covered1
RS-4.6-14.6A tag or anti-tag operation stores a control artifact with exactly one T-card and derives its state by crosslinking that artifact.covered1
RS-5.1-15.1A T-card prefix - is stored as tagtype 0, + as 1 and * as 2.covered2
RS-5.1-25.1Any other leading character on a T-card is a fatal error and is never stored as a tag type.covered2
RS-5.2-15.2tagxref holds at most one row per (rid, tag), carrying tagtype, srcid, origid, value and mtime.covered2
RS-5.3-15.3A direct application is skipped when the (tag, rid) row already has an mtime greater than or equal to the incoming one, whether that row was applied directly or inherited by propagation.covered5
RS-5.3-25.3Otherwise the row is replaced with the card's raw tagtype, srcid = the artifact carrying the card, origid = rid = the target.covered2
RS-5.3-35.3A cancel application keeps the T card's value on the row it writes, NULL when the card has none.covered4
RS-5.3-45.3A singleton is propagated as a cancel: it removes the inherited same-name rows of the target's descendants.covered2
RS-5.3-55.3When a check-in's ancestor carries a propagating tag newer than a direct tag of the same name on the check-in, the result follows arrival order: the direct tag applied first keeps the direct value and stops the propagation; the propagation arriving first makes the direct tag skipped, so the check-in keeps the inherited value and, for a date tag, its D-card time.covered4
RS-5.3-65.3For cached state such as the event table, and for the propagation walk, a cancel's value is treated as null.covered2
RS-5.3-75.3The tag cards of one artifact are applied in card order, all with the artifact's mtime, so between two cards of one artifact for the same tag and target the first in card order wins.covered2
RS-5.4-15.4Propagation follows primary-parent links only and never crosses a merge link.covered2
RS-5.4-25.4Re-propagating a parent's full tag set treats its singleton rows as cancels.covered2
RS-5.4-35.4A child with a same-tag row qualifies only when that row has srcid 0 and an mtime strictly earlier than the propagating tag's; an equal mtime keeps the row.covered2
RS-5.4-45.4A child with no same-tag row qualifies for a propagating walk; a cancel walk does not qualify there and does not continue past it.covered1
RS-5.4-55.4A qualifying child of a propagating walk gets tagtype 2, srcid 0, the origin's origid, value and mtime.covered4
RS-5.4-65.4A qualifying child of a cancel walk has its same-tag row deleted.covered2
RS-5.4-75.4Every child updated by the walk is itself walked, so the effect reaches all qualifying primary descendants.covered2
RS-5.5-15.5A directly applied same-tag row (srcid nonzero) stops propagation regardless of its mtime.covered2
RS-5.5-25.5A cancel tag on a check-in deletes the inherited row there and keeps the tag from its descendants.covered2
RS-5.5-35.5A singleton tag on a check-in keeps a same-name propagating tag from its descendants.covered2
RS-6.1-16.1A check-in's branch is the value of its branch tag row with tagtype greater than 0.covered1
RS-6.1-26.1A check-in with no active branch tag is attributed to the default branch.covered1
RS-6.1-36.1Creating a branch, including the default branch of a new repository, creates its sym-<branch> tag, propagating like its branch tag.covered1
RS-6.1-46.1The default branch is the main-branch setting, and trunk only when that setting is unset.covered3
RS-6.2-16.2Branch creation writes a propagating branch tag with the name as value and a propagating sym-<name> tag on the branch-root check-in.covered1
RS-6.2-26.2Branch creation emits a cancel card on the root for every propagating sym-* tag active on the parent other than the new branch's own.covered1
RS-6.2-36.2Branch creation fails, before writing anything, when an open branch already has the name.covered1
RS-6.2-46.2A branch root carrying both a propagating and a cancel card for its own sym-<name> keeps the propagating tag: the * card precedes the - card in card order, and the cancel is skipped.covered2
RS-6.3-16.3The branch list has one entry per distinct active branch-tag value, with that value's greatest event.mtime and check-in count.covered1
RS-6.3-26.3A listed branch is closed exactly when its representative (greatest event.mtime) check-in carries an active closed tag.covered1
RS-6.4-16.4The current branch of a checkout is read with the same tagtype > 0 rule as any branch membership.covered3
RS-7.2-17.2The leaf test passes a check-in exactly when no plink child of it, primary or merge, is on the same branch; the leaf table holds the Section 7.3 candidates that passed it when last rechecked.covered5
RS-7.3-17.3A full leaf rebuild gives the table crosslinking every check-in in one batch gives: the candidates are the check-ins a branch tag is applied or propagated to, and their parents; a candidate with no same-branch child is a member, and a check-in that is not a candidate is not, even with no same-branch child. A check-in keeps its verdict when a child carrying no branch row is linked to it in a later batch, so the table is not a function of the repository alone.covered7
RS-7.3-27.3An incremental leaf check removes a check-in with a same-branch child and inserts one without, tolerating an existing row.covered1
RS-7.3-37.3A branch tag applied to a check-in, or a propagation walk updating or deleting its branch entry, rechecks the check-in and each of its parents, merge parents included; crosslinking a check-in or creating a plink edge schedules no recheck by itself.covered10
RS-7.3-47.3Scheduled leaf rechecks have all been applied before the leaf table is read.covered3
RS-7.4-17.4An open leaf is a leaf without a closed tag row of tagtype greater than 0.covered2
RS-7.5-17.5A branch's open leaves are its leaf-table members that are not closed and share its branch.covered1
RS-7.5-27.5The ambiguity test answers no for a check-in that is not itself a leaf.covered1
RS-7.5-37.5For a leaf, the ambiguity test answers yes exactly when another open leaf shares its branch.covered2
RS-7.6-17.6Directly applying a branch tag re-evaluates that check-in's leaf status.covered2
RS-7.6-27.6Each descendant that gains or loses a branch tag by propagation has its leaf status re-evaluated.covered4
RS-8.2-18.2A plain name N resolves to the check-in carrying an active sym-N tag with the greatest event.mtime.covered2
RS-8.2-28.2A closed tag on a candidate does not affect name resolution.covered1
RS-8.2-38.2Whether a candidate is a leaf does not affect name resolution.covered1
RS-8.2-48.2A name no form matches fails to resolve.covered2
RS-8.3-18.3"rid:DIGITS" resolves to that rid.covered1
RS-8.3-28.3"tag:NAME" resolves NAME by the plain-name rule without trying it as a hash.covered1
RS-8.3-38.3"tip" resolves to the check-in with the greatest event.mtime.covered1
RS-8.3-48.3"current", "prev"/"previous" and "next" resolve relative to the open checkout; "ckout" names the checkout only in a "ci+" request with an open checkout and only as the whole name given, and is otherwise resolved like any other name, the trailing-punctuation retry and the contained names of root:, start: and merge-in: included.covered16
RS-8.3-58.3"root:BR" resolves to the first primary ancestor of BR that is off BR's branch.covered1
RS-8.3-68.3"start:BR" resolves to the earliest primary ancestor of BR still on BR's branch.covered1
RS-8.3-78.3"merge-in:BR" resolves to the most recent merge-in point of BR from its parent branch.covered1
RS-8.3-88.3Date forms and NAME:TIMESTAMP resolve to the latest eligible event with mtime at or below the expanded upper bound.covered1
RS-8.3-98.3A hexadecimal name of 4 or more digits is tried as a hash prefix before the plain-name rule.covered1
RS-8.3-108.3A hash prefix matching more than one artifact is rejected as ambiguous.covered1
RS-8.3-118.3A name that matches nothing is retried without one trailing . _ ) > ! ? or , when longer than four characters, or without two when longer than five; three or more are never stripped.covered5
RS-8.3-128.3A branch-type request resolves to the first check-in of the branch the name resolves into.covered3
RS-8.5-18.5Name resolution and open-leaf enumeration stay distinct: a newer closed sym carrier wins resolution while the leaf view omits it.covered1
RS-9-19The current trunk is the main-branch setting's name resolved by the Section 8 symbolic-name procedure.covered3
RS-9-29Resolving a forked branch picks one check-in by greatest mtime and is not an error.covered1
RS-9-39A branch's open leaf carries its active branch tag, is in the leaf table and is not closed; a branch with none is not open.covered2
RS-9-49A report naming one open leaf of a branch with several picks the greatest mtime.covered1
RS-12-112An artifact that the artifact-format rules reject contributes no crosslink state.covered2

Sync protocol

draft-fossil-sync-protocol-00: 169 requirements, 169 covered; 350 cases.

Requirement§TextStatusCases
SP-3.2-13.2Client: every request carries pragma client-version.covered1
SP-3.2-23.2Client: pragma client-version precedes every content-requesting card (gimme, uvgimme, reqconfig) in the request.covered1
SP-3.2-33.2Client: every request ends with a comment line of random bytes.covered3
SP-3.2-43.2Client: in private sync, pragma send-private precedes client-version in the first request and follows it in later requests.covered1
SP-3.2-53.2Client: a push, pull or sync session carries its push and/or pull card in every request until Section 10.2 suppresses push.covered1
SP-3.2-63.2Client: a returned state cookie follows the fixed operation card, or client-version when there is none.covered1
SP-3.2-73.2Server: a completed reply ends with the "# timestamp DATETIME errors N" comment.covered1
SP-3.2-83.2Server: pragma server-version precedes every clone-specific card in a clone reply.covered1
SP-3.3-13.3Receiver: igot HASH creates a phantom only when HASH is absent and the current direction lets the receiver obtain it (client pull or clone, server push).covered9
SP-3.3-23.3Receiver: a delta file or cfile whose DELTASRC is absent stores the delta, deletes HASH's phantom, creates a DELTASRC phantom and sets the content-received flag; no per-artifact received state is kept, and HASH is not requested again.covered1
SP-3.3-33.3Client: the phantom scan requests no hash the peer asked for this round, no shunned name and no private hash unless private sync is on.covered3
SP-3.3-43.3Receiver: a gimme for content the current direction may not send produces neither content nor an error and is not deferred.covered2
SP-3.3-53.3Receiver: a gimme for an absent hash is silently skipped.covered2
SP-3.3-63.3Receiver: a gimme for held content that direction and policy permit is answered with that content in this or a later message.covered1
SP-3.6-13.6Client: a received cookie card replaces the stored cookie.covered1
SP-3.6-23.6Server: does not depend on a cookie and tolerates foreign and repeated cookie cards.covered1
SP-3.7-13.7Client: continues when stored content or an igot-created phantom leaves the phantom table non-empty (limb a).covered2
SP-3.7-23.7Client: continues when processing the reply appended file or delta content to the next request, or the UV upload phase is selected (limb b).covered1
SP-3.7-33.7Client: continues once when, without private sync, the first round's reply was answered by appending at least one igot HASH 1 for a gimme of private content (limb c).covered1
SP-3.7-43.7Client: continues for uvgimme as limb d states: sent uvgimme with a uvfile reply or round below 3, or a uvgimme appended.covered2
SP-3.7-53.7Client: a modern clone continues after the first round, after a round that stored content, or while a positive sequence and the raw artifact count advance (limb e).covered2
SP-3.7-63.7Client: remaining phantoms alone neither continue the session nor cause an error.covered2
SP-3.7-73.7Client: with no continuation condition true, the session stops without another request.covered2
SP-3.9-13.9Sender: never emits a card with a seventh token.covered2
SP-3.9-23.9Receiver: tokens beyond the sixth are invisible to card handlers and create no other card condition.covered2
SP-4-14Client: posts to the repository URL path unchanged and never appends /xfer.covered1
SP-4-24Client: every request carries an exact Content-Length and a nonempty body.covered1
SP-4-34Server: a POST with Content-Type application/x-fossil or application/x-fossil-debug dispatches to sync whatever its path.covered2
SP-4-44Client: follows at most 19 redirects with status 301, 302, 307 or 308, re-posting the same request body; the twentieth is fatal.covered3
SP-4-54Client: refuses a redirect from HTTPS to HTTP.covered1
SP-4-64Client: strips one trailing /xfer, if present, from a redirect target before using it as the new base.covered1
SP-4-74Client: only HTTP 200 is a protocol reply; any other non-redirect status aborts before card parsing.covered2
SP-4-84Client: a reply without Content-Type is compressed; an x-fossil-debug or x-fossil-uncompressed prefix is uncompressed; an x-fossil prefix is compressed; any other type is rejected.covered5
SP-4.1-14.1Sender: the compressed container is the 4-byte big-endian actual input length followed by a zlib stream.covered2
SP-4.1-24.1Client: production requests use application/x-fossil, never application/x-fossil-debug.covered1
SP-4.1-34.1Receiver: the advertised container length is a capacity; a shorter decoded body is not rejected for that alone.covered1
SP-4.1-44.1Receiver: bytes after a successfully decoded zlib stream are ignored.covered1
SP-4.1-54.1Server: a clone version 3 reply is sent as application/x-fossil-uncompressed.covered1
SP-4.1-64.1Receiver: decodes the container whatever DEFLATE level it was compressed at.covered1
SP-4.2-14.2Client: a reply that ends without a terminal card is complete, not an error.covered1
SP-5.1-15.1Receiver: a byte-counted payload ends only at its declared count and may contain LF and card-like text.covered4
SP-5.1-25.1Sender: a cfile payload not ending in LF is followed by one padding LF, which the receiver consumes as an empty line.covered2
SP-5.1-35.1Server: a payload cut short by the end of the body is not stored; the card is a validation failure of its handler, with error malformed file line, malformed cfile line or malformed uvfile line.covered1
SP-5.1-45.1Client: a payload cut short by the end of the reply is not stored; the client stops reading the reply at that card and keeps the prefix it processed.covered1
SP-5.2-15.2Sender: emits canonical cards: one SP between tokens, no leading or trailing whitespace, one LF.covered3
SP-5.2-25.2Receiver: accepts canonical cards and splits tokens on at most SP, HTAB, VT, FF and CR runs.covered5
SP-5.2-35.2Receiver: defossilizes fossilized arguments.covered1
SP-5.2-45.2Server: an unknown operator resets accumulated output, emits error with fossilized TEXT "bad command: LINE" and continues with later request cards.covered2
SP-5.2-55.2Client: an unknown operator records a local warning, sends no error, and ends the reply-card loop; earlier cards stay effective and continuation is evaluated.covered2
SP-5.2-65.2Server: a defined operator with the wrong arity or received in the wrong direction (including client-sent error and clone_seqno) gets error bad command and later cards are processed.covered6
SP-5.2-75.2Server: a file, cfile or uvfile handler validation failure resets output, emits the handler's fossilized error, counts it and stops request parsing.covered5
SP-5.2-85.2Client: a malformed defined card records a warning and ends the reply-card loop; earlier cards stay effective and continuation is evaluated.covered5
SP-5.2-95.2Receiver: private ignores visible surplus tokens and still sets the marker.covered2
SP-5.2-105.2Receiver: igot accepts at least two visible tokens; a third token of exactly 1 marks it private, any other third token public, and later tokens are ignored.covered2
SP-5.2-115.2Receiver: imposes no maximum line length before LF.covered1
SP-5.3-15.3Receiver: a line beginning with # is not dispatched as a card.covered2
SP-5.3-25.3Server: the timestamp comment is "# timestamp YYYY-MM-DDTHH:MM:SS errors N" in UTC with N canonical decimal.covered1
SP-5.3-35.3Server: answering req-clusters, a nonempty run of public cluster igot cards is enclosed by # sending-clusters and # end-of-clusters, and an empty run by neither.covered3
SP-5.3-45.3Server: N counts the errors raised while handling the request, including those whose cards a later reset discarded; the unknown-operator error, the private-content refusal and the SHA3 version refusal are not counted.covered4
SP-5.3-55.3Receiver: does not act on N.covered1
SP-6.1-16.1Sender: the login card is login USER NONCE SIGNATURE with USER fossilized and NONCE and SIGNATURE 40 lowercase hex characters.covered1
SP-6.1-26.1Server: a second login in one request is fatal: output is reset and an error emitted.covered2
SP-6.2-16.2Client: NONCE is the SHA-1 of every decompressed body byte after the login line's LF.covered1
SP-6.3-16.3Client: the shared secret is SHA1(project-code "/" login "/" password) in lowercase hex.covered1
SP-6.4-16.4Client: SIGNATURE is SHA1 of the NONCE hex followed by the shared-secret hex.covered1
SP-6.4-26.4Server: nobody and anonymous logins succeed without a signature check.covered2
SP-6.4-36.4Server: a named login succeeds when SHA1(NONCE || stored credential) equals SIGNATURE, compared case-sensitively.covered3
SP-6.4-46.4Server: when that fails and the stored credential is not exactly 40 bytes, the secret is derived from the stored cleartext and retried.covered1
SP-6.4-56.4Server: NONCE must equal the SHA-1 of the body after the login line, compared case-sensitively.covered3
SP-6.4-66.4Server: a failed login keeps HTTP 200, discards staged output, emits error login failed and ends card processing without rolling back the request.covered1
SP-6.4-76.4Server: a successful login only adds capabilities to the request's baseline.covered2
SP-6.4-86.4Server: after a failed login, the end-of-request steps still run for a direction an earlier card established, and the reply ends with the timestamp comment.covered6
SP-6.5-16.5Client: once the recorded server version passes the gate (VERSION >= 22700 and DATE/TIME at or after 20250727 110500), login goes in Cookie: x-f-l-c=login+USER+NONCE+SIGNATURE and no body login is sent.covered1
SP-6.5-26.5Client: before server-version is seen, or when the gate is false, a named login uses the body card and never the cookie.covered1
SP-6.5-36.5Server: accepts body login whatever the gate.covered1
SP-6.5-46.5Server: accepts a login carried in the x-f-l-c cookie through the body-login path.covered3
SP-6.6-16.6Server: each card is checked against its capability (o read, i write, g clone, x private, a admin) and an error is emitted when it is lacking.covered6
SP-6.6-26.6Server: a push without Write after an accepted pull gets message "pull only - not authorized to push" without a reset; otherwise output is reset and error not authorized to write is emitted; neither ends card processing.covered4
SP-6.6-36.6Server: while push is not enabled, the first file or cfile card is refused with reset output and error not authorized to write, ends card processing, and end-of-request steps for an earlier direction still run.covered2
SP-6.6-46.6Client: a refusal is recognized by the text the draft gives at the start of the decoded text, not by the whole text, since a server may append further words.covered1
SP-7.1-17.1Receiver: file HASH SIZE and file HASH DELTASRC SIZE carry exactly SIZE payload bytes with no trailing separator.covered3
SP-7.1-27.1Sender: push and pull transfer content with file cards, not cfile.covered1
SP-7.2-17.2Receiver: cfile HASH [DELTASRC] USIZE CSIZE carries exactly CSIZE payload bytes.covered4
SP-7.2-27.2Receiver: USIZE is parsed but not validated against the payload at the transfer layer.covered1
SP-7.2-37.2Server: a clone cfile payload is the repository's stored compressed blob, retransmitted verbatim.covered1
SP-7.2-47.2Server: clone version 3 transfers content with cfile cards only.covered1
SP-7.3-17.3Receiver: uvfile NAME MTIME HASH SIZE FLAGS has a fossilized NAME, carries SIZE payload bytes unless FLAGS has 0x0001 or 0x0004, and HASH is a hash or -.covered3
SP-7.3-27.3Receiver: rejects negative FLAGS and ignores reserved FLAGS bits.covered3
SP-7.3-37.3Sender: emits a deletion as HASH -, SIZE 0 and FLAGS with 0x0001 set, and clears reserved FLAGS bits.covered1
SP-7.3-47.3Receiver: HASH - with a positive SIZE and no payload-suppressing flag is rejected without storing or deleting.covered1
SP-7.3-57.3Receiver: before applying a uvfile, recomputes its status from the current row: statuses 3 to 5 change nothing and status 2 updates MTIME only.covered2
SP-7.3-67.3Receiver: content omitted by FLAGS 0x0004, or SIZE 0, is stored with size zero and NULL content.covered1
SP-7.3-77.3Server: a client uvfile requires UV write permission, and an unauthorized one is an error.covered2
SP-7.3-87.3Server: a uvgimme for an absent NAME emits no card.covered1
SP-7.3-97.3Server: a uvgimme is answered with uvfile FLAGS 0 for a live file or HASH - SIZE 0 FLAGS 1 for a tombstone.covered2
SP-7.3-107.3Receiver: for status 0 or 1, a uvfile creates or replaces the row with the received NAME, MTIME, HASH and content.covered1
SP-7.3-117.3Server: a uvgimme from a requester without Read permission emits neither content nor error.covered1
SP-7.3-127.3Server: for the uvgimme Read check, Clone permission implies Read.covered1
SP-7.4-17.4Receiver: a card for an already verified HASH is consumed and ignored and never replaces or downgrades it; delta-source handling may run first or be skipped.covered2
SP-7.4-27.4Receiver: for an unverified target with a missing DELTASRC, the delta is kept under HASH and the DELTASRC phantom carries the card's private classification.covered2
SP-7.5-17.5Client: private marks the next file or cfile; repetition, comments, other cards and uvfile do not consume it, and it survives a reply boundary.covered2
SP-7.5-27.5Server: private sets the marker only for a sender with Private capability; otherwise it emits the private authorization error and leaves no marker.covered1
SP-7.5-37.5Receiver: entering the file or cfile handler clears the marker, so it applies to one card.covered1
SP-7.5-47.5Sender: never sends a delta against a private basis to a peer without private authorization; it sends full content.covered1
SP-7.5-57.5Receiver: an unauthorized igot HASH 1 is not an error and creates no phantom, but reclassifies a held HASH or phantom as private.covered6
SP-7.5-67.5Server: private content is sent only after a successful send-private.covered1
SP-7.6-17.6Sender: to a peer whose recorded VERSION is below 20000, a SHA3 file or cfile, or a uvfile with a 64-hex HASH, is replaced by error Fossil version 2.0 or later required., and the rest of the message is still built.covered5
SP-7.6-27.6Server: the client VERSION is 0 until pragma client-version arrives.covered1
SP-7.6-37.6Client: the recorded server VERSION starts as the client's own release and is replaced by server-version.covered1
SP-7.7-17.7Receiver: a non-clone file whose target is in the shun table is consumed and discarded with no error, no content-received and no mutation.covered2
SP-7.7-27.7Receiver: a cfile with a shunned target is discarded after its payload, even in a clone.covered1
SP-7.7-37.7Receiver: admission applies to the target hash, not the DELTASRC.covered1
SP-7.7-47.7Receiver: before commit, every newly stored artifact whose bytes are available is hashed and a mismatch aborts the commit.covered14
SP-8-18Client: a clone starts with client-version, clone 3 1 and randomness, and no login card.covered1
SP-8.1-18.1Server: an authorized three-token clone with integer VERSION >= 2 and a digit-only SEQNO of 0 clears output, rolls back, emits error invalid clone sequence number and stops parsing.covered3
SP-8.2-18.2Server: an accepting clone reply sends cfile cards in RID order from SEQNO, skipping gaps, then clone_seqno NEXT, then push SERVERCODE PROJECTCODE; NEXT 0 marks exhaustion.covered3
SP-8.2-28.2Client: records a digit-only NEXT; a nondecimal NEXT leaves the sequence unchanged and does not stop parsing.covered2
SP-8.2-38.2Server: a clone authorization refusal resets output and emits push SERVERCODE PROJECTCODE then error, with no cfile and no clone_seqno.covered1
SP-8.2-48.2Client: reissues clone 3 NEXT only when the reply carried a well-formed push and NEXT is positive; otherwise it sends the operation-less cleanup.covered1
SP-8.2-58.2Client: after NEXT 0 no clone, pull or push card is sent; cleanup carries no operation card.covered2
SP-8.2-68.2Server: in a directionless request, gimme yields neither file, cfile nor error.covered1
SP-8.2-78.2Server: accepts and ignores igot cards received without push enablement.covered1
SP-8.3-18.3Client: an error in the first clone reply is not fatal: later cards are parsed, a later push is recorded and the second clone request is made.covered2
SP-8.4-18.4Client: reqconfig and uv-hash are deferred until after clone round 0.covered1
SP-8.4-28.4Server: with UV sync enabled, an authorized clone reply carries pragma uv-pull-only and the full UV catalog.covered1
SP-8.5-18.5Server: a push or pull whose PROJECTCODE differs from the repository's is refused.covered2
SP-8.5.1-18.5.1Client: the UV send table starts with every local row whose hash is non-NULL; tombstones are excluded.covered1
SP-8.5.1-28.5.1Client: pragma uv-hash is sent exactly once, in the first eligible round, never in clone round 0.covered1
SP-8.5.1-38.5.1Sender: the UV catalog hash is the SHA-1 of "NAME SP YYYY-MM-DD SP HH:MM:SS SP HASH LF" for each non-tombstone row, sorted by name bytes.covered1
SP-8.5.1-48.5.1Server: a matching uv-hash gets no catalog; a mismatch with Read gets uv-push-ok or uv-pull-only and one uvigot per entry, tombstones as HASH -.covered2
SP-8.5.1-58.5.1Client: each uvigot is classified into status 0 to 5 and handled as Table 6 states.covered3
SP-8.5.1-68.5.1Client: after uv-pull-only, status 4 and 5 names are removed from the send table.covered1
SP-8.5.1-78.5.1Client: never sends uvigot, neither the well-formed form nor the short tombstone form.covered2
SP-8.6-18.6Client: under private sync, lists its private inventory as igot HASH 1 in every request that carries push, starting with the first, with no peer-date check.covered1
SP-8.6-28.6Sender: without private sync, a gimme for private content is answered with igot HASH 1 only when the peer's date is 2020-04-13 or later, and with nothing otherwise.covered2
SP-9-19Receiver: an unknown pragma name is ignored silently, whatever its arguments.covered2
SP-9-29Receiver: a known pragma received in the wrong direction is ignored and changes no state.covered2
SP-9-39Server: a bare pragma with no NAME gets error bad command and later cards are processed.covered1
SP-9.1-19.1Server: a full client-version replaces the peer VERSION, DATE and TIME and is answered with a full server-version; a short one updates VERSION only and gets no reply.covered2
SP-9.1-29.1Client: a full server-version replaces the peer VERSION, DATE and TIME; a short one updates VERSION only.covered1
SP-9.2-19.2Server: on a uv-hash mismatch with Read, sends uv-push-ok when the principal may write unversioned files, otherwise uv-pull-only, exactly once.covered2
SP-9.3-19.3Server: reqconfig without Read is silently ignored.covered1
SP-9.3-29.3Server: reqconfig for a name matching no group emits no config card and no error.covered1
SP-9.3-39.3Sender: a scalar setting is config /config SIZE whose payload is MTIME 'NAME' value 'VALUE', followed by one LF.covered1
SP-9.3-49.3Receiver: consumes one byte after a config payload without checking that it is LF.covered1
SP-9.3-59.3Server: a config card whose SIZE is signed or not decimal takes the bad command path.covered1
SP-9.3-69.3Server: a config card requires Admin; otherwise it emits error not authorized to push configuration and applies nothing.covered1
SP-9.4-19.4Server: ci-lock for a hash held by a different client emits ci-lock-fail LOGIN MTIME; the same client gets no lock result; no live lock writes one, with no positive acknowledgement.covered8
SP-9.4-29.4Server: ci-unlock CLIENT-ID deletes that client's locks and emits nothing.covered2
SP-9.4-39.4Server: after processing a ci-lock that passes the argument guard, written or not, emits pragma avoid-delta-manifests when its forbid-delta-manifests setting (default on) is true, after ci-lock-fail when that is emitted; a ci-lock that fails the guard emits neither.covered6
SP-9.5-19.5Server: send-private without Private capability appends error not authorized to sync private content without resetting output, and parsing continues.covered2
SP-9.5-29.5Client: sends pragma send-private in every private round.covered1
SP-9.5-39.5Server: emits no link pragma in reply to a request without req-links.covered1
SP-9.5-49.5Receiver: stores a link's ARG defossilized and verbatim, and never parses, alters or echoes it.covered3
SP-9.5-59.5Client: keeps a link only in share-links mode, with exactly URL, ARG and MTIME, a URL that parses as HTTP(S) and a positive decimal MTIME; otherwise it discards every field.covered6
SP-9.5-69.5Client: sends pragma req-links only in share-links mode.covered3
SP-9.5-79.5Client: pragma avoid-delta-manifests SHOULD be followed by writing a pending commit as a baseline manifest; the pragma changes neither the artifacts the client sends or requests nor the repository.covered1
SP-10.1-110.1Client: a server error outside the first clone reply ends the reply-card loop; earlier cards stay committed and continuation is evaluated.covered4
SP-10.1-210.1Server: at wrong-project, authorization, duplicate-login and unknown-card errors, partial output is discarded before the error, except for the push refusal's message form.covered6
SP-10.1-310.1Server: the SHA3 gate and unauthorized send-private append their error without reset, and parsing continues.covered2
SP-10.1-410.1Server: card errors keep HTTP status 200.covered1
SP-10.1-510.1Server: only invalid clone sequence number and invalid config record roll back the request; other card errors keep earlier mutations.covered1
SP-10.1-610.1Client: a handler-reported content error that leaves the stored artifacts consistent, such as a malformed card or a refused private file, ends the reply-card loop, and the prefix of the reply processed before it stays committed.covered2
SP-10.1-710.1Client: after a handler-reported content error that leaves the stored artifacts consistent, continuation (Section 3.7) is evaluated.covered2
SP-10.1-810.1Client: a received file or cfile whose reconstructed content does not match its HASH fails the round: nothing the round received is committed, its processed prefix included, and no further round starts, in a clone too.covered5
SP-10.2-110.2Receiver: message takes exactly two visible tokens, its TEXT is defossilized and it is not fatal.covered2
SP-10.2-210.2Client: with push enabled, a message matching "pull only *" clears push: later gimme cards in that reply append no content and later requests omit push.covered2
SP-10.2-310.2Client: any other message changes no state.covered1
SP-11.4-111.4Sender: never truncates, renames or re-identifies a SHA3 name as SHA1.covered1

Sub-manifests

draft-fossil-submanifests-00: 76 requirements, 76 covered; 143 cases.

Requirement§TextStatusCases
SM-3.1-13.1A card letter outside A-Z is rejected, and the in-range undefined letters O, V, X and Y are rejected; S is defined.covered6
SM-3.2-13.2An S card carries exactly a filename and a hash; a third token, or a missing hash, is rejected.covered2
SM-3.3-13.3The S card filename is escape-decoded; the S card hash is never decoded.covered2
SM-3.4-13.4S cards repeat, and an S run ascends strictly by decoded filename under the canonical comparator; an equal or descending neighbour is rejected.covered4
SM-3.4-23.4S falls between R and T in the card order, so a manifest's S run follows its R card and precedes its T cards.covered2
SM-3.5-13.5The S card hash is exactly 40 or 64 case-insensitive hexadecimal characters.covered4
SM-3.6-13.6The decoded S card filename passes the pathname predicate; one that does not is rejected.covered2
SM-4.2-14.2A manifest may carry an S card alongside B C D F N P Q R T U Z, and requires D and Z.covered2
SM-4.2-24.2A sub-manifest may carry only F, S and Z cards, and requires a Z card.covered3
SM-4.3-14.3S is a manifest-setting letter, and a manifest with no D card is reclassified as SUBMANIFEST once its type is final and before legality is checked; no card assigns SUBMANIFEST directly.covered4
SM-4.3-24.3No artifact valid under the base artifact format changes classification.covered1
SM-4.4-14.4A manifest carrying both a B card and an S card is rejected.covered2
SM-4.4-24.4A manifest carrying both F cards and S cards is rejected.covered1
SM-4.4-34.4A sub-manifest carrying both F cards and S cards, or neither, is rejected.covered2
SM-4.4-44.4Every F card of a sub-manifest carries a hash; a delete marker in a sub-manifest is rejected.covered1
SM-4.4-54.4The tree walk delivers each emitted F card's hash, permission and old-name tokens to consumers unaltered.covered1
SM-4.5-14.5An interior sub-manifest, whose first card is S, is not rejected by a pre-filter on its first card letter.covered1
SM-5-15A manifest is a tree manifest if and only if it carries an S card, and a consumer that needs its file set derives it by the tree walk.covered1
SM-5.1-15.1The walk enumerates a tree depth first and in order, emitting each leaf's F cards in order, through interior sub-manifests as well as leaves.covered1
SM-5.1-25.1Each S card's decoded filename, and each emitted filename, compares strictly greater than the last filename emitted; an enumeration that does not ascend across sibling slices fails.covered2
SM-5.1-35.1The enumeration fails when a referenced sub-manifest is absent.covered1
SM-5.1-45.1The enumeration fails when a referenced artifact is not of type SUBMANIFEST.covered1
SM-5.1-55.1The enumeration fails when a referenced artifact is the artifact of a frame already on the walk's stack.covered1
SM-5.1-65.1The enumeration fails when a sub-manifest lies deeper than 16 sub-manifests, counting the leaf; a depth of 16 is accepted.covered2
SM-5.1-75.1A leaf's first emitted filename is byte-identical to the filename of the S card that reached it.covered1
SM-5.1-85.1An interior sub-manifest's first S card filename is byte-identical to the filename of the S card that reached it.covered1
SM-5.1-95.1Downstream consumers do not distinguish a walked enumeration from a flat one: a tree check-in's file-change records are those of a flat check-in of the same files.covered1
SM-5.2-15.2The enumeration entry points, the full walk and single-name lookup, treat an unresolvable sub-manifest as a fatal error, and no partially resolved tree is presented as a complete file set.covered1
SM-5.2-25.2A consumer that defers records the gap, keyed by the dependent and the missing hash and inserted idempotently, and retries when the sub-manifest arrives.covered1
SM-5.3-15.3Single-name lookup binary-searches each S run for the last card at or before the name, descending one sub-manifest per level to a leaf; a name before the first S card is absent.covered2
SM-5.3-25.3A lookup that would resolve a sub-manifest deeper than 16 fails, and a sub-manifest it cannot resolve fails it hard.covered1
SM-5.4-15.4A delta manifest may name a tree manifest as its baseline: the merge walk takes the tree walk as its baseline cursor, and single-name lookup takes the tree lookup as its baseline step.covered1
SM-5.4-25.4A writer with the enable-submanifests setting off does not create a delta manifest against a tree baseline.covered1
SM-5.5-15.5A tree manifest's R card is computed over the walked enumeration, and a delta over a tree baseline's over the composed enumeration.covered1
SM-6.1-16.1The partition predicate is the count of leading zero bits of the SHA3-256 digest of the decoded filename, tested against k for leaves and (h+1)*k at height h; content, permission and old name never influence the partition.covered2
SM-6.2-16.2The construction is deterministic: leaves carry their group's F cards and a Z card, interiors one S card per member and a Z card, each S card names its child under the repository hash policy, and two writers produce byte-identical artifacts for the same check-in and k.covered4
SM-6.2-26.2A scan yielding fewer than two groups emits a flat manifest and no sub-manifest: N = 0, N = 1, at most MAX names with no qualifying boundary, and a boundary suppressed by MIN.covered3
SM-6.2-36.2A group holding MAX members forces a boundary whatever the predicate says.covered1
SM-6.2-46.2A final group shorter than MIN merges into its predecessor when the two fit in MAX, at height 0 and at every interior height.covered2
SM-6.2-56.2A scan yielding one group, or as many groups as nodes, ends the construction with the manifest carrying that height's nodes; otherwise interior sub-manifests form the next height, never a node of height 16.covered1
SM-6.2-66.2S card filenames and a leaf's filename and old-name tokens take the canonical encoding: exactly space, newline and backslash escaped, every other byte raw.covered1
SM-6.2-76.2Sub-manifests are stored before the manifest that references them, and an unchanged subtree is shared by content addressing.covered1
SM-6.2-86.2Sparse writers produce the full canonical construction, including MAX-cut shifts, MIN and final-small-group merges, renames and propagation at every height; necessary absent nodes are fetched or cause explicit refusal without a partial check-in.covered1
SM-6.2-96.2Opaque reuse requires partition verification under the requested k or trusted local derivation tied to the immutable parent identity, construction rules and k; a different or unknown parent k requires validation or reconstruction even when filenames are unchanged.covered1
SM-6.3-16.3A supporting server answers reqconfig /config, the scalar marker, with submanifest-k, enable-submanifests and submanifest-auto-retune when the requester holds Read permission.covered1
SM-6.3-26.3A receiver validates the adopted state and applies all three settings or none: an invalid value, or enable-submanifests on without a submanifest-k from 1 to 12, leaves the repository's values unchanged, and card order does not affect the result.covered1
SM-6.3-36.3A client supporting this specification requests the three settings with reqconfig /config in the clone's cleanup round, after clone authorization succeeds, and a pull does not request them.covered1
SM-6.3-46.3A newly cloned repository that could not retrieve the settings leaves enable-submanifests false.covered1
SM-6.3-56.3The writer takes k from the stored pin, never derives it per commit, and supports every value from 1 to 12.covered2
SM-6.3-66.3A stored k outside 1 to 12 makes the writer fall back to flat manifests rather than substitute a value, and report it.covered1
SM-6.3-76.3Automatic selection costs every k from 1 to 12 over the current check-in's entries under the sha3 policy, C(k) = S + sum(L*L)/sum(L), choosing the least cost and the lowest k on a tie; with no candidate it has no result. With no checkout the current check-in is the newest leaf of the main branch. The snapshot choice k_s is refined by replaying the last 200 check-ins under k_s - 1, k_s and k_s + 1, as zit refines it.covered3
SM-6.4-16.4A re-tune is forward-only and operator-initiated: the next commit is built under the new value, sharing exactly the byte-identical sub-manifests, and no history is rewritten.covered1
SM-6.4-26.4A writer re-tunes automatically only while submanifest-auto-retune is true (default false), and only when a distinct candidate costs less than (1 - m) times the pin's cost; m is 15%, as zit's.covered1
SM-7.1-17.1Storing a structural artifact whose S references are absent creates a phantom for each, with the referencing artifact's privacy.covered1
SM-7.1-27.1Dephantomizing a sub-manifest retries the deferred processing of every recorded dependent.covered1
SM-7.2-17.2A sender refuses to transmit a SUBMANIFEST artifact, or a manifest carrying an S card, to a peer that has not sent pragma send-submanifests, whatever version it announces, with an explicit error and never by converting, downgrading or silently omitting it; a server decides from the request it answers, a client from the replies of its session.covered5
SM-7.2-27.2A server whose enable-submanifests setting is false sends pragma avoid-submanifests in every reply, clone replies included, in the leading pragma run after server-version.covered1
SM-7.2-37.2A client that received avoid-submanifests emits no S card in a commit created during that session; a commit created outside a session follows the client's own setting, and the pragma does not gate receipt.covered4
SM-7.2-47.2A peer that reads sub-manifests sends pragma send-submanifests: a client in every request, right after client-version, and a server in every reply, clone replies included, right after server-version, whatever the enable-submanifests setting and the avoid-submanifests pragma; the version it announces is the fossil release whose protocol it speaks.covered3
SM-7.3-17.3Crosslinking a tree manifest uses its full enumeration wherever a flat manifest's F cards are used, and an absent sub-manifest defers it as an absent baseline defers a delta.covered1
SM-7.3-27.3A SUBMANIFEST artifact has no crosslink effect of its own, and a derived view over an incomplete tree closure is not presented as complete.covered2
SM-7.4-17.4Sub-manifest enumeration results are cached by artifact name, so a reader parses each distinct sub-manifest once and a tree that shares all but one leaf with one already read parses only its manifest and that leaf.covered1
SM-8.1-18.1A writer emits no S card unless the enable-submanifests setting is true, which is false by default.covered2
SM-8.1-28.1When the first S-bearing artifact is stored, a seen-submanifest indicator is recorded.covered1
SM-8.1-38.1A local request to enable emission keeps a valid pin and refuses a different explicit k; a stored k outside 1 to 12 refuses a request without an explicit k, naming the stored value, and is replaced by an explicit k from 1 to 12; with no stored k it pins an explicit k from 1 to 12, refuses one outside, or selects one automatically; a request that cannot be met changes neither setting.covered2
SM-8.1-48.1Disabling the setting stops new tree manifests and leaves existing ones in place.covered1
SM-9.1-19.1SUBMANIFEST is determined by the post-pass reassignment, not while cards are read, and required-card logic treats it as an exception to the D card.covered1
SM-9.2-19.2A sweep that discovers crosslink work by the absence of derived rows excludes SUBMANIFEST artifacts or records a completion marker for them, so it never reselects them.covered1
SM-9.3-19.3Every consumer of a check-in's file set (checkout, diff, crosslink, rebuild, annotate, commit) obtains it through one shared enumeration interface.covered1
SM-9.4-19.4When a tree manifest's processing is deferred, enough is recorded to rediscover it when the missing sub-manifest arrives, and the dephantomization path traverses that record.covered1
SM-10-110The tree walk enforces the depth bound and the repeated-artifact check, and bounds the total sub-manifests visited per enumeration.covered3
SM-A-1A.2, A.3The Appendix A.2 and A.3 artifacts parse, determine their types, recompute their names, walk to the four-file enumeration, and the R card verifies over it.covered1
SM-A-2A.4The Appendix A.4 artifacts parse, recompute their names, walk to the nine-file enumeration, and the R card verifies over it.covered1
SM-A-3A.5The authored Appendix A.5 acceptance vectors (three-level tree, height-0 merge, canonical encoding, delta over a tree) parse, walk, and verify their R cards; the reader accepts them at any partition parameter.covered4
SM-A-4A.5The writer vectors of A.5: the A.4 set reproduced at k = 3, the height-0 merge and three-level vectors reproduced, flat output for N = 1 and a MIN-suppressed boundary, no selection over one name with a first enable failing atomically, and an injected persistence failure leaving no setting applied.covered6
SM-A-5A.6The SHA3 MAX-propagation, final-small-group-merge and different/unknown-parent-basis vectors compare successful results and every transitive node byte with full construction; absent S payloads require fetching or atomic explicit refusal, and dense runs require canonical success.covered10

Sparse cones

draft-fossil-sparse-cone-00: 63 requirements, 63 covered; 121 cases.

Requirement§TextStatusCases
SC-2-12A member covers a path when it equals the path or is a prefix of it ending at a '/' boundary; a cone has at least one inclusion member, and the absent cone covers everything (dense operation).covered1
SC-3.1-13.1A worktree cone is checkout-local state recorded with the checkout's other local records; it is not an artifact, does not synchronize, and affects no artifact's bytes or name.covered1
SC-3.1-23.1A cone may be widened or narrowed at any time.covered1
SC-3.1-33.1The canonical serialization marks a cone carrying members of other kinds with a distinct version, and an implementation that does not understand a version refuses the cone rather than reading it as path members.covered1
SC-3.1-43.1Refusal of a store cone is policy loss: the store heals toward dense.covered1
SC-3.2-13.2Members are normalized through the worktree-path validation applied to tracked paths: no dot or dot-dot components, no empty components, no reserved roots.covered1
SC-3.2-23.2A member covered by another member of the same polarity with no opposite-polarity member between them is removed, and the normalized cone is what classification uses.covered1
SC-3.2-33.2At least 64 members are supported, and 255 should be.covered1
SC-3.2-43.2A cone contains at least one inclusion member; constructing one with none is refused, as a dead exclusion is, with or without exclusions.covered1
SC-3.3-13.3Coverage is decided by the longest member of either polarity that covers the path, which is order-independent, so the canonical sorted serialization and the digest do not depend on input order.covered2
SC-3.3-23.3Polarity may alternate along a nesting chain: a subtree excluded from an inclusion may contain a deeper re-inclusion.covered1
SC-3.3-33.3A member whose nearest covering member has the same polarity is redundant and is removed.covered1
SC-3.3-43.3An exclusion that no inclusion covers is a dead rule and is refused.covered1
SC-3.3-53.3One path carried with both polarities is a contradiction and is refused.covered1
SC-3.3-63.3A key range wholly inside an inclusion and outside every exclusion classifies as before; a range an exclusion intersects is classified per file, at no cost to correctness.covered1
SC-3.4-13.4Members are literal path prefixes; glob and pattern members are not part of the mechanism.covered1
SC-3.4-23.4A member names a directory subtree or a single file with equal standing.covered1
SC-3.4-33.4A metacharacter in a member is a literal character of the path: it is never expanded, and the member may be refused.covered1
SC-3.5-13.5Amending a cone by wholesale replacement and by member addition or removal are equivalent, and the incremental form should be offered.covered1
SC-3.5-23.5Widening fetches what the cone newly covers (the policy form of demand fetch).covered4
SC-3.5-33.5Narrowing dematerializes and leaves reclamation to explicit compaction.covered1
SC-4-14The sparse worktree is available to any conforming repository, with flat or tree-structured manifests.covered1
SC-4.1-14.1A checkout operation given a cone materializes exactly the covered files.covered2
SC-4.1-24.1The managed-file record covers only in-cone files.covered1
SC-4.1-34.1Status, untracked-file listing and bulk tracking operate within the cone; an uncovered on-disk path is neither reported as untracked nor eligible for tracking.covered1
SC-4.1-44.1A request to track a path outside the cone is refused, and the refusal names the cone as the reason; a diagnostic that reports a missing file or alleges damage does not conform.covered1
SC-4.1-54.1All file-set enumeration flows through the shared enumeration interface with the cone applied there as a range predicate, never filtered at individual call sites.covered1
SC-4.2-14.2A commit from a sparse worktree produces a check-in whose file set is the in-cone files as observed in the worktree and the baseline's out-of-cone entries carried unchanged.covered1
SC-4.2-24.2For flat manifests the baseline's out-of-cone F cards are copied byte-verbatim, merged in sorted order with the in-cone F cards.covered1
SC-4.2-34.2Tree commits produce full canonical construction under the requested k; opaque reuse requires compatible partition evidence bound to the immutable parent, rules and k or verification from needed descriptors and entries. The structural affected range includes MAX-cut shifts, final-small-group merges and propagation at every height; necessary absent nodes are fetched or cause explicit refusal without a partial check-in.covered17
SC-4.2-44.2The result is an ordinary check-in: a reader cannot detect that it was committed sparsely, and no new artifact form is introduced.covered2
SC-4.3-14.3A sparse-worktree commit over a dense store may compute the R card by reading out-of-cone content from the store.covered1
SC-4.3-24.3A commit over a sparse store omits the R card.covered1
SC-4.3-34.3Verifiers do not treat an absent R card as damage.covered1
SC-4.3-44.3A verifier checking a present R card during a sparse materialization computes the aggregate over the dense enumeration, reading out-of-cone content from the store.covered2
SC-4.3-54.3A verifier over a sparse store skips R verification rather than report disagreement.covered2
SC-4.4-14.4Over a dense store, merge, update and revert apply changes to out-of-cone files to the record without materializing them.covered9
SC-4.4-24.4The count of out-of-cone changes applied should be reported.covered1
SC-4.4-34.4Read operations on an uncovered path over a dense store read the store: the cone governs materialization, not readability.covered1
SC-5-15A sparse store requires tree manifests for the segment it elides; a flat segment may elide only its content blobs and holds its manifests densely.covered1
SC-5.1-15.1A store sparse at a cone holds every manifest, every in-cone sub-manifest node and every blob an in-cone F card names, and every non-manifest structural artifact densely. Out-of-cone nodes and blobs MAY be absent as elided phantoms; already-held or demand-fetched payloads need not be discarded.covered3
SC-5.2-15.2Transit phantoms, shunned artifacts and elided phantoms are distinguished; synchronization does not spontaneously request an elided phantom, whose absence is healthy.covered2
SC-5.2-25.2Elision is computed from the cone, not stored on the phantom: reclassification on cone change is recomputation, and losing the store cone should reclassify every elided phantom as a transit phantom.covered2
SC-5.2-35.2Verification reports a store complete within its cone as healthy, reports elision counts distinctly from damage, and reports transit phantoms and damaged in-cone artifacts as for a dense store.covered1
SC-5.3-15.3A commit may reference elided subtrees proved identical to canonical construction by hash without possession; nodes required for boundary propagation or partition validation are fetched or cause explicit refusal. Pushing a canonically valid check-in is sound.covered2
SC-5.3-25.3A server should refuse to be a clone origin for cones it does not cover, unless configured as a partial mirror, with one error card and no content.covered2
SC-5.3-35.3A client treats a clone-round reply that carries an error card and no clone progress as fatal.covered3
SC-5.4-15.4Widening reclassifies the newly covered elided phantoms as transit phantoms and fetches them.covered1
SC-5.4-25.4Narrowing does not by itself delete held content; only explicit compaction deletes, dropping out-of-cone blobs no in-cone F card references and retaining every manifest and sub-manifest node already held, through the store-rewrite machinery and its locks.covered4
SC-5.5-15.5The flat prefix of a hybrid history holds its manifests densely; its content blobs may be elided by F-card classification.covered1
SC-6.1-16.1A cone-scoped pull or clone adds one pragma cone card per inclusion member, encoded exactly as an F-card filename, and one pragma cone-not card per exclusion.covered1
SC-6.1-26.1For check-in content a cone-scoped request asks for spines, in-cone sub-manifest nodes and in-cone blobs, and neither expects nor requests the remainder.covered2
SC-6.2-16.2A cone-aware server walks each check-in's tree descending only nodes whose key range intersects the cone, emits the spine, the in-cone nodes and blobs, and bounds the per-round walk as a dense clone bounds its batches.covered8
SC-6.2-26.2A cone-aware server does not serve a delta whose base is outside the keep set it computed for the request; it serves that artifact in full form.covered1
SC-6.2-36.2A recipient treats a phantom that a retained delta names as its source as a transit phantom whatever its cone classification.covered1
SC-6.2-46.2The per-round bound governs the tree walk only; a cone request's pull inventory may be announced densely or filtered to the cone, and the requester relies on neither for correctness: an out-of-cone blob announced with its check-in is requested as a transit phantom and elided on arrival, and one announced after the check-in that classifies it is never requested.covered1
SC-6.3-16.3Against a cone-ignorant server the requester filters locally: it stores in-cone blobs and every manifest and sub-manifest node received, records elided phantoms for the out-of-cone blobs and reports the counts.covered2
SC-6.3-26.3A cone-aware server should acknowledge each reply that applied the request's whole cone with pragma cone-served, in the reply's leading pragma run, never in a reply that refused the request, served densely or ignored a member; the requester counts acknowledged replies.covered3
SC-6.4-16.4An operation over a sparse store that crosses the cone resolves elided phantoms by a targeted request or by the policy form, which is recommended for lasting intent.covered2
SC-6.4-26.4With no configured peer the operation refuses, and the diagnostic names the class (the count elided by the cone and the absence of a peer), never missing or corrupt.covered2
SC-7-17Derived caches are cone-independent: their keys do not incorporate the cone.covered1
SC-8-18The member count and member length of a cone are bounded with the same limits applied to F-card filenames.covered2
SC-8-28The server-side tree walk on cone requests carries the depth and visited-node bounds of single-name lookup.covered2

Horizons

draft-fossil-horizon-00: 76 requirements, 76 covered; 161 cases.

Requirement§TextStatusCases
HZ-1.1-11.1An implementation may provide the content horizon alone; the structural horizon presupposes the content horizon.covered1
HZ-3.1-13.1A horizon names one check-in C by its full artifact hash and one of two held-set rules: descendants (the default), C and every descendant of C; or leaves, those plus, for every childless check-in L not descended from C, every descendant of each nearest common ancestor of L and C, that ancestor included.covered2
HZ-3.1-23.1A client that expects to merge across live branches offline should choose the leaves rule knowingly.covered1
HZ-3.1-33.1The held set is a function of C, the rule and the check-in graph, recomputed by clone and origin from what each holds, and stored by no party.covered2
HZ-3.1-43.1Both rules are stated over P cards alone and yield a set closed under descendants: every child of a check-in in K is in K. Childless means no check-in names it in a P card, open or closed, not the same-branch leaf of repo-state.covered3
HZ-3.2-13.2A horizon is store-adjacent local state: not an artifact, not synchronized, affecting no artifact's bytes or name; its loss reclassifies every elided artifact as a transit phantom and the store heals toward dense.covered1
HZ-3.2-23.2With both a horizon and a path cone, the blobs kept are the intersection of the two keep sets; the check-in manifests held are governed by the horizon alone; sub-manifest nodes by both, the horizon deciding whose trees are held and the path cone eliding within them the nodes no S-card slot that may hold an in-cone path reaches, as the sparse store does; every other structural artifact is held whatever either says.covered2
HZ-3.3-13.3A horizon serializes into the canonical cone form as one member of a distinct kind carrying C's hash and the rule name, canonically, so the cone's digest stays a valid memoization key.covered1
HZ-3.3-23.3A cone with a horizon member is marked with a version distinct from a cone without one, so that an implementation predating this document refuses rather than misreads it.covered1
HZ-3.4-13.4A tool that suggests a C should show what each rule would hold (check-ins and bytes) before the choice is made; this is guidance for the tool, not a wire obligation, and an origin may expose such figures through an interface outside this protocol.covered1
HZ-3.4-23.4A client that wants N recent check-ins or the tip of a branch may name it with the horizon-name pragma, resolved once by the origin, and records only the check-in it resolved to; clients should not send a count or a name in any later request, and should not express a horizon as a date at the protocol layer.covered1
HZ-4.1-14.1A content-horizon clone holds every structural artifact of every age but clusters (under a path cone, of the sub-manifest nodes only those on a path into the cone), every blob an F card of a check-in in the held set names, and elided phantoms for every other blob; it holds, mints and requests no cluster.covered4
HZ-4.1-24.1Composed with a path cone, a content horizon holds, of every check-in of every age, the sub-manifest nodes reached from the manifest through S-card slots that may hold an in-cone path; the others are elided phantoms, which an origin withholds, every in-cone tree is whole, and an operation needing an elided node (a commit, a listing outside the cone) obtains it as the sparse-cone draft's §5.3 provides.covered2
HZ-4.2-14.2A blob is above the horizon when a check-in in the held set names it, directly or through a sub-manifest; elision is the sparse-cone draft's third phantom class with all of its rules: never spontaneously requested, counted distinctly from damage, reclassified by recomputation.covered1
HZ-4.2-24.2A phantom created because a held artifact arrived as a delta against it is a transit phantom whatever its horizon classification.covered2
HZ-4.3-14.3Derived caches and prefix-anchored checkpoints are horizon-independent: their keys do not incorporate the horizon.covered1
HZ-4.3-24.3The derivation of repository state runs over check-in manifests and control artifacts and reads no sub-manifest node; a content horizon holds every one of them, with or without a path cone, so the derivation is the dense repository's.covered1
HZ-4.4-14.4An operation needing a blob below the horizon resolves the elided phantom by demand fetch, targeted, or by moving C (a deepen).covered2
HZ-4.5-14.5A horizon clone does not hold the clusters it is sent. Against an origin whose replies carry horizon-served it does not request a phantom whose only reference is a cluster artifact; against a horizon-ignorant origin it requests the phantoms a received cluster names, as transit, and classifies what arrives. It requests phantoms named by igot cards, by the P, F and S cards of held artifacts, and by delta sources of held artifacts.covered2
HZ-5.1-15.1A structural-horizon clone holds the manifests and nodes of check-ins in the held set and everything they reach through B and S cards, every control, wiki, ticket, event, forum and attachment artifact, the blobs of the content horizon, elided phantoms for the rest, and the seed, which it keeps from every peer; under a path cone, of those trees' nodes only those on a path into the cone.covered3
HZ-5.1-25.1A clone does not enter the structural horizon against a horizon-ignorant peer.covered1
HZ-5.2-15.2.1The seed is a control artifact minted by the origin whose T cards apply to every entry of K (C, and each check-in of K whose primary parent is not in K) every tag in force there in the dense repository, each with the value the dense derivation holds; its D and U cards are those of Section 5.2.2.covered1
HZ-5.2-85.2.1Every seed carries one binding card, T +horizon-seed <C> <rule>, a singleton tag on C whose value is the rule, part of the signed bytes; it is not a tag in force: the clone strips it before derivation, and the origin never counts it toward the one T card a control artifact needs, so with no other tag in force it still mints no seed.covered1
HZ-5.2-135.2.1An origin must not derive a horizon-seed tag into a seed.covered1
HZ-5.2-25.2.2The origin sets each seed's D card to the latest mtime of any tag event in the repository, whether it applied, propagated or cancelled a tag, rounded up to a whole second and written with no fractional part (C's own event time, rounded the same way, in a repository with no tag event); no new tag event moves it earlier, and an origin should also date a seed no earlier than the latest D it has minted and keep that D across restarts, so a shun of the latest tag events does not move it earlier; it changes whenever any tag in the repository changes and the next exchange carries the new seed; its U card is the origin's own seed label, never a user's login, and the label must appear on no artifact the origin writes for sharing; an origin should choose a label no user holds, and a user whose login equals it has their pushed control artifacts refused; a seed is a function of C, the tag state and the latest D its origin has minted, so two origins mint the same seed for the same C and state up to the U card, unless a shun has left one a later D than the other. No seed need be dated later than the seed it replaces.covered6
HZ-5.2-35.2.3A clone never sends its seed to any peer, private-content synchronization included; it holds the seed private or outside the artifact store and applies it at every open.covered1
HZ-5.2-45.2.3An origin must refuse a seed offered to it, identifying one by its own seed label on the U card of a pushed control artifact, judged on the expanded content after any delta is applied, a delta whose base arrives later in the same request included; the refusal is atomic: it stores nothing the request carried and replies with one error card alone, seed refused: a seed is private to the clone that holds it; it is never pushed. It may also refuse a pushed artifact whose name matches a seed the same request offered as held.covered4
HZ-5.2-95.2.3A seed is judged when it first becomes expandable, by whatever path supplies its missing base (a push, a pull or clone from another peer, a local check-in); a delta that then expands to a seed is never crosslinked, applied or served, and is recorded as refused in local state that is never synchronized, never in the shun list; the rest of the transfer that supplied the base is stored and crosslinked normally; the atomic refusal applies to the request that carried the seed whenever the seed can be judged within it.covered4
HZ-5.2-105.2.3An origin refuses only its own label, a control artifact bearing another implementation's seed label being by that label ordinary; it must also refuse, in the same way and with the same error card, any pushed control artifact carrying a horizon-seed T card whatever its U card; only a foreign artifact carrying neither the origin's label nor a binding card is stored as ordinary.covered3
HZ-5.2-145.2.3A store never keeps a seed it did not receive through a horizon-seed announcement: on every receive path (pull, clone and sync) it drops an artifact that is a seed by its own seed label or by a binding card, and stores one that carries neither as an ordinary control artifact; the test is made when the artifact first becomes storable, whether it arrives in full or as a delta completed in a later round; a dropped artifact is not counted as received and must not be requested again in the same session; a seed found on the origin path is dropped the same way; a store still skips a stored seed when deriving.covered11
HZ-5.2-155.2.3Across sessions a store should keep a record of the hashes it dropped, keyed by hash and never synchronized, and skip them when a peer announces them; a store without one asks again and drops again.covered1
HZ-5.2-165.2.3A store that keeps a pushed or received delta whose base it lacks must not announce or serve that delta while it cannot be expanded; dropping such deltas also conforms.covered1
HZ-5.2-55.2.4An origin holding a signing key should sign the seed with the clear-signing envelope.covered1
HZ-5.2-65.2.4A clone that knows its origin's public key verifies every seed's signature and discards an unsigned or wrongly signed seed, falling back to the content horizon; a clone with no key accepts an unsigned seed.covered2
HZ-5.2-115.2.4Before holding a seed, signed or not, a clone must check that it carries exactly one horizon-seed card naming its own store cone's C and rule, and must refuse a seed whose D card is earlier than the held seed's (an equal D is accepted; a deepen discards the held seed first, so the floor restarts at the new C); a refused seed is handled as a wrongly signed one, the clone falling back to the content horizon and reporting it.covered5
HZ-5.2-125.2.4An origin's seed-signing command is configured apart from its check-in signing command and, for SSH, signs under the namespace fossil-horizon-seed, never the check-in namespace; an origin with no seed-signing command configured sends seeds unsigned even when it signs check-ins; PGP relies on the binding card alone.covered2
HZ-5.2-75.2.1When no tag is in force at any check-in the seed would cover, the origin mints no seed and serves the request at the content level, since a control artifact carries at least one T card.covered1
HZ-5.3-15.3A boundary hash is a P-card parent, not in K, of any check-in manifest the clone holds, a held baseline below C included; a clone classifies a labelled boundary hash as an elided phantom and an unlabelled unheld reference as a transit phantom, which it requests.covered2
HZ-5.3-25.3When a new check-in forks from below the horizon, or a new delta manifest reaches a baseline below it, the origin labels the new parents in the round that delivers the manifest naming them; a clone requests an unheld unlabelled parent, and an origin does not send one it does not keep.covered1
HZ-5.4-15.4A boundary hash should be rendered as the horizon and is never described as damage; verification reports manifests below the horizon as elided, distinctly from damage.covered2
HZ-5.5-15.5An operation needing history below the horizon (a merge base, a symbolic name, a checkout, diff or annotate below C, a bisection) detects the crossing, names the horizon in its diagnostic and offers the stated remedy.covered4
HZ-5.5-25.5An implementation never merges against a base it does not hold.covered1
HZ-5.5-35.5Whenever the ancestry of either side of a merge crosses the horizon the clone asks the origin for the base, even when it finds a common ancestor among what it holds, and deepens to the base when it lies below the horizon.covered1
HZ-5.6-15.6A clone requests the seed at each synchronization, naming the seed it holds; the origin replies with a new seed only when it differs, keeping no per-client state, and the clone replaces the seed it holds with the new one whole.covered1
HZ-5.7-15.7A commit from a structural horizon is an ordinary commit: on an existing branch it writes no branch tag; creating a branch it writes the repository-state T cards, the parent branch's cancellation included.covered1
HZ-5.7-25.7An origin should check a pushed cancellation against its own derivation and refuse on disagreement, naming the stale seed and the parent's branch, judging the check-in's expanded content, a delta whose base arrives later in the same request included; it admits the check-in when the push or its store carries a control artifact cancelling the parent's branch tag on it.covered2
HZ-5.8-15.8A deepen names an ancestor C' of C, recomputes the held set and synchronizes at C'; nothing held is replaced, and the deepening clone discards the old seed before applying the new one.covered3
HZ-5.8-25.8A deepen that must reach a check-in outside K names as C' a common ancestor of C and that check-in, computed locally or asked of the origin; when none is known it is refused naming the remedy, a fresh clone with an earlier horizon, and C never moves to a check-in that is not its ancestor.covered1
HZ-5.9-15.9An implementation should offer seed verification by deepening as a verification mode.covered1
HZ-6.1-16.1A horizon-scoped request carries at most one pragma horizon <hash> <rule>, may carry path-cone pragmas (the keep set is then the intersection), and adds pragma horizon-structural for the structural horizon; any request may carry pragma horizon-cursor.covered2
HZ-6.1-26.1A request may carry pragma horizon-name <name> <rule> <depth> in place of pragma horizon, never both: name is tip, a symbolic name or a full check-in hash, as a card token with Fossil's \s escaping; rule as for pragma horizon; depth required, plain base-10 digits that fit an unsigned 32-bit integer, 0 the named check-in itself; the structural, seed, cursor and path-cone pragmas combine with it as with pragma horizon. A client sends it only in the first request of a clone; every later request of the clone, and every later pull, sync or deepen, sends pragma horizon <hash> <rule> with the resolved hash, and the store records the hash, never the name.covered4
HZ-6.2-16.2An origin receiving a horizon pragma computes the held set over the dense graph and restricts the blobs it sends; for a structural request it also restricts manifests and nodes, sends every other structural artifact, the boundary labels and the seed, and bounds the per-round walk.covered4
HZ-6.2-26.2An origin should not send cluster artifacts in reply to a horizon-scoped request.covered1
HZ-6.2-36.2.1An origin does not send, in reply to a horizon-scoped request, a delta whose base is outside the keep set; it sends that artifact in full, may send in-keep-set deltas verbatim, should bound reconstruction per round, and may send a delta verbatim when it cannot reconstruct it.covered1
HZ-6.2-46.2.2For a structural request the origin emits pragma horizon-below for every boundary hash the manifests in the reply introduce, the parents of every check-in manifest a baseline below C included, no later than the reply carrying the first manifest that names it.covered1
HZ-6.2-56.2.3A structural request carries pragma horizon-seed with the held seed or '-'; the origin announces a differing seed with the pragma before its file card; the client verifies the bytes hash to the announced name and parse as a control artifact, drops a card failing either, routes it to its seed holding, and never announces or sends it.covered1
HZ-6.2-66.2.3An origin does not advertise the structural level unless it sends a seed in the same reply or the client's offered seed is the one it would send; because the D card is fixed by the repository's tag events and the latest D the origin has minted, two mints over unchanged state produce the same name.covered2
HZ-6.2-76.2.4A client may ask pragma horizon-mergebase <primary> <secondary> [<secondary>]; an origin that can answer repeats every hash of the query in the order asked and appends Fossil's pivot of the primary over the secondaries, or '-' when no common ancestor exists, and bounds the ancestry walk; an answer whose hashes do not repeat the query is no answer.covered1
HZ-6.2-166.2.4In a merge the primary is the check-in merged in and the secondaries are the checkout and each plain merge pending in it (not a cherry-pick, backout or integrate); a query carries at most two secondaries and an origin answers none with more, nor one naming a check-in it does not hold.covered1
HZ-6.2-86.2.5An origin emits pragma horizon-served <level> [<url>] in every reply to a horizon request; a client does not enter the structural horizon unless its first reply carried structural, and should report the mode a transfer used.covered3
HZ-6.2-96.2An origin should keep its classification keyed by the cone digest and the store prefix it classified, extend it by the artifacts appended since, and recompute in full only when an appended artifact carries a name a held P, B or S card cited while it was absent.covered1
HZ-6.2-106.2An origin should read each structural artifact's kind and P, B, S, F and A references once per store into a cone-independent graph keyed to the same prefix, extend it by appended artifacts, and classify every cone over that graph.covered1
HZ-6.2-116.2.6An origin that classified a request emits pragma horizon-cursor <n> in every reply, n its artifact-sequence position through which the reply was served; receiving a cursor it announces no artifact at or below it and every kept artifact above it the request did not name, and after a reclassification, or after an appended tree reaches through an in-cone slot an older node the classification withheld (which it then keeps), answers a request carrying a cursor below the position it recorded once as if it carried none; it announces with igot only in reply to a request that pulls, and a reply to a push-only request announces nothing, cursor or not.covered6
HZ-6.2-146.2When a horizon request also carries path members, the origin withholds at either depth the sub-manifest nodes of the trees it keeps that no S-card slot that may hold an in-cone path reaches, neither sending them in a clone nor answering a request for them; a request without path members receives every node of those trees.covered1
HZ-6.2-156.2Under a content horizon with path members the origin's walk should be kept like the classification: descending only slots that may reach the cone, visiting each node once per bound it is reached under (a last slot's bound its parent's, a wider bound deciding for a narrower), and recording what it walked, so that a later request walks only the trees appended since.covered1
HZ-6.2-126.2.6A client that converged records the last reply's cursor and its own artifact count per origin and sends the cursor on every request to that origin; it may then announce nothing on a pull-only request, must still announce on a request that sends but may announce only artifacts appended after the recorded count, and advances the count only past artifacts the origin holds.covered2
HZ-6.2-136.2.6The cursor changes what is announced, never what is answered: an origin answers a gimme for any kept artifact whatever cursor the request carried, a client requests every phantom it wants as without one, and either side may drop the cursor and fall back to a full announcement.covered2
HZ-6.2-176.2.7An origin resolves a horizon-name over its dense repository: a well-formed full hash (40 or 64 hex digits) is looked up as a hash first and names that check-in if one has it, otherwise it is tried as a symbolic name; tip is the most recent check-in; any other name is the most recent check-in carrying sym-<name> as an active tag (singleton or propagated, not cancelled), covering branches and tags alike; most recent means the highest event mtime with a tie going to the lexicographically lowest full hash, never a local row number, and a hash prefix is never accepted; it then steps back depth times along primary parents, stopping at a check-in with none. Before any file card and before horizon-served it emits pragma horizon-resolved <hash> <steps>, C's full hash and the steps taken, and serves the request as if it carried pragma horizon <hash> <rule>, minting any seed for that C.covered7
HZ-6.2-186.2.7A horizon-name that resolves to nothing, a malformed depth, or both pragma forms in one request is answered with one error card and nothing else, horizon\sname\snot\sfound:\s<name> or malformed\shorizon-name\spragma; login and authorization errors come first and a name error after them, as the single error card; the client then fails the clone and leaves nothing on disk.covered4
HZ-6.2-196.2.7A client whose first reply carries horizon-resolved takes its hash as C and reports when the steps taken are fewer than the depth requested, history having run out.covered1
HZ-6.2-206.2.7The client fails the clone and leaves nothing on disk when horizon-resolved names a malformed hash, takes more steps than the depth requested, arrives after any file card or in reply to a request that sent no horizon-name, or when the clone ends without the resolved check-in having been received.covered1
HZ-6.2-216.2.7A client whose reply carries no horizon-resolved completes the dense transfer, resolves the name and depth over what it holds by the same rule, classifies locally at the content horizon (Section 6.3), records the hash and reports that the name was resolved locally; a structural request against such a peer falls back to the content horizon.covered2
HZ-6.3-16.3Against a horizon-ignorant peer a content-horizon client classifies locally, stores the blobs above the horizon, records elided phantoms and reports the counts; a structural clone request falls back to the content horizon for that transfer and reports that it did.covered3
HZ-6.3-26.3A store at the structural horizon whose pull or sync replies carry no horizon-served structural falls back to the content horizon at the same C and rule, records that depth, discards its seed, fetches the manifests and nodes below C, and reports that it did.covered2
HZ-6.4-16.4A server over a horizon clone refuses a dense clone request, and a horizon request whose held set is not a subset of its own, with one error card and no content; the requesting client treats that reply as fatal.covered4
HZ-8-18The origin's held-set walk and merge-base query carry the depth and visited-node bounds of any server-side graph walk, and delta inflation on the serve path is bounded by the round's batch limit.covered2