fix(812): classify the narrative sites by who-benefits; keep the detector's reach #882

Merged
timothy merged 1 commits from fix/812-session-narrative-remediation into main 2026-08-29 22:28:15 +02:00
Owner

Closes #812.

#784 generalized docs.no-session-narrative and reported the leak rather than remediating it.
This is the remediation — 64 dispositions, manifest below.

The population was not 21

The issue's table is dated at 706674272 (2026-08-21). Since then 1924 lines have been added to
docs/**/*.md outside docs/decisions/ plus root-level *.md, measured against origin/main at
8aeacd534, and every line number in the issue had drifted. So the population was
re-derived on the current tree rather than read off the issue.

1 of the 21 no longer exists #872 rewrote guard-inventory.md's scope-limit section; the autobiography went with it and the why survived
4 sites postdate the sweep ci-cd 1674/1682, remote-state-inventory 149 (×2)
The rest were already in the corpus and missed by both of the sweep's passes
Some are invisible to the detector by construction it is line-based, so "an earlier \n draft" never matches — and a line-based grep inherits that blind spot, which is how several sites here stayed hidden until the sweep was re-run over whitespace-joined text

Auditing exactly the named lines would have repeated the defect the issue is about —
guard-inventory.md already records it as "the issue's list of files to assess was a starting
point, not the population"
.

Three dispositions, not the issue's binary

