Skip to content

glaeda-disk: a reserved fleet mini gets floor-pressure eviction only - #1626

Merged
teamleaderleo merged 9 commits into
mainfrom
disk-glaeda-reservation-guard
Oct 26, 2026
Merged

teamleaderleo merged 9 commits into
mainfrom
disk-glaeda-reservation-guard

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Oct 26, 2026 •

Copy link
Copy Markdown
Owner

Leo, 2026-10-26: "Just throw it away. Just delete more stuff, more often." That holds on every mini except one a person has reserved.

What changes

This lands in front of #1622 (12 h ages), #1625 (12 h mirrors) and #1624 (node-store cap). On a reserved host they act only under floor pressure.

  • No reservation data lives in this repository. glaeda-disk reads the list only from the host: ~/.local/share/glaeda/fleet-reservations.json in the home of the user that owns /Users/Shared/cmux-build-fleet (schema glaeda-fleet-reservations/v1: {"expires","reservations":[{"id","owner","hosts":[...],"from","until"}],"aliases":{host:[...]}}; the writer stamps expires 13 h after each write and refreshes it every 6 h), written there by the fleet's own writer, plus the host-local /Users/Shared/cmux-build-fleet/reservation.json (glaeda-reservation/v1, the file the runner hook reads).
  • host_reservation() matches this host by glaeda-update's configured host name or its machine name. Fails closed: a missing, unreadable, malformed or expired list (or one with no expires) (hosts not a list of names, a bad time on any entry, aliases not lists) reads as reserved, whatever the host-local file says. An entry lapses by itself after until.
  • On a reserved fleet mini, every --apply of glaeda-disk (the --runner-caches profile included) runs no idle sweep. A pressure pass starts at the runner floor itself (not floor + low_margin) and frees only up to the floor plus target_margin_gib. Any other apply deletes nothing and says why.
  • glaeda-fleet-cas-prune --apply on a reserved host above its floor defers before anything, store gc included. It loads glaeda-disk registered in sys.modules, so the dataclasses load and the check is real (a test loads the real script against a made-up list).

Before / after

Before: a merged glaeda change reaches every mini through OTA, and its idle sweeps age out state on a host someone has reserved. After: on a reserved host, glaeda acts only to keep the disk above the floor until the reservation lapses. Baseline free-disk minimums are in #1622.

Risk

Low. Reserved hosts delete less. A host with no list yet also deletes less (fail closed), but the floor still protects jobs. Unreserved hosts with a list behave exactly as before.

