Instruction files kept true (09 §3 decision 150): stale gate lists, paths and facts corrected; no code change
gates / gates (push) Successful in 52s

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
2026-10-06 13:44:01 +02:00
parent 36088fd82e
commit 31242786af
5 changed files with 40 additions and 26 deletions
+10 -10
View File
@@ -6,17 +6,17 @@ paths: ["controller/**/*.go", "controller/**/*.html", "controller/**/*.css", "co
## The ONE entry point
**Run `python3 controller/scripts/controller_gates.py` (from `controller/`) after ANY change in this
repo.** It runs the local gates — `template_id_gate`, `emoji_gate`, `native_confirm_gate`,
`offbox_rename_gate`, `app_row_dedup_gate`, `mojibake_gate`, `docker_run_volume_path_gate`,
`secret_in_markup_gate`, `retrieval_promise_gate`, `debug_route_gate` — plus `reuse_refs_check`,
`instructions_gate` and `observations_gate` on the repo root, streaming each gate's own output and
exiting non-zero if any fails. **The runner's `GATES` table is the list; this sentence is a pointer to
it, not a second copy** — it has already drifted once (it said "seven" while nine were registered).
**Run `python3 scripts/controller_gates.py` from `controller/` (or `python3
controller/scripts/controller_gates.py` from the repo root) after ANY change in this repo.** It runs
every gate in the runner's `GATES` table, the shared `reuse_refs_check`, `instructions_gate` and
`observations_gate` among them, streaming each gate's own output and exiting non-zero if any fails;
one, `golden-notice`, is ADVISORY and never refuses. **The `GATES` table is the list; this sentence is a
pointer to it, not a second copy** — it drifted twice (it said "seven" while nine were registered, then
named ten local gates while fourteen were).
- `--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
- **The shared `reuse_refs_check.py`, `instructions_gate.py` and `observations_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
@@ -59,7 +59,7 @@ fast, and wrong.
**A decoy is the LABEL without the FACT** — a directory with the right name and no bake log, a
handler case that exists only in a comment, a note whose prose mentions the marker it lacks. Write
one for every new gate, run it, and watch it convict. `scripts/decoy_coverage_gate.py` refuses a gate
one for every new gate, run it, and watch it convict. `felhom.eu/scripts/decoy_coverage_gate.py` (run by felhom.eu's `repo_gates.py`, for all four repos) refuses a gate
registered without one, or without a named exemption carrying its row.
**Earned by five instances, every one found by accident:** R-410, R-400, R-378, R-419, R-94. The
@@ -75,4 +75,4 @@ green and correct today, blind the moment anyone adds a subdirectory. Prefer `os
glob over a hand-maintained list of files.
**A decoy nobody would write proves nothing** — say the gate is sound and move on. Five of mine were
withdrawn as illegitimate and are named in `documentation/audits/AUDIT-gate-decoys-2026-09-01.md`.
withdrawn as illegitimate and are named in `felhom.eu/documentation/audits/AUDIT-gate-decoys-2026-09-01.md`.
+12 -1
View File
@@ -6,7 +6,8 @@ unconditional: true
> Goal sessions, nightly sessions, "work the register" sessions. **A session that starts from
> `/goal` or a standing brief inherits these rules exactly as it inherits the gates.** They are the
> part of `PROMPT-TEMPLATE.md` that a task file used to carry and a goal does not. Same wording lives
> in all three repos' `.claude/rules/`; change it in all three or in none.
> in `felhom.eu`, `felhom-controller` and `app-catalog-felhom.eu` `.claude/rules/`, and in the workspace root's
> unversioned `.claude/rules/`; change all four or none.
## 1. What you may pick up on your own
@@ -56,3 +57,13 @@ One screen, plain language, in this order: **decisions you took** (§2) first; w
what broke and whether you fixed it; rows opened and closed with the register size before and after;
what needs the operator, each with what happens if they do nothing. No file paths, no function
names, no row numbers as the subject of a sentence.
## 5. Instruction files
**Instruction files (`CLAUDE.md`, `.claude/rules/*`) are kept true by the session that finds them wrong**
(operator ruling 2026-10-06, `09` §3 decision 150). A session MAY, without asking: correct a stale fact (a command, a
count, a version, a path, a description of what a gate does), add a fact it proved, and remove a reference to something
that no longer exists. Each edit is named in the report (file, line, before, after, why). A session MAY NOT, without the
operator's word: loosen a safety rule, a fence, a „never", a protected machine, a secret rule, or a review step; or
remove a rule. When in doubt, it is a rule change, and it goes to the operator. If Claude Code's own permission check
asks before such an edit, wait for the operator's click; if it refuses, record that and file the exact line.
+6
View File
@@ -1,3 +1,9 @@
## Unreleased (2026-10-06 afternoon) — instruction files kept true (`09` §3 decision 150); no code change
- `.claude/rules/unprompted-work.md`: §5 „Instruction files" (the operator's standing rule) and the copies line names the four copies (it said „all three repos").
- `.claude/rules/gates.md` + `CLAUDE.md`: the gates command is `python3 scripts/controller_gates.py` from `controller/` (the old path did not exist from there); the gate list is a pointer to the `GATES` table (it named ten local gates while fourteen run; `golden-notice` is advisory); `observations_gate.py` is shared too; the decoy gate is named with its `felhom.eu/` prefix.
- `CLAUDE.md`: protected stacks include samba, always (`config.go` `alwaysProtectedStacks`); the design pointer names `architecture/NN-*.md`.
## v0.300.0 — the night backup leaves an app alone that runs another version than it saved; after a crash boot app mails wait 15 minutes (R-645, R-856; operator rulings `09` §3 142, 143) (2026-10-06)
**MinAgent: 0.131.0** (unchanged — R-856 reads the agent's `GET /host/crash-guard` (agent 0.149.0); an older agent answers 404 and the controller keeps the normal 90 s grace).
+4 -4
View File
@@ -27,7 +27,7 @@ integrations, git-sync, notifications. Disk/host/Proxmox concerns are delegated
| which box may I break | `felhom.eu/documentation/runbooks/target-selection.md` |
| host addresses, break-glass, node facts | `felhom.eu/documentation/operations/nodes.md` |
| what version is live anywhere | ask the hub (`/hosts`, `/configs`) or the box — **never a doc** |
| the authoritative design | `felhom.eu/documentation/architecture/01/02/03-*.md` |
| the authoritative design | `felhom.eu/documentation/architecture/NN-*.md` (01–03 for this repo; 07 backup, 09 updates, 10 language) |
## Session-critical invariants
@@ -37,8 +37,8 @@ The rest live in `REUSE.md`. These cost incidents to learn:
- Docker's `.State` says "running" even for unhealthy containers — the `.Status` parse is the truth.
- In-memory `Deployed` is set BEFORE `compose up -d` (slow-pull race); reverted on failure.
- `compose up -d` exits 0 on crash-loops — the post-start status check is the detection.
- Env var KEYS are logged, never values. Protected stacks (traefik, cloudflared, felhom-controller)
cannot be stopped from the UI.
- Env var KEYS are logged, never values. Protected stacks (traefik, cloudflared, felhom-controller,
and always samba) cannot be stopped from the UI.
- Verify a container image HAS the healthcheck tool before using it (BusyBox wget / python3 / curl —
the catalog `REUSE.md` maps the families).
- `IsRunning()` is CONCURRENCY, false during a verification restore — display MUST use
@@ -61,7 +61,7 @@ credentials) — they load when you touch a template or stylesheet.
| Surface | Command |
|---|---|
| Gates (after ANY change) | `python3 controller/scripts/controller_gates.py` — from `controller/` |
| Gates (after ANY change) | `python3 scripts/controller_gates.py` — from `controller/` |
| Green gate | `go build ./... && go vet ./... && go test ./...` |
| Build + deploy | the **`felhom-build-deploy`** skill — do not hand-roll it |
+8 -11
View File
@@ -1,13 +1,10 @@
# REPORT — controller v0.300.0 (2026-10-06, the operator's ten answers)
# REPORT — instruction files kept true (2026-10-06 afternoon)
Full session report: `felhom.eu/REPORT.md`. Baseline `13bda27` (v0.299.0). **MinAgent 0.131.0**.
Operator ruling 2026-10-06 13:25 (`09` §3 decision 150): a session corrects a stale fact in an instruction file
itself and names the edit; it may not loosen a rule. No code changed in this repo. The full session report, with every
instruction-file edit (file, before, after, why), is `felhom.eu/REPORT.md`.
- **R-645** (`09` §3 decision 142): the night backup skips an app that runs another version than it saved (pin ≠
running), in every night leg; one amber line on the backups page. Proven by `TestR645_HandLiftedHoldKeepsTheGoodUnit`
(red-proved). Residual: once the boot reconciler starts the new version, pin = running again (a design question).
- **R-856** (decision 143): after a crash boot of the host, app mails wait ~15 min; a normal boot keeps 90 s; unknown =
normal. Reads the agent's new `GET /host/crash-guard` (agent v0.149.0). Live on demo-hp and demo-felhom: both logged the
NORMAL branch with the right reason; the crash branch is covered by tests only (no crash allowed).
Released: image `felhom-controller:0.300.0`, golden 0.300.0 (pinned Docker set), vouched with agent 0.149.0, floors 0.300.0
for demo-hp, demo-felhom, Tester 1 — all three run it. Full suite rc 0, gates rc 0, CI 1424 success.
Edits here:
- `.claude/rules/unprompted-work.md`: new §5 (the standing rule, verbatim); the copies line now names felhom.eu, felhom-controller, app-catalog-felhom.eu and the workspace root (it said „all three repos").
- `.claude/rules/gates.md`: command `python3 controller/scripts/controller_gates.py` (from `controller/`) → `python3 scripts/controller_gates.py` from `controller/`. Why: the old path does not exist from there (the runner's own usage line and CI use the new one). The list of ten local gates → a pointer to `GATES` (fourteen local + three shared + the advisory `golden-notice`). `observations_gate.py` added to the shared list. Decoy gate path gained `felhom.eu/`.
- `CLAUDE.md`: the same command fix in the Commands table; „Protected stacks (traefik, cloudflared, felhom-controller)" → „…, and always samba" (`internal/config/config.go` `alwaysProtectedStacks`); design pointer `architecture/01/02/03-*.md` → `architecture/NN-*.md` (01–03 for this repo; 07, 09, 10).