Skip to content
zit Erratum — draft-fossil-artifact-format-00 §4.6.3, §5.3
Login

Erratum — draft-fossil-artifact-format-00 §4.6.3, §5.3

Document draft-fossil-artifact-format-00
Section 4.6.3 — Reserved Filenames; 5.3 — Type Determination
Type Technical (divergence from the reference implementation)
Status Applied in draft-fossil-artifact-format-01 (2026-10-12)
Reported 2026-10-11
Submitter Dan Mestas
Found via Checking an illustrated reading of the draft against Fossil 2.28

1. Summary

§5.3 says the F card sets the artifact type to MANIFEST unconditionally, and that the untyped fallback is therefore reachable only through the C or P card. In Fossil an F card whose current filename is reserved (§4.6.3) is dropped before it sets the type. Such a card leaves the type unset, so the artifact can reach the fallback, become a CONTROL artifact and fail the allowed-card check because it contains an F card. An earlier copy of the draft said this correctly; the current text removed it.

2. Location

§5.3, Table 5 and the paragraph introducing it:

Thirteen card letters are type-setting; each unconditionally assigns the artifact type when processed …

B, F, Q, R MANIFEST

§5.3, fallback paragraph:

In practice this fallback is reachable only via the C card or P card (the F card already sets MANIFEST directly), because the C and P card grammars never assign a type.

§4.6.3 says nothing about where the drop falls relative to type assignment.

3. The divergence

Verified against Fossil 2.28 (52445a27f1) by source reading and by running its parser.

3.1 Source

In manifest_parse()'s F-card case (src/manifest.c:678), the reserved-name test (:710) decrements nFile and breaks out of the case (:714-715). The type assignment p->type = CFTYPE_MANIFEST comes after it (:721), so a dropped card never reaches it. The card's letter is still recorded in seenCard (:564), because that happens before the switch.

After the loop, the fallback (:1076-1082) tests p->zComment, p->nFile and p->nParent. A dropped card does not count towards nFile, so an artifact whose only F cards were reserved, and which has no C or P card, becomes CONTROL. The allowed-card check (:1086) then rejects it, because F is not in CONTROL's allowed set DTUZ (:134).

3.2 Experiment

The SHA1 below is a valid hash token. Each file ends with a correct Z card.

Input cards fossil test-parse-manifest
D, F foo.txt <h>, Z ok (MANIFEST via F)
D, F _FOSSIL_ <h>, Z ERROR: line 3: F-card in tag
D, F _FOSSIL_ <h>, T +sym-x *, U u, Z ERROR: line 5: F-card in tag
C x, D, F _FOSSIL_ <h>, Z ok (MANIFEST via fallback on C)

The second and third rows reach the fallback with no C or P card, which §5.3 says cannot happen. The third row also shows that a dropped F card does not fit cleanly into a control artifact either: F is still a seen card.

4. Impact

A parser built to §5.3 sets MANIFEST when it reads a reserved-name F card. It accepts the second-row artifact as an empty manifest where Fossil rejects it, so the two disagree on which artifacts are valid. That is an interoperability failure in the direction that matters: the reimplementation accepts and cross-links content that every Fossil peer refuses.

The case is narrow (reserved names reach manifests only through old writers), but the draft states the opposite of the observable behavior as a fact about reachability.

5. Correction

§4.6.3, after "Dropping removes the card from the effective file set.":

    An F card whose decoded current filename is reserved MUST be silently
    dropped, not rejected.  Dropping removes the card from the effective
-   file set.  Such names leaked into historical manifests, and existing
+   file set.  The drop occurs before the F card would set the artifact
+   type to MANIFEST (Section 5.3): a dropped card assigns no type and
+   records no file entry, though its letter still counts as present
+   for the allowed-card check of Section 5.2.  Such names leaked into
+   historical manifests, and existing
    documentation contains no mention of this behavior (Appendix C); the

§5.3, introduction to Table 5:

-   cards.  Thirteen card letters are type-setting; each unconditionally
-   assigns the artifact type when processed, with no guard against a
-   previously assigned value:
+   cards.  Thirteen card letters are type-setting; each assigns the
+   artifact type when processed, with no guard against a previously
+   assigned value.  The one exception is an F card dropped for a
+   reserved filename (Section 4.6.3), which assigns nothing:

§5.3, fallback paragraph:

-   In practice this fallback is reachable only via the C card or P card
-   (the F card already sets MANIFEST directly), because the C and P card
-   grammars never assign a type.  The allowed-card and required-card
+   In practice this fallback is reachable via the C card or P card,
+   whose grammars never assign a type, and also when every F card was
+   dropped for a reserved filename.  In the last case, with no C card
+   and no P card, the artifact resolves to CONTROL and is then rejected
+   because F is not an allowed CONTROL card.  The allowed-card and
+   required-card

6. Rationale

7. Verification


Prepared against draft-fossil-artifact-format-00. The RFC remains the oracle; the reference implementation is used only to confirm the observable behavior.