a0b50eb48f
gates / gates (push) Successful in 8s
Found by the checklist's own last item (confirm your push's CI run by run ID). Corrected here and in the three sibling repos. Ledger J2 records the two lessons: a trim is a VOLUME operation and carries stale claims forward unless each is re-checked, and the gate cannot catch this class -- "this register item is closed" is not mechanically checkable from the instruction file.
171 lines
8.2 KiB
Markdown
171 lines
8.2 KiB
Markdown
# REPORT — instruction trim part 2: `felhom.eu`, the memory index, the versioned workspace
|
|
|
|
**2026-08-06.** Closes R-229 legs (a) and (c). Opens R-230 and R-231.
|
|
Full per-block accounting: `documentation/audits/LEDGER-instruction-trim-part2-2026-08-06.md`.
|
|
|
|
> **Parallel session.** A second Claude Code session was live in these repos throughout. Per
|
|
> `CLAUDE.md`'s rule this report is a `REPORT-<topic>.md` sibling; the shared `REPORT.md` was not
|
|
> touched.
|
|
|
|
## 1. Baselines
|
|
|
|
`felhom.eu` `c21bcf84f709` · `felhom-controller` `7db42c5fec3b` · `felhom-agent` `062a7027abff` —
|
|
all clean, all `HEAD == origin/main` at start. Only `felhom.eu` was written to.
|
|
|
|
## 2. `felhom.eu/CLAUDE.md`
|
|
|
|
| | before | after |
|
|
|---|---|---|
|
|
| raw lines | 252 | **130** |
|
|
| **effective lines** | **227** | **115** |
|
|
| bytes | 16,698 | 7,824 |
|
|
|
|
Split into a core plus `.claude/rules/{hub,website,manifests,docs}.md` — 4 files, all
|
|
`paths:`-scoped, all ≤60 effective lines. **`instructions_gate` is registered** in
|
|
`scripts/repo_gates.py`: six gates, all OK. Order was load-bearing — trim first, register second,
|
|
because a registered-but-failing gate refuses every push through `.githooks/pre-push`.
|
|
|
|
Two blocks were kept in the core against §6's sketch, both to avoid rebuilding the failure class
|
|
they prevent: **register discipline** (applies to every session, not only `documentation/**` ones)
|
|
and the **R-110 installer fence** (triggered by `scripts/felhom-host-install.sh`, which no fixed glob
|
|
matches). Ledger §C.
|
|
|
|
## 3. Hook evidence for Scenario B — both directions
|
|
|
|
Two **fresh** sessions, so the negative control cannot be explained by prior loading:
|
|
|
|
| Run | File read | `hub.md` | `website.md` |
|
|
|---|---|---|---|
|
|
| A | `website/index.html` | — | `path_glob_match` |
|
|
| B | `hub/internal/api/handler.go` | `path_glob_match` | — |
|
|
|
|
**Why fresh sessions were required — the session's most useful negative result:** after creating
|
|
`.claude/rules/`, in-session reads that should have matched produced **no hook line at all**. A
|
|
directory whose instructions were already seeded is not re-scanned. A rule file can be correct, pass
|
|
every gate, and reach the model never, purely because of when it was created.
|
|
|
|
## 4. Always-loaded total
|
|
|
|
Measured `/context` (operator-supplied, this session): Memory files held at **11.5k tokens** across
|
|
three rule loads while Messages grew 8 → 105.7k. **The 11.5k baseline is unchanged by this work**,
|
|
because `MEMORY.md` moved 17,688 → 17,977 bytes (+1.6%) — the reconciliation was net-neutral by
|
|
design, trading 40 archived entries for 4 indexed ones plus trimmed detail. A fresh session is needed
|
|
for a post-change token reading; the byte figures above are exact.
|
|
|
|
## 5. Memory reconciliation
|
|
|
|
Backup: `/mnt/5_hdd/felhom.eu/backups/claude-memory-20260806-103418` (158 files, taken first).
|
|
|
|
| | before | after |
|
|
|---|---|---|
|
|
| `.md` files | 158 | **158 — zero deletions** |
|
|
| orphaned | **44** | **0** |
|
|
| indexed / archived | 113 / — | 117 / **40** |
|
|
| `MEMORY.md` | 145 ln / 17,688 B | **150 ln / 17,977 B** |
|
|
|
|
**Headroom: 50 lines and 7,622 bytes (29%)** against the 200-line / 25 KB limits. The
|
|
index-vs-archive discriminator was the store's own `type:` field: all 4 `reference` orphans indexed,
|
|
all 39 `project` + 1 untyped archived.
|
|
|
|
## 6. Staleness diagnosis — **diagnosed, not fixed** (R-230(a))
|
|
|
|
- **21 lines** carry component version literals
|
|
- **5 lines** carry bare host addresses `nodes.md` owns
|
|
- **3** expired temporal statements; **2** undated open items
|
|
|
|
**The structural finding, not the counts:** `felhom-agent/CLAUDE.md` had its expired
|
|
`TEMPORARY … until ~2026-08-02` block deleted in part 1 and the gate now fails any such block — while
|
|
`MEMORY.md` still asserts *"demo boxes REMOTE till ~08-02"*. The contradiction was **moved, not
|
|
resolved**: the hand-written half is clean, the auto-written half — which is larger and loads every
|
|
session — still states the retired fact.
|
|
|
|
## 7. Secrets scan
|
|
|
|
535 keyword-matching lines across 104 files; **1** `key: value`-shaped hit, which is prose; **0**
|
|
private-key blocks. **No credential values.** Nothing from the store was committed regardless.
|
|
|
|
## 8. Gates
|
|
|
|
`repo_gates.py --fast` → **6 gates, all OK, rc=0**. Test suite **20 → 39 assertions, 0 failures**.
|
|
|
|
Red-proof against the **real** store, not a fixture — ceiling 200 → 100:
|
|
|
|
```
|
|
memory index : 150 lines (ceiling 100), 17977 bytes (ceiling 25600)
|
|
instructions_gate: 1 FAILURE(S)
|
|
- /mnt/5_hdd/felhom.eu/git/.claude-memory/MEMORY.md: 150 lines, ceiling 100. Content past the
|
|
auto-memory limit is DROPPED WITH NO ERROR — a truncated index is a silent failure with no
|
|
observable. …
|
|
```
|
|
|
|
Ceiling restored; gate `rc=0` and suite 39/0 again.
|
|
|
|
## 9. Installer
|
|
|
|
Idempotency: run 2 reported *"nothing to do"* and `settings.json` sha was **identical** before and
|
|
after — the claim is "changed nothing the second time", not "ran twice without erroring".
|
|
|
|
Merge safety: `sha256` of `settings.json` **minus `.hooks`** was `f1775e94aa9d1ca9` before and after
|
|
the write; all 7 top-level keys, 30 permission entries, 3 plugins, `effortLevel`, `tui` and
|
|
`additionalDirectories` survived byte-identically.
|
|
|
|
## 10. Backup coverage — positive observable
|
|
|
|
From the journal of the real unit:
|
|
|
|
```
|
|
Including Claude auto-memory store: /mnt/5_hdd/felhom.eu/git/.claude-memory
|
|
start backup on [/mnt/4_hdd/data /mnt/5_hdd/felhom.eu/git/.claude-memory]
|
|
```
|
|
|
|
**Three caveats that make this weaker than "backed up" sounds:** the destination is on the **same
|
|
physical disk** as the store; the DooPlex backup set has **no off-site leg**
|
|
(`sync-hetzner-backups.sh` is jarrs.eu and pulls the other way); and `/opt/backup/scripts/` is itself
|
|
**unversioned host state** (R-231). One-time cost: adding a path invalidated restic's parent match,
|
|
so the first run re-reads 405 GiB — dedup keeps storage flat and later runs are incremental again.
|
|
|
|
## 11. Rules report — first run
|
|
|
|
8 events; `session_start` 4, `path_glob_match` 3, `nested_traversal` 1. **6 of 9 rule files had never
|
|
fired.** Not a defect list: the log only covers since the hook was armed, and
|
|
`felhom-controller/gates.md` proves the distortion — it fired at 08:11 the same day, before
|
|
installation, and reads as silent.
|
|
|
|
The hook now **self-rotates at 5 MB**, one generation.
|
|
|
|
## 12. context7 — nothing written
|
|
|
|
`plugin:context7:context7` is **`✘ failed`** (ENOENT on `npx -y @upstash/context7-mcp`); `/mcp` lists
|
|
only the six Google auth stubs. Per §5 that means **write nothing**. The Go code is not the use case
|
|
either: one direct dependency in `felhom-agent`, and the hub and controller are stdlib-only by
|
|
standing rule.
|
|
|
|
## 12b. A stale claim the checklist caught — corrected in all four repos
|
|
|
|
Confirming this session's own push by run ID (checklist's last item) surfaced that **four instruction
|
|
files claimed CI was still owed** (R-168) — and **R-168 was CLOSED on 2026-08-02**. CI exists, runs
|
|
`repo_gates.py --fast` on every push, and emails on failure; this session's commits produced runs
|
|
117 (`success`) and 118.
|
|
|
|
One of the four was `felhom.eu/CLAUDE.md`, where **this session carried the stale sentence forward
|
|
through the trim**. `felhom-agent/CLAUDE.md` **contradicted itself** — its release section already
|
|
said R-168 mails the failure. Corrected in all four, pushed.
|
|
|
|
**Two lessons about this task, not about CI:** a trim is a *volume* operation and carries stale
|
|
content forward unless each claim is re-checked; and the gate cannot catch this class — "this
|
|
register item is closed" is not mechanically checkable from the instruction file. The thing that
|
|
caught it was the checklist item demanding a **run ID** rather than a memory.
|
|
|
|
## 13. Registers
|
|
|
|
- **R-229** re-scoped — legs (a) and (c) **CLOSED**; (b) remains; (d) moved to R-230.
|
|
- **R-230** opened — the auto-written-staleness ruling, the symlink decision, the spec-as-failing-test pilot.
|
|
- **R-231** opened — `/opt/backup/scripts/` is unversioned host state.
|
|
- **S-36** added to `CONTEXT.md` standing rulings.
|
|
|
|
## 14. Observations — not acted on
|
|
|
|
`target-selection.md`'s t740 error; `felhom-agent/CLAUDE.md` at 173 effective lines; the
|
|
`/context` Messages-accounting inference (§A of the ledger — reasoned, not measured); `MEMORY.md`'s
|
|
header still reading "felhom-controller Project Memory" though it indexes all four repos.
|