The issue framed it as NARRATIVE (cut) or FINDING (kept, left alone). For most sites that is a false
choice: the corrected claim and the autobiography sat in one sentence, so cutting loses the
finding (#542) and leaving it keeps the narrative. The rule already licenses the third — "only the
corrected claim enters the doc"
. A clause is cut where its only content is that this artifact
used to say something else; otherwise the autobiographical phrase is severed and the trap,
rejected argument or why-behind-a-choice kept. Phrase-level only — no paragraph restructured.

What is NOT claimed

Six review rounds each found another survivor of the one class swept here (a bare attribution of
who found a finding). Each round's word-list was locally correct and the sequence did not
converge, so no closure over a phrasing space is claimed: the manifest's sites were remediated,
and a joined-text sweep for the constructions found so far returns only deliberate carve-outs. The
same sweep outside the docs corpus hits .claude/ hooks and a C# test — a different corpus with a
different verification story, tracked in #876.

docs/superpowers/**: the rule reaches it, and the detector keeps its reach

I built a wholesale detector exemption for that path, on the grounds that all 35 files are
frozen. Cold review killed it:

  • --diff, the mode CI runs, scans ADDED lines, and a frozen file contributes none. The exemption bought nothing where the check actually runs. What it would suppress is a plan being written or revised now — 15 of the 35 have more than one commit — which is exactly where the remedy still exists.
  • The premise was also partly false: the script comment had claimed plans are "never revised".

The exemption is gone, EXEMPT_PREFIXES is unchanged, and the rejected proposal is recorded in
the script and the record so it is not re-proposed on plausibility. Since the rule reaches the path,
its identified narrative sites were remediated with the rest of the corpus.

The exemption test took four rounds and three failed controls

hits(out) == set() passes when the scan examined nothing, so a non-exempt control is genuinely
required — that part always held. But proving a sample's absence is due to the prefix rather than
its shape defeated three successive fixtures:

Control Defeated by
a lone depth-1 control a depth-1 population rule
a depth-3 control a count("/") <= 3 cap
minimal twins (same path, exempt dir renamed) a directory-name rule keyed on the rename

Each fix was locally correct and the sequence did not converge — the shape this repo already records
in the withdrawn test_review_verdict_vocabulary_parity.py (six rounds, then deleted). I retracted
the claim; cold review then showed the retraction was itself premature, because a closed-form
proof exists that is not a fixture: compare is_scanned_path against an independent restatement
of the rule (written over path segments, not string prefixes) across every tracked *.md path.

Building it found one more thing worth stating: the real corpus alone is insufficient, and that
is measured rather than assumed — no scanned path carries more than three slashes today, so the
<= 3 cap is a no-op against it and would have shipped latent. The oracle therefore also spans a
cross product of four dimensions a population rule has been observed to key on here (depth,
first segment, second segment, extension), since widened with basename, case and dotted directories
after a later round found a mutant keyed on each. That list enumerates; it is not a universal
over the space of rules.

The residual after all of that is the wiring, and it is named rather than closed

Every proof above is about is_scanned_path. None of them establishes that the scan consults
it.
A continue added at either call site re-exempts a path with the function untouched — I
measured it: --all silently drops from 66 files to 31 while the closed-form oracle stays green.
That is precisely the docs/superpowers/** exemption this PR spends its argument rejecting,
reinstated invisibly.

A fixture under docs/superpowers/ is now asserted to reach the output, so that one
re-exemption is witnessed rather than assumed (verified: the oracle alone passes that mutant, the
full test file fails). The general residual — that no test pins the call sites — stands, and is
stated in the record rather than papered over.

Verification

  • scripts/tests/ full suite: 1230 passed, 2 skipped, 0 failed
  • check-doc-narrative.py --all → 66 files, 9 → 1 warning; the survivor is the carve-out
  • decisions_validate.py --base origin/main → OK; catalog in sync; Decisions-Edit: yes parses as a trailer (an earlier revision had it inert behind a colon-less fixes #812, which made the validator exit 1)
  • ruff check + ruff format --check clean
  • Six independent cold review rounds, two model families

Docs updated

docs/decisions/records/docs/no-session-narrative.md (rule:, mechanics:, signals:, body —
Decisions-Edit: yes), regenerated docs/decisions/README.md, and
docs/decisions/records/release/verdict-vocabulary-shared.md (a scope claim that said #812 was
still undecided).

Disposition manifest (Done-when box 1)

Counting rule, stated because a hunk count does not match a site count: a site is one
location where narrative was addressed; a clause is one cut or severance (three sites carried
two each). git diff -U0 reports 41 hunks with deletions across these files rather than 46,
because consecutive changed table rows merge into a single hunk — remote-state-inventory.md's
rows are one long line each, so its 13 sites fall in 8 hunks.

docs/ci-cd.md — 14 edited, 5 kept

~line Disposition Reason
822 REWRITE "the first cut shipped this bug" → "this bug shipped once"; the docs-only-skip trap and the #416 pointer stay
946 REWRITE "two independent reviews rejected it" → "it was rejected"; the rejected step-inside-build design and its circularity stay
950 REWRITE "Review found ~10 false negatives" → "That parser had ~10 false negatives"; the measurement stays
982 REWRITE "was a live bug in an earlier draft" → "would be a live bug"; both weaker readings and their consequences stay
987 REWRITE "the first version of that script reported healthy" → the trap stated directly, plus "which has happened here"
1011 CUT "an earlier draft here claiming it would was simply wrong" — the positive claim is complete without it
1082 REWRITE "the residual this paragraph used to describe" → what the measurement rules out
1674 REWRITE "is too strong and is retracted" → the corrected scope, stated once
1682 REWRITE dropped the doc's own retraction, kept the pointer that #763's framing overstates it
1869 REWRITE the retracted overclaim kept as an explicit non-guarantee — naming what the guard does not catch
1897 REWRITE why a RANGE is given kept; "an earlier draft cited a bare 18" dropped
1907 REWRITE why the counts are deliberately omitted kept
1910 CUT attribution; and a false location introduced by an earlier pass here was corrected (see below)
1933 REWRITE "and a cold review caught it" dropped; "the guard was written against 100 anyway" stays
1072, 1267, 1489, 1687, 2159 KEPT rejected verification methods; the "pure stdlib" local-pass trap; the set -u abort; don't-credit-the-wrong-mechanism; a priced decision

docs/remote-state-inventory.md — 13 edited, 2 kept

~line Disposition Reason
44 CUT "the second was missing from the first wording" — both shapes are then enumerated
68 REWRITE orphaned ordinal ("the second overclaim…") severed; the rejected "no async window" claim kept
69 (×2) CUT + REWRITE "graded down by cold review, which was right" cut; the circularity argument restated as a counterfactual
99 REWRITE "That last clause is new" → "load-bearing"; the [ -n ]-makes-it-a-no-op defect and the mutation claim stay
100 (×2) CUT + REWRITE "graded honestly after cold review" and "this row previously said…" cut; the ABA argument untouched
105 REWRITE the backreference-inverts trap kept, restated as a rule rather than as this row's history
138 CUT provenance about the row's own addition
149 (×2) REWRITE + CUT stale-cross-reference trap kept as a rule; "This row said the head alias was unfenced" cut (the dated fact is already stated)
150 CUT "Graded down by cold review, correctly"
151 REWRITE the rejected concurrency-group argument kept, stated directly
152 CUT "Graded up from N/A by cold review, which was right" — the combined-status consequence stays
156 CUT "the first draft's"; the refutation of "an advisory job never reaches the combined status" stays (#598)
182 REWRITE "Cold review rejected the distinction" → "That distinction does not survive the evidence"; the git fetch evidence untouched
103, 104 KEPT two rejected re-grade arguments, each the argument a future reader will re-make

docs/guard-inventory.md — 9 edited, 1 kept

~line Disposition Reason
42 REWRITE "Cold review caught it" dropped; "the objection is right twice over" + both reasons stay
74 REWRITE "only review caught" → "nothing mechanical caught" — the point is the absent mechanism, not the reviewer
167 REWRITE attribution dropped; "missed by the local gate" and "a starting point, not the population" stay
361 REWRITE the wrong figures and "both cold reviewers" dropped; "a hand-maintained summary is a second copy" and that it has already drifted stay
375 REWRITE trap kept: a summarised removal silently drops an invariant
401 REWRITE trap kept; the dangling absolute repaired ("it would be worst committed by the table itself")
457 REWRITE "found by cross-family review" dropped; why relative paths anchor at the launch cwd stays
468 CUT "which is how the first census here was wrong" — the double-count trap is fully stated before it
493 REWRITE "cold review showed" dropped; the rejected test design and its concrete failure stay
499 KEPT the "every X hook" double-counting trap

Other files

Site Disposition Reason
blazor-route-parity.md ~52 CUT "not Blazor-only as an earlier draft implied" — the note stands alone
blazor-route-parity.md ~229 REWRITE "Found by the #91 cold review" → "As of the #91 sweep"; the dated boundary kept
defect-shapes-773.md ~675 REWRITE the script-works ≠ wiring-works conflation kept as how the judgement goes wrong
superpowers/plans/…unified-logo-bug.md ~734 REWRITE "the first draft of this plan got this wrong" → "the ticked-state rule below is a trap"
superpowers/plans/…unified-logo-bug.md ~1154 CUT "Caught in independent review"
superpowers/specs/…-design.md ~104 CUT "(revised after independent review)"
superpowers/specs/…-design.md ~119 CUT "Caught in independent review."
superpowers/specs/…-design.md ~149 REWRITE "the test the first draft of this plan promised but omitted" → "a case the test suite must cover explicitly"
superpowers/specs/…-design.md ~152 CUT "the review's blocker"; "pinned by a regression test" stays
superpowers/plans/…qsv-native-decode.md ~268 REWRITE "Fable review corrected the original approach" → "the naive approach below does not work"
superpowers/specs/…-design.md ~113 KEPT the surviving detector hit — a rejected design with the concrete harm that killed it
spa-conventions.md ~1073 KEPT three concrete FieldHelp drift examples
.claude/skills/ersatztv/SKILL.md ~482 KEPT tested-and-rejected (MPEG-TS was not the fix); outside the detector's population
guard-inventory.md (old :45) ALREADY REMEDIATED #872 rewrote that section; the autobiography went, the why stayed

Found in review round 6 — the sibling sweep

Round 5's grep had no "Fable review" in its word-list, and one of these sits in the design sibling
of a plan this change had already edited
— the fix-one-path-check-its-twin shape.

Site Disposition Reason
superpowers/specs/…kickoff-design.md ~49 CUT "(revised after Fable review)" — exact twin of the one cut at …unified-logo-bug-design.md:104
superpowers/specs/…kickoff-design.md ~63 CUT same construction
superpowers/plans/…kickoff.md ~25 CUT "(Fable review #6; …)" — the reason follows in the same parenthesis and stays
superpowers/plans/…kickoff.md ~40 CUT "(Fable review #3/#4)"
superpowers/specs/…qsv-native-decode-design.md ~158-160 KEPT ## Post-review revisions (Fable, 2026-07-20) — a dated section, not a bare attribution: an explicitly stated snapshot boundary, and its intro says why it exists ("so this spec doesn't mislead")
superpowers/plans/…kickoff.md ~1268 KEPT ## Fable review fold (2026-07-21) — same shape; a dated record of what was folded, with the verdict and each finding

The two KEPT sections are the line this change draws: a bare parenthetical attribution goes,
because the reason follows it and the attribution carries nothing a reader acts on; a dated
section that records what changed and why
stays, because the rule's carve-out protects an
explicitly stated snapshot boundary. Stated here so the distinction is a classification rather than
an inconsistency.

Totals: 50 edited (53 clauses) + 13 kept + 1 already remediated = 64.

Closes #812. #784 generalized `docs.no-session-narrative` and **reported** the leak rather than remediating it. This is the remediation — 64 dispositions, manifest below. ## The population was not 21 The issue's table is dated at `706674272` (2026-08-21). Since then **1924** lines have been added to `docs/**/*.md` outside `docs/decisions/` plus root-level `*.md`, measured against `origin/main` at `8aeacd534`, and every line number in the issue had drifted. So the population was re-derived on the current tree rather than read off the issue. | | | |---|---| | **1 of the 21 no longer exists** | #872 rewrote `guard-inventory.md`'s scope-limit section; the autobiography went with it and the *why* survived | | **4 sites postdate the sweep** | `ci-cd` 1674/1682, `remote-state-inventory` 149 (×2) | | **The rest** were already in the corpus and missed by **both** of the sweep's passes | | | **Some are invisible to the detector by construction** | it is line-based, so `"an earlier \n draft"` never matches — and a line-based *grep* inherits that blind spot, which is how several sites here stayed hidden until the sweep was re-run over whitespace-joined text | Auditing exactly the named lines would have repeated the defect the issue is about — `guard-inventory.md` already records it as *"the issue's list of files to assess was a starting point, not the population"*. ## Three dispositions, not the issue's binary The issue framed it as NARRATIVE (cut) or FINDING (kept, left alone). For most sites that is a false choice: the corrected claim and the autobiography sat in **one sentence**, so cutting loses the finding (#542) and leaving it keeps the narrative. The rule already licenses the third — *"only the corrected claim enters the doc"*. A clause is **cut** where its only content is that this artifact used to say something else; otherwise the autobiographical *phrase* is **severed** and the trap, rejected argument or why-behind-a-choice kept. Phrase-level only — no paragraph restructured. ## What is NOT claimed Six review rounds each found another survivor of the one class swept here (a bare attribution of *who* found a finding). Each round's word-list was locally correct and the sequence did not converge, so **no closure over a phrasing space is claimed**: the manifest's sites were remediated, and a joined-text sweep for the constructions found so far returns only deliberate carve-outs. The same sweep outside the docs corpus hits `.claude/` hooks and a C# test — a different corpus with a different verification story, tracked in **#876**. ## `docs/superpowers/**`: the rule reaches it, and the detector keeps its reach I **built** a wholesale detector exemption for that path, on the grounds that all 35 files are frozen. Cold review killed it: - **`--diff`, the mode CI runs, scans ADDED lines, and a frozen file contributes none.** The exemption bought nothing where the check actually runs. What it *would* suppress is a plan being **written or revised** now — 15 of the 35 have more than one commit — which is exactly where the remedy still exists. - The premise was also partly false: the script comment had claimed plans are "never revised". The exemption is gone, `EXEMPT_PREFIXES` is unchanged, and the **rejected proposal is recorded** in the script and the record so it is not re-proposed on plausibility. Since the rule reaches the path, its identified narrative sites were remediated with the rest of the corpus. ## The exemption test took four rounds and three failed controls `hits(out) == set()` passes when the scan examined **nothing**, so a non-exempt control is genuinely required — that part always held. But proving a sample's absence is due to the **prefix** rather than its **shape** defeated three successive fixtures: | Control | Defeated by | |---|---| | a lone depth-1 control | a depth-1 population rule | | a depth-3 control | a `count("/") <= 3` cap | | minimal twins (same path, exempt dir renamed) | a directory-**name** rule keyed on the rename | Each fix was locally correct and the sequence did not converge — the shape this repo already records in the withdrawn `test_review_verdict_vocabulary_parity.py` (six rounds, then deleted). I retracted the claim; **cold review then showed the retraction was itself premature**, because a closed-form proof exists that is not a fixture: compare `is_scanned_path` against an **independent restatement** of the rule (written over path segments, not string prefixes) across every tracked `*.md` path. Building it found one more thing worth stating: the real corpus **alone** is insufficient, and that is measured rather than assumed — no scanned path carries more than three slashes today, so the `<= 3` cap is a no-op against it and would have shipped latent. The oracle therefore also spans a cross product of **four dimensions a population rule has been observed to key on here** (depth, first segment, second segment, extension), since widened with basename, case and dotted directories after a later round found a mutant keyed on each. That list enumerates; it is **not** a universal over the space of rules. ### The residual after all of that is the wiring, and it is named rather than closed Every proof above is about `is_scanned_path`. **None of them establishes that the scan consults it.** A `continue` added at either call site re-exempts a path with the function untouched — I measured it: `--all` silently drops from 66 files to 31 while the closed-form oracle stays green. That is precisely the `docs/superpowers/**` exemption this PR spends its argument rejecting, reinstated invisibly. A fixture under `docs/superpowers/` is now asserted to reach the **output**, so that one re-exemption is witnessed rather than assumed (verified: the oracle alone passes that mutant, the full test file fails). The general residual — that no test pins the call sites — stands, and is stated in the record rather than papered over. ## Verification - `scripts/tests/` full suite: **1230 passed, 2 skipped, 0 failed** - `check-doc-narrative.py --all` → 66 files, **9 → 1** warning; the survivor is the carve-out - `decisions_validate.py --base origin/main` → OK; catalog in sync; `Decisions-Edit: yes` **parses as a trailer** (an earlier revision had it inert behind a colon-less `fixes #812`, which made the validator exit 1) - `ruff check` + `ruff format --check` clean - Six independent cold review rounds, two model families ## Docs updated `docs/decisions/records/docs/no-session-narrative.md` (`rule:`, `mechanics:`, `signals:`, body — `Decisions-Edit: yes`), regenerated `docs/decisions/README.md`, and `docs/decisions/records/release/verdict-vocabulary-shared.md` (a scope claim that said #812 was still undecided). ## Disposition manifest (Done-when box 1) **Counting rule**, stated because a hunk count does not match a site count: a **site** is one location where narrative was addressed; a **clause** is one cut or severance (three sites carried two each). `git diff -U0` reports **41** hunks with deletions across these files rather than 46, because consecutive changed table rows merge into a single hunk — `remote-state-inventory.md`'s rows are one long line each, so its 13 sites fall in 8 hunks. ### `docs/ci-cd.md` — 14 edited, 5 kept | ~line | Disposition | Reason | |---|---|---| | 822 | REWRITE | "the first cut shipped this bug" → "this bug shipped once"; the docs-only-skip trap and the #416 pointer stay | | 946 | REWRITE | "two independent reviews rejected it" → "it was rejected"; the rejected step-inside-`build` design and its circularity stay | | 950 | REWRITE | "Review found ~10 false negatives" → "That parser had ~10 false negatives"; the measurement stays | | 982 | REWRITE | "was a live bug in an earlier draft" → "would be a live bug"; both weaker readings and their consequences stay | | 987 | REWRITE | "the first version of that script reported healthy" → the trap stated directly, plus "which has happened here" | | 1011 | CUT | "an earlier draft here claiming it would was simply wrong" — the positive claim is complete without it | | 1082 | REWRITE | "the residual this paragraph used to describe" → what the measurement rules out | | 1674 | REWRITE | "is too strong and is retracted" → the corrected scope, stated once | | 1682 | REWRITE | dropped the doc's own retraction, kept the pointer that **#763's framing** overstates it | | 1869 | REWRITE | the retracted overclaim kept as an explicit **non**-guarantee — naming what the guard does not catch | | 1897 | REWRITE | why a RANGE is given kept; "an earlier draft cited a bare 18" dropped | | 1907 | REWRITE | why the counts are deliberately omitted kept | | 1910 | CUT | attribution; **and a false location introduced by an earlier pass here was corrected** (see below) | | 1933 | REWRITE | "and a cold review caught it" dropped; "the guard was written against 100 anyway" stays | | 1072, 1267, 1489, 1687, 2159 | **KEPT** | rejected verification methods; the "pure stdlib" local-pass trap; the `set -u` abort; don't-credit-the-wrong-mechanism; a priced decision | ### `docs/remote-state-inventory.md` — 13 edited, 2 kept | ~line | Disposition | Reason | |---|---|---| | 44 | CUT | "the second was missing from the first wording" — both shapes are then enumerated | | 68 | REWRITE | orphaned ordinal ("the second overclaim…") severed; the rejected "no async window" claim kept | | 69 (×2) | CUT + REWRITE | "graded down by cold review, which was right" cut; the circularity argument restated as a counterfactual | | 99 | REWRITE | "That last clause is new" → "load-bearing"; the `[ -n ]`-makes-it-a-no-op defect and the mutation claim stay | | 100 (×2) | CUT + REWRITE | "graded honestly after cold review" and "this row previously said…" cut; the ABA argument untouched | | 105 | REWRITE | the backreference-inverts trap kept, restated as a rule rather than as this row's history | | 138 | CUT | provenance about the row's own addition | | 149 (×2) | REWRITE + CUT | stale-cross-reference trap kept as a rule; "This row said the head alias was unfenced" cut (the dated fact is already stated) | | 150 | CUT | "Graded down by cold review, correctly" | | 151 | REWRITE | the rejected `concurrency`-group argument kept, stated directly | | 152 | CUT | "Graded up from `N/A` by cold review, which was right" — the combined-status consequence stays | | 156 | CUT | "the first draft's"; the refutation of "an advisory job never reaches the combined status" stays (#598) | | 182 | REWRITE | "Cold review rejected the distinction" → "That distinction does not survive the evidence"; the `git fetch` evidence untouched | | 103, 104 | **KEPT** | two rejected re-grade arguments, each the argument a future reader will re-make | ### `docs/guard-inventory.md` — 9 edited, 1 kept | ~line | Disposition | Reason | |---|---|---| | 42 | REWRITE | "Cold review caught it" dropped; "the objection is right twice over" + both reasons stay | | 74 | REWRITE | "only review caught" → "nothing mechanical caught" — the point is the absent mechanism, not the reviewer | | 167 | REWRITE | attribution dropped; "missed by the local gate" and "a starting point, not the population" stay | | 361 | REWRITE | the wrong figures and "both cold reviewers" dropped; "a hand-maintained summary is a second copy" **and** that it has already drifted stay | | 375 | REWRITE | trap kept: a summarised removal silently drops an invariant | | 401 | REWRITE | trap kept; the dangling absolute repaired ("it would be worst committed by the table itself") | | 457 | REWRITE | "found by cross-family review" dropped; why relative paths anchor at the launch `cwd` stays | | 468 | CUT | "which is how the first census here was wrong" — the double-count trap is fully stated before it | | 493 | REWRITE | "cold review showed" dropped; the rejected test design and its concrete failure stay | | 499 | **KEPT** | the "every X hook" double-counting trap | ### Other files | Site | Disposition | Reason | |---|---|---| | `blazor-route-parity.md` ~52 | CUT | "not Blazor-only as an earlier draft implied" — the note stands alone | | `blazor-route-parity.md` ~229 | REWRITE | "Found by the #91 cold review" → "As of the #91 sweep"; the dated boundary kept | | `defect-shapes-773.md` ~675 | REWRITE | the script-works ≠ wiring-works conflation kept as how the judgement goes wrong | | `superpowers/plans/…unified-logo-bug.md` ~734 | REWRITE | "the first draft of this plan got this wrong" → "the ticked-state rule below is a trap" | | `superpowers/plans/…unified-logo-bug.md` ~1154 | CUT | "Caught in independent review" | | `superpowers/specs/…-design.md` ~104 | CUT | "(revised after independent review)" | | `superpowers/specs/…-design.md` ~119 | CUT | "Caught in independent review." | | `superpowers/specs/…-design.md` ~149 | REWRITE | "the test the first draft of this plan promised but omitted" → "a case the test suite must cover explicitly" | | `superpowers/specs/…-design.md` ~152 | CUT | "the review's blocker"; "pinned by a regression test" stays | | `superpowers/plans/…qsv-native-decode.md` ~268 | REWRITE | "Fable review corrected the original approach" → "the naive approach below does not work" | | `superpowers/specs/…-design.md` ~113 | **KEPT** | the surviving detector hit — a rejected design with the concrete harm that killed it | | `spa-conventions.md` ~1073 | **KEPT** | three concrete FieldHelp drift examples | | `.claude/skills/ersatztv/SKILL.md` ~482 | **KEPT** | tested-and-rejected (MPEG-TS was not the fix); outside the detector's population | | `guard-inventory.md` (old :45) | **ALREADY REMEDIATED** | #872 rewrote that section; the autobiography went, the *why* stayed | ### Found in review round 6 — the sibling sweep Round 5's grep had no "Fable review" in its word-list, and one of these sits in the **design sibling of a plan this change had already edited** — the fix-one-path-check-its-twin shape. | Site | Disposition | Reason | |---|---|---| | `superpowers/specs/…kickoff-design.md` ~49 | CUT | "(revised after Fable review)" — exact twin of the one cut at `…unified-logo-bug-design.md:104` | | `superpowers/specs/…kickoff-design.md` ~63 | CUT | same construction | | `superpowers/plans/…kickoff.md` ~25 | CUT | "(Fable review #6; …)" — the reason follows in the same parenthesis and stays | | `superpowers/plans/…kickoff.md` ~40 | CUT | "(Fable review #3/#4)" | | `superpowers/specs/…qsv-native-decode-design.md` ~158-160 | **KEPT** | `## Post-review revisions (Fable, 2026-07-20)` — a **dated section**, not a bare attribution: an explicitly stated snapshot boundary, and its intro says why it exists ("so this spec doesn't mislead") | | `superpowers/plans/…kickoff.md` ~1268 | **KEPT** | `## Fable review fold (2026-07-21)` — same shape; a dated record of what was folded, with the verdict and each finding | The two KEPT sections are the line this change draws: a **bare parenthetical attribution** goes, because the reason follows it and the attribution carries nothing a reader acts on; a **dated section that records what changed and why** stays, because the rule's carve-out protects an explicitly stated snapshot boundary. Stated here so the distinction is a classification rather than an inconsistency. **Totals**: 50 edited (53 clauses) + 13 kept + 1 already remediated = **64**.
timothy added 1 commit 2026-08-29 21:23:48 +02:00
fix(812): classify the narrative sites by who-benefits; keep the detector's reach
Build ErsatzTV Image / CI toolchain image resolves (pull_request) Successful in 11s
Build ErsatzTV Image / Delimiter ban (release path) (pull_request) Successful in 18s
PR Gates / CI image pin matches docker/ci (pull_request) Successful in 15s
PR Gates / Docs update reminder (pull_request) Successful in 12s
PR Gates / Fix proofs (Proves trailers) (pull_request) Successful in 9s
PR Gates / decisions lifecycle (pull_request) Successful in 27s
Review verdict / Set review-verdict status (pull_request_target) Successful in 15s
PR Gates / Script lint and tests (ruff + pytest) (pull_request) Successful in 7m45s
review-verdict/h10 Review-verdict: MERGEABLE @ ae8f736 (base: main)
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 13m36s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 9m18s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Skipped
Build ErsatzTV Image / Functional E2E (curl + UI contracts) (pull_request) Successful in 8m58s
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (pull_request) Successful in 11s
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (pull_request) Successful in 8s
ae8f736a66
#784 generalized `docs.no-session-narrative` and REPORTED the leak rather than
remediating it. This is the remediation: 64 dispositions, manifest in the PR body.

THE POPULATION WAS NOT 21. The issue's table is dated at 706674272 (2026-08-21). Since
then 1924 lines have been added to `docs/**/*.md` outside `docs/decisions/` plus
root-level `*.md`, measured against origin/main at 8aeacd534, and every line number in
the issue had drifted. Measured, not assumed:

  - one of the 21 no longer exists — #872 rewrote guard-inventory.md's scope-limit
    section and the autobiography went with it, the *why* surviving. No action.
  - FOUR sites postdate the sweep (ci-cd 1674/1682, remote-state 149 x2).
  - The rest were already in the corpus and missed by BOTH of the sweep's passes.
  - Some are invisible to the detector BY CONSTRUCTION: it is line-based, so
    "an earlier \n draft" wrapped across a newline never matches. A line-based grep
    inherits that blind spot, which is how several sites stayed hidden until the sweep
    was re-run over WHITESPACE-JOINED text.

Auditing exactly the named lines would have repeated the defect the issue is about —
`guard-inventory.md` already records it as "the issue's list of files to assess was a
starting point, not the population".

DISPOSITIONS — 64 sites, one row per site in the PR body. Three kinds, not the issue's
binary, because for most sites the corrected claim and the autobiography sat in ONE
sentence: cutting loses the finding (#542), leaving it keeps the narrative. The rule
already licenses the third — "only the corrected claim enters the doc". 50 sites EDITED
(53 clauses; three sites carried two each), 13 KEPT as carve-outs, 1 ALREADY REMEDIATED.
Phrase-level only — no paragraph was restructured.

NO CLOSURE IS CLAIMED OVER A PHRASING SPACE, and that is the finding rather than a
caveat. One class was swept — a bare attribution of who found a finding, where the
reasons follow in the next clause. SIX review rounds each surfaced another survivor,
every round's grep a locally-correct word-list that never converged; the last found
"(revised after Fable review)" in a file whose SIBLING this change had already edited,
which is the fix-one-path-check-its-twin shape. So the claim is bounded: the manifest's
sites were remediated. NOT that the class is closed — not globally, and not inside the
docs corpus either. #876 carries the same bounded wording for the corpus outside `docs/`.

THE EXEMPTION TEST NEEDED A CLOSED-FORM PROOF, and three finite ones failed first.
`hits(out) == set()` passes when the scan examined NOTHING, so a non-exempt control is
required and that part always held. But proving a sample's absence is due to the PREFIX
rather than its SHAPE defeated a depth-1 control (by a depth-1 rule), a depth-3 control
(by a `count("/") <= 3` cap) and minimal twins (by a directory-NAME rule keyed on the
rename). Each was locally correct; the sequence did not converge. I retracted the claim;
review then showed the RETRACTION was itself premature, because a closed-form proof
exists that is not a fixture: `is_scanned_path` compared against an INDEPENDENT
restatement of the rule — written over path segments, not string prefixes — across every
tracked `*.md` path, plus a cross product of four dimensions a population rule has been
OBSERVED to key on here, since widened with basename, case and dotted directories. That
list enumerates; it is not a universal over the space of rules.

THE RESIDUAL AFTER ALL OF THAT IS THE WIRING, and it is named rather than closed. Every
proof above is about `is_scanned_path`; none establishes that the SCAN consults it. A
`continue` added at either call site re-exempts a path with the function untouched —
measured to drop `--all` from 66 files to 31 while the oracle stays green. A fixture
under `docs/superpowers/` is asserted to reach the OUTPUT so the one re-exemption this
change argues against is witnessed; the general residual stands.

`docs/superpowers/**` IS REACHED BY THE RULE and the detector's population is UNCHANGED.
A wholesale exemption was built, then killed under review: `--diff`, the mode CI runs,
scans ADDED lines and a frozen file contributes none, so it buys nothing where the check
runs; what it WOULD suppress is a plan being written or revised now — 15 of the 35 have
more than one commit. Two dated review SECTIONS there ("## Post-review
revisions (Fable, 2026-07-20)" and "## Fable review fold (2026-07-21)") are kept as stated
snapshot boundaries; the bare parenthetical attributions around them are not.

`--all` goes 9 -> 1. The survivor is the carved-out one: a rejected design kept with the
concrete harm that killed it.

Corrected in review: the sweep had replaced a true attribution at ci-cd.md:1910 with a
FALSE location — the third nil-slice instance was introduced by #622 on 2026-07-25, 12
days before the #751 fix, which does not touch that gate. And two edits had converted
observed defects into hypotheticals (ci-cd.md:982) and one round's yield into a total
(ci-cd.md:951); both are restored.

fixes #812

Decisions-Edit: yes
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019T79beF1Ufid3dXju4yqkF
Author
Owner

Review-verdict: MERGEABLE @ ae8f736

Round 10 cold review of head ae8f736a6. No BLOCKER/HIGH/MEDIUM; 3 NITs not warranting a commit. Nine prior rounds each found one overclaim; this round found none. The clause that was wrong twice (a fabricated citation, then a self-referential anchor) is now bound to a dated snapshot neither this commit nor a future one can move, verified under adversarial re-reading. Docs half cleared for over-stripping by two independent rounds. Suite 1230 passed; --all 66 files/1 warning (the carve-out); --diff origin/main 0 warnings.

Review-verdict: MERGEABLE @ ae8f736 Round 10 cold review of head ae8f736a6. No BLOCKER/HIGH/MEDIUM; 3 NITs not warranting a commit. Nine prior rounds each found one overclaim; this round found none. The clause that was wrong twice (a fabricated citation, then a self-referential anchor) is now bound to a dated snapshot neither this commit nor a future one can move, verified under adversarial re-reading. Docs half cleared for over-stripping by two independent rounds. Suite 1230 passed; --all 66 files/1 warning (the carve-out); --diff origin/main 0 warnings.
timothy merged commit 736649b3b7 into main 2026-08-29 22:28:15 +02:00
timothy deleted branch fix/812-session-narrative-remediation 2026-08-29 22:28:17 +02:00
Sign in to join this conversation.