# REPORT — CI runs the static catalog gate on every push (R-168, 2026-08-02) **Overwritten** per the standing rule. The prior contents (`catalog_gates --fast` + the pre-push hook, same day) have their durable record in `CHANGELOG.md`. **No version bump, no build, no deploy.** This adds `.gitea/workflows/gates.yml` and a CHANGELOG entry. Nothing compiled changed. ## What changed `.gitea/workflows/gates.yml` — on every push, a Gitea Actions runner obtains this repo at the **exact pushed SHA** (shallow `git fetch`, no `uses:` step anywhere) and runs `python3 scripts/catalog_gates.py --fast` and nothing else. The exit code is the job's result: no `|| true`, no pipe that could swallow it. **It REPORTS, it cannot REFUSE**, and the workflow header says so in the pre-push hook's voice: this repo pushes straight to `main` with no pull request, so there is no merge for a status check to stand at. The refusing half is `.githooks/pre-push` (per-clone, `--no-verify`-able); this half notices when that was skipped. Making CI blocking needs branch protection plus a PR workflow — an operator decision, tracked as `felhom.eu` `OPEN-ITEMS.md` **R-169**. **A failed run emails the operator.** Probe P5 measured that Gitea itself sends **nothing** on a failed run — no mail, no notification row, no log line — so the workflow sends its own via Resend and prints the provider's accepted id, making "a message left the machine" an observable. Demonstrated on a real red run in `felhom.eu`: `RESEND-ACCEPTED id=5ff34766-c5f8-4588-8104-08296aeb45ab`. **`--fast` only, and that is the point.** `check-image-pins.py` runs; `check-image-resolvable.py` (network) and `check-volume-persistence.py` (Docker, minutes per app) do **not**. CI that pulls 53 images on every push gets disabled, and the bypass becomes the habit. No sibling clone is needed here — unlike the controller and the agent, `catalog_gates --fast` does not invoke the shared reuse checker. ## Verification First run: run #1, id=10, conclusion **success**, sha `aa57588f`. **Scenario F proven from the run log:** `image-pin gate OK — 53 templates, 0 unpinned images`, the skip announced (`--fast SKIPPED: image-resolvable, volume-persistence …`), and **zero** lines of resolvability output, volume-persistence output, canary output or image pulls. The runner is unprivileged host-mode, shared with the other three repos on a single owner-scoped registration (measured: all four repos' tasks claimed by `felhom-gates-runner`). Full probe detail, the security posture and the teardown: `felhom.eu/documentation/audits/SPIKE-ci-runner-2026-08-02.md` and `felhom.eu/REPORT.md`.