# RECORD-HYGIENE-INDEX — record-hygiene rules, split out VERBATIM from MEMORY.md 2026-09-07 (doyle)
> Moved by the documented method (byte identity of the moved block and of both untouched regions asserted in the move script; zero entries dropped). MEMORY.md keeps the section header + one pointer. Read this BEFORE writing a commune, a shared memory file, a preservation claim, or a correction.

- [preservation is its OWN step, before any reap broadcast](preservation-is-its-own-step-before-any-reap-broadcast.md) ⭐⭐ doyle standing intake rule 2026-08-29: a broadcast has NO ordering, so anything that must happen first cannot be a sentence inside it. The v0.65.0 pools-released call named the rca-236 instrument as worth keeping AND started the reap party; my file copies lost to doyle's reap by ~1 min (diffs landed, verbatim copies did not). Release call must carry `preservation confirmed by <owner>` or `nothing named worth keeping`. Write the RESTORE COST down too — a preserved artifact everyone assumes is restorable is worse than one whose cost is stated.
- ["preserved at scratchpad/" is preserved NOWHERE](scratchpad-is-not-preservation.md) ⭐⭐ 2026-09-07: my commune recorded the ONLY capture of the live rc break as preserved; it sat in a DEAD session's %TEMP% (scratchpad is SESSION-KEYED) during a reap party. Scratchpad = work, never keep. Name the survivor property, cp -rp, verify the copy by count+hash+the strings it was kept FOR, and audit what a reap census EXCLUDES (doyle asked only about target/; TEMP was the risk).
- [audit whole file](doc-audit-reads-whole-file.md) · [amendment falsifies more](amendment-falsifies-more-than-named.md) · [correct by replacement](correct-by-replacement-not-annotation.md) · [stale carried-forward](stale-carried-forward-sentence.md) · [retraction sweeps STRINGS](retraction-sweeps-diagnostic-strings.md) · [docs positive framing](docs-positive-framing.md) must-DO not must-NOT; upstream in experimplate.
- [resume: re-ground BEFORE acting](resumed-session-reground-before-acting.md) ⭐⭐ a commune's next-steps decay fastest; mine were ALL already done and origin was 20 ahead. Rulings durable, state/next-steps = hypothesis. 3rd face: ROUTE ORDER ≠ CONTENT RECENCY — my LATER-routed brief carried the STALER project-context (4 checkable facts off, incl. a closed issue listed as "next task"). ⚠ UNCORRELATED, NOT INVERTED — todlando's pair ranked RIGHT by the same counter, so you cannot flip the heuristic either; that is the harder failure, since it reads reliable until it re-opens a closed issue. Rank by content vs measurement, never by timestamp. ⚠ 7th face INBOUND: a peer's dispatch can BE their stale commune next-step — doyle re-dispatched a run he had already ACCEPTED as "fresh"; a dispatch is a STATE claim, measure it against the record and hand the contradiction back with the deliverable; the author rules (withdrew, 2026-08-23).
- [NEVER `cat >` a shared memory file blind](write-a-shared-memory-file-only-after-checking-it-exists.md) ⭐⭐ my clobber 2026-08-21: wrote a NEW file over a peer’s richer one, same slug — filenames derive from the LESSON, so two agents learning it from one incident collide, and the collision is likeliest when the topic is LIVE. No git/backup here; only MEMORY.md’s pointer survived to reconstruct from. Detector: index line richer than the file = you truncated. Append or merge; never blind-write. ⚠ CORRECTED: file was a THIRD agent’s, and the substance survived in IR-55 — but I measured that too: IR-55 was UNCOMMITTED (` M`, absent from HEAD, no -S history) in a dirty shared checkout, so both copies were one `git checkout --` from gone. **tracked ≠ committed ≠ pushed** — state the property you MEASURED, not the one you want true (same shape as counting pipefail for containment).
- [commune = testimony](commune-is-testimony-not-an-artifact.md) · [ingest dies silently](commune-ingest-dies-silently.md) can resume you STALE · [echo-commune clobbers fresh commune](echo-commune-overwrites-fresh-commune.md) ⭐⭐ latest-write-wins drop-box; echo brief can be newer AND staler; writer = core echo.rs (2 of 3 Self communes lost 2026-09-06); OPERATOR RULED echo never writes the drop → releases#276 todlando lane · [drops are box-wide](commune-drops-orphaned-box-wide.md) ⭐⭐ · [two roots diverged](two-memory-roots-diverged.md) ⭐⭐ session root picks which loads; ⛔ the compaction nag on THIS file is wrong — do not comply · [infra register ruling](infra-register-ruling.md) infra/CI debt → INFRA-REGISTER.md.
- [ER briefing-copy datums](er-briefing-copy-ledger-ruling.md) singles-per-session = by design (#164/#177); 6-burst = #208 mechanism (DONE via #212); never ledger post-close datums on a DONE issue — new evidence files NEW.

- [`git status` cannot see gitignored records](git-status-cannot-see-gitignored-records.md) ⭐ 2026-09-08 reap: tree reported clean (one `?? .spt-clippy/`), actually held the ONLY copy of a 36 KB rig patch, a rig script and a clippy record. ⚠ ITS STATED CAUSE IS CORRECTED 2026-09-09 — `.spt/` is NOT gitignored; the blindness was my one-line status read and my unnamed byte summary. `--ignored=matching` AND plain `--porcelain` + a `find` over `.spt*`, diff by name against main, hash-verify source-vs-dest, THEN rm. Records preserve regardless of size (doyle, 24 KB qualified).
- [`git check-ignore <dir>/` mints a FALSE IGNORED](git-check-ignore-with-a-trailing-slash-mints-a-false-ignored.md) ⭐⭐ 2026-09-09: the TRAILING SLASH alone flips the verdict — `.spt/preserved/` exits 0 citing `.gitignore:20` (a BLANK line, empty pattern field = the tell); no slash, and every real file under it, exit 1. Nothing under `.spt/` is ignored, so `git add -A` at root stages the golden evidence + ~325 MB of xtask binaries. CONTROLS: `.worktrees/` and `target/` exit 0 on the SAME slash spelling with a POPULATED pattern — so all four dirs exit 0 and the EXIT CODE discriminates nothing. Read the PATTERN FIELD (empty = fabricated); real file path + `git status --porcelain` are the backup. Stage by PATH.
- [a worktree registered at `<dir>\.git` refuses BOTH paths](worktree-registered-at-dot-git-refuses-both-paths.md) 2026-09-08: `worktree remove` rc=128 on the dir ("not a working tree") and on the registered path ("`\.git/.git` does not exist") — git appends `/.git` to whatever you name. Not a pin, not a dirty tree: read the porcelain path, delete the SUBTREE, `prune -v` retires the entry.
- [crates/spt-daemon pin: holder NAMED](worktree-remnant-pinned-at-crates-spt-daemon.md) ⭐ promoted pattern→mechanism 2026-09-08 (3 more instances): rust-analyzer pid 47316 holds a dir handle at the watched crate dir, remnant is always an EMPTY `crates/spt-daemon`, 0 bytes. One `Get-Process` names it; never kill an editor server to delete 0 bytes.
- [correcting a memory BODY leaves its INDEX LINE lying](correcting-a-memory-body-leaves-its-index-line-lying.md) ⭐⭐ hertz+todlando 2026-09-09. **THE METHOD, and it is MECHANICAL: after any memory-body edit, `grep -l "<slug>" *.md` across the dir — the BARE slug, never `<slug>.md`, which misses `[[wiki-link]]` cross-refs where most claim copies live (measured 5 files vs 1) — then check each hit as a LOOKUP (does this clause still presuppose what I retired?), and fix every hit in the SAME act as the body.** Do NOT 're-read it as a standalone sentence': that is the RETIRED method, retired by this entry's own evidence. WHY a body edit is not the fix: every CITING SURFACE is a copy of the claim, and the index line is merely the one with the most readers (MEMORY.md loads every session; the file is opened only by someone already suspicious). The re-read ritual proves the BYTES landed, not that you edited every copy. FOUR CARRIERS in one hour — imperative TAIL · `[[wiki-link]]` cross-ref in another entry · PARENTHETICAL ASIDE · RIVAL IMPERATIVES with the retired one FIRST (this very line, twice) — so CHECK BOTH ENDS, first is what gets EXECUTED, last what gets SKIMMED PAST — because a correction targets a CLAIM while staleness lives in every clause that PRESUPPOSES it, and asides/adjectives presuppose without asserting. **ALL FOUR found by the PEER, none by the author**, both of us hunting this exact defect: you cannot read past a presupposition you wrote, so re-reading your own edit is NOT a control — the grep works because it does not comprehend, and a peer beat the author 4/4. Related: [[correction-belongs-where-the-falsifier-is]] (same no-false-window argument, one hop out); record-hygiene face of "a trap entry without its CONTROL teaches only the symptom".
- [ignoring a directory BURIES what the repo CITES in it](ignoring-a-directory-buries-what-the-repo-cites-in-it.md) 2026-09-09 .spt/ lane PR #212: a blanket dir ignore does NOT untrack tracked files (git ls-files, not check-ignore); census what docs/ CITES inside before burying it -- launch-battery.py had ALREADY been lost once to a .spt/ sweep and the register cites it; a path can be cited by CATEGORY ("a tool in .spt/") where a path grep cannot see it; and an ACTIONABLE stale line ("Restore with: git apply <old path>") gets RUN, not just misread. Ignore comments carry a RULE AND A COUNT, never a list -- the first draft enumeration was stale the day it landed.
- [an UNSTAMPED running count in a durable record is stale on arrival](an-unstamped-running-count-in-a-durable-record-is-stale-on-arrival.md) hertz 2026-09-09, banked by doyle: IR-92 shipped two censuses of one thing (5/5+3/3 beside 12/12) because neither carried its as-of; stamp with time + cursor or leave the number out; ask which figure supersedes before writing either.
- [a recharge wake marker is ARMED durable state, not merely stale](a-recharge-wake-marker-is-armed-durable-state.md) deployah 2026-09-10, banked by doyle: my wake text opened every wake with a clause doyle had WITHDRAWN (the two-Summary VOID test); a marker freezes instructions at authoring time and re-presents them with no transcript to contradict them. Cannot rewrite mid-run: NAME the withdrawn clause and the form you work to. Corollary: correcting a peer is not done when the message sends -- ask what durable state still carries the withdrawn form.
