Artifact 7e8ecce19eb50e460aa4ff03fb7128e6216475c7bf51fff2ffbdb1855535f74f:
- File docs/rfcs/erratum/repo-state-01-s8.3-ckout-ci-plus.md — part of check-in [3221a15806] at 2026-10-13 14:32:36 on branch trunk — repo-state §8.3: the ci+ keyword applies to the whole name only (user: dmestas, size: 5668) [annotate] [blame] [check-ins using]
Erratum — draft-fossil-repo-state-01 §8.3
| Document | draft-fossil-repo-state-01 |
| Section | 8.3 — Procedure, step 3 (the ckout keyword) |
| Type | Technical (the keyword is recognized for a narrower request type than the draft says) |
| Status | Applied in draft-fossil-repo-state-01 (2026-10-13) |
| Reported | 2026-10-13 |
| Submitter | Dan Mestas |
| Found via | Reading Fossil 2.29's symbolic_name_to_rid() against §8.3 |
1. Summary
§8.3 says ckout resolves to the checkout sentinel "only when the
requested type is "ci" or a checkout-inclusive type". Fossil recognizes it
only for the request type ci+. For ci, for an unconstrained request,
and for any other type, ckout is not a keyword and falls through to the
remaining forms, where it resolves like any other name (for example to a
check-in tagged ckout), or not at all. The draft also leaves "checkout-
inclusive type" undefined, and does not say that the keyword needs an
open checkout. The "ci+" semantics also apply only to the name as given:
Fossil rewrites the type to "ci" before the forms that resolve a
contained name and before the trailing-punctuation retry, so ckout.
under "ci+" names a tag called ckout, not the checkout.
2. Location
§8.3, step 3, the ckout bullet:
* *ckout* (only when the requested type is "ci" or a checkout-
inclusive type) resolves to the sentinel checkout RID rather
than an ordinary artifact RID, and marks that a local checkout
is in use.
3. The reference behavior
Verified against Fossil 2.29 source.
symbolic_name_to_rid()(src/name.c:482-536) setsisCheckin = 1for typeciandisCheckin = 2for typeci+, rewritingci+tocifor the rest of the lookup (:493-499).- The keyword block runs only when the type is unconstrained or a
check-in type and a checkout is open (
0<ridCkout,:519). Within it,current,prev,previousandnextneed no more, butckoutis tested asisCheckin>1 && fossil_strcmp(zTag, "ckout")==0(:529), so onlyci+matches. It returnsRID_CKOUT(RID_MAX+1,:30-34) and setsg.localOpento the checkout's RID (:530-532). - The function's header comment (
:462-468) documents the same: "A value of "ci+" works like "ci" but adds these semantics: if zTag is "ckout" and a checkout is open, "ci+" causes RID_CKOUT to be returned". name_to_uuid()(:834-836) mapsRID_CKOUTback to the checkout's RID before reading its hash.- The rewrite of
ci+toci(:497-498) happens before the forms that resolve a contained name,root:,start:andmerge-in:(:585,:591,:597), and before the trailing-punctuation retry (:730,:739), all of which pass the rewritten type on. The keyword therefore applies only whenckoutis the whole name as given. - No caller in Fossil 2.29's
src/passesci+; the only occurrences of the string are inname.c. Commands that acceptckout(for example the/docpage,src/doc.c:973,:1033) test for it themselves before resolving a name.
4. Impact
Observable only in corner cases. A resolver that follows the draft
returns the sentinel for ckout with type ci, where Fossil resolves
ckout as an ordinary name; a repository with a ckout tag then gives a
different check-in, and one without such a tag gives no check-in in
Fossil and the sentinel in the reader's resolver.
5. Correction
§8.3, step 3:
- * *ckout* (only when the requested type is "ci" or a checkout-
- inclusive type) resolves to the sentinel checkout RID rather
- than an ordinary artifact RID, and marks that a local checkout
- is in use.
+ * *ckout* is a keyword only when the requested type is "ci+"
+ and a local checkout is open. It then resolves to the
+ sentinel checkout RID rather than an ordinary artifact RID,
+ and marks that a local checkout is in use; a caller that
+ needs the check-in itself maps the sentinel to the checkout's
+ RID. The type "ci+" otherwise behaves as "ci". For any other
+ requested type, including "ci" and an unconstrained request,
+ or when no checkout is open, "ckout" is not a keyword and is
+ resolved by the remaining forms of this procedure like any
+ other name. The "ci+" semantics apply only to the name as
+ given: the trailing-punctuation retry below and every form
+ that resolves a contained name (root:, start:, merge-in:)
+ resolve that name under "ci", where "ckout" is an ordinary
+ name.
6. Rationale
Names the one type that enables the keyword, replacing the undefined
"checkout-inclusive type", states the open-checkout condition the other
keywords in the list already carry, and says what happens to the name
when the keyword does not apply, so a resolver gives Fossil's answer for
ckout under ci.
7. Verification
- Source: Fossil 2.29
src/name.c:30-34,:462-468,:482-536,:834-836;src/doc.c:973,:1033. - Run: Fossil 2.28 in an open checkout.
fossil info currentresolves;fossil info ckoutfails withcannot resolve name: ckout; afterfossil tag add ckouton another check-in,fossil info ckoutshows that check-in, not the checkout. - Not run: no Fossil 2.29 command passes
ci+, so the sentinel path is read from the source only. - Run (go-libfossil, Fossil 2.28):
fossil test-name-to-id --type ci+ ckout.with the checkout on c2 and a tag named ckout on c1 answers c1, the tag.