docs: R-94 closed, R-29 leg (a) closed + leg (b) half, R-168 minted

hub/CHANGELOG v0.87.0 + scripts/CHANGELOG gate-enforcement entry. CONTEXT gains S-6 (the
hub renders no host-install version and the gate pins its absence) and S-7 (gates run from
one entry point per repo; reuse_refs_check was fixed rather than the REUSE.md convention,
with both rejected alternatives recorded).

OPEN-ITEMS: R-94 CLOSED all three legs, leg (a) by DELETION with its reason; R-29 leg (a)
CLOSED and leg (b) HALF-SHIPPED with the census result written into the row (13 gates; every
gate a CLAUDE.md names was green, two of the four unnamed were red); R-161 gains its
successor pointer. NEW R-168 (grep established R-167 was the highest in use): Gitea Actions
runner — measured 2026-08-02 as Gitea 1.26.2, Actions enabled on all four repos, 0 runners,
0 workflow runs, 0 branch protections, and the consequence that trunk-based direct-to-main
pushes leave no merge for a status check to gate, so CI here can detect but not block.
BLOCKED on a spike over host-mode vs privileged DinD on DooPlex and whether the workflow can
avoid JavaScript actions.

ROADMAP: R-94 collapsed to its one-liner, R-29 updated, R-168 added.
This commit is contained in:
2026-08-02 15:28:31 +02:00
parent 9bd1a54d71
commit 4707be755c
6 changed files with 137 additions and 5 deletions
+46
View File
@@ -1,3 +1,49 @@
## Gate enforcement — one entry point per repo, and a pre-push hook (2026-08-02)
**No version bump: `scripts/` carries no version, and this is tooling.** Recorded explicitly so the
omission reads as a decision rather than a miss.
**The census that started it.** Thirteen gate scripts exist across the four felhom repos. A full run
on 2026-08-02 found one clean correlation: **every check a `CLAUDE.md` tells a person to run was
passing, and two of the four nobody is told to run were failing** — `hostinstall_gates.py` since
14 July, and `reuse_refs_check.py` on all four repos. Both failures were harmless in effect, which
was checked line by line; nothing would have said so if they had not been.
**`scripts/repo_gates.py` (new)** — THE entry point for this repo. Runs `site_gates`,
`hostinstall_gates`, `hub_confirm_gate`, `manifest_bearer_gate` and `reuse_refs_check` on this root,
streams each gate's own output, exits worst-wins non-zero, and reports exit 2 distinctly as
INCONCLUSIVE. **A missing gate script is a FAILURE and prints the path tried** — fail-closed, because
a runner that quietly skips a gate is the inert-seam failure this project has shipped four times. It
copies `app-catalog-felhom.eu/scripts/catalog_gates.py` (R-161), **not** `site_gates.py`, which is a
gate and not a runner — copying that would have produced a ninth monolith.
**`scripts/reuse_refs_check.py` — resolution taught, not loosened.** RED on all four repos with 13
findings, of which a hand audit found **zero** genuine drift: twelve were package shorthand whose
file sits a couple of directories deeper, and `wgsync/reconciler.go`, cited by the controller, lives
in the hub. `REUSE.md` cites by package shorthand and across repos on purpose; the tool was wrong.
New order, first hit wins: exact → suffix → ambiguous (real citation, imprecise shorthand — not a
failure) → sibling repo (as-is, or with the sibling's own name stripped off the front) → FAIL.
**Every non-exact hit is printed** and every root prints a per-rule tally, because "0 failures" alone
cannot tell a working checker from a blind one. A failure lists every resolution attempted. Evidence
trees (`audits/`, `documentation/tests/`) are excluded from the suffix index — a copy of a file is
not the file. An absent sibling is never a failure; an unreadable parent says so and continues.
Result: 13/13 resolve, all four roots exit 0.
**`scripts/test_reuse_refs_check.py` (new, 13 tests)** — one per resolution row plus the kill
condition. Red-proof: making `resolve()` return `exact` for an unresolvable token turns four of them
red. **`scripts/test_repo_gates.py` (new, 3 tests)** — a SEAM test asserting each member gate's own
distinctive stdout, never the runner's summary line; red-proofed with an inert `run_gate` that still
prints "all felhom.eu gates OK" and exits 0.
**`.githooks/pre-push` (new)** — runs `repo_gates.py --fast` and refuses the push. Its honest limits
are written into the hook itself: it is **per-clone** (`core.hooksPath` is local config; arm with
`git config core.hooksPath .githooks`, and any manual entry-point run WARNS when a clone is unarmed)
and **`git push --no-verify` bypasses it on purpose** — an escape hatch that cannot be reached is one
that gets removed the first time it is inconvenient; using it must be stated in the session report.
Measured on git 2.47.3: a relative `core.hooksPath` resolves correctly and the hook's cwd is the repo
root whether `git push` is issued from the root or any subdirectory. The half that is neither
per-clone nor skippable is CI — now tracked as R-168.
## ISO v1.26.1 — the PUBLIC installer ISO, PUBLISHED (2026-07-31)
**Live at `https://iso.felhom.eu/felhom-installer-1.26.1-pve9.2-1.iso`**