The producer half of a cross-repo contract whose consumer half already shipped
in daniel/gitdan#28. That PR
deliberately scoped this side out — a sibling agent was working in this repo at
the time — and it was never filed. This is that follow-up.
The contract, and why only one side of it is written down
daniel/gitdan's host-level cache arbiter (scripts/ci-cache-reclaim.sh)
reclaims dot-prefixed leftovers that this repo's scripts create inside the
cache volumes it scans:
.stage-<tag> — cache-lib.sh's hardlink_clone_into staging path. <tag> is unique per job per run, so a job killed between staging and the
atomic rename strands a full hardlink tree that nothing here ever sweeps.
.evicting-<name>-<pid> — prune-cache.sh's eviction rename-aside.
This one has its own sweeper, so it is the milder case.
.reading-<source>-<tag> — reader_lock_acquire's marker. Not
garbage: the arbiter reads these to decide whether a leftover is live, and
never deletes one.
gitdan's script now carries a LEFTOVER NAMING CONTRACT block naming each
shape, the function that produces it, the condition that strands it, and this
rule:
no new dot-prefixed entry under a cache root without a matching prefix in scripts/ci-cache-reclaim.sh
Nothing in this repo says any of that. A contributor here can add a fourth
dot-prefixed shape — or rename an existing one — with no local signal that
anything outside the repo depends on the spelling. The arbiter enumerates by
explicit prefix rather than dotglob (deliberately, so it never sees .reading-* markers as candidates), which means an unannounced fourth shape
is simply invisible to it: gitdan#28 returning by a different route.
The staleness half has a direction
gitdan mirrors two constants from here — CACHE_READ_STALE_SECONDS
(cache-lib.sh) and STALE_LOCK_SECONDS (prune-cache.sh), both 7200. Its
copies must be ≥ ours, never below:
If we raise ours (longer jobs) and gitdan stays at 7200, its arbiter
reads a marker whose owner still considers it live as stale, and deletes the
tree under an in-flight clone. Its minimum-age guard does not back-stop
that — a clone holding a 3h-old marker has a ~3h-old staging tree, so both
its guards pass.
The reverse drift only costs disk.
So raising either constant here is a change that requires a matching change
there, and lowering one is safe. That asymmetry is documented on gitdan's side
and nowhere on ours.
Ask
Add the producer's half, sited where someone changing these names will
actually see it — cache-lib.sh for the marker and staging shapes, prune-cache.sh for the aside, and a short section in README.md tying them
together. State:
Which names are part of the contract, and which function produces each.
That .reading-* is read by the arbiter and must never be deleted by it —
so it is a protective marker, not garbage.
Adding a shape counts as much as renaming one, and what to do about it
(add the matching prefix in gitdan's ci-cache-reclaim.sh).
That raising CACHE_READ_STALE_SECONDS or STALE_LOCK_SECONDS requires
raising gitdan's mirrors first, and why lowering is safe.
Point at daniel/gitdan's block rather than restating it in full — one side
should be the canonical description and the other a pointer with the local
obligations spelled out.
Acceptance criteria
Each of the three dot-prefixed shapes is documented at its producing
site, naming the contract.
The add-a-shape rule is stated, not just the rename rule.
The staleness-constant direction is stated with its asymmetry.
README.md carries a short section a newcomer would find before adding
a scratch directory under a cache root.
No behaviour change: comments and docs only.
The producer half of a cross-repo contract whose consumer half already shipped
in [`daniel/gitdan#28`](https://gitdan.com/daniel/gitdan/issues/28). That PR
deliberately scoped this side out — a sibling agent was working in this repo at
the time — and it was never filed. This is that follow-up.
## The contract, and why only one side of it is written down
`daniel/gitdan`'s host-level cache arbiter (`scripts/ci-cache-reclaim.sh`)
reclaims dot-prefixed leftovers that **this repo's scripts create** inside the
cache volumes it scans:
- **`.stage-<tag>`** — `cache-lib.sh`'s `hardlink_clone_into` staging path.
`<tag>` is unique per job per run, so a job killed between staging and the
atomic rename strands a full hardlink tree that nothing here ever sweeps.
- **`.evicting-<name>-<pid>`** — `prune-cache.sh`'s eviction rename-aside.
This one has its own sweeper, so it is the milder case.
- **`.reading-<source>-<tag>`** — `reader_lock_acquire`'s marker. **Not**
garbage: the arbiter reads these to decide whether a leftover is live, and
never deletes one.
gitdan's script now carries a `LEFTOVER NAMING CONTRACT` block naming each
shape, the function that produces it, the condition that strands it, and this
rule:
> no new dot-prefixed entry under a cache root without a matching prefix in
> `scripts/ci-cache-reclaim.sh`
**Nothing in this repo says any of that.** A contributor here can add a fourth
dot-prefixed shape — or rename an existing one — with no local signal that
anything outside the repo depends on the spelling. The arbiter enumerates by
explicit prefix rather than `dotglob` (deliberately, so it never sees
`.reading-*` markers as candidates), which means an unannounced fourth shape
is simply invisible to it: gitdan#28 returning by a different route.
## The staleness half has a direction
gitdan mirrors two constants from here — `CACHE_READ_STALE_SECONDS`
(`cache-lib.sh`) and `STALE_LOCK_SECONDS` (`prune-cache.sh`), both 7200. Its
copies must be **≥** ours, never below:
- If we **raise** ours (longer jobs) and gitdan stays at 7200, its arbiter
reads a marker whose owner still considers it live as stale, and deletes the
tree under an in-flight clone. Its minimum-age guard does **not** back-stop
that — a clone holding a 3h-old marker has a ~3h-old staging tree, so both
its guards pass.
- The reverse drift only costs disk.
So raising either constant here is a change that requires a matching change
there, and lowering one is safe. That asymmetry is documented on gitdan's side
and nowhere on ours.
## Ask
Add the producer's half, sited where someone changing these names will
actually see it — `cache-lib.sh` for the marker and staging shapes,
`prune-cache.sh` for the aside, and a short section in `README.md` tying them
together. State:
1. Which names are part of the contract, and which function produces each.
2. That `.reading-*` is read by the arbiter and must never be deleted by it —
so it is a protective marker, not garbage.
3. **Adding a shape counts as much as renaming one**, and what to do about it
(add the matching prefix in gitdan's `ci-cache-reclaim.sh`).
4. That raising `CACHE_READ_STALE_SECONDS` or `STALE_LOCK_SECONDS` requires
raising gitdan's mirrors first, and why lowering is safe.
Point at `daniel/gitdan`'s block rather than restating it in full — one side
should be the canonical description and the other a pointer with the local
obligations spelled out.
## Acceptance criteria
- [ ] Each of the three dot-prefixed shapes is documented at its producing
site, naming the contract.
- [ ] The add-a-shape rule is stated, not just the rename rule.
- [ ] The staleness-constant direction is stated with its asymmetry.
- [ ] `README.md` carries a short section a newcomer would find before adding
a scratch directory under a cache root.
- [ ] No behaviour change: comments and docs only.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
The producer half of a cross-repo contract whose consumer half already shipped
in
daniel/gitdan#28. That PRdeliberately scoped this side out — a sibling agent was working in this repo at
the time — and it was never filed. This is that follow-up.
The contract, and why only one side of it is written down
daniel/gitdan's host-level cache arbiter (scripts/ci-cache-reclaim.sh)reclaims dot-prefixed leftovers that this repo's scripts create inside the
cache volumes it scans:
.stage-<tag>—cache-lib.sh'shardlink_clone_intostaging path.<tag>is unique per job per run, so a job killed between staging and theatomic rename strands a full hardlink tree that nothing here ever sweeps.
.evicting-<name>-<pid>—prune-cache.sh's eviction rename-aside.This one has its own sweeper, so it is the milder case.
.reading-<source>-<tag>—reader_lock_acquire's marker. Notgarbage: the arbiter reads these to decide whether a leftover is live, and
never deletes one.
gitdan's script now carries a
LEFTOVER NAMING CONTRACTblock naming eachshape, the function that produces it, the condition that strands it, and this
rule:
Nothing in this repo says any of that. A contributor here can add a fourth
dot-prefixed shape — or rename an existing one — with no local signal that
anything outside the repo depends on the spelling. The arbiter enumerates by
explicit prefix rather than
dotglob(deliberately, so it never sees.reading-*markers as candidates), which means an unannounced fourth shapeis simply invisible to it: gitdan#28 returning by a different route.
The staleness half has a direction
gitdan mirrors two constants from here —
CACHE_READ_STALE_SECONDS(
cache-lib.sh) andSTALE_LOCK_SECONDS(prune-cache.sh), both 7200. Itscopies must be ≥ ours, never below:
reads a marker whose owner still considers it live as stale, and deletes the
tree under an in-flight clone. Its minimum-age guard does not back-stop
that — a clone holding a 3h-old marker has a ~3h-old staging tree, so both
its guards pass.
So raising either constant here is a change that requires a matching change
there, and lowering one is safe. That asymmetry is documented on gitdan's side
and nowhere on ours.
Ask
Add the producer's half, sited where someone changing these names will
actually see it —
cache-lib.shfor the marker and staging shapes,prune-cache.shfor the aside, and a short section inREADME.mdtying themtogether. State:
.reading-*is read by the arbiter and must never be deleted by it —so it is a protective marker, not garbage.
(add the matching prefix in gitdan's
ci-cache-reclaim.sh).CACHE_READ_STALE_SECONDSorSTALE_LOCK_SECONDSrequiresraising gitdan's mirrors first, and why lowering is safe.
Point at
daniel/gitdan's block rather than restating it in full — one sideshould be the canonical description and the other a pointer with the local
obligations spelled out.
Acceptance criteria
site, naming the contract.
README.mdcarries a short section a newcomer would find before addinga scratch directory under a cache root.