Files
ersatztv/docs/tracker-retrofit-triage-237.md
T
timothy f355a4a96b
Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 11s
Build ErsatzTV Image / CI image pin matches docker/ci (pull_request) Successful in 10s
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (pull_request) Successful in 10s
Build ErsatzTV Image / decisions lifecycle (pull_request) Successful in 19s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 37s
Build ErsatzTV Image / Functional E2E (curl contracts) (pull_request) Successful in 37s
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (pull_request) Successful in 36s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 38s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
docs(524): triage #237's 111 comments — no decision retrofit is owed
Exhaustive triage of the closed tracker ersatztv#237, whose 111 comments
server-management#642 excludes from MemPalace ingestion (over the per-file
cap) and #520 removes from startup. #524's premise was that facts living only
in those comments would be orphaned and need curating into lifecycle records.

Result: zero decision-shaped orphans. Every durable decision-shaped fact is
already held by the decision corpus or by the individual issue the comment
narrates -- which the exporter does ingest. The tracker was always the lossy
copy, because the session protocol required the fuller closing record on the
worked issue first.

- docs/decisions.md: new active record docs.tracker-comment-retrofit, leading
  with the reusable rule (check the worked issue BEFORE the decision corpus)
  and the consequence for #642's benchmark row, which has no valid subject.
