Artifact 821dd715d950228ef1aa06a1214b3e456ae60160b0fb14a7bc2415b9f39a6789:
- File
conformance/rfcs/erratum/repo-state-01-s6.2-self-cancelling-sym-tag.md
— part of check-in
[f61c8174a8]
at
2026-10-17 20:27:53
on branch main
— test(conformance): re-pin the -01 drafts with the 2026-10-14/16 errata (#436)
zit check-in 3f86ff4261 applies six more errata to the -01 drafts. Copy the three drafts and the five new -01 errata files, re-pin their SHA-256 in the requirements tables, and record the check-in in the README.
The draft text changes add six requirements and reword two:
- AF-4.7.3-2: a named delta's delete markers are filtered out of a delta-of-delta's file set and lookups. - AF-4.7.8-1: an absent and a present empty J value decode alike. - AF-6.2-7: the Z verification state is read from the bytes at n-35 and n-34, not from card lines. - RS-5.3-3: a cancel keeps its card's value on the row it writes. - RS-5.3-6: the event table and propagation treat that value as null. - RS-5.3-7: an artifact's tag cards apply in card order. - RS-6.2-4: a branch root carrying *sym-NAME and -sym-NAME keeps the tag. - SP-6.6-4: a client recognizes a refusal by its leading text.
go-libfossil already behaves this way. Each row has a case, checked against fossil 2.28 where the harness does: 421 requirements, 420 covered, 1 partial (SP-9.5-7, as before).
The repo-state §5.3 step 3 change is filed in zit as a -00 erratum and is not pinned, like the other -00 errata; the -01 draft carries its text. (user: [email protected], size: 4848) [annotate] [blame] [check-ins using]
Erratum: draft-fossil-repo-state-01 §6.2 and §5.3
| Document | draft-fossil-repo-state-01 |
| Section | 6.2, Branch creation (a sym tag both applied and cancelled on the root); 5.3, Direct Application Procedure, step 1 |
| Type | Technical (a combined effect left undefined that Fossil determines) |
| Status | Applied in draft-fossil-repo-state-01 (2026-10-14) |
| Reported | 2026-10-14 |
| Submitter | Dan Mestas |
| Found via | A review of the drafts from libfossil; confirmed by running Fossil 2.28 and reading its source |
1. Summary
§6.2 records that fossil branch new can write both T *sym-NAME * and
T -sym-NAME * on a branch root, when the parent already carries a
propagating sym-NAME, and then says "this document does not define their
combined effect". Fossil determines it. Crosslink applies an artifact's tag
cards one at a time in card order, all with the artifact's own mtime, so the
§5.3 skip rule decides: the * card sorts first and writes the row, and the
- card meets a row with an equal mtime and is skipped. The root keeps the
propagating tag.
§5.3 calls the equal-mtime case implementation-defined because the winner depends on write order. For two cards of one artifact the order is fixed by the artifact, so the case is defined once the draft says the cards are applied in card order.
2. The text in error
Page 18 (§6.2, informative paragraph):
If the parent itself carries a propagating sym-* tag of the new branch's own name, branch new emits both the propagating card and a cancel card for that name; this document does not define their combined effect.
Page 15 (§5.3 step 1):
If two competing applications for the same (tag, artifact) pair carry exactly equal mtime, the >= skip rule makes the winner depend on write order, so that equal-mtime case is implementation-defined rather than crosslink-order-independent.
3. What Fossil implements
manifest_crosslink() in src/manifest.c:
for(i=0; i<p->nTag; i++){
...
switch( p->aTag[i].zName[0] ){
case '-': type = 0; break;
case '+': type = 1; break;
case '*': type = 2; break;
}
tag_insert(&p->aTag[i].zName[1], type, p->aTag[i].zValue,
rid, p->rDate, tid);
}
Every card of the artifact goes to tag_insert() with the same mtime,
p->rDate, in the order the cards appear. The artifact format sorts T
cards by their full name token, sign included ([FossilArtifact] §4.7.16),
and * (0x2A) and + (0x2B) sort before - (0x2D). tag_insert() skips a
write when the existing row's mtime is greater than or equal to the
incoming one (§5.3 step 1).
Checked with Fossil 2.28 [52445a27f1]: commit c1 on trunk; commit c2 with
--branch feat; add a closed tag to c2; fossil branch new feat c2. The
new root's manifest carries
T *branch * feat
T *sym-feat *
T -sym-feat *
and its tagxref rows after crosslink, and again after fossil rebuild, are
| tag | tagtype | srcid |
|---|---|---|
branch |
2 (feat) |
the root |
sym-feat |
2 | the root |
The cancel left nothing behind. zit trunk, given the same repository
through import-fossil, lists branch feat and sym-feat as active on the
root.
4. Corrected text
§5.3 step 1, replace the sentence quoted in Section 2 with:
If two competing applications for the same (tag, artifact) pair carry exactly equal mtime, the >= skip rule makes the winner depend on write order. The tag cards of one artifact MUST be applied in the order they appear in the artifact, all with that artifact's mtime, so between two cards of one artifact the first in card order wins. Between applications from different artifacts with equal mtime the case is implementation-defined rather than crosslink-order-independent.
§6.2, replace the sentence quoted in Section 2 with:
If the parent itself carries a propagating sym-* tag of the new branch's own name, branch new emits both the propagating card and a cancel card for that name. The card order decides their combined effect (Section 5.3, step 1): the sign is part of the ordering key ([FossilArtifact], Section 4.7.16), so the * card precedes the - card, and the cancel meets the row the * card wrote with an equal mtime and is skipped. The root carries the propagating sym-* tag as if the cancel card were absent.
5. Observable consequence of the uncorrected text
An implementation that applies a cancel last regardless of card order, or
that treats the case as undefined and picks the cancel, leaves the root
without its own sym-NAME. Branch listings and name resolution for that
branch then differ from Fossil's for the same artifacts.
6. Implementations
zit already applies an artifact's tag cards in card order and matches Fossil. No change is needed.