Remediate the 21 session-narrative sites #784's sweep found — 21 judgements, not a regex #812

Closed
opened 2026-08-21 22:49:00 +02:00 by timothy · 3 comments
Owner

Spawned by #784, which generalized docs.no-session-narrative and reported the existing leak rather than remediating it. This issue is the remediation decision.

What the sweep found (2026-08-21, at 706674272)

Two independent passes over the tracked docs corpus, excluding docs/decisions/** (exempt by the rule):

  • a reading pass applying the who-benefits test: 18 sites
  • scripts/check-doc-narrative.py --all, the advisory string predicate: 10 sites

Union 21 sites across 7 files; each pass missed sites the other caught, which is the measured case for why the detector is advisory. Every line below was re-read in the file, not taken from a summary.

File Lines
docs/ci-cd.md 714, 738, 809, 1314, 1341, 1350
docs/remote-state-inventory.md 69, 98, 99, 104, 145, 150, 175
docs/guard-inventory.md 45, 138, 152, 167
docs/blazor-route-parity.md 52
docs/defect-shapes-773.md 583
docs/superpowers/plans/2026-07-20-unified-logo-bug.md 734
docs/superpowers/specs/2026-07-20-unified-logo-bug-design.md 115

Why this is not a mechanical sweep

Several of these are load-bearing and must stay. The docs/remote-state-inventory.md cluster is mostly of the form "this row was graded down by cold review, and the earlier wording was circular" — that tells the next reader not to regrade it back, so it passes the who-benefits test and is a finding, not narrative. The docs/guard-inventory.md cluster is similar: the summary counts were wrong in the first draft because a hand-maintained summary of a table is a second copy of it, which is the argument the table exists to make.

Others are plainly narrative: an earlier draft of a paragraph having been wrong, where only the corrected claim matters to a reader.

So this is 21 individual judgements, not a regex. And this repo has the inverse failure on record — #542, where a pruned narrative turned out to be the only copy — which is why #784 deliberately did not batch them behind the rule that authorized them.

The two docs/superpowers/** hits are a separate question: plans and specs are session artifacts by nature, and it is arguable the rule should not reach them at all. Decide that before touching them.

Done-when

  • Each of the 21 sites classified NARRATIVE (cut, with the reasoning moved to a commit message) or FINDING (kept, and left alone), with the classification stated per site
  • A decision on whether docs/superpowers/** is in scope for docs.no-session-narrative, recorded in the record if it changes the rule
  • scripts/check-doc-narrative.py --all re-run and its remaining output explained rather than driven to zero — the surviving hits should be the carved-out ones
  • Adversarial review passed
Spawned by #784, which generalized `docs.no-session-narrative` and **reported** the existing leak rather than remediating it. This issue is the remediation decision. ## What the sweep found (2026-08-21, at `706674272`) Two independent passes over the tracked docs corpus, excluding `docs/decisions/**` (exempt by the rule): - a **reading** pass applying the who-benefits test: 18 sites - `scripts/check-doc-narrative.py --all`, the advisory string predicate: 10 sites Union **21 sites across 7 files**; each pass missed sites the other caught, which is the measured case for why the detector is advisory. Every line below was re-read in the file, not taken from a summary. | File | Lines | |---|---| | `docs/ci-cd.md` | 714, 738, 809, 1314, 1341, 1350 | | `docs/remote-state-inventory.md` | 69, 98, 99, 104, 145, 150, 175 | | `docs/guard-inventory.md` | 45, 138, 152, 167 | | `docs/blazor-route-parity.md` | 52 | | `docs/defect-shapes-773.md` | 583 | | `docs/superpowers/plans/2026-07-20-unified-logo-bug.md` | 734 | | `docs/superpowers/specs/2026-07-20-unified-logo-bug-design.md` | 115 | ## Why this is not a mechanical sweep **Several of these are load-bearing and must stay.** The `docs/remote-state-inventory.md` cluster is mostly of the form "this row was graded down by cold review, and the earlier wording was circular" — that tells the next reader not to regrade it back, so it passes the who-benefits test and is a *finding*, not narrative. The `docs/guard-inventory.md` cluster is similar: the summary counts were wrong in the first draft **because a hand-maintained summary of a table is a second copy of it**, which is the argument the table exists to make. Others are plainly narrative: an earlier draft of a paragraph having been wrong, where only the corrected claim matters to a reader. So this is 21 individual judgements, not a regex. And this repo has the inverse failure on record — #542, where a pruned narrative turned out to be the only copy — which is why #784 deliberately did not batch them behind the rule that authorized them. The two `docs/superpowers/**` hits are a separate question: plans and specs are session artifacts by nature, and it is arguable the rule should not reach them at all. Decide that before touching them. ## Done-when - [x] Each of the 21 sites classified NARRATIVE (cut, with the reasoning moved to a commit message) or FINDING (kept, and left alone), with the classification stated per site - [x] A decision on whether `docs/superpowers/**` is in scope for `docs.no-session-narrative`, recorded in the record if it changes the rule - [x] `scripts/check-doc-narrative.py --all` re-run and its remaining output explained rather than driven to zero — the surviving hits should be the carved-out ones - [x] Adversarial review passed
timothy added the priority: medium label 2026-08-21 22:49:00 +02:00
timothy added the in-progress label 2026-08-29 11:03:56 +02:00
Author
Owner

Claiming this (Claude Code session, worktree main-2).

Pre-claim checks per process.parallel-session-claim, all clear: no open PR references #812, git ls-remote --heads origin '*812*' returns nothing, no prior comments, and origin/main re-fetched at b6b3520bd.

Bundle scan (all three axes): no milestone, no cross-references, and the only label is priority: medium. The nearest sibling considered was #869 (the other open docs-prose remediation sweep, also spawned by a predecessor that deliberately deferred). Rejecting that bundle: #869 needs live Gitea-source re-probes at v1.27.1 and edits .gitea/workflows/review-verdict.yml + scripts/, which is a different verification story and would cost this issue its docs-only exemption from the review-verdict gate. #812 goes alone.

Working it as the issue frames it — 21 individual classifications, each re-read in the file, not a regex sweep, with the docs/superpowers/** scope question decided before those two sites are touched.

Claiming this (Claude Code session, worktree `main-2`). Pre-claim checks per `process.parallel-session-claim`, all clear: no open PR references #812, `git ls-remote --heads origin '*812*'` returns nothing, no prior comments, and `origin/main` re-fetched at `b6b3520bd`. **Bundle scan** (all three axes): no milestone, no cross-references, and the only label is `priority: medium`. The nearest sibling considered was **#869** (the other open docs-prose remediation sweep, also spawned by a predecessor that deliberately deferred). **Rejecting that bundle**: #869 needs live Gitea-source re-probes at `v1.27.1` and edits `.gitea/workflows/review-verdict.yml` + `scripts/`, which is a different verification story and would cost this issue its docs-only exemption from the review-verdict gate. #812 goes alone. Working it as the issue frames it — 21 individual classifications, each re-read in the file, not a regex sweep, with the `docs/superpowers/**` scope question decided before those two sites are touched.
Author
Owner

Claim RETRACTED — duplicate pickup. This claim collided with a parallel session already working #812 on branch fix/812-session-narrative-remediation; that session owns the issue and the in-progress label. Disregard this comment as a claim.

My findings were handed to that session directly rather than duplicated here. The one point worth recording publicly, because it changes the shape of the task: the issue's 21 sites are dated at 706674272 (2026-08-21) and the docs have churned ~4,000 lines since, so the line numbers have drifted, one of the 21 (docs/guard-inventory.md:45) no longer exists — its section was rewritten by #872 when the guard population became derived — and a re-derived reading pass at HEAD finds sites the list does not contain. The population has to be re-derived rather than inherited from the table.

**Claim RETRACTED — duplicate pickup.** This claim collided with a parallel session already working #812 on branch `fix/812-session-narrative-remediation`; that session owns the issue and the `in-progress` label. Disregard this comment as a claim. My findings were handed to that session directly rather than duplicated here. The one point worth recording publicly, because it changes the shape of the task: **the issue's 21 sites are dated at `706674272` (2026-08-21) and the docs have churned ~4,000 lines since**, so the line numbers have drifted, one of the 21 (`docs/guard-inventory.md:45`) no longer exists — its section was rewritten by #872 when the guard population became derived — and a re-derived reading pass at HEAD finds sites the list does not contain. The population has to be re-derived rather than inherited from the table.
Author
Owner

Closing record

Outcome: Shipped in PR #882, merged as 736649b3b. 64 dispositions across the tracked docs corpus — 50 sites edited (53 clauses), 13 kept as carve-outs, 1 already remediated upstream by #872. The per-site manifest is in the PR body. scripts/check-doc-narrative.py --all goes 9 → 1; the survivor is a carve-out (a rejected watermark-lookup design kept with the concrete harm that killed it). Deferred: the same class outside the docs corpus (#876), and the mechanism that let four false claims into this PR (#881).

Root cause: #784 generalized the rule and reported the leak rather than remediating it, so the leak was the backlog. The interesting cause is the second one: the issue's list was not the population. Its table was dated at 706674272; 1924 lines had landed in the corpus since, every line number had drifted, one of the 21 sites no longer existed (#872 had rewritten it, keeping the why and dropping the autobiography — the correct outcome, reached independently), four sites postdated the sweep, and more were missed by both of #784's passes. Auditing exactly the 21 named lines would have repeated the defect the issue is about.

Decisions/conventions changed: docs.no-session-narrativerule:, mechanics:, signals: and body (Decisions-Edit: yes). Two substantive additions: docs/superpowers/** is reached by the rule and the detector's population is unchanged, with the rejected exemption recorded so it is not re-proposed; and the exemption test's limits are stated rather than overstated. Also release.verdict-vocabulary-shared — a scope claim that said #812 was still undecided.

Reusable knowledge:

  • A --diff-mode check never sees a frozen file. The case for exempting docs/superpowers/** was that its 35 files are frozen — but --diff scans lines a PR adds, and a frozen file adds none. The exemption would have bought nothing where the check runs, while suppressing exactly the case where the remedy (move it to the commit message) is still available. Exempting a path costs a detector its only reach.
  • A line-based grep inherits a line-based detector's blind spot. "an earlier \n draft" wrapped across a newline is invisible to both. Re-running the sweep over whitespace-joined text found sites six rounds of grepping had missed.
  • hits(out) == set() passes when the scan examined nothing. A scanned-zero run is indistinguishable from a working exemption. A non-exempt control asserted HIT in the same invocation is what separates them — and three successive finite controls (depth-1, depth-3, minimal twins) were each defeated by the next round's mutant. What closed it was a closed-form proof rather than a fourth fixture: compare the predicate against an independent restatement of the rule across every tracked path, plus a cross product of the dimensions a population rule keys on. The real corpus alone is insufficient, measured: no scanned path carries more than three slashes, so a count("/") <= 3 cap is a no-op against it and would ship latent.
  • A proof about a function is not a proof about its wiring. A continue at either call site re-exempts a path with the predicate untouched — measured to drop --all from 66 files to 31 with the oracle still green. Named as an open residual, with one fixture witnessing the specific re-exemption this change argues against.
  • A squash merge writes its OWN commit message. Gitea's squash took the title I passed and dropped the entire body — rationale and Decisions-Edit: yes trailer both. On a change whose own rule says the path to the end state goes in the commit message, the merge deleted the commit message. No CI consequence (pr-checks.yml triggers on pull_request: only, so the decisions guard never re-ran on the push), but the rationale survives only because it is also in the PR body and here. Pass message explicitly on a squash, or merge-commit.
  • fixes #N on its own line voids the entire trailer block. Decisions-Edit: yes parsed as nothing; decisions_validate exited 1 on two records. Put the closing keyword in its own paragraph.

Verification: scripts/tests/ 1230 passed / 2 skipped / 0 failed. --all 66 files, 1 warning; --diff origin/main 10 files, 0 warnings. decisions_validate --base origin/main OK; catalog in sync; frontmatter parses under PyYAML. ruff check + format --check clean. Ten independent cold review rounds across two model families, every one worktree-isolated and review-only; the final round on the merging head found no BLOCKER/HIGH/MEDIUM. Two separate rounds audited every deleted line for over-stripping and found no loss existing nowhere else — the risk that mattered most here, given #542.

Deferred: #876 (the rule reaches .claude/ hooks and code comments; nothing has ever swept them) and #881 (mutation claims written as prose sit outside testing.mutation-claims-are-executed, whose population is guard-inventory.md rows — the #773 shape, and the mechanism behind four false claims in this PR, each caught by a separate round).

Docs updated: docs/decisions/records/docs/no-session-narrative.md, docs/decisions/README.md (regenerated), docs/decisions/records/release/verdict-vocabulary-shared.md, plus the remediated corpus: docs/ci-cd.md, docs/remote-state-inventory.md, docs/guard-inventory.md, docs/blazor-route-parity.md, docs/defect-shapes-773.md, and five files under docs/superpowers/.

## Closing record **Outcome:** Shipped in PR #882, merged as `736649b3b`. 64 dispositions across the tracked docs corpus — 50 sites edited (53 clauses), 13 kept as carve-outs, 1 already remediated upstream by #872. The per-site manifest is in the PR body. `scripts/check-doc-narrative.py --all` goes 9 → 1; the survivor is a carve-out (a rejected watermark-lookup design kept with the concrete harm that killed it). Deferred: the same class outside the docs corpus (#876), and the mechanism that let four false claims into this PR (#881). **Root cause:** #784 generalized the rule and reported the leak rather than remediating it, so the leak was the backlog. The interesting cause is the *second* one: **the issue's list was not the population.** Its table was dated at `706674272`; 1924 lines had landed in the corpus since, every line number had drifted, one of the 21 sites no longer existed (#872 had rewritten it, keeping the *why* and dropping the autobiography — the correct outcome, reached independently), four sites postdated the sweep, and more were missed by *both* of #784's passes. Auditing exactly the 21 named lines would have repeated the defect the issue is about. **Decisions/conventions changed:** `docs.no-session-narrative` — `rule:`, `mechanics:`, `signals:` and body (`Decisions-Edit: yes`). Two substantive additions: `docs/superpowers/**` **is** reached by the rule and the detector's population is **unchanged**, with the rejected exemption recorded so it is not re-proposed; and the exemption test's limits are stated rather than overstated. Also `release.verdict-vocabulary-shared` — a scope claim that said #812 was still undecided. **Reusable knowledge:** - **A `--diff`-mode check never sees a frozen file.** The case for exempting `docs/superpowers/**` was that its 35 files are frozen — but `--diff` scans lines a PR *adds*, and a frozen file adds none. The exemption would have bought nothing where the check runs, while suppressing exactly the case where the remedy (move it to the commit message) is still available. **Exempting a path costs a detector its only reach.** - **A line-based grep inherits a line-based detector's blind spot.** `"an earlier \n draft"` wrapped across a newline is invisible to both. Re-running the sweep over whitespace-**joined** text found sites six rounds of grepping had missed. - **`hits(out) == set()` passes when the scan examined nothing.** A scanned-zero run is indistinguishable from a working exemption. A non-exempt control asserted HIT *in the same invocation* is what separates them — and three successive finite controls (depth-1, depth-3, minimal twins) were each defeated by the next round's mutant. What closed it was a **closed-form** proof rather than a fourth fixture: compare the predicate against an independent restatement of the rule across every tracked path, plus a cross product of the dimensions a population rule keys on. The real corpus alone is insufficient, measured: no scanned path carries more than three slashes, so a `count("/") <= 3` cap is a no-op against it and would ship latent. - **A proof about a function is not a proof about its wiring.** A `continue` at either call site re-exempts a path with the predicate untouched — measured to drop `--all` from 66 files to 31 with the oracle still green. Named as an open residual, with one fixture witnessing the specific re-exemption this change argues against. - **A squash merge writes its OWN commit message.** Gitea's squash took the `title` I passed and dropped the entire body — rationale and `Decisions-Edit: yes` trailer both. On a change whose own rule says *the path to the end state goes in the commit message*, the merge deleted the commit message. No CI consequence (`pr-checks.yml` triggers on `pull_request:` only, so the decisions guard never re-ran on the push), but the rationale survives only because it is also in the PR body and here. Pass `message` explicitly on a squash, or merge-commit. - **`fixes #N` on its own line voids the entire trailer block.** `Decisions-Edit: yes` parsed as nothing; `decisions_validate` exited 1 on two records. Put the closing keyword in its own paragraph. **Verification:** `scripts/tests/` 1230 passed / 2 skipped / 0 failed. `--all` 66 files, 1 warning; `--diff origin/main` 10 files, 0 warnings. `decisions_validate --base origin/main` OK; catalog in sync; frontmatter parses under PyYAML. `ruff check` + `format --check` clean. Ten independent cold review rounds across two model families, every one worktree-isolated and review-only; the final round on the merging head found no BLOCKER/HIGH/MEDIUM. Two separate rounds audited **every deleted line** for over-stripping and found no loss existing nowhere else — the risk that mattered most here, given #542. **Deferred:** #876 (the rule reaches `.claude/` hooks and code comments; nothing has ever swept them) and #881 (mutation claims written as prose sit outside `testing.mutation-claims-are-executed`, whose population is `guard-inventory.md` rows — the #773 shape, and the mechanism behind four false claims in this PR, each caught by a separate round). **Docs updated:** `docs/decisions/records/docs/no-session-narrative.md`, `docs/decisions/README.md` (regenerated), `docs/decisions/records/release/verdict-vocabulary-shared.md`, plus the remediated corpus: `docs/ci-cd.md`, `docs/remote-state-inventory.md`, `docs/guard-inventory.md`, `docs/blazor-route-parity.md`, `docs/defect-shapes-773.md`, and five files under `docs/superpowers/`.
timothy removed the in-progress label 2026-08-29 22:29:37 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: timothy/ersatztv#812