docs: R-168 SHIPPED, R-29 CLOSED on the demonstrated alarm, R-169 minted
gates / gates (push) Successful in 7s
gates / gates (push) Successful in 7s
SPIKE-ci-runner-2026-08-02.md: all six probes with method, measurement and ruling; none STOPped. P2 (stock image has git but no python3) and P6 (a runner that loses its state re-registers and orphans the old record) changed the design; P5 (a failed run signals NOTHING) is why the alarm exists at all. R-168 SHIPPED with its evidence. R-29 CLOSED — on the demonstrated alarm and not on a green run, as required: the class it opened is answered at both ends, the hook refusing locally and CI catching a --no-verify bypass and emailing. R-161 noted: its automatic half now exists for the STATIC gate, while its original scope, the runtime gate, is deliberately still not automatic and should stay that way. NEW R-169 (grep established R-168 was the highest in use): CI can only report, because there is no gate in the road. Making it blocking needs branch protection plus a PR workflow, both of which change how the operator works — so it is theirs to decide, and the row states the cost honestly rather than recommending it. CONTEXT gains S-8 (CI detects, does not block, and why that is structural), S-9 (a detector that tells no one is not finished, plus the curl and Cloudflare-1010 traps), S-10 (the runner is unprivileged because DooPlex is Tier 2), S-11 (CI reproduces the sibling layout). CLAUDE.md gains the rule earned by red-proofing: a go test -run pattern that matches no test prints ok and exits 0, and an instrument that can silently drop results is not a measurement.
This commit is contained in:
@@ -1,3 +1,52 @@
|
||||
## CI — a Gitea Actions runner, and a red run that reaches a person (2026-08-02, R-168)
|
||||
|
||||
**No version bump anywhere: nothing in the product repos is compiled, built or deployed by this.**
|
||||
Recorded explicitly so the omission reads as a decision rather than a miss.
|
||||
|
||||
**What this closes.** Session 1 (same day) gave every repo one gate entry point and a
|
||||
`.githooks/pre-push` that refuses a failing push. That hook is per-clone and `--no-verify` skips it,
|
||||
so nothing independent of the person pushing ever saw whether the gates passed. This is the
|
||||
independent half, and with it **R-29 CLOSES** — on the demonstrated alarm, not on a green run.
|
||||
|
||||
**`.gitea/workflows/gates.yml` (new)** — triggers on `push`, `runs-on: felhom-gates`, obtains the
|
||||
source with a shallow `git fetch` of the **exact pushed SHA** from the in-cluster Gitea Service, and
|
||||
runs `scripts/repo_gates.py --fast` and nothing else. **No `uses:` step anywhere** — JavaScript
|
||||
actions need a node runtime the host-mode runner does not have, and probe P3 measured that a plain
|
||||
`git fetch` is sufficient and lands on the pushed commit. No `|| true`; the entry point's exit code
|
||||
IS the job's result.
|
||||
|
||||
**The alarm, which is the half that matters.** Probe P5 measured that a failed run produces **no
|
||||
mail, no notification row and no log line** from Gitea. A red tick in a web UI nobody watches is
|
||||
exactly the defect R-29 filed, rebuilt one layer up — so the workflow sends its own email on failure
|
||||
via Resend (the hub's existing transactional path) and **prints the provider's accepted id**, making
|
||||
"a message left the machine" an observable. **Demonstrated, not asserted:** a deliberately broken
|
||||
commit pushed with `--no-verify` produced run #6 `failure` and
|
||||
`RESEND-ACCEPTED id=5ff34766-c5f8-4588-8104-08296aeb45ab`.
|
||||
|
||||
Two traps found while building it, both worth keeping because each looks like something else:
|
||||
the runner image has **no `curl`** on purpose (python3 and git only — so the step uses `urllib`
|
||||
rather than growing the image), and `api.resend.com` sits behind **Cloudflare, which 403s the default
|
||||
`Python-urllib` User-Agent with error 1010** — a failure that reads exactly like an auth failure and
|
||||
is not one.
|
||||
|
||||
**The standing limit, written into the workflow itself: it REPORTS, it cannot REFUSE.** Every repo
|
||||
pushes straight to `main` with no pull request, so there is no merge for a status check to stand at.
|
||||
That is not a gap in the runner; there is no gate in the road. Making it blocking needs branch
|
||||
protection plus a PR workflow, which changes how the operator works → **R-169**, waiting on them.
|
||||
|
||||
**`documentation/audits/SPIKE-ci-runner-2026-08-02.md` (new)** — all six probes, method, measurement
|
||||
and ruling; none produced a STOP. Also records a near-miss worth more than the probes: a `| tail -5`
|
||||
inside my own census query silently dropped rows and looked exactly like a baseline drift big enough
|
||||
to change the task. **An instrument that can drop results silently is not a measurement.**
|
||||
|
||||
**`CLAUDE.md`** gains the matching rule from session 1's red-proofing: a `go test -run` pattern that
|
||||
matches no test prints `ok` and exits 0, so a red-proof using `-run` must first prove the filter
|
||||
matched something.
|
||||
|
||||
**`CONTEXT.md`** gains S-8 (CI detects, does not block, and why that is structural), S-9 (a detector
|
||||
that tells no one is not finished), S-10 (the runner is unprivileged because DooPlex is Tier 2), and
|
||||
S-11 (CI reproduces the workspace's sibling layout, because two entry points depend on it).
|
||||
|
||||
## 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
|
||||
|
||||
Reference in New Issue
Block a user