--- paths: ["controller/**/*.go", "controller/**/*.html", "controller/**/*.css", "controller/scripts/**"] --- # Gates and logging — felhom-controller ## The ONE entry point **Run `python3 controller/scripts/controller_gates.py` (from `controller/`) after ANY change in this repo.** It runs all seven local gates — `template_id_gate`, `emoji_gate`, `native_confirm_gate`, `offbox_rename_gate`, `app_row_dedup_gate`, `mojibake_gate`, `docker_run_volume_path_gate` — plus `reuse_refs_check` and `instructions_gate` on the repo root, streaming each gate's own output and exiting non-zero if any fails. - `--fast` selects the gates that touch no network and no container runtime; today that is all of them. - **A missing gate script is a FAILURE, never a skip.** - **The shared `reuse_refs_check.py` and `instructions_gate.py` live in `felhom.eu/scripts/` and are never copied here** — a copy would recreate the drift they detect; an absent sibling clone FAILS. - **The pre-push hook** (`.githooks/pre-push`) runs it with `--fast` and refuses a failing push. It is per-clone — switch it on once with `git config core.hooksPath .githooks`, and a manual run WARNS when this clone is unarmed. `git push --no-verify` bypasses it deliberately; **say so in the session report when you use it.** Both facts are why CI is still owed (`OPEN-ITEMS.md` R-168). ## Logging New leveled lines use `internal/logx` — DEBUG always reaches the debug ring; stdout respects `logging.level`. English, keys-never-values, durations on outcomes. Full rules: `felhom.eu/documentation/runbooks/logging-conventions.md`. ## Health checks issue no block I/O A probe that touches a wedged device enters uninterruptible sleep, survives `SIGKILL`, and cannot be recovered until the device returns or the host reboots — so `systemctl restart` hangs too. A timeout protects the caller's control flow and nothing else: the blocked thread remains. Liveness is decided from `/proc` and kernel state, never by reading or writing the filesystem.