docs.no-session-narrative reaches hooks and code comments, but nothing has ever swept them — 4 known sites
#876
Closed
opened 2026-08-29 18:54:40 +02:00 by timothy
·
3 comments
No Branch/Tag Specified
main
renovate/meziantou.analyzer-3.x
release/v26.15.0-notes
fix/830-add-items-error-surface
renovate/lucene.net
renovate/cliwrap-3.x
issue-806-guard-populations
renovate/dotnet-monorepo
scratch/767b-poisoned
scratch/767b-control
release/v26.14.0-notes
release/v26.14.0
renovate/sqlitepclraw.bundle_e_sqlite3-3.x
docs/510-skill-logo-bug-policy
fix/510-watermark-resolution-policy
fix/629-verdict-classifier-falseopens
fix/609-decisions-edit-token-scope
issue-135-clear-to-none
release/v26.12.0-notes
fix/409b-lastscan-api-parity
fix/401-updatechannel-mirror-422
fix/327-playlist-rename-validation
fix/410-scancancel-log-level
fix/409-447-librariesscreen-neverscanned
fix/338-zap-exit-code
fix/367-plex-budget-message
fix/310-debom-legacy-cs
ci/604-lane-rebalance
feat/388-design-mirror
feat/247-test-ownership
feat/247-primary-action
feat/357-player-owned-playback
feat/357-jellyfin-plugin-poc
fix/289-mcp-hardening
issue58-mcp
feat/244-channels-extract
ci/auto-bump-prod-compose
feat/multi-rerun-collections-api
feat/collections-api
feat/quick-wins
feat/185-docs-part2
feat/140-collections-screen
feat/146-channel-edit
feat/147-classic-ui-link
issue22-renovate-dashboard
feat/91-cutover
feat/63-composite-create
feat/65-library-browse
feat/85-epg
feat/86-schedule-editor
feat/109-dashboard-data
feat/99-session-tracking
fix/dockerfile-node-tag
feat/59-spa-foundation
docs/59-ui-redesign-brief
feat/102-json-guide
feat/111-schedule-durations
feat/104-artwork-upload
feat/103-media-sources-api
feat/playouts-read-api
feat/108-health-api
feat/105-picker-list-endpoints
issue-97-channel-state-api
issue42-jellyfin-musicvideos
issue46-rest-api-error-contract
dependabot/nuget/ErsatzTV.FFmpeg.Tests/multi-d307a2e06f
qsv-improvements
hdr-vulkan-cuda-test
v26.15.0
v26.14.0
v26.13.0
v26.12.0
v26.11.0
v26.10.0
v26.9.0
v26.8.0
v26.7.0
blazor-final
v26.6.0
v26.5.0
v26.4.0
v26.3.1
v26.3.0
v26.2.0
v26.1.1
v26.1.0
v25.9.0
v25.8.0
v25.7.1
v25.7.0
v25.6.0
v25.5.0
v25.4.0
v25.3.1
v25.3.0
v25.2.0
v25.1.0
v0.8.8-beta
v0.8.7-beta
v0.8.6-beta
v0.8.5-beta
v0.8.4-beta
v0.8.3-beta
v0.8.2-beta
v0.8.1-beta
v0.8.0-beta
v0.7.9-beta
v0.7.8-beta
v0.7.7-beta
v0.7.6-beta
v0.7.5-beta
v0.7.4-beta
v0.7.3-beta
v0.7.2-beta
v0.7.1-beta
v0.7.0-beta
v0.6.9-beta
v0.6.8-beta
v0.6.7-beta
v0.6.6-beta
v0.6.5-beta
v0.6.4-beta
v0.6.3-beta
v0.6.2-beta
v0.6.1-beta
v0.6.0-beta
v0.5.8-beta
v0.5.7-beta
v0.5.6-beta
v0.5.5-beta
v0.5.4-beta
v0.5.3-beta
v0.5.2-beta
v0.5.1-beta
v0.5.0-beta
v0.4.5-alpha
v0.4.4-alpha
v0.4.3-alpha
v0.4.2-alpha
v0.4.1-alpha
v0.4.0-alpha
v0.3.8-alpha
v0.3.7-alpha
develop
v0.3.6-alpha
v0.3.5-alpha
v0.3.4-alpha
v0.3.3-alpha
v0.3.2-alpha
v0.3.1-alpha
v0.3.0-alpha
v0.2.5-alpha
v0.2.4-alpha
v0.2.3-alpha
v0.2.2-alpha
v0.2.1-alpha
v0.2.0-alpha
v0.1.5-alpha
v0.1.4-alpha
v0.1.3-alpha
v0.1.2-alpha
v0.1.1-alpha
v0.1.0-alpha
v0.0.62-alpha
v0.0.61-alpha
v0.0.60-alpha
v0.0.59-alpha
v0.0.58-alpha
v0.0.57-alpha
v0.0.56-alpha
v0.0.55-alpha
v0.0.54-alpha
v0.0.53-alpha
v0.0.52-alpha
v0.0.51-alpha
v0.0.50-alpha
v0.0.49-prealpha
v0.0.48-prealpha
v0.0.47-prealpha
v0.0.46-prealpha
v0.0.45-prealpha
v0.0.44-prealpha
v0.0.43-prealpha
v0.0.42-prealpha
v0.0.41-prealpha
v0.0.40-prealpha
v0.0.39-prealpha
v0.0.38-prealpha
v0.0.37-prealpha
v0.0.36-prealpha
v0.0.35-prealpha
v0.0.34-prealpha
v0.0.33-prealpha
v0.0.32-prealpha
v0.0.31-prealpha
v0.0.30-prealpha
v0.0.29-prealpha
v0.0.28-prealpha
v0.0.27-prealpha
v0.0.26-prealpha
v0.0.25-prealpha
v0.0.24-prealpha
v0.0.23-prealpha
v0.0.22-prealpha
v0.0.21-prealpha
v0.0.20-prealpha
v0.0.19-prealpha
v0.0.18-prealpha
v0.0.17-prealpha
v0.0.16-prealpha
v0.0.15-prealpha
v0.0.14-prealpha
v0.0.13-prealpha
v0.0.12-prealpha
v0.0.11-prealpha
v0.0.10-prealpha
v0.0.9-prealpha
v0.0.8-prealpha
v0.0.7-prealpha
v0.0.6-prealpha
v0.0.5-prealpha
v0.0.4-prealpha
v0.0.3-prealpha
v0.0.2-prealpha
v0.0.1-prealpha
Labels
Clear labels
ad-hoc
api
bug
ci-cd
content
dependencies
enhancement
frontend
in-progress
jellyfin
parked
priority: high
priority: low
priority: medium
review
security
One-off / ad-hoc work not tracked by a dedicated issue
REST API / HTTP endpoints
Something isn't working
Build, test, deploy pipeline
Channel content / schedules / playlists
Dependency updates (Renovate)
New feature or improvement
ChicoryTV React SPA frontend
Claimed by an active session — do not pick up
Jellyfin tuner / IPTV integration
Excluded from automatic queue pickup; work only when explicitly selected
Adversarial review finding
Security / vulnerability fix
No labels
priority: medium
Milestone
No items
No Milestone
Projects
Clear projects
No projects
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: timothy/ersatztv#876
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Spawned by #812, which swept the docs corpus and deliberately stopped at its boundary.
The gap
docs.no-session-narrativestates its scope as "every durable artifact — an in-repodocs/page, askill, a README, a code comment, an Obsidian vault page". The DETECTOR's population is much narrower
and says so:
docs/**/*.mdminusdocs/decisions/**, plus root-level*.md. Everything else —.claude/hooks and skills,web/, C# comments — is in scope for the RULE and has never been sweptby anything, mechanical or human.
#812 closed one class inside the docs corpus (a bare attribution of who found a finding, where the
reasons always follow in the next clause and the attribution carries nothing a reader acts on). The
same grep run outside that corpus finds the identical class, untouched:
.claude/hooks/pretooluse-merge-consent.sh:178.claude/hooks/pretooluse-merge-consent.sh:448.claude/hooks/pretooluse-merge-consent.sh:681ErsatzTV.Tests/Application/Channels/CreateChannelFromLineupHandlerTests.cs:467Found by cold review of #812 (measured 2026-08-29 at
37d86cda0). Four is what ONE class's grepreturns — it is a floor, not the population.
Why it was not folded into #812
#812's scope is the docs sweep, and its verification story is the detector plus a reading pass over
that corpus. These sites are a different corpus with a different verification story, and expanding
mid-PR would have made the change unreviewable.
#812 does NOT claim the class is closed even inside the docs corpus, and neither should this
issue. Six review rounds each surfaced another survivor there, every round's grep being a
locally-correct word-list over a phrasing space that never converged — the last one found
(revised after Fable review)in a file whose sibling had already been edited, which is the"fix one path, then check its twin" shape. What #812 claims is bounded: its manifest's sites were
remediated. Treat the table above the same way — a floor from one grep, not a population.
The judgement this needs — do not treat it as mechanical
The carve-out matters more here than in docs, not less:
CreateChannelFromLineupHandlerTests.cs:467cites the issue AND the PR that found it, and the sentence after it names the exact defect (a third writer ofPlaylistItem.PlaybackOrdermissed when the other two were gated). A reader deleting that test would want all of it. It is genuinely arguable that "found by adversarial review of PR #402" should stay as a citation.So this is per-site judgement, the same as #812 — the three dispositions #812 used (CUT / sever the
phrase and keep the claim / KEEP) transfer directly.
Also worth deciding
Whether the detector's population should grow to cover
.claude/**, or whether these corpora stay ahuman judgement. #812 rejected a population change in the other direction (removing
docs/superpowers/**) partly because--diffonly ever sees ADDED lines — the same argument appliesto any addition here, so a population change would help only for newly written comments.
Done-when
.claude/**, recorded in the record if it changesNot claiming — but flagging a file collision for whoever does.
Three of this issue's four known sites are in
.claude/hooks/pretooluse-merge-consent.sh(lines 178 / 448 / 681), and I am editing that file right now for #858+#859 (branchfix/858-859-merge-consent-hook-residuals). My diff lands in the branch-protection fetch block around line 448 and the guard-scope freshness block near 681 — both of which move line numbers and rewrite adjacent prose. So the table's line numbers will be stale once my PR merges, and a sweep started before then will conflict.Suggested sequencing: take this after #858/#859 lands, and re-derive the sites by grep rather than by the line numbers above — which the issue body already tells you to do ("the population stated and derived from source, not from the table above").
Why I am not folding it into my bundle, since it is tempting on a shared-file basis: this issue was split out of #812 precisely because a comment sweep is a different corpus with a different verification story, and its own Done-when asks for a derived population, per-site dispositions, and a decision on whether the detector grows to
.claude/**. Attaching that to a hook-behaviour PR would make both halves unreviewable — which is the reason #812 gave for not expanding mid-PR, and it applies unchanged in this direction. Shared file is not shared verification.One substantive note for the eventual sweep, from having just read all three sites closely for #858/#859: line 448's attribution is load-bearing and I would grade it KEEP, or at most sever-and-keep. The sentence is "It was used first, with the list consulted only on a 404, and cold review found what that left behind: the precedence argument below guarded the 404 path while the 200 path — the one this repo actually takes — granted without it." The clause after the colon is a rejected design and the exact false-open it produced (a by-name
branch_protections/{name}lookup that knows nothing about Priority). Cutting back to "cold review found" would be safe; cutting the whole sentence would delete the only record of why the by-name endpoint must never come back, and that is precisely the "severing the attribution must not sever the rejection" case this issue's own judgement section warns about. Line 178 and line 681 read to me as ordinary sever-the-phrase candidates by comparison.Claiming (session 2026-09-03). #858/#859 landed as #897, so the file-collision flagged above is cleared. Plan: derive the population by grep over every corpus the rule names outside the detector (
.claude/**,scripts/**,web/**, C#), classify each site with #812's three dispositions, decide the detector-population question, one PR.Closing record
Outcome: Shipped in PR #906, merged as
efadbec297. The population outside the detector was derived by a whitespace-joined sweep (453 sites in 108 files atfb5592971, plus a second phrasing pass), every site classified with #812's CUT / SEVER / KEEP dispositions (per-corpus manifests on the PR: SEVER 467 · CUT 49 · KEEP 208 over 724 manifest rows), and the detector's population grown to.claude/,.gitea/,.husky/andscripts/regardless of extension, minus the detector, its test andscripts/tests/fixtures/. Three latent detector defects fixed on the way: a tracked symlink or gitlink was opened by--all, an unmerged path was scanned once per index stage, and a+++filename containing a space was dropped silently in--diff.Root cause: the rule was established for the docs corpus and its detector never extended to the class it names (
#773shape); the corpus it did not reach is the one where narrative is actively written — 287 of 453 sites were under 30 days old.Decisions/conventions changed:
docs.no-session-narrative—mechanics:(population, exemptions, regular-files rule, re-dated depth measurement, tab arm on the proven list),signals:, body (the #876 paragraph).Decisions-Edit: yes.Reusable knowledge:
scripts/tests/fixtures/) is not a durable artifact; exempting it is what keeps the depth claim true, and the oracle now asserts it so it cannot go stale silently.def test_count unchanged (one removed, one added). A by-function-name diff againstorigin/mainis the check; a count is not.it.eachwhose array spans lines with parentheses; walk each changed title line back to its anchor instead.h.sh~HEAD), so that index shape needsupdate-index --index-infoto witness.Verification:
scripts/tests1569 passed / 3 skipped on the final tree; web lint + typecheck + 1319 vitest green;check-doc-narrative.py --all179 files / 1 warning (the #812 carve-out),--diff origin/main0 warnings;decisions_validate --base origin/mainOK; ten detector mutants each red; BOM unchanged on every touched.cs. Reviews: Codex rounds 1–5 (cross-family, read-only) and Opus rounds 1–6 (worktree-isolated, every deleted line read); final Opus verdict MERGEABLE with 0 new findings; CI green ona7d91bf15.Deferred: none.
web/and C# stay outside the detector on a stated measurement (3 of 74 PATTERNS-matching sites); the predicate did not grow, by the record's own argument.Docs updated:
docs/decisions/records/docs/no-session-narrative.md,docs/decisions/README.md(regenerated),docs/ci-cd.md.