Files
felhom-controller/.claude/rules/backup-paths.md
T
admin 7db42c5fec
gates / gates (push) Successful in 12s
docs: CLAUDE.md becomes a core plus path-scoped rules (R-229)
215 lines -> 110 (92 effective; block-level HTML comments are stripped before
injection and never reach the model, verified empirically on Claude Code 2.1.222
with a control and a treatment run).

Four new .claude/rules/*.md, each with a paths: glob list so it loads only when a
matching file is read: gates, ui-hungarian, backup-paths, agent-coupling.

The ## Layout tree was deleted as derivable; REUSE.md already owns the per-package
seams its annotations stood in for. The host/access table was deleted in favour of
a pointer to documentation/operations/nodes.md -- it carried three defects at once:
demo-felhom given as the LAN fallback address as if it were the route, a pinned
"agent 0.93.0" against the project's own no-versions-in-docs rule, and the claim
that no drill VM was provisioned on demo-hp. Measured live: qm list shows VM 300
drill-r50. felhom-agent/CLAUDE.md was right; this file was wrong.

Kept verbatim: the seven session-critical invariants, the F9 live-validation fence,
the end-of-session checklist.

controller_gates.py registers the shared instructions gate (felhom.eu/scripts/,
never copied here; an absent sibling clone FAILS).

Docs only -- no Go, no version bump, no image, no deploy.
Ledger: felhom.eu/documentation/audits/LEDGER-instruction-trim-2026-08-06.md

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

2.2 KiB

paths
paths
controller/internal/backup/**
controller/internal/appbackup/**
controller/internal/recovery/**
controller/internal/appexport/**
controller/internal/quiesce/**

Backup, recovery units and export — felhom-controller

Assert the consequence across the whole run, not the mechanism inside one function

The R-181 recovery-unit refusal claimed "the previous unit is untouched and NOTHING was deleted". Nothing deleted held; untouched was measured false — the floor was checked ONLY in captureAllRecoveryUnits, while the two dump legs wrote the bulk into the same tree first and unguarded, so a 182,272 B tar became 2,147,666,432 B under a manifest that had not moved. A full green suite plus three of its own red-proofs missed it, because every one asserted the mechanism inside captureAllRecoveryUnits.

The test that catches this class: fingerprint the tree before and after the whole backup run, and compare. Full doctrine and the other eight instances: the felhom-testing skill.

Presence is not success

A timestamp recording an attempt must never be read as evidence of a result. Where a status field travels alongside a timestamp, the verdict consults both — or the timestamp records only successes. Ask of any timestamp: what exactly must have happened for this to be set? If the answer is "we tried", it cannot answer "did it work".

Corollary: when a verdict changes which field it counts from, the alarm text has to change with it. last run 8h ago while alarming on a six-day-old success turns a true alarm into one the operator dismisses.

Storage keys and paths

  • Never guess a persisted key — it is offbox, not offbox_target (R-7b).
  • .fab export/import uses strict segment validation; bundles from controller ≤0.124.0 are hollow.
  • Recovery-unit restore and tier-2 copies share appbackup's path primitives — change them there, once, not per caller.