foremerge: schedule the stale-intent reap on vpn (kanban nix-config#945) #1971
No reviewers
Labels
No labels
backlog
bug
enhancement
in-progress
review
todo
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
ymrtech/nix-config!1971
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "kb/NCFG-945-foremerge-reap-timer"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Kanban card nix-config#945.
nix-config#944 shipped
foremerge work reap; nothing ran it. This wires it to an hourly systemd unit+timer on vpn, besideforemerge-intent-advisory.hosts/vpn/foremerge-stale-reap.py- dry-run by default,--applyfrom the unit; walks the fleet's four ledgers (nix-config, nix-config-private, clientsv, ymrtech); never passes--stale-seconds, so the binary's own three gates decide (owner silence, live claim lease, open ChangeSet).hosts/vpn/default.nix- Type=oneshot as hermes, Nice=19, hourly timer; the driver is py_compile +--selftested at build time..forgejo/tests/test-foremerge-reap-timer.sh- pins the scheduler: the driver selftest, three mutation arms, the unit's exact ExecStart, and (with a real binary) the shipped argv over a throwaway ledger..forgejo/workflows/nix-build-check.yml- hermeticforemerge-reap-timerjob plus a step inforemerge-accept-order, where the pinned foremerge store path exists.A ledger that cannot be reached is journalled and the run still exits 0 (
systemctl --failedfeeds vpn's deploy health gate); only a missing binary is fatal.Measured dry-run over the live ledgers before the change:
nix-config scanned=22 would reap=0,nix-config-private 27/0,clientsv 11/0,ymrtech 3/0- all retained by the binary's ownopen_changesetgate.nix-config#944 shipped `foremerge work reap` and nothing ran it: the verb is CLI-only on purpose ("a GC is an operator or scheduled action, not a worker's own lifecycle verb"), so without a clock the four fleet ledgers refill with ghosts exactly as before the reap existed and the collision signal a worker reads to decide "is someone else here?" goes noisy again -- the state #944 was filed from (148 dead open intents against 23 live ones; 73 open conflicts on hosts/vpn/default.nix alone, every one against an intent whose owner had no session anywhere). hosts/vpn/foremerge-stale-reap.py drives it. Dry-run is the DEFAULT; the systemd unit is the one caller that passes --apply, so a reap is always the explicit path and a stray manual run reports without changing a ledger. It walks the fleet's four ledgers (nix-config, nix-config-private, clientsv, ymrtech), skips a repo whose clone does not exist yet, and runs exactly `foremerge --cwd <clone> --json work reap [--dry-run]`. The GATES stay in the binary. The driver never passes --stale-seconds, so the fleet reaps at the ledger's own threshold and a live claim lease or a ChangeSet on the acceptance ladder withholds the reap there -- the three gates `.forgejo/tests/test-foremerge-stale-reap.sh` already pins. A ledger that cannot be reached is journalled and the run still exits 0: `systemctl --failed` is an input to vpn's deploy health gate, and a GC that cannot read one clone is the state before #944, not an incident. Only a missing binary is fatal. The service is a Type=oneshot as hermes, Nice=19 / IOSchedulingClass=idle beside the existing foremerge-intent-advisory unit, on an hourly timer (OnBootSec 20min, RandomizedDelaySec 5min). The driver is py_compile'd and `--selftest`ed at build time (hermetic: the binary is stubbed), so a broken driver reds a PR instead of a timer that silently stops reaping. .forgejo/tests/test-foremerge-reap-timer.sh pins the half nothing else did -- the SCHEDULER. Part 1 runs the driver's selftest; part 2 mutates a copy of the driver three ways (the dry-run default, the fleet repo list, the no---stale-seconds rule) and requires each copy to go RED naming the rule it lost; part 3 pins the unit's ExecStart by exact text (with a mutation proving the pin is anchored on the real line) plus the build-time selftest and the timer; part 4, when a foremerge binary is on PATH, runs the SHIPPED argv against the pinned binary over a throwaway ledger: it is accepted (scanned=1), an owner-present intent is RETAINED (reaped=0 -- the timer cannot eat a live worker), a second apply run over the same ledger also reaps 0, and the fixture intent's status is unchanged. Wired as the `foremerge-reap-timer` job in nix-build-check.yml (hermetic, no host condition: a tests-only diff scopes no host) and as a step of foremerge-accept-order, where the pinned foremerge store path exists, so one build carries both verdicts. Co-Authored-By: Hermes Agent <noreply@nousresearch.com>foremerge intent coverage (advisory) — 2 of 4 changed path(s) in ymrtech/nix-config#1971 have no live foremerge intent:
.forgejo/tests/test-foremerge-reap-timer.shhosts/vpn/foremerge-stale-reap.pyCoverage was decided by reading the repo's foremerge ledger (43 in-flight intent(s) considered) against this PR's changed paths — no branch or session name is involved, so a force-push does not change the answer. Paths that legitimately need no claim (docs,
.md,flake.lock) are excluded.This is advisory and does not block the merge. To clear it, publish intent for the paths above (
foremerge intent publish --agent <your agent id> --task <task> --summary <what and why> --scope file:<path>=modify), or ignore it if the work genuinely collides with nobody.foremerge intent coverage (advisory) — update for ymrtech/nix-config#1971: all 4 claimable changed path(s) are now covered by a live foremerge intent. Nothing to do; this comment closes the earlier gap warning.