From 4da6e8d30f36948576e01d9c2f4413eacc133e35 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 24 Aug 2026 17:08:54 -0500 Subject: [PATCH] docs(cache): write down the producer half of the depended-upon names contract MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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-, 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 Claude-Session: https://claude.ai/code/session_01MJHKJFJVUjnvVsemVBnvrd --- README.md | 30 ++++++++++++++++++++++++++++++ cargo-cache/action.yml | 8 ++++++++ scripts/cache-lock.sh | 13 +++++++++++++ 3 files changed, 51 insertions(+) diff --git a/README.md b/README.md index f36e244..e48ab41 100644 --- a/README.md +++ b/README.md @@ -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 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-` | `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 diff --git a/cargo-cache/action.yml b/cargo-cache/action.yml index a7e3d97..f3eba09 100644 --- a/cargo-cache/action.yml +++ b/cargo-cache/action.yml @@ -165,6 +165,14 @@ runs: # 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 # 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 run: | set -euo pipefail diff --git a/scripts/cache-lock.sh b/scripts/cache-lock.sh index 8665c45..07c68d2 100755 --- a/scripts/cache-lock.sh +++ b/scripts/cache-lock.sh @@ -14,6 +14,19 @@ # 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 # forever would let one crashed job pin a directory permanently. +# +# `.ci-lock-` 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 MODE="${1:?usage: cache-lock.sh acquire|release }"