feat(knotserver): threshold-gate and local-stage post-receive maintenance
Post-receive maintenance previously ran `git repack -a -d
--write-bitmap-index` plus `commit-graph write --reachable` in place over
the network-backed FUSE mount on every successful push, blocking the push
handler for minutes even on trivial pushes to large repos.
Gate the work behind a cheap check run on every push: a single
objects/pack listing yields pack count and bitmap presence, plus a
bounded, early-exiting loose-object scan. Repack only when pack count or
loose count crosses a threshold, or when a non-empty repo has no bitmap
(the bitmap floor keeps clones fast and is not defeatable by high
thresholds). A sub-threshold push does nothing beyond the gate.
When the gate fires, stage the repack on ephemeral disk: copy the bare
repo to a per-run dir under the configured stage dir, repack and write the
commit-graph on the copy, then write back additively. New packs install
companion-first with the .idx last so a reader never sees a pack without
its index; the commit-graph installs via temp-file rename. Only
snapshotted old packs are pruned, .idx first, and only after every new
file installs, so an interruption or concurrent push never leaves the live
repo invalid and loose objects are never removed. Pack files are
content-addressed, so same-named live files are skipped rather than
rewritten.
Add a KNOT_MAINTENANCE_ config section (loose threshold, pack threshold,
stage dir) threaded into the maintainer, create the stage dir in the
image, and keep the call synchronous with the per-repo lock.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Patch category: aerie-distribution