From 31242786af691d4f6fd606456ee15d2cee70308e Mon Sep 17 00:00:00 2001 From: kisfenyo Date: Tue, 6 Oct 2026 13:44:01 +0200 Subject: [PATCH] =?UTF-8?q?Instruction=20files=20kept=20true=20(09=20?= =?UTF-8?q?=C2=A73=20decision=20150):=20stale=20gate=20lists,=20paths=20an?= =?UTF-8?q?d=20facts=20corrected;=20no=20code=20change?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS --- .claude/rules/gates.md | 20 ++++++++++---------- .claude/rules/unprompted-work.md | 13 ++++++++++++- CHANGELOG.md | 6 ++++++ CLAUDE.md | 8 ++++---- REPORT.md | 19 ++++++++----------- 5 files changed, 40 insertions(+), 26 deletions(-) diff --git a/.claude/rules/gates.md b/.claude/rules/gates.md index 708f722..c886a47 100644 --- a/.claude/rules/gates.md +++ b/.claude/rules/gates.md @@ -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`. diff --git a/.claude/rules/unprompted-work.md b/.claude/rules/unprompted-work.md index d7a83c5..49df8ff 100644 --- a/.claude/rules/unprompted-work.md +++ b/.claude/rules/unprompted-work.md @@ -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. diff --git a/CHANGELOG.md b/CHANGELOG.md index 7326455..e02be9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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). diff --git a/CLAUDE.md b/CLAUDE.md index 97f87aa..8c788c0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -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 | diff --git a/REPORT.md b/REPORT.md index a239aa8..d2d0ee9 100644 --- a/REPORT.md +++ b/REPORT.md @@ -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).