Files
admin c21bcf84f7
gates / gates (push) Successful in 7s
docs+gate: instruction files cannot silently regrow (R-229)
New shared scripts/instructions_gate.py, registered in controller_gates.py and
agent_gates.py, never copied into a sibling repo (the reuse_refs_check.py
precedent). 20 fixture tests, all asserting the effect: exit code AND that the
message names the file and the reason.

It is a consistency gate, not a budget gate, and the failure message says so. A
/context reading measured the instruction files at 15k tokens against 869k free in
a 1M window -- space is not the constraint, and a future reader must not re-derive
the wrong reason. The 200-line ceiling is adherence guidance; a file nobody can
hold in their head is where contradictions hide, and five were found here.

Checks run against effective text (HTML comments stripped, because they are
stripped before injection): the line ceiling; every .claude/rules/*.md declares
paths: or an explicit unconditional: true; no component version literal; no
TEMPORARY block carrying a past date; and the workspace-root CLAUDE.md is
byte-identical to its versioned copy -- the live file sits outside any git repo,
so that copy is its only version-controlled record.

Two traps recorded so they are not reintroduced: a bare \d+\.\d+\.\d+ matches the
first three octets of every IPv4 (the gate excludes dotted quads, or it fails on
192.168.0.180 in the agent's own file); and unconditional: true is NOT a Claude
Code feature but this project's own marker.

Workspace-root CLAUDE.md 208 -> 182 lines (142 effective), copy kept identical.
The nine-instance invariant table moved into the felhom-testing skill, which
triggers when writing or reviewing a test; all three directive bullets stayed in
the core. felhom.eu/CLAUDE.md got surgical corrections only and is knowingly still
over the ceiling at 227 effective lines -- closing it needs the restructure R-229
defers, said plainly rather than quietly absorbed.

CONTEXT.md gains standing ruling S-35. OPEN-ITEMS.md gains R-229.

Docs only -- no Go, no version bump, nothing built or deployed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JJc8sAGRWmavP3rMtdpkr2
2026-08-06 09:38:52 +02:00

10 KiB
Raw Permalink Blame History

REPORT — instruction-file rightsizing (core + path-scoped rules), 2026-08-06

Docs and gate only. No Go changed, no version bumped, no image built, nothing deployed, no customer machine touched. One read-only command ran against live hardware (ssh demo-hp "qm list"), permitted by the task for exactly one purpose.

The headline is the contradiction count, not a token saving. A /context reading measured the instruction files at 15k tokens against 869k free in a 1M window. Space was never the constraint; five stale or conflicting facts were.


1. Baselines

Repo main @ start Clean Note
felhom-controller a62bb3874b25 yes matched spec
felhom-agent a2e914f683bd yes matched spec
felhom.eu d30c2a51ed2a yes matched spec
app-catalog-felhom.eu ee2c8102016a yes untouched — 79 lines, already the target shape, cited as the model

One correction: the workspace-root CLAUDE.md measured 16,642 B / 208 lines, not the spec's 15,431 / 207 — it was edited at 08:32 that morning, after the spec was written. The other five files matched exactly. Also structural: /mnt/5_hdd/felhom.eu/git is not a git repository, so the live root CLAUDE.md is untracked; only its copy under felhom.eu/ is version-controlled.

2. Contradictions: 5 before → 0 after

# What conflicted Resolution
1 agent said demo-hp hosts drill VM 300; controller said none was provisioned Measured live: qm list300 drill-r50 stopped. felhom-agent was right. nodes.md:96 already said so correctly — both CLAUDE.md blocks became pointers, no new text needed
2 agent's TEMPORARY block (expired 2026-08-02) said felhom-pve was remote; controller said it was back on the LAN both deleted; the audit holds the record. The gate now fails any past-dated TEMPORARY block
3 controller pinned agent 0.93.0, against the root file's own no-versions rule every version literal removed from effective text in all four files
4 controller gave demo-felhom as the LAN fallback address as if it were the route host tables removed from all three CLAUDE.md files → nodes.md
5 root file said memory held (119 files); it holds 157 + the index parenthetical deleted, not corrected — derivable, and it would go stale again

The sweep found none beyond the five.

3. Before / after (effective = HTML comments stripped, i.e. what the model receives)

File before after raw after effective gate
workspace-root CLAUDE.md 208 ln / 16,642 B 182 / 11,280 142 / 8,105 pass
versioned copy 208 / 16,642 182 / 11,280 142 / 8,105 pass — cmp identical
felhom-controller/CLAUDE.md 215 / 14,775 110 / 6,341 92 / 4,881 pass
felhom-agent/CLAUDE.md 216 / 15,554 205 / 13,619 173 / 11,491 pass
felhom.eu/CLAUDE.md 241 / 17,471 235 / 17,003 227 / 16,286 over — deferred

A controller session's instruction load: 31,417 → 12,986 effective bytes (59%).

Figures are bytes, deliberately. The measured /context ratio shows a bytes/4 token estimate understates the true cost by 1.591.90×, so byte counts are the honest unit here.

felhom.eu/CLAUDE.md is knowingly left over the ceiling. Getting it under 200 needs the core+rules restructure the spec explicitly forbade for reviewability, and the gate is registered only in the controller and agent runners. Deferred as R-229, said plainly rather than quietly absorbed.

4. Files created / modified

Created: felhom-controller/.claude/rules/{gates,ui-hungarian,backup-paths,agent-coupling}.md · felhom-agent/.claude/rules/health-checks.md · felhom.eu/scripts/instructions_gate.py · felhom.eu/scripts/test_instructions_gate.py · felhom.eu/documentation/audits/LEDGER-instruction-trim-2026-08-06.md

Modified: the four CLAUDE.md files + the versioned copy · controller_gates.py · agent_gates.py · skills/felhom-testing/SKILL.md (gained the nine-instance table) · three CHANGELOG.md · CONTEXT.md (S-35) · OPEN-ITEMS.md (R-229)

5. Mechanism verification — done before relying on it

The whole design rests on three claims. Two were confirmed, one was false:

Claim Verdict
.claude/rules/*.md + paths: loads only on a matching file read confirmed against the installed 2.1.222 build
HTML comments are stripped before injection confirmed empirically — control (both markers plain → both reported) vs treatment (one commented → not reported, twice)
unconditional: true frontmatter NOT a product feature. It is this project's own marker; the gate's docstring says so, so nobody hunts for it in the docs

The HTML-comment test failed its first red-proof — an open-ended prompt returned one marker in both arms, so the instrument was dropping a result silently. Rewritten as forced yes/no questions with a both-plain control, it discriminated. Worth recording: this project's own rule ("an instrument that can drop results silently is not a measurement") caught a measurement made for this task.

6. Amnesty list (the list to review)

Deliberately short — one item qualified:

  • Three generic code-quality bullets in felhom.eu/CLAUDE.md ("always double-check generated code", "handle edge cases without overcomplicating", "add debug capabilities"). No recorded production violation, recoverable worst case, and duplicated in the workspace root. "ask first — don't guess" was kept — that one is a real behavioural directive.

Nothing on the protected list was touched. The nine-row invariant table, "presence is not success", the four R-96 rules, the F9 fence, secrets handling, trunk-based, the DooPlex protections, the destructive-target fences with their permitted targets, and the clean-tree gate all survive — moved or compressed, never dropped, each compressed fence keeping its target and its reason.

7. Gate results

  • controller_gates.py --fastall 9 gates OK, including the new instructions.
  • agent_gates.py --fastboth gates OK.
  • test_instructions_gate.py20 passed, 0 failed.
  • go build ./... && go vet ./... && go test ./...green in all three modules (felhom-controller/controller, felhom.eu/hub, felhom-agent) — and unchanged, as required: no Go was touched.
  • Registration seam asserted by parsing each runner's GATES list from the AST, not by grepping the source — a commented-out registration would not satisfy it.

Red-proof (ceiling temporarily 100, real trimmed files):

  CLAUDE.md effective lines : 92 (ceiling 100)     [felhom-controller]
  CLAUDE.md effective lines : 173 (ceiling 100)    [felhom-agent]
instructions_gate: 1 FAILURE(S)
  - .../felhom-agent/CLAUDE.md: 173 effective lines, ceiling 100. This is an ADHERENCE limit,
    not a space limit — long instruction files get followed less reliably and hide contradictions.

It discriminated: agent failed and was named, controller still passed. Threshold restored, suite re-run green.

8. MEMORY.md — measured only, unchanged

146 lines / 17,688 B (17.3 KB) against the 200-line / 25 KB limits: within both, nothing truncated. The expected finding is absent; a different one is present — the index references 113 memory files while 157 exist on disk, and zero referenced files are missing. So 44 memory files are unindexed. Recorded, not acted on (the ruling deferred this).

9. Delegation

No subagent was used. All search, inventory and verification was done in-session. Nothing was delegated, so nothing needs the read-only caveat.

10. Which files actually load

Settled from the supplied /context, not assumed: at the workspace root exactly two memory files load — the root CLAUDE.md (6.6k tokens) and MEMORY.md (8.4k). Per-repo CLAUDE.md files are not loaded at launch; they load on demand when a file in that directory is read. This is why the irreversible fences were kept in the root file.

Still outstanding (HUMAN): /context all from inside felhom-controller after this trim, to give the measured after-figure and confirm which rule files a repo session actually pulls in. Claude Code cannot invoke a slash command on itself. The after-figures above are byte counts from disk, not measured tokens, and are labelled as such.

11. Register

OPEN-ITEMS.md row taken: R-229 (READY, owner Viktor) — covering felhom.eu/CLAUDE.md's restructure, felhom-agent's remaining headroom, the auto-memory decision, and the spec-as-failing-test pilot.

12. Observations — not acted on

  1. target-selection.md's known t740 off-site-tier error is still there (out of scope).
  2. The root CLAUDE.md could be a symlink to its versioned copy, removing the divergence class entirely — same filesystem, and Claude Code reads through symlinks (the four skills already are). Not done, per the spec. If adopted, the gate's copy-identity check should become a symlink-target check.
  3. A blanket version-literal ban has a false-positive class the spec did not anticipate: a bare \d+\.\d+\.\d+ matches the first three octets of every IPv4. Without the dotted-quad exclusion the gate fails on 192.168.0.180 in the agent's own file.
  4. The spec calls the invariant table "the eight-invariant table"; it has nine rows and its own text says "Nine instances". Flagged so the protected list is not later applied to eight of nine.
  5. demo-hp also hosts VM 321 c11-appliance, running — seen in the same qm list, not mentioned in nodes.md. Not investigated.
  6. Two unused Claude Code plugins (typescript-lsp, context7) and a broad user-scope allowlist (Bash(python3:*), Bash(curl:*), Bash(scp:*) — standing arbitrary execution and network egress in every project) were found by the earlier setup audit. They live in ~/.claude/settings.json, not in any repo, and are deliberately out of scope. Recorded only.