Tests: HostReservationTest (active entry or alias, lapse, missing and malformed lists fail closed, the fleet owner's home, floor-exact pressure, the main-flow gate with and without --runner-caches); the prune's real-loader check and its gate before store gc. Fixtures use made-up ids, hosts and owners.

Agent session: agent session

🤖 Generated with Claude Code

config/fleet-reservations.json is glaeda's copy of leo-workspace's fleet-registry
reservations (a test compares the two where the registry is checked out); mini-setup
installs it. On a host an active entry (or the host-local reservation.json) names,
glaeda-disk runs no idle sweep and a pressure pass acts only below the runner floor,
back to floor + target_margin_gib. glaeda-fleet-cas-prune leaves a reserved host above
its floor alone. An unreadable list fails closed. Entries lapse by themselves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3
@teamleaderleo

Copy link
Copy Markdown
Owner Author

Owned by an agent session · session

… closed on any malformed entry

The list no longer ships in this repository. glaeda-disk and glaeda-fleet-cas-prune read it only from
~/.local/share/glaeda/fleet-reservations.json in the home of the user that owns /Users/Shared/cmux-build-fleet
(written there by the fleet's own writer), plus FLEET_ROOT/reservation.json. A missing, unreadable or
malformed list (hosts not a list of names, a bad time on any entry, aliases not lists) reads as reserved,
whatever the host-local file says.

Also from review: the prune registers the glaeda-disk module in sys.modules before running it, so its
dataclasses load and the gate is real; the reservation gate runs before store_gc; --runner-caches is held to
the same floor-only rule; and a reserved host's pressure starts at the floor itself, not floor + low_margin.
Test fixtures use made-up ids, hosts and owners.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3
@gitguardian

gitguardian Bot commented Oct 26, 2026

Copy link
Copy Markdown

⚠️ GitGuardian has uncovered 1 secret following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

🔎 Detected hardcoded secret in your pull request
GitGuardian id GitGuardian status Secret Commit Filename
35581672 Triggered Generic Password 5922735 scripts/test-glaeda-disk.py View secret
🛠 Guidelines to remediate hardcoded secrets
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secret safely. Learn here the best practices.
  3. Revoke and rotate this secret.
  4. If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

To avoid such incidents in the future consider


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

teamleaderleo and others added 5 commits October 26, 2026 15:37
…e, reads as reserved

The writer (leo-workspace host-baseline ci-minis) stamps expires 13 h after each write and refreshes it every
6 h, so a mini the writer stopped reaching (for one, a host reserved after its last write) falls back to
reserved by itself.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3
… markers and intervals fail closed

Review findings on #1626:
- a FLEET_ROOT/reservation.json that is there but unreadable, not glaeda-reservation/v1 or without integer
  since/until holds the host, as host_busy reads it (absent: no hold);
- a fleet entry with from >= until fails the whole list closed;
- on a reserved host, after the floor-pressure pass, no stale-marker clearing, paused-work cleanup, test-residue
  reaping, home-clone gc or runner repack runs, and --dedupe / --dedupe-builds do nothing (the reservation is
  asked for them too);
- filesystems() gets reserved= only when set, so callers and mocks that pass positionals keep working.
Each gate has a test that fails when its check is removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3
…ous commit lost this edit)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3
…ure since holds, as the runner hook reads it

Review findings on #1626: lexists() read a permission error as absence; only FileNotFoundError on the read is
absence now. The runner hook holds while now < until whatever since says; host_reservation matches it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3
…the runner-caches case gets a root

CI found two order effects: HostReservationTest's full main run left ROLE/RUNNER_CACHE_PROFILE and the floor
globals set for LinuxLayoutTest, and on Linux the --runner-caches case stopped at 'no configured cache roots'
before the reservation gate. Tests only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3
@teamleaderleo
teamleaderleo merged commit 753d0a7 into main Oct 26, 2026
18 checks passed
@teamleaderleo
teamleaderleo deleted the disk-glaeda-reservation-guard branch October 26, 2026 23:33
teamleaderleo added a commit that referenced this pull request Oct 27, 2026
… h go above the floor (#1622)

* glaeda-disk: a reserved fleet mini gets floor-pressure eviction only

config/fleet-reservations.json is glaeda's copy of leo-workspace's fleet-registry
reservations (a test compares the two where the registry is checked out); mini-setup
installs it. On a host an active entry (or the host-local reservation.json) names,
glaeda-disk runs no idle sweep and a pressure pass acts only below the runner floor,
back to floor + target_margin_gib. glaeda-fleet-cas-prune leaves a reserved host above
its floor alone. An unreadable list fails closed. Entries lapse by themselves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: judge the reservation before any family is built

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: every disposable age is 12 h; runner checkouts unused 12 h go above the floor

Leo, 2026-10-26: "When have we ever had something useful greater than 12 hours?"
DerivedData, CoreSimulator runtimes, package caches, runner work dirs and build dirs
now go once idle DEFAULT_AGE_HOURS (12 h). The per-host cmux-next build root, the
newest warm compile cache per builder, is exempt by role (only under the floor).
The git-mirror window stays 168 h: past it a checkout's unpushed commits are not checked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* test-glaeda-disk: age-dependent cases follow DEFAULT_AGE_HOURS

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: a stale runner checkout above the floor keeps git's vetoes (no lock, no commit only here)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: a reserved host keeps the ages before 12 h until its reservation lapses

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: a reserved host's families are built with the legacy ages

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: read the fleet reservation list only from the host; fail closed on any malformed entry

The list no longer ships in this repository. glaeda-disk and glaeda-fleet-cas-prune read it only from
~/.local/share/glaeda/fleet-reservations.json in the home of the user that owns /Users/Shared/cmux-build-fleet
(written there by the fleet's own writer), plus FLEET_ROOT/reservation.json. A missing, unreadable or
malformed list (hosts not a list of names, a bad time on any entry, aliases not lists) reads as reserved,
whatever the host-local file says.

Also from review: the prune registers the glaeda-disk module in sys.modules before running it, so its
dataclasses load and the gate is real; the reservation gate runs before store_gc; --runner-caches is held to
the same floor-only rule; and a reserved host's pressure starts at the floor itself, not floor + low_margin.
Test fixtures use made-up ids, hosts and owners.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: a stale runner checkout keeps git's operation markers and every worktree's HEAD; explicit policy keys stay

Review findings on #1622:
- the above-floor veto now also keeps a checkout with FETCH_HEAD.lock, MERGE_HEAD, REBASE_HEAD, a rebase or
  sequencer dir, CHERRY_PICK_HEAD, REVERT_HEAD or BISECT_LOG (files or dirs, linked worktrees' git dirs too);
- a commit that only a linked worktree's HEAD names keeps the checkout;
- keep_legacy_ages leaves a key disk-policy.json sets alone even when its value equals the new default
  (policy_overrides gives the file's keys).
Tracked edits and reflog-only commits still go with a runner checkout: actions/checkout's next job runs
git clean -ffdx and git reset --hard there, so they never carry from one job to the next.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: a fleet reservation list past its expires, or without one, reads as reserved

The writer (leo-workspace host-baseline ci-minis) stamps expires 13 h after each write and refreshes it every
6 h, so a mini the writer stopped reaching (for one, a host reserved after its last write) falls back to
reserved by itself.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: a reserved host runs the pressure pass and nothing else; markers and intervals fail closed

Review findings on #1626:
- a FLEET_ROOT/reservation.json that is there but unreadable, not glaeda-reservation/v1 or without integer
  since/until holds the host, as host_busy reads it (absent: no hold);
- a fleet entry with from >= until fails the whole list closed;
- on a reserved host, after the floor-pressure pass, no stale-marker clearing, paused-work cleanup, test-residue
  reaping, home-clone gc or runner repack runs, and --dedupe / --dedupe-builds do nothing (the reservation is
  asked for them too);
- filesystems() gets reserved= only when set, so callers and mocks that pass positionals keep working.
Each gate has a test that fails when its check is removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: the runner checkout git veto drops the caller's GIT_* and keeps what it cannot read

Review findings on #1622: GIT_DIR/GIT_WORK_TREE from the caller would point git -C at another repository (as
_checkout_git already strips them); an unreadable directory under .git (a hidden worktree's lock) now raises
in the walk and keeps the checkout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: pass reserved= to filesystems() only when set (the previous commit lost this edit)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: pass reserved= to filesystems() only when set

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: a local marker that cannot be read holds the host; a future since holds, as the runner hook reads it

Review findings on #1626: lexists() read a permission error as absence; only FileNotFoundError on the read is
absence now. The runner hook holds while now < until whatever since says; host_reservation matches it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: a reserved host keeps the 168 h runner-cache age

runner_cache_families now reads RUNNER_CACHE_IDLE_HOURS (12 h by default), which keep_legacy_ages puts back to 168 h on a reserved host, as before the 12 h default.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
teamleaderleo added a commit that referenced this pull request Oct 27, 2026
…not); glaeda-disk pressure passes run it (#1624)

* glaeda-disk: a reserved fleet mini gets floor-pressure eviction only

config/fleet-reservations.json is glaeda's copy of leo-workspace's fleet-registry
reservations (a test compares the two where the registry is checked out); mini-setup
installs it. On a host an active entry (or the host-local reservation.json) names,
glaeda-disk runs no idle sweep and a pressure pass acts only below the runner floor,
back to floor + target_margin_gib. glaeda-fleet-cas-prune leaves a reserved host above
its floor alone. An unreadable list fails closed. Entries lapse by themselves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* fleet-cas prune: the node store is a hard cap (writer too, builds or not); glaeda-disk pressure passes run it

The node store was pruned only while no build ran, which on a busy mini is never, and never
on the writer: cmux15's reached 73 GiB (2026-10-26). The writer writes through, so its node
store is a cache like a reader's. Files the node touched within 2 h (twice its TOUCH_EVERY)
stay as a running build's working set. The local Xcode CAS still goes only while no build runs,
now above 20 GiB. glaeda-disk's pressure passes (before every job, under the floor) run
`glaeda-fleet-cas-prune --apply --node-only`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* fleet-cas prune: a hard cap (no age exemption); the writer keeps its kv entries, its objects go

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: judge the reservation before any family is built

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: read the fleet reservation list only from the host; fail closed on any malformed entry

The list no longer ships in this repository. glaeda-disk and glaeda-fleet-cas-prune read it only from
~/.local/share/glaeda/fleet-reservations.json in the home of the user that owns /Users/Shared/cmux-build-fleet
(written there by the fleet's own writer), plus FLEET_ROOT/reservation.json. A missing, unreadable or
malformed list (hosts not a list of names, a bad time on any entry, aliases not lists) reads as reserved,
whatever the host-local file says.

Also from review: the prune registers the glaeda-disk module in sys.modules before running it, so its
dataclasses load and the gate is real; the reservation gate runs before store_gc; --runner-caches is held to
the same floor-only rule; and a reserved host's pressure starts at the floor itself, not floor + low_margin.
Test fixtures use made-up ids, hosts and owners.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* fleet-cas prune: never count or remove an in-flight daemon write (name.tmp<pid>.<seq>)

Review finding: the hard-cap walk included the daemon's temporaries under node-store/cas, and unlinking one
mid-write fails the rename and the build. Skip any name with a dot, as fleet-cas gc.rs does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: a fleet reservation list past its expires, or without one, reads as reserved

The writer (leo-workspace host-baseline ci-minis) stamps expires 13 h after each write and refreshes it every
6 h, so a mini the writer stopped reaching (for one, a host reserved after its last write) falls back to
reserved by itself.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* fleet-cas prune: --node-only caps even when ps fails; a temp file untouched 6 h counts and goes first

Review findings: the node cap needs no build check, so a ps failure no longer skips it under --node-only; an
interrupted daemon's name.tmp<pid>.<seq> left for TMP_STALE_S (6 h) is abandoned, counted against the cap and
removed before any object, while a younger one is still an in-flight write and stays.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: a reserved host runs the pressure pass and nothing else; markers and intervals fail closed

Review findings on #1626:
- a FLEET_ROOT/reservation.json that is there but unreadable, not glaeda-reservation/v1 or without integer
  since/until holds the host, as host_busy reads it (absent: no hold);
- a fleet entry with from >= until fails the whole list closed;
- on a reserved host, after the floor-pressure pass, no stale-marker clearing, paused-work cleanup, test-residue
  reaping, home-clone gc or runner repack runs, and --dedupe / --dedupe-builds do nothing (the reservation is
  asked for them too);
- filesystems() gets reserved= only when set, so callers and mocks that pass positionals keep working.
Each gate has a test that fails when its check is removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: pass reserved= to filesystems() only when set (the previous commit lost this edit)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: a local marker that cannot be read holds the host; a future since holds, as the runner hook reads it

Review findings on #1626: lexists() read a permission error as absence; only FileNotFoundError on the read is
absence now. The runner hook holds while now < until whatever since says; host_reservation matches it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
teamleaderleo added a commit that referenced this pull request Oct 27, 2026
… bundled to ~/archive first (#1625)

* glaeda-disk: a reserved fleet mini gets floor-pressure eviction only

config/fleet-reservations.json is glaeda's copy of leo-workspace's fleet-registry
reservations (a test compares the two where the registry is checked out); mini-setup
installs it. On a host an active entry (or the host-local reservation.json) names,
glaeda-disk runs no idle sweep and a pressure pass acts only below the runner floor,
back to floor + target_margin_gib. glaeda-fleet-cas-prune leaves a reserved host above
its floor alone. An unreadable list fails closed. Entries lapse by themselves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: judge the reservation before any family is built

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: every disposable age is 12 h; runner checkouts unused 12 h go above the floor

Leo, 2026-10-26: "When have we ever had something useful greater than 12 hours?"
DerivedData, CoreSimulator runtimes, package caches, runner work dirs and build dirs
now go once idle DEFAULT_AGE_HOURS (12 h). The per-host cmux-next build root, the
newest warm compile cache per builder, is exempt by role (only under the floor).
The git-mirror window stays 168 h: past it a checkout's unpushed commits are not checked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* test-glaeda-disk: age-dependent cases follow DEFAULT_AGE_HOURS

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: a stale runner checkout above the floor keeps git's vetoes (no lock, no commit only here)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: a reserved host keeps the ages before 12 h until its reservation lapses

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: a reserved host's families are built with the legacy ages

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: mirrors go at 12 h, their unpushed commits and local-only refs bundled to ~/archive first

Before a mirror family's item (cmux-job-cache, the hq build cache) goes, archive_mirror finds every
repository it takes along (checkouts, bare repos, a linked worktree's repository inside it, submodule
stores, embedded submodules) and writes each one's commits no remote holds, plus branches and tags only
this host has, into git bundles under ~/archive/glaeda-disk, named with a 30-day expiry and pruned by
that name. Each bundle passes `git bundle verify` and lists every ref it must hold before the tree is
deleted; a failure keeps the tree, records blocked:bundle-failed in the receipt and run line, and alerts
on stderr. CMUX_JOB_MIRROR_HOURS drops from 168 to DEFAULT_AGE_HOURS (12).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: a reserved host keeps the 168 h mirror age

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: read the fleet reservation list only from the host; fail closed on any malformed entry

The list no longer ships in this repository. glaeda-disk and glaeda-fleet-cas-prune read it only from
~/.local/share/glaeda/fleet-reservations.json in the home of the user that owns /Users/Shared/cmux-build-fleet
(written there by the fleet's own writer), plus FLEET_ROOT/reservation.json. A missing, unreadable or
malformed list (hosts not a list of names, a bad time on any entry, aliases not lists) reads as reserved,
whatever the host-local file says.

Also from review: the prune registers the glaeda-disk module in sys.modules before running it, so its
dataclasses load and the gate is real; the reservation gate runs before store_gc; --runner-caches is held to
the same floor-only rule; and a reserved host's pressure starts at the floor itself, not floor + low_margin.
Test fixtures use made-up ids, hosts and owners.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: mirror bundles trust only the server, never overwrite, keep dirty trees, recheck before delete

Addresses the Codex review of #1625:
1. "held" comes only from what the servers confirm (ls-remote heads and tags, and fetch --negotiate-only
   acks, asked one commit at a time when a batch fails); stale remote-tracking refs are only candidates.
2. Bundle names carry a hash of the repository's real path and ref, the pid and the time, and are linked
   into place with os.link, so an existing bundle is never replaced.
3. A work tree with tracked edits, untracked non-ignored files or files hidden from status keeps the item
   (blocked:uncommitted); ignored build output still goes.
4. Checkouts inside ignored directories are bundled like the others.
5. An unreadable submodule store keeps the item (os.walk onerror).
6. Right before the delete, fresh process evidence and a snapshot of every ref, HEAD, reflog and work tree
   status taken before bundling are checked again; any change keeps the tree.
7. Pruning deletes only bundles manifest.jsonl lists, only at the sha256 it recorded, and only after the
   process-evidence gate.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: a stale runner checkout keeps git's operation markers and every worktree's HEAD; explicit policy keys stay

Review findings on #1622:
- the above-floor veto now also keeps a checkout with FETCH_HEAD.lock, MERGE_HEAD, REBASE_HEAD, a rebase or
  sequencer dir, CHERRY_PICK_HEAD, REVERT_HEAD or BISECT_LOG (files or dirs, linked worktrees' git dirs too);
- a commit that only a linked worktree's HEAD names keeps the checkout;
- keep_legacy_ages leaves a key disk-policy.json sets alone even when its value equals the new default
  (policy_overrides gives the file's keys).
Tracked edits and reflog-only commits still go with a runner checkout: actions/checkout's next job runs
git clean -ffdx and git reset --hard there, so they never carry from one job to the next.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: a fleet reservation list past its expires, or without one, reads as reserved

The writer (leo-workspace host-baseline ci-minis) stamps expires 13 h after each write and refreshes it every
6 h, so a mini the writer stopped reaching (for one, a host reserved after its last write) falls back to
reserved by itself.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: a reserved host runs the pressure pass and nothing else; markers and intervals fail closed

Review findings on #1626:
- a FLEET_ROOT/reservation.json that is there but unreadable, not glaeda-reservation/v1 or without integer
  since/until holds the host, as host_busy reads it (absent: no hold);
- a fleet entry with from >= until fails the whole list closed;
- on a reserved host, after the floor-pressure pass, no stale-marker clearing, paused-work cleanup, test-residue
  reaping, home-clone gc or runner repack runs, and --dedupe / --dedupe-builds do nothing (the reservation is
  asked for them too);
- filesystems() gets reserved= only when set, so callers and mocks that pass positionals keep working.
Each gate has a test that fails when its check is removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: the runner checkout git veto drops the caller's GIT_* and keeps what it cannot read

Review findings on #1622: GIT_DIR/GIT_WORK_TREE from the caller would point git -C at another repository (as
_checkout_git already strips them); an unreadable directory under .git (a hidden worktree's lock) now raises
in the walk and keeps the checkout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: mirror bundling finds nested submodules, rediscovers repos and rechecks owners before delete

Addresses the second Codex review of #1625:
1. mirror_repos queues every initialized submodule work tree (embedded or in modules/), so a submodule's
   own submodules are bundled too.
2. and 3. mirror_moved finds the item's repositories again right before the delete: a repository created
   meanwhile, or a work tree no longer clean (hidden-file flags included), keeps the tree.
4. mirror_moved re-reads owner_retired and the fleet artifact references after bundling.
5. A locked linked worktree keeps the tree, as in git_loss.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: pass reserved= to filesystems() only when set (the previous commit lost this edit)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: pass reserved= to filesystems() only when set

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: a local marker that cannot be read holds the host; a future since holds, as the runner hook reads it

Review findings on #1626: lexists() read a permission error as absence; only FileNotFoundError on the read is
absence now. The runner hook holds while now < until whatever since says; host_reservation matches it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: mirror bundling re-asks the servers, fails closed on read errors, honours locks inside

Addresses the third Codex review of #1625:
1. The commits the bundles leave to the servers (their prerequisites from rev-list --boundary, and tips no
   bundle holds) are asked about again right before the delete; one no server holds any more keeps the tree.
2. The repository search for a mirror item is strict: a directory that cannot be read (EIO, ESTALE) makes
   it incomplete, and the item stays.
3. A locked linked worktree keeps the item even when its repository is inside it, as in git_loss.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: mirror recheck asks the servers first, symlinked module stores keep, empty repos go

Addresses the fourth Codex review of #1625:
1. mirror_moved asks the servers first and rereads the repositories and their snapshot last, so a local
   commit made while the servers were asked keeps the tree.
2. A symlinked modules/ store, or a symlinked directory inside one, is unreadable, as in submodule_loss.
3. An unborn repository (no refs, no reflog, HEAD naming a branch with no commit) needs no bundle; the
   snapshot reads HEAD as a file, so it is comparable too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: mirror recheck ends on process and owner checks; unborn and worktree reads fail closed

Addresses the fifth Codex review of #1625:
1. mirror_moved now asks the servers, then rereads git, then the owner, artifact references and fresh
   process evidence last, so a job that starts during the slow steps keeps the tree.
2. The unborn-repository fast path applies only when the repository has no linked worktrees.
3. Linked worktree records are read strictly: an unreadable worktrees/ or record keeps the item.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: mirror bundling reads reflogs strictly and checks linked worktrees inside the item

Addresses the sixth Codex review of #1625:
1. Reflog directories are walked with files_strict (os.walk with onerror), so an unreadable one makes
   local_tips, the unborn check and the snapshot fail closed instead of skipping it.
2. A linked worktree inside the item (even one under ignored output such as target/) is walked like any
   work tree: it must be clean and unlocked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: mirror bundling treats symlinked reflog dirs and unreadable linked worktrees as unreadable

Addresses the seventh Codex review of #1625:
1. files_strict returns None when a directory below the root is a symlink, which os.walk would not enter,
   so a symlinked logs/refs/heads cannot hide a reflog-only commit.
2. Linked worktrees are probed with os.stat: only FileNotFoundError means absent; EACCES or EIO keeps the
   item instead of skipping the outside-worktree check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: a bundled mirror's git metadata is checked again after the rename; references rechecked

Addresses the eighth Codex review of #1625:
1. mirror_rename_recheck runs as remove()'s after_rename: once the tree is renamed aside, a hash of every
   git dir's HEAD, packed-refs, refs, logs and worktrees (mirror_git_digest, read relative to the item)
   must equal the one taken before bundling, or the tree is renamed back and kept (changed:in-use).
   mirror_moved compares the same digest too.
2. mirror_moved re-runs referenced_main_checkout for git-disposable families.
3. files_strict also refuses a symlinked or special file, which is_file() readers would skip.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: after the rename, a bundled mirror gets the whole pre-bundle check again; kept trees are marked

Addresses the ninth Codex review of #1625 (replaces the metadata digest):
1, 2. mirror_rename_recheck runs mirror_repos on the renamed tree (a fresh strict scan of repositories and
   linked worktrees, every work tree clean, staged and untracked included, and unlocked) and compares each
   repository's local tips with what was bundled or left to the servers; any new repository or commit, or
   any error, puts the tree back.
3. local_tips refuses a symlinked or special HEAD or packed-refs.
4. A tree that cannot be renamed back gets .glaeda-disk-keep, which finish_deletion and the
   interrupted-deletions family (keep_verdict) honour, so nothing deletes it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: unborn means strictly empty; post-rename recheck compares refs; keep marker first

Addresses the tenth Codex review of #1625:
1. repo_unborn needs a regular HEAD, no packed-refs and an empty refs/ read strictly.
2. mirror_tips records each repository's local refs by name as well as its tips; the post-rename recheck
   requires the refs to be unchanged, so a branch or tag named after the last check puts the tree back.
3. The keep marker is a sidecar written before the rename (a failed write leaves the tree in place) and
   removed only once the recheck passes, so a kept aside tree always carries it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

* glaeda-disk: a mirror whose repositories have linked worktrees is kept

Addresses the eleventh Codex review of #1625: worktree records name absolute paths, so once the item is
renamed aside its linked worktrees cannot be found and checked again. Any repository in a mirror item with
linked worktree records (inside or outside the item) now keeps the item; the post-rename recheck finds the
same records and keeps it too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent-Session: https://cmux.com/deeplink/agent?id=aid-85ca59f74f02d81734c3

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant