- 08 §10: built (controller 5bd03ad, hub 7e57e824, commit only); putback_pending as on the wire; as-built notes
- audits/d53-held-apps-2026-10-26: live proof on 9202 against a test hub (3-min grace), red-proofs, teardown
- R-1291 BUILT (not released); R-1298 filed (9202's orphan holds + PrivateBin leftover)
- test_gate_decoys.py: the register-shape cases also run the script and assert its exit code — R-1297's decoy 2
showed an inert main() passed every case (9 cases red with it now)
- audits/r1297-ci-trim-2026-10-26: runners, times, decoys
R-1297 — faster CI: two runners, the trim, the numbers, the decoys (2026-10-26 evening)
1. Both runners work (R-1297 B, done by the operator)
Two harmless docs commits pushed to two repos, read from the Gitea jobs API (runner_name is the job page's runner):
| Job | Repo, commit | Runner | Started | Ended |
|---|---|---|---|---|
| 2374 | felhom.eu 8143a2c8 |
felhom-gates-runner (id 2) |
17:11:15 | 17:17:06 |
| 2375 | felhom-agent ad80ee7 |
felhom-gates-runner-2 (id 3) |
17:11:41 | 17:12:56 |
At 17:11:41 UTC both jobs ran at the same time, on two different runners. The agent job queued 3 s.
2. The trim (R-1297 A, ecd82aba)
scripts/script_tests_gate.pyPATH_FILTERED: on a CI branch push with a known file list, three suites run only when one of their paths changed —test_gate_decoys.py(scripts/,.gitea/,.githooks/),test_due_checks_gate.py(its gate, itself,repo_gates.py,script_tests_gate.py),dooplex-offsite/test_dooplex_offsite.py(scripts/dooplex-offsite/). No list, an empty list or an unreadable list runs every suite. The pre-push hook sets no list, so it still runs every suite..gitea/workflows/gates.yml: a nightly schedule (03:20 UTC); the list is set only forpush:refs/heads/*. A tag, the nightly run and a manual dispatch run everything. A trimmed commits array (total_commits> listed) is an unknown list.test_repo_gates.pytests the wiring instead of running the whole gate set a second time: the real runner,GATESnarrowed by label to the five fingerprinted gates (130 s → 2.7 s). The same fortest_due_checks_gate.pygroup G (one more full run inside it, ~130 s → under 1 s).- Red-proved: the filter cases and the workflow pins (
test_script_tests_gate.py, red on the oldgates.yml), an inertrun_gate(test_repo_gates.pyred), an unregistered due-checks gate (group G red).
Not done: a Go build cache for hub-gofmt. The R-1297 row was wrong about it: CI has no Go toolchain, so hub-gofmt
says NOT CHECKED there in 0.1 s. The ~110 s after it in job 2366 was security-scan (gitleaks over the depth-1 tree);
on the 2-CPU runners it takes 27 s. Nothing to cache.
3. Times
| Commit | Before | After |
|---|---|---|
| (a) docs only | job 2370 (1 runner, 1 CPU): 810 s; job 2374 (2 CPUs, before the trim): 351 s | see the R-1297 row (the next docs-only push) |
| (b) touches a gate script | 351 s (every suite ran on every push) | job 2376 ecd82aba: 203 s (decoys ran; off-site skipped) |
| (c) a hub change | 351 s | job 2378 7e57e824: 118 s (all three skipped) |
Per-suite lines: ci-job-*-suites.txt.
4. Decoys — a broken gate still goes red with the filter ON
A red commit cannot be pushed (the pre-push hook refuses it; --no-verify is forbidden), so each decoy was run through
CI's own entry point (repo_gates.py --fast, FELHOM_CHANGED_FILES = the commit's file list, exactly as
gates.yml sets it) in a scratch clone of all four repos.
- Decoy 1 (docs only): R-1297's row loses its state and owner cells. All three heavy suites SKIPPED;
register-shapeCONVICTED; rc=1.decoy1.txt - Decoy 2 (a gate made inert):
register_shape_gate.pymain() convicts nothing. The decoy suite RAN (its path changed) — and stayed green, rc=0: its register-shape cases calledcheck()directly, never the script the runner calls. A real hole, older than the trim.decoy2.txt - Fixed in the same session (small;
test_gate_decoys.pynow asserts the script's exit code on every register-shape case). Decoy 2 again: 9 decoys exposed the hole,script-testsFAILED, rc=1.decoy2b.txt