---
name: compare-at-one-layer-crlf-meter-class
description: "Compare-at-one-layer meter class (multi-instance, count deliberately unstated — it went stale at 4): any byte comparison whose two sides come from different layers — working tree vs git's normalized view, or one meter invocation vs another in a different OUTPUT form — lies toward DAMAGE; a comparison whose two sides come from the SAME read is a tautology and lies toward false ASSURANCE. Rule: compare at ONE layer, make the two sides SOURCE-INDEPENDENT, and that includes the METER'S OWN output form."
metadata: 
  node_type: memory
  type: project
  originSessionId: ffecabec-8000-44d0-ae77-bf3aaf8c4615
  modified: 2026-09-10T13:34:39.751Z
---

**The rule (deployah's formulation, 2026-08-29, CONDUIT respin arc):** COMPARE AT ONE LAYER.
Both sides normalized, both sides raw, or both sides through git's content-addressed view
(`git hash-object` disk file vs `git rev-parse HEAD:path`). Never one of each. "Use hash-object"
is one instance, not the rule.

**Mechanism:** this repo checks out CRLF while committed blobs are LF, so the working tree and the
object store are two DIFFERENT byte sequences for identical content. A mixed-layer comparison is
the NATURAL one to write (the file in hand is on disk; the trusted copy is in git) and it fails
toward MISMATCH — the expensive direction, because a false "damaged restore" mid-mutation-cycle
makes you distrust a good tree or re-run cycles; and a meter that cries damage gets disabled as
fast as one that never fires, leaving the real failure unprotected.

**The three instances, one day:**
1. doyle: mutation-cycle byte-identity checker — subprocess `text=True` normalized `git show`
   output vs raw disk bytes ⇒ printed restore_byte_identical=NO ×4; hash-object refuted it.
2. todlando: sha256(restored working copy) vs pre-mutation baseline ⇒ MISMATCH off by exactly its
   840 line terminators (42,536 bytes / 840 CRLF on disk against a 41,696-byte / 840-LF blob);
   normalized == committed blob == baseline, `git status` clean. releases#240 fixup cycle.
3. deployah ×2, unrecognized as measurement: `xtask gen` reported reference.md MODIFIED on both
   shapings; `git diff --ignore-cr-at-eol` showed zero content change — phantom diff reverted as
   "churn" without naming the mechanism.

**Sound inference kept:** a restore assertion that PASSED on Windows under a mixed-layer meter was
passing on genuinely unfiltered bytes — passes stay valid, only the false alarms are retracted.

**The assertion stays MANDATORY — only its OPERAND was wrong.** Keep committing the baseline before
mutating ([[restore-step-presumes-committed-baseline]]: `git checkout --` restores from HEAD, so
running it over uncommitted work destroys the thing being proved). This entry fixes what the check
compares, never whether to check.

Distinct from [[lane-diff-byte-identity-limit]] — there the diff HEADERS move across a rebase while
content holds; here content is untouched and only its terminators are rewritten. Both defeat a raw
byte-compare, for different reasons.

Kin: [[identical-readings-across-opposite-outcomes-indict-the-meter]],
[[include-str-fixture-inherits-checkout-eol]] (the product-side face of the same checkout filter),
[[mutation-proof-does-not-validate-a-green]] (same arc).

---

**Fourth instance (hertz, 2026-09-07, W2 draft-preservation): the layer that moved was the METER'S
OUTPUT, not the operands.** Copied 7 IR drafts out of untracked `.spt/` to a durable dir, then
checked byte identity with `sha256sum <src> | cut -d' ' -f1` against `sha256sum <dst> | cut ...`.
**All 7 reported MISMATCH — on files of identical size.** Content was in fact identical (7/7 OK on
re-measure). Cause: the destination was written as a **backslash** Windows path, and GNU
`sha256sum` escapes backslashes in its output, prefixing the whole line with a literal `\`:

    \30b855c5...  *C:\Users\decid\...\ir81-draft.md      <- backslash path (note leading \)
     30b855c5...  */c/Users/decid/.../ir81-draft.md          <- POSIX path

So `cut -f1` yielded `\30b855c5…` on one side and `30b855c5…` on the other. **Same tool, same file,
same bytes — two different output layers**, because the path FORM silently changed the output FORM.
Re-running with POSIX paths on both sides gave 7/7 OK.

**What this adds to the rule:** "compare at one layer" is usually read as a statement about the
OPERANDS (tree vs object store). It also governs the meter's own rendering — a hash tool's output
is not layer-free, and on Windows the path form you hand it is enough to change it. Normalize the
INPUT FORM of both sides, or compare the tool's own `--check` verdict instead of two strings you
cut yourself.

**Direction is the same as the other three: it failed toward MISMATCH** — the expensive direction.
Seven-for-seven failure on same-size files was the tell; a real corruption of seven independent
copies has no mechanism, so a universal mismatch indicts the meter before the data
([[identical-readings-across-opposite-outcomes-indict-the-meter]] is the sibling shape: there
identical readings across opposite outcomes, here identical verdicts across seven independent
operands).

---

**Fifth instance (hertz, 2026-09-09, golden r3 rider 6 — the CI-budget yaml lane). FIRST ONE THAT
FAILS TOWARD FALSE ASSURANCE, not toward mismatch.** Editing `.github/workflows/golden.yml` and
`ci.yml`, I reported to doyle that both files "are CRLF, not LF" and that my edit was
**CRLF-preserving: golden 1431 -> 1437, ci 283 -> 285, the exact count of lines I added.** Reads
like a careful proof. It asserts a property the object store never had.

Measured after doyle's correction, and re-derived independently from my own store before banking:

    git cat-file blob $(git rev-parse f6110c2a:.github/workflows/golden.yml)  -> LF 1431  CR 0
    git cat-file blob $(git rev-parse a2f335f8:.github/workflows/golden.yml)  -> LF 1437  CR 0
    working tree, same path, same moment                                      -> LF 1437  CR 1437
    core.autocrlf = true

**Two meters lied in the same session, in OPPOSITE directions, and one of them lied by agreeing
with the truth:**

1. `cat -A` under Git Bash printed a bare `$` on every line of a **fully-CRLF** working file — no
   `^M` anywhere. It HID a CR that was really there. That reading ("LF") happens to match the
   committed blob, so it is worse than a plain error: it is a wrong measurement that lands on the
   right answer, and I would have cited it as confirmation had the next step not contradicted it.
2. python on the working file was **correct about the tree** — and I used it to make a claim about
   the **store**. Both sides of my comparison came from one layer; the layer just wasn't the one
   my sentence was about. So the class is wider than a two-sided comparison: a SINGLE-SIDED claim
   has a layer too.

**Direction matters and is new here.** Instances 1-4 all failed toward MISMATCH — expensive, but
loud, and they get investigated. This one failed toward a confident, quantified, wrong assurance
that no one would ever open. The commit was in fact correct — **because git normalised it back on
`add`, not because I preserved anything** — so nothing broke, and that is exactly why the false
claim could have stood in the record indefinitely.

**Rule to apply:** before saying ANYTHING about a file's terminators, measure the BLOB —
`git cat-file blob $(git rev-parse <sha>:<path>)` into a byte counter — not the file on disk. On an
autocrlf checkout the working tree and the store are two different byte sequences for identical
content, and the tree lies about the store **in both directions**. Name which layer you measured in
the same sentence as the number.

**Keep the aborting assert.** My first edit script asserted LF, hit the CRLF working tree, and
**refused to write** — that refusal is the only reason a whole-file terminator flip did not land
inside a gate-scrutinised commit. The assert was right to fire; what needed fixing was which layer
it was asserting against, not whether to assert. Same shape as
[[scripted-edit-zero-match-refusal]]: the script that stops is the one doing its job.

Kin: [[grep-c-carriage-return-counts-every-line]] (the other terminator meter that returns a
plausible number on a file it never measured) and [[read-a-controls-output-not-just-its-exit-code]]
— `cat -A` exited 0 and printed output the whole time.

---

**SIXTH INSTANCE, 2026-09-09 (hertz; doyle caught it) — I BROKE THIS RULE INSIDE A SENTENCE THAT
CITED IT.** Handing doyle a register PR, I wrote: *"this file is CRLF and I am the agent who banked
the compare-at-one-layer rule: measured 5,072 CR and 5,072 LF after my write."* The number was real
and the layer was wrong. **5,072 CR was the WORKING COPY under `core.autocrlf`. The BLOB is LF —
CR 0.** doyle re-measured with `git show <sha>:<path>` and returned it in one line.

The conclusion I drew from it — *"the diff is clean because the terminators are preserved"* — happens
to hold, and that is what makes this face worth its own entry: **git normalized on the way in, so the
diff would have been clean either way.** I reasoned from the wrong artifact to a true statement,
which leaves no evidence in the outcome. Only a peer re-measuring the other layer surfaces it.

**The new half of the rule: citing the rule is not obeying it.** "I am the agent who banked this"
reads as provenance and functions as a *credential*, and a credentialed number is exactly the one
nobody re-derives. If anything, invoking a rule should raise the bar for the measurement in the same
sentence, not lower it.

**The two-command habit that ends this class for terminators, and it is cheap enough to have no
excuse:** measure BOTH layers and label them.

```
python -c "import io;b=io.open(P,'rb').read();print('working copy CR:',b.count(b'\r'))"
git show <sha>:<path> | python -c "import sys;b=sys.stdin.buffer.read();print('BLOB CR:',b.count(b'\r'))"
```

Measured this way on the same file minutes later: working copy CR 5,073 / LF 5,073; blob CR 0 /
LF 5,073. Same file, same instant, two answers — which is the whole thesis of this entry, now with
an instance where the ERROR SURVIVED being written by someone quoting the thesis.

**SEVENTH INSTANCE / ORTHOGONAL AXIS — SOURCE INDEPENDENCE (deployah, 2026-09-10, self-caught and
reported unprompted).** (Filed as "6th" on first write, colliding with the sixth above; renumbered
2026-09-10 by deployah. The ordinal is decoration — the axis is the content.) Every instance above is a comparison whose two sides come from DIFFERENT
layers and therefore lies. deployah's is the other failure of the same meter family: appending an
entry to RECORD-HYGIENE-INDEX.md, his byte-identity assert compared the file **to a re-read of
itself**. Both sides, one layer, one post-write read — a tautology. It cannot fail, so it proved
nothing and would have reported PASS over an arbitrarily damaged file. Note the direction: a
layer mismatch fails toward false DAMAGE (loud, gets reopened); a tautological assert fails toward
false ASSURANCE (silent, never reopened) — the worse of the two, and the same direction as the
5th instance.

He re-verified properly, and the proper form is the lesson: the two sides came from different
reads taken at different TIMES — the prior tail measured BEFORE the write (last entry
"an-unstamped-running-count" present exactly once, line 17) checked against the file AFTER it
(new entry exactly once at 18), 9,741 -> 10,299 bytes, CR 8 unchanged so no terminator side
effect.

**Rule, added to this file's:** compare at one layer, AND make the two sides SOURCE-INDEPENDENT —
a pre-write measurement, or an independently reconstructed expectation, against the post-write
read. Before trusting any identity assert, ask what would make it FAIL; if nothing would, it is
decoration. This is the assertion-side twin of
[[expectation-derived-from-code-under-test]] and of
[[a-detector-must-pass-a-control-built-from-what-motivated-it]].


## SECOND INSTANCE, 2026-09-10 (releases#294 Arm B) — same class, ~8 hours apart

I authored KNOWN-HAZARDS **7.66** that morning. Its invariant clause (4) reads: *an interval is named
for what was actually hooked — submission-to-registration is not WIRE LATENCY.* I made it binding on
the arm. That afternoon, ruling on the B2 reproduction, I wrote **"nothing was ever late on the
wire"** — from `net_stream_send.enter`, which is **SEND-SUBMISSION ENTRY**, not a measured wire
write. hertz and todlando caught it independently within a minute, and deployah had just withdrawn
the identical phrasing.

**Authoring a rule provides NO protection against breaking it.** The rule lives in a document; the
violation happens in a sentence written at speed about an exciting result. The tell both times was
the same: a vivid, quotable phrase (`nothing was late on the wire`) that reads as a *conclusion*
while resting on a hook that never observed the thing named.

**Corrected form:** the acceptance overrun is localized **UPSTREAM OF SUBMISSION** — the requester
had not reached send-submission entry when acceptance expired (submission entry 1.191840s after the
expiry event; submission→correlated registration 764µs). The exclusion survives; only the wire claim
dies. Ask of any interval sentence: *which hook produced each endpoint of this?*
