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 ## The ONE entry point
**Run `python3 controller/scripts/controller_gates.py` (from `controller/`) after ANY change in this **Run `python3 scripts/controller_gates.py` from `controller/` (or `python3
repo.** It runs the local gates — `template_id_gate`, `emoji_gate`, `native_confirm_gate`, controller/scripts/controller_gates.py` from the repo root) after ANY change in this repo.** It runs
`offbox_rename_gate`, `app_row_dedup_gate`, `mojibake_gate`, `docker_run_volume_path_gate`, every gate in the runner's `GATES` table, the shared `reuse_refs_check`, `instructions_gate` and
`secret_in_markup_gate`, `retrieval_promise_gate`, `debug_route_gate` — plus `reuse_refs_check`, `observations_gate` among them, streaming each gate's own output and exiting non-zero if any fails;
`instructions_gate` and `observations_gate` on the repo root, streaming each gate's own output and one, `golden-notice`, is ADVISORY and never refuses. **The `GATES` table is the list; this sentence is a
exiting non-zero if any fails. **The runner's `GATES` table is the list; this sentence is a pointer to pointer to it, not a second copy** — it drifted twice (it said "seven" while nine were registered, then
it, not a second copy** — it has already drifted once (it said "seven" while nine were registered). 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. - `--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.** - **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. 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 - **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 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 **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 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. 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 **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. 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 **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 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 > `/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 > 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 ## 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 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 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. 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) ## 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). **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` | | which box may I break | `felhom.eu/documentation/runbooks/target-selection.md` |
| host addresses, break-glass, node facts | `felhom.eu/documentation/operations/nodes.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** | | 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 ## 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. - 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. - 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. - `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) - Env var KEYS are logged, never values. Protected stacks (traefik, cloudflared, felhom-controller,
cannot be stopped from the UI. and always samba) cannot be stopped from the UI.
- Verify a container image HAS the healthcheck tool before using it (BusyBox wget / python3 / curl — - Verify a container image HAS the healthcheck tool before using it (BusyBox wget / python3 / curl —
the catalog `REUSE.md` maps the families). the catalog `REUSE.md` maps the families).
- `IsRunning()` is CONCURRENCY, false during a verification restore — display MUST use - `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 | | 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 ./...` | | Green gate | `go build ./... && go vet ./... && go test ./...` |
| Build + deploy | the **`felhom-build-deploy`** skill — do not hand-roll it | | 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 ≠ Edits here:
running), in every night leg; one amber line on the backups page. Proven by `TestR645_HandLiftedHoldKeepsTheGoodUnit` - `.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").
(red-proved). Residual: once the boot reconciler starts the new version, pin = running again (a design question). - `.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/`.
- **R-856** (decision 143): after a crash boot of the host, app mails wait ~15 min; a normal boot keeps 90 s; unknown = - `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).
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.