- docs/tracker-retrofit-triage-237.md: the audit trail -- method, per-comment
  classification of all 111, totals, and the one candidate raised and
  disproved (#497's Guids/Directors scope, stated more fully on its own issue).
- docs/handoffs/chicorytv-issue-queue.md: sweeps the two genuinely orphaned
  LORE facts the triage surfaced (e2e-local.sh readiness probe hanging on a
  reused config dir; troubleshooting playback cannot exercise channel branding).
- docs/README.md: index the new doc.

The claim is deliberately narrow: no *decision-shaped* orphans. The lore bucket
was classified but not coverage-checked, and it was not empty -- hence the sweep.

fixes #524
2026-07-21 17:31:43 +02:00

12 KiB
Raw Blame History

Tracker-retrofit triage — ersatztv#237 (#524)

Evidence for the decision record docs.tracker-comment-retrofit (docs/decisions.md). That record states the rule; this file is the audit trail — what was examined, by what method, and how every one of the 111 comments was classified, so the result can be spot-checked or re-derived rather than taken on trust.

Deliberately not under docs/decisions/: files there are parsed as decision records by scripts/decisions_lib.py, and this is evidence, not a record. It is also not in docs/decisions/migration-map.md, whose scope is the #521 legacy-heading→key migration.

Why the triage happened

server-management#642 exports Gitea issue history into MemPalace but excludes #237 — at 111 comments it exceeds the miner's per-file cap. #520 separately removed #237 from session startup. The worry behind #524: a durable fact living only in a #237 comment would become unretrievable, and should be curated into lifecycle records.

Method

  1. Corpus. All 111 comments pulled verbatim from the Gitea API with per-comment provenance (id, author, timestamp, canonical URL). Nothing sampled — every comment read. The corpus itself is not committed (that would be the 1:1 dump #524 rejects); to re-derive or spot-check a row below, re-pull from the permanent primary source: GET /api/v1/repos/timothy/ersatztv/issues/237/comments (returns all 111 in one call).
  2. Three-way split (from #524), applied to each content item, since one session comment routinely mixes all three:
    • decision — a durable "we do X rather than Y because Z" that governs future behavior;
    • issue-work — per-session/per-issue narration (closures, PR/CI numbers, review loops, claims), which already lives on the individual Gitea issue and is ingested from there;
    • lore — a cross-cutting workflow/orchestration lesson, belonging in the handoff lore or MEMORY.
  3. Coverage test, applied to decision-shaped items only. Semantic candidate discovery against the ErsatzTV-Decisions / ErsatzTV-Decisions-Archive MemPalace wings, then verification against canonical Markdown by exact search (docs/decisions.md, docs/decisions/*.md, docs/decisions/archive/*.md, docs/handoffs/chicorytv-issue-queue.md, convention docs). No item was declared covered on a semantic hit alone — MemPalace was discovery, never authority.
  4. Worked-issue check. For any item surviving step 3, the issue the comment narrates was read live. This is the step that disposes of most apparent orphans.

Result

Decision-shaped orphans: zero. No durable decision-shaped fact exists only in #237.

Item-level counts from the coverage pass (units are items, so totals exceed 111 — one comment commonly carries a decision restatement, its issue-work narration, and a lore aside):

Slice Only-in-#237 Already covered Issue-work Lore
comments 128 0 14 12 2
comments 2956 0 18 22 14
comments 5784 0 12 14 8
comments 85111 0 (1 raised, disproved) 16 21 9
total 0 60 69 33

Comment-level primary class (units are comments; sums to exactly 111): decision 14, issue-work 88, lore 9.

The one candidate raised, and its disproof

Comment [106/111] (issues/237#issuecomment-14077) recorded #497's deliberate scope exclusions — Guids (not eager-loaded by GetOrAdd, so reconciling would duplicate-insert every scan) and Directors (not add-persisted for MusicVideoMetadata). Absent from the decision corpus, so it survived the corpus check. It fails the worked-issue check: issue #497's comments 14013 and 14072 state both exclusions with fuller reasoning, and the exporter ingests that issue as 497.md. Category 2, not a retrofit target. (scan.musicvideo-reconciliation covers #494's neighbouring reconcile decision but not this field-scope question — distinct records.)

Spot-checks verified independently

  • #357, parked player-owned-playback architecture options — preserved on issue #357 itself (8 comments carrying the three paths and the no-go). Note the docs copy is not on main: docs/player-owned-playback-poc.md and the docs/decisions.md verdict entry exist only on the unmerged feat/357-player-owned-playback branch, so the issue is currently the sole reachable home. Category 2 holds, but by a narrower margin than the other items.
  • #235 / PR #267, the Unlock: isLast batch fix — this was a fresh design decision (Fable prescribed lock-once-per-provider batching because the naive per-source fix would starve the 2nd+ media source; now live at SchedulerService.cs), not merely an application of locking.entitylocker-atomic-flags. It is still category 2: issue #235 comment 8880 and PR #267 comment 8794 both carry the rationale.

Known gap in this triage

The 33 lore-class items were classified but not coverage-checked. That bucket is not empty: two facts from comment [109/111] have no home anywhere and were swept into docs/handoffs/chicorytv-issue-queue.md by this PR — the e2e-local.sh readiness-probe hang on a reused config dir, and the troubleshooting playback API's inability to exercise channel branding. A future tracker triage should coverage-check the lore bucket too, or state that it didn't.

Per-comment classification

primary-class is the single dominant class of each comment; durable home names where that content lives (the worked issue, a doc, or ephemeral for queue bookkeeping with no durable home).

# primary-class durable home
1 issue-work #231#235 filed (triage session); ephemeral
2 decision triage-verdict rule (Blocker/High ⇒ priority pickup); decisions.md 2026-07-11
3 issue-work #213, #215, #217#221, #236
4 decision tracker "Pending adversarial reviews" section; ephemeral (protocol)
5 issue-work #126, #207, #212 closed; #230, #238 filed
6 issue-work #231, #232 via PR #241
7 lore re-review the fix commit, not just the initial PR diff
8 issue-work #244 via PR #249 (ChannelsScreen extraction)
9 issue-work #233, #234 via PR #250; #235 remainder
10 issue-work audit sweep filing #251#254
11 issue-work arc/backlog triage for #251#254; ephemeral
12 issue-work #251, #252 via PR #258
13 issue-work adversarial-reviewer#24; #255#257 triage
14 issue-work #238, #243, #246 body edits; ephemeral
15 decision #253 concurrency contract (Version, ETag, 412); optimistic-concurrency.md
16 decision #204 redirect matcher; decisions.md spa.legacy-redirect-matcher
17 decision #205, #206 auth posture + rollback tag; blazor-route-parity.md §5
18 issue-work #202, #255#257 via PR #262; #264 filed
19 issue-work #253 PR1 landed; #265 filed
20 lore api-conventions.md §7a/§7b section-number collision on parallel merge
21 issue-work #235 via PR #267 (F9 gate closed)
22 issue-work #91b SPA pre-work PR #272; #271 filed
23 lore Codex "interrupted" status unreliable; trust the rollout transcript
24 issue-work #253 PR3 landed; #269 filed
25 decision #91b Blazor removal; rollback tag blazor-final = bb310f6b
26 decision #253 PR4 phasing — collapse Phase-1/428 flip, no separate soak release
27 issue-work #197 decomposed into #280#289; PR #279 Phase-0
28 decision #197 Bundle A — single API key, RequireKeyForReads default true
29 issue-work #283, #294
30 issue-work #289 (PR #76) — ERSATZTV_ALLOW_WRITES posture
31 issue-work #295 design ratified (OIDC + local login)
32 issue-work #245#247 (App.tsx modularization plan review)
33 issue-work #287, #288 (Bundle C)
34 issue-work #271
35 issue-work ephemeral (arc/tracker bookkeeping correction)
36 lore queue-status-in-prose drift; docs/handoffs/chicorytv-issue-queue.md
37 issue-work #295 PR1, #299, #301
38 issue-work #269 (500-exposure slice); #303 H6/H10
39 decision #303 H9 append-only + H3 root-png guard; release-ci-governance.md
40 decision #303 H10 review-verdict merge gate; release-ci-governance.md
41 issue-work #269 closed; #308 filed
42 decision #311 H11 rebase-not-merge + scoped format gate; contributing.md
43 issue-work #303 close-out; #314, #315 filed
44 issue-work #317 merge-gate double-prompt fix; #314, #319
45 issue-work #295 PR2, #301; #320 filed
46 lore merge-gate needs ETV_GITEA_BASICAUTH in env; #315
47 issue-work #319 (CSP / Permissions-Policy)
48 issue-work #253, #265 closed
49 issue-work #238 (TopBar primary action)
50 issue-work #286 (/api/v1 versioning); #289 superseded
51 issue-work #172 (scheduling API hardening); #327 filed
52 issue-work #314 (authenticated security scan); #330 filed
53 issue-work #197 go-live gate closed; #334 filed
54 issue-work #335, #336 (v26.8.0 go-live)
55 issue-work #237 tracker closure summary; ephemeral
56 issue-work #330 (CORP header); #340 filed
57 issue-work #333, #344#346
58 issue-work #344, #347
59 issue-work #245, #350, #352
60 issue-work #354#357
61 issue-work #357, #358 (player-owned playback PoC)
62 issue-work #246, #359, #360
63 issue-work #243, #247 (modularization epic)
64 issue-work #299, #363
65 issue-work #99, #333, #334 (queue-selection correction)
66 issue-work #345, #357, #367
67 issue-work #99, #368
68 decision selector tier order; docs/handoffs/chicorytv-issue-queue.md
69 issue-work #354, server-management#599
70 decision selector eligibility — exclude parked / closed milestones; #334, #371, #372
71 lore coverlet.runsettings Migrations exclusion (exit-137 OOM); #15, #373
72 issue-work #333, #344, #345
73 lore Gitea ?milestones= filter no-ops on :/+ names
74 issue-work #70, #73, #77, #383#386
75 issue-work #383#386, #397
76 issue-work #72, #164, #401, #405, #414, #415, #417
77 issue-work #70, #376, #383, #385, #386, #419, #421
78 issue-work #176, #320, #385, #386, #423
79 issue-work #385, #386, #425, #428
80 issue-work #164, #385, #425, #430, #431
81 issue-work #386, #425, #432
82 issue-work #386, #425, #439
83 issue-work #308, #441; optimistic-concurrency.md
84 issue-work #176, #293, #395, #425, #442
85 issue-work #363, #444, #445, #447
86 issue-work #350, #446
87 issue-work #381, #383, #395, #396, #448
88 issue-work #310, #327, #338, #367, #401, #409, #410, #447, #458
89 issue-work #350, #403, #404, #412, #431
90 issue-work #398, #420 (upload-artifact@v3 pin)
91 issue-work #409, #458, #460
92 issue-work v26.10.0 release; #350, #461 (selector script)
93 issue-work #404, #463, #464
94 issue-work #431, #469
95 issue-work #363, #444
96 issue-work #350, #472#474, server-management#630
97 lore verify the emitter is deployed before trusting an empty log
98 issue-work #350, #412, server-management#604
99 issue-work #476, #478
100 issue-work #478, server-management#631
101 issue-work #474, #477, #480, #484, #485
102 issue-work #350, #472
103 issue-work #381, #395, #480
104 issue-work #474, #487, #488, #491, #494
105 issue-work #494, #496
106 issue-work #497, #498, #500 (the raised-and-disproved candidate)
107 issue-work #25, #67, #68, #502, #503
108 issue-work #350, #474, #487, #510, #511
109 issue-work #502, #510, #511 (+ the two lore facts swept to the handoff)
110 decision retire #237 from startup; #520, #521, server-management#642
111 lore independent caps don't compose into a budget; #511