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
+10 -3
View File
@@ -245,7 +245,7 @@ block is the canonical description; this side owns the names.
| name | produced by | if the job dies holding it |
|---|---|---|
| `.stage-<tag>` | `cache-lib.sh`, `hardlink_clone_into()` | stranded; only the arbiter reclaims it |
| `.publish-new-<tag>` | `publish-snapshot.sh` | stranded, and not in the arbiter's list |
| `.publish-new-<tag>` | `publish-snapshot.sh` | stranded; see `daniel/gitdan#30` |
| `.publish-old-<key>-<tag>` | `publish-snapshot.sh` | swept by the next publish of that key |
| `.evicting-<name>-<pid>` | `prune-cache.sh`, `evict_dir()` | swept at the start of the next prune pass |
| `.reading-<source>-<tag>` | `cache-lib.sh`, `reader_lock_acquire()` | not garbage — see below |
@@ -263,8 +263,15 @@ renaming one. That script enumerates by explicit prefix rather than by dotglob
stream alongside the trees they protect — so a name it has not been told about
is not handled conservatively, it is invisible, and an unreclaimed staging tree
is a full clone of a multi-GB target dir on the one volume whose entire problem
is disk. `.publish-new-` is the standing example: it strands exactly as
`.stage-` does and is in neither side's sweep.
is disk. `.publish-new-` is the worked example: the two `.publish-*` names were
outside the contract when it was written, and `.publish-new-` strands exactly
as `.stage-` does, so it is the one that needed catching. Bringing both under
the arbiter's enumeration is tracked as `daniel/gitdan#30`.
The two lists are meant to be the same length — the five names above, and the
prefixes `ci-cache-reclaim.sh` enumerates. A mismatch means one side gained a
shape without telling the other, which is the drift the rule exists to catch
and the cheapest thing to check.
**The staleness constants are part of the same contract, and that half has a
direction.** `CACHE_READ_STALE_SECONDS` (`cache-lib.sh`) and