docs(cache): state the .publish-* gap as a ticket, not a present state

The contract block asserted that neither side reclaims .publish-new- 'today'.
True when written and about to stop being true: gitdan#30 tracks adding both
.publish-* prefixes to the arbiter's enumeration, and a sibling track is
landing it this round. A comment that dates itself against a merge in flight
is worse than no comment.

Rewords all four sites (cache-lib.sh, publish-snapshot.sh, and README's table
row and prose) to reference gitdan#30 and keep the mechanism that made the
shape worth catching — .publish-new- is tagged per job per run exactly as
.stage- is — rather than the arbiter's momentary contents. The rule itself is
unchanged; it is the durable part, and it is what found this.

Adds the counting check while there: the five names here and the prefixes
ci-cache-reclaim.sh enumerates are meant to be the same length, so a mismatch
is the cheapest signal that one side gained a shape without telling the other.
This commit is contained in:
2026-08-24 12:56:18 -05:00
parent 0cf6cc5973
commit 0118c28f01
3 changed files with 28 additions and 15 deletions
+11 -6
View File
@@ -55,12 +55,17 @@
# is invisible: an unreclaimed staging tree is a full clone of a multi-GB
# target dir on the one volume whose entire problem is disk.
#
# Of the five above, the arbiter enumerates `.stage-`, `.evicting-` and
# `.reading-`. The two `.publish-*` names predate the contract and are not in
# it, which is why `.publish-new-` — tagged per job per run exactly as
# `.stage-` is — is a shape neither side reclaims today. Closing that is a
# change over there, not here; the rule above is what stops the list growing
# another one.
# The two `.publish-*` names predate the contract and were outside it when this
# block was written — the rule catching an uncovered shape on its first
# application. `.publish-new-` is the one that mattered: it is tagged per job
# per run exactly as `.stage-` is, so a publisher killed before the swap
# strands a tree under a name no later run of that script matches, which is
# precisely the shape only the arbiter can reach. Bringing both in is tracked
# as daniel/gitdan#30.
#
# The two lists are meant to be the same length. A shape here without a prefix
# there is one side having changed without telling the other, and it is
# cheapest to notice by counting.
#
# The two staleness constants the arbiter mirrors are part of the same
# contract, and that half has a direction to it — see CACHE_READ_STALE_SECONDS
+7 -6
View File
@@ -55,12 +55,13 @@ DST=$(snapshot_dir_for "$ROOT" "$OWN_KEY")
# `.publish-old-` and `.publish-new-` are dot-prefixed names under a cache
# root, so the cross-repo contract at the top of cache-lib.sh covers them:
# renaming either, or adding a third, requires a matching prefix in
# daniel/gitdan's ci-cache-reclaim.sh. Neither is in its list today, and
# `.publish-new-` is the shape that most needs to be — it is tagged per job per
# run, so a publisher killed between staging its snapshot and the swap below
# strands a full hardlink clone that no later run of this script will ever
# match. `.publish-old-` is milder: the sweep further down reclaims it on the
# next publish of the same key.
# daniel/gitdan's ci-cache-reclaim.sh. Both were outside its list when that
# contract was written, and `.publish-new-` is why it mattered: it is tagged
# per job per run, so a publisher killed between staging its snapshot and the
# swap below strands a full hardlink clone that no later run of this script
# will ever match. `.publish-old-` is milder the sweep further down reclaims
# it on the next publish of the same key. Bringing both under the arbiter's
# enumeration is tracked as daniel/gitdan#30.
OLD="${ROOT}/.publish-old-${OWN_KEY}-${TAG}"
SNAP_NAME=$(basename "$DST")
GRACE="${CACHE_READ_GRACE_SECONDS}"