Skip to content
zit Erratum — draft-fossil-repo-state-00 §6.2
Login

Erratum — draft-fossil-repo-state-00 §6.2

Document draft-fossil-repo-state-00
Section 6.2 — Branch creation (symbolic-tag cancels; name-reuse check)
Type Compatibility note (the draft is correct; Fossil's two creation commands differ from each other and, in corner cases, from the draft)
Status Applied in draft-fossil-repo-state-01 (2026-10-12)
Reported 2026-10-11
Submitter Dan Mestas
Found via Cross-check of the illustrated reading and an older draft copy against Fossil 2.28 src/branch.c and src/checkin.c; confirmed by running Fossil 2.28

1. Summary

§6.2 is right as written. Two things Fossil does around it are worth recording, because an implementer comparing manifests or behavior against Fossil will meet them:

  1. The cancel cards differ by command. fossil commit --branch cancels only the propagating sym-* tags of the parent, which are exactly the ones the new root would inherit. fossil branch new cancels every active sym-* tag of the parent, singletons included, so its root manifest also carries cancel cards for tags the root would never have inherited. The active tags of the root are the same either way.
  2. Fossil's reuse check is not §9's open-leaf test. It requires a propagating branch tag and treats only a singleton closed tag as closing. A branch whose leaf carries a propagated closed tag is listed as closed by fossil branch list, yet fossil branch new refuses to reuse its name as open. fossil commit --branch --force skips the check entirely.

2. Location

§6.2. Current text:

Branch creation MUST also cancel every pre-existing active sym-* tag on the branch-root check-in by emitting corresponding - (cancel) cards, because symbolic tags are otherwise inherited from a check-in's parent.

Branch creation MUST NOT succeed if the requested branch name already names an open branch. An implementation MUST check openness of the candidate name before emitting the branch-root manifest and MUST reject the operation if a branch of that name is already open.

3. The divergence

Verified against Fossil 2.28 by reading the source and by running it.

3.1 Cancel cards

Both commands read the tags of the parent check-in, since the root does not exist yet.

Run: trunk check-in c4 carries singleton sym-rel, sym-release, sym-relx and inherits propagating sym-prop and sym-trunk.

$ fossil branch new b1 c4          $ fossil commit --branch b2   (from c4)
T *branch * b1                     T *branch * b2
T *sym-b1 *                        T *sym-b2 *
T -sym-prop *                      T -sym-prop *
T -sym-rel *                       T -sym-trunk *
T -sym-release *
T -sym-relx *
T -sym-trunk *

The three extra cards in b1 cancel nothing the root had; they leave cancel-type rows on the root and nothing else. §6.2's "every pre-existing active sym-* tag on the branch-root check-in" is the inherited, propagating set, which is what commit --branch emits. Both commands satisfy it.

3.2 Reuse check

branch_is_open() (src/branch.c:388-401), used by both commands (src/branch.c:116, src/checkin.c:2735-2741):

SELECT rid FROM tagxref AS ox
 WHERE tagid=<branch> AND tagtype=2 AND value=<name>
   AND rid IN leaf
   AND NOT EXISTS(SELECT 1 FROM tagxref AS ix
                   WHERE tagid=<closed> AND tagtype=1 AND ox.rid=ix.rid)

§9's open-leaf test, and Fossil's own branch listing (src/branch.c:249-250, src/leaf.c:148-153), use tagtype>0 for both tags. The two tests disagree in two corner cases:

Leaf of branch X carries §9 / fossil branch list branch_is_open
propagated *closed closed open: reuse refused
singleton +branch X open not open: reuse allowed

Run (first row): fossil tag add --raw --propagate closed b1; fossil branch list -c lists b1; fossil branch new b1 trunk fails with an open branch named "b1" already exists. The control, a singleton closed on b2, lets fossil branch new b2 trunk succeed. The second row is from the source only; Fossil never writes a singleton branch tag itself.

In addition, commit --branch skips the check under --force and for the name private (src/checkin.c:2735-2737), so Fossil can create a second open branch of an existing name, which §6.2 forbids.

4. Impact

Small. The cancel-card difference is visible only in the root manifest's bytes and in cancel rows on the root; resolution, branch membership and leaves are unchanged. The reuse-check difference needs a propagated closed tag or a singleton branch tag, neither of which Fossil's own branch commands write, or the undocumented --force. Fossil's check disagreeing with its own branch listing is Fossil's to fix; the draft should not copy it.

5. Correction

No normative change. Add an informative paragraph at the end of §6.2:

   This paragraph is informative.  Fossil computes the cancel cards from
   the parent check-in.  Its commit --branch command emits them only for
   the parent's propagating sym-* tags other than the new branch's own,
   which are the tags the root would inherit.  Its branch new command
   emits them for every active sym-* tag of the parent, singletons
   included; the extra cards cancel nothing on the root.  Fossil's
   name-reuse check treats a branch as open only when a leaf carries a
   propagating branch tag and no singleton closed tag, which differs
   from the open-leaf test of Section 9 when a leaf carries a propagated
   closed tag or a singleton branch tag, and commit --branch skips the
   check when forced.

6. Rationale

7. Verification


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