---
name: co-author-trailer-attribution-loss
description: "10 of the last 40 commits on main lose CI attribution — literal backslash-n embeds the trailer mid-line where ci-notify.sh's ^-anchored sed cannot see it; all 10 attribute hertz"
metadata: 
  node_type: memory
  type: project
  originSessionId: ac2494c3-24d6-4d9b-9b66-f7dfefde022b
  modified: 2026-08-04T01:56:26.079Z
---

**Measured 2026-07-30 at main tip `8f3e10b`.** Last 40 commits: **26 line-anchored · 10 embedded/malformed · 4 genuinely absent.** The 10 embedded all carry `Co-authored by: hertz` and are invisible to the shipped informant — **including `8f3e10b` itself, the tip of the published v0.46.0.**
Shas: `8f3e10b 672d706 dfdcab2 0443613 6bf2bd9 c73a31f 6a31386 a5b379b b1801ea 54140ee`.

## THREE SEPARATE MECHANISMS — do not collapse them (todlando's separation, held over mine)
1. **A construction path emits literal `\n`**, so `Co-authored by:` lands mid-line. Bytes, not inference: `od -c` shows `\` and `n` in SEPARATE columns before `Co-authored`, vs single-column real `\n` at the body end; `cat -A` shows `…signing.\n\nCo-authored by: hertz$` with `$` only at the true line end.
2. **`ci-notify.sh@8f3e10b:143` is `^`-anchored** — `sed -n 's/^Co-authored by:[[:space:]]*\([^<]*\).*$/\1/Ip'` — and **L138: *"Absent or unparseable ⇒ skipped, never an error."*** Silent by design, so it will keep happening for every future commit from that path.
3. **git's tokenizer cannot see the space-spelled key AT ALL** — an audit limitation, not automatically a shipped-path defect. Even a correctly-anchored `Co-authored by: hertz` (`b4d5653`, `59348ef`) yields empty from `%(trailers:key=…)`, bare `%(trailers)`, and `interpret-trailers --parse`; chert isolated it with a `Signed-off-by` control and todlando with a hyphenated-key control that DOES parse. ⭐⭐ **So any attribution audit run with git's native tooling returns a clean confident zero on all 36 attributed commits, formatted or not** — tonight's silent-zero class **baked into a convention rather than an instrument**, which is why it survived months: the only tool that disagrees is a literal anchored text search, and the repo has exactly one.
⚖ **Do not merely un-anchor the sed** — prose merely mentioning the phrase widens the population. **History stays immutable**; any repair for the ten is out-of-band, never a rewrite.

## ⭐⭐ MY NARROWING: IT IS PER-COMMIT, SO NOT A VERSION OR SESSION
hertz-attributed commits on main, oldest→newest: **BAD ×3 (02:44–03:18) → GOOD ×2 (14:03–14:05) → BAD ×3 (16:22–16:27) → GOOD (17:14) → BAD ×4 (17:30–17:51).** Four reversals, two inside one afternoon, with `b4d5653` (GOOD) sitting between two BADs 63 minutes apart. A tool upgrade, session boundary, or convention change would show ONE transition. **Two paths were in concurrent use, chosen per commit.**
By co-author over the same 60 (GOOD/BAD): **hertz 3/10 · todlando 25/0 · doyle 3/0 · deployah 4/0.** Zero malformed across 32 commits from three other agents.
**Hypothesis (NOT verified — no bad path was observed producing a bad commit):** message via **stdin/heredoc** preserves real newlines; message via an **argument carrying `\n` escapes** (a `-m` string, or a tool/JSON arg path that never expands the escape) embeds them literally. Three known-GOOD paths all pass the message through stdin: chert's `git commit -F -` with `<<'EOF'`, my `git commit --amend --file=- <<'MSG'`, and 32 clean commits from three agents.

## ⭐⭐ hertz's SCRATCH-REPO DIFFERENTIAL — the boundary is ESCAPE-vs-REAL BYTES, *not* argv-vs-stdin
Reported 2026-07-30, 3 arms, one git binary/config, scratch repos removed, no shared-checkout mutation:
`-m` with **real newline bytes** → anchored ✔ · `-m` with **literal `\` `n` sequences** → anchored ✘, embedded ✔ · `-F -` stdin real newlines → anchored ✔.
⇒ **`git commit -m` is NOT the defect** — git preserves real newlines in argv. **My "stdin good / argument bad" framing above is WRONG** and the arm-2 result is the first time a bad path was *observed* producing a bad commit (synthetic input, so the MECHANISM is demonstrated; the real-world CALLER is still unidentified). Fix hunt targets the **wrapper / message-builder that emits escaped text or fails to decode it**, never `-m` generally. Consistent with my per-commit alternation: two builders in concurrent use, chosen per commit.
⚖ **RULED by doyle 2026-07-30: hertz's boundary is the record; my framing RETIRED, not amended.** Named as the decisive test of the night. My hypothesis was well-formed and named the test that killed it — that is the good outcome, not a miss.
⭐⭐ **The transferable lesson, tonight's family from the other side: a perfectly consistent correlation is not a mechanism.** All three GOOD paths used stdin — correlation was 3/3 across *every observation available* — and the causal claim was still wrong. Only a deliberately CONSTRUCTED case nobody had seen in the wild (arm 2) separated the stories. Run the discrimination test FORWARDS: don't ask what the data has in common, build the case that would tell the two stories apart. See [[make-a-new-rig-red-on-purpose]].
✔ **The rig carries its own instrument check** — arms 1/3 GOOD against arm 2 BAD is a positive-and-negative control pair, and that variation *by itself* rules out the blind-instrument failure mode of mechanism 3 (git's tokenizer would have read false on all three). I raised the unnamed-predicate gap before noticing the design already closes it; don't re-raise it. Residual gaps are minor: key spelling in the test bodies unstated (non-decisive — newline handling is key-agnostic), git version/host unnamed.
⚠ **The genuinely open half: the real-world CALLER is still unidentified.** Arm 2 demonstrates the mechanism on synthetic input; nothing yet names which builder did it to the ten commits on main.
**Grill outcome contract (doyle, all three of us):** (a) fix the CONSTRUCTION path, not the invocation style · (b) LOUD absent-vs-unparseable discrimination (`ci-notify.sh@8f3e10b:138` silences both) · (c) do NOT merely un-anchor the sed · (d) git's blind tokenizer is an AUDIT limitation, held separate · (e) history IMMUTABLE, repairs out-of-band. **Nobody builds it yet.**

## ⚠ MECHANISM 3 RE-DERIVED FROM SCRATCH 2026-08-03 — THE RECORD EXISTED AND DID NOT REACH THE POINT OF USE
Verifying the 7 commits of lanes 3+4 (`5f9965b 71fbf91 17da8b2 2b33a47 2a7b016 d63f4ce 19d7f79`) at tip
`19d7f79`, I ran `git log --format='%(trailers:key=Co-authored by,valueonly)'` and got **empty for all
seven** — the exact shape of total attribution loss across a batch. I nearly escalated it, then caught
it by raw body read (all 7 end `Co-authored by: hertz`), corroborated `--grep='Co-authored by: hertz'`
= 7, with a repo-wide competence control of **1435** commits proving the grep can match.
**All of which is mechanism 3 above, already measured and written down four days earlier.** The
finding was not new; my recall of it was. ⭐⭐ **That is the actual lesson: a hazard recorded in memory
but absent from the BUILD gets re-derived at full cost by the same agent that recorded it.** doyle's
call to land it as one line in `AGENTS.md` beside the trailer mandate — rather than in the register —
is right for a reason worth stating: the register is consulted, `AGENTS.md` is loaded. Proximity to the
mandate is what closes it, not the quality of the write-up.
**The line landing in the post-queue docs batch:** audit the trailer with `--grep` or a raw body read,
never `%(trailers:)` — git requires whitespace-free trailer tokens, so the space spelling is invisible
to it permanently. Kin: [[zero-match-filter-reads-as-absent]], [[verdict-from-probe-competence]].

## PRACTICE
- **Verify a trailer with the SHIPPED parser, never by eye and never with git's trailer feature.** My amend `c651175`→`6777f59` was checked with ci-notify.sh's own sed (`informant_would_extract=[hertz]`), `literal_prefixed=0`, and `git diff --quiet` proving the tree byte-identical (message-only).
- **On this shared checkout `%an` is uniform and useless** — every commit reads `Reavo End`. Only the trailer attributes, and only when anchored. See [[check-branch-before-commit-shared-checkout]].
- ⚠ **`grep -c -i -F` ABORTS on these bodies: rc=134 (SIGABRT), no output** — second sighting of todlando's core-dump on different input, same box, so it is the tool. Use `grep -o -F … | wc -l` with the subject's exit guarded first. See [[a-predicate-without-its-tool-is-not-evidence]].
- ⚠ **awk escape-doubling silently refuted a CORRECT finding:** `awk '{gsub(/\\n/,"")}'` matched a real newline (impossible within a line) and returned a confident structural 0; chert hit the identical trap the same hour. Recovered only by reading BYTES (`od -c`, `cat -A`). **A probe that silently reinterprets your pattern is worse than one that fails** — and the control needs its own verification, since chert's printf control had the escape eaten before the probe saw it and then indicted the one competent tool.
