foremerge: reap stale intents (kanban nix-config#944) #1970
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!1970
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "kb/NCFG-944-foremerge-stale-reaper"
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#944.
What
A ledger garbage collector for foremerge, shipped as a second fleet-local patch on the pinned v0.5.0 binary (ec74d7c):
patches/foremerge-stale-reap.patchaddsforemerge work reap, applied inoverlays/foremerge.nixbeside the existingforemerge-changeset-release.patch, plus its offline test.forgejo/tests/test-foremerge-stale-reap.shand theforemerge-stale-reapCI job.Why (measured 2026-10-13)
Nothing in v0.5.0 ends work whose agent is simply gone:
work discardrefuses work that is not the caller's, andwork adoptneeds a successor that is still here. So intents outlive their sessions and hold their claims forever. Publishing one intent onhosts/vpn/default.nixreturned 73 open conflicts, 53 of them HIGH, all false positives against prior days' intents; across the four fleet ledgers, 148 dead open intents against 23 live ones. The per-repo collision signal a worker uses to decide whether a peer is really there was pure noise on the fleet's busiest file.The three gates (the same ones
work adoptalready enforces)An intent ends only when all three hold:
--stale-seconds(default: the ledger's ownAGENT_STALE_AFTER_SECONDS, shared withwork adoptand the status report, via onesilent_forhelper);Everything else is reported as
retained, with the gate that stopped it, so a run distinguishes a clean ledger from a busy one. A reap is never a delete: the intent goes DISCARDED, its claims are released, its open conflicts are dismissed, and onework.reapedevent records the reason.--dry-runreports and changes nothing. CLI-only on purpose, likechangeset release- a GC is an operator or scheduled action, not a worker's own lifecycle verb.Test
.forgejo/tests/test-foremerge-stale-reap.shruns the real binary in a throwaway repo (no fleet ledger, no network, ~4s): default threshold reaps nothing while every owner is live (owner_active);--dry-runat an aggressive threshold reports the abandoned intent and leaves the ledger reading its original state; a live lease withholds (live_claim); an open ChangeSet withholds (open_changeset); the apply ends the unclaimed intent AND the claimed one whose lease had expired, both reading back DISCARDED, with the dead claim released and twowork.reapedevents on the chain; the reaped intent's open conflict is DISMISSED; a reaped intent is out of the candidate set on the next run; and a negative--stale-secondsis refused.Wired as job
foremerge-stale-reapinnix-build-check.yml, gated on vpn being in scope like the accept-order job. The patch pair was checked to apply in EITHER order to a clean checkout of the pinned rev (a first cut anchored a hunk next toRecordCommitRequest, which made the two patches unappliable together - fixed, and the stacking constraint is now recorded inoverlays/foremerge.nix).The reap path itself is compiled by this job; the live ledger on vpn is exercised after the deploy.
f3d077da2d86860a7bc8