Author SHA1 Message Date
claudeandClaude Opus 5 4da6e8d30f docs(cache): write down the producer half of the depended-upon names contract
daniel/gitdan's ci-cache-reclaim.sh hard-codes four dot-prefixed names it
reads to make correctness decisions but never reclaims as leftovers —
.ci-lock-*, .cache-last-used, .gitea-last-used, .ci-keep — none of which
carried a matching note here (gitdan#32, the follow-up shape to #28/#30
that #7/PR #8 covered for the leftover names specifically).

Of the four, this repo actually produces two:

- .ci-lock-<id>, written by scripts/cache-lock.sh (acquire/release) and
  cache-lib.sh's write_cache_lock(). Documents the contract at
  cache-lock.sh's header, the site someone renaming the marker would
  most likely be editing.
- .cache-last-used, stamped every run by cargo-cache/action.yml. Documents
  the contract at the exact line that writes it.

The other two are read by gitdan's script but produced by nothing in this
repo: .gitea-last-used is a legacy naming convention individual repos
used before adopting the shared cargo-cache action (nothing here writes
it today), and .ci-keep is a per-repo, hand-placed opt-out any consuming
repo's own workflow may drop directly into a cache directory, with no
single owner. Both get a paragraph in README.md's new subsection
explaining why no producer-side counterpart exists for them, rather than
inventing an owner this repo doesn't have.

README.md's "Scratch names in a cache root are a cross-repo contract"
section gains a new subsection, "Names this repo doesn't reclaim, but
the arbiter depends on", covering all four and pointing at gitdan's
DEPENDED-UPON NAMES CONTRACT block as the canonical description.

No behaviour change: comments and docs only.

Ref: gitdan#32. Consumer-side counterpart: daniel/gitdan (this branch's
sibling PR).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJHKJFJVUjnvVsemVBnvrd
2026-08-24 17:08:54 -05:00
3 changed files with 51 additions and 0 deletions
+30
View File
@@ -287,6 +287,36 @@ Lowering either here needs no coordination: the arbiter then only defers a
reclamation this side would already have permitted, which costs disk rather reclamation this side would already have permitted, which costs disk rather
than correctness. than correctness.
### Names this repo doesn't reclaim, but the arbiter depends on
The five names above are leftovers — dead trees gitdan's arbiter finds and
deletes. Four other dot-prefixed names change that arbiter's *behaviour*
without ever being a leftover: it reads them to make a correctness decision
and never reclaims them. They are a real cross-repo dependency too, on the
name's spelling rather than on the tree's lifetime — gitdan's
`DEPENDED-UPON NAMES CONTRACT` block (in `scripts/ci-cache-reclaim.sh`) is the
canonical description; this is the producer's half for the two we own.
| Name | Produced here by | Consequence of an unannounced rename |
|---|---|---|
| `.ci-lock-<id>` | `scripts/cache-lock.sh` (acquire/release) and `cache-lib.sh`'s `write_cache_lock()` | The arbiter's lock check silently stops matching — a live job's staging tree loses its liveness guard and becomes an ordinary reclaim candidate while still in use |
| `.cache-last-used` | `cargo-cache/action.yml`, stamped every run | The arbiter falls back to directory mtime — silently reordering its eviction order, and possibly failing to recognise the directory as a cache dir at all |
Two more names are in gitdan's list — `.gitea-last-used` and `.ci-keep` — and
neither is produced by anything in this repo, so there is no producer-side
half to write here. `.gitea-last-used` is a naming convention individual
repos used before adopting this shared action; nothing here writes it, and
gitdan's script reads it only for compatibility with directories created
under that older scheme. `.ci-keep` is a per-repo, hand-placed opt-out a
consuming repo's own workflow drops directly into a cache directory it wants
exempted from eviction — never something this action or its scripts write.
**Adding a fifth depended-upon name counts as much as renaming one of the two
above.** If a future change here makes gitdan's arbiter start depending on the
spelling of some new dot-prefixed name — a name it reads for a decision but
never reclaims — that is exactly this category, and it needs the matching
`DEPEND_*` entry on gitdan's side before it ships, not after.
--- ---
## Inputs ## Inputs
+8
View File
@@ -165,6 +165,14 @@ runs:
# touched unconditionally every run: a run that hits the cache for every # touched unconditionally every run: a run that hits the cache for every
# crate may write nothing at all inside the tree, which would make a # crate may write nothing at all inside the tree, which would make a
# just-used directory look stale to the eviction pass. # just-used directory look stale to the eviction pass.
#
# `.cache-last-used` IS A CROSS-REPO CONTRACT NAME with daniel/gitdan's
# `scripts/ci-cache-reclaim.sh`, which reads this exact marker for its own
# LRU ordering and to recognise a directory as a cache dir at all. Rename
# it here without a matching change there and that script silently falls
# back to directory mtime for both — see README.md's "Scratch names in a
# cache root" section and the `DEPENDED-UPON NAMES CONTRACT` block in
# gitdan's script.
- shell: bash - shell: bash
run: | run: |
set -euo pipefail set -euo pipefail
+13
View File
@@ -14,6 +14,19 @@
# until STALE_LOCK_SECONDS, after which it is treated as abandoned by a job # until STALE_LOCK_SECONDS, after which it is treated as abandoned by a job
# the runner killed before it reached its own release step. Honouring a lock # the runner killed before it reached its own release step. Honouring a lock
# forever would let one crashed job pin a directory permanently. # forever would let one crashed job pin a directory permanently.
#
# `.ci-lock-<id>` IS A CROSS-REPO CONTRACT NAME with daniel/gitdan's
# `scripts/ci-cache-reclaim.sh`: that host-level arbiter reads this same
# marker (its `leftover_is_locked()`) to decide whether a leftover it is about
# to reclaim is still held open by a live job. `cache-lib.sh`'s
# `write_cache_lock()` writes the identical shape independently of this
# script. Rename or reshape this marker here without a matching change on
# gitdan's side and the arbiter's lock check silently stops matching — a live
# job's staging tree loses its liveness guard and becomes an ordinary reclaim
# candidate while still in use. See the "Scratch names in a cache root" section
# in README.md, and daniel/gitdan's `DEPENDED-UPON NAMES CONTRACT` block in
# `scripts/ci-cache-reclaim.sh`, for the full arrangement — this repo's half
# is: don't rename `.ci-lock-` without telling that script.
set -euo pipefail set -euo pipefail
MODE="${1:?usage: cache-lock.sh acquire|release <dir> <lock-id>}" MODE="${1:?usage: cache-lock.sh acquire|release <dir> <lock-id>}"