Files
ersatztv/docs
timothyandClaude Opus 5 c3ccfa95e0
PR Gates / CI image pin matches docker/ci (pull_request) Successful in 12s
PR Gates / Docs update reminder (pull_request) Successful in 15s
PR Gates / decisions lifecycle (pull_request) Successful in 16s
review-verdict/h10 Exempt: docs-only change (no code, no protected path)
Review verdict / Set review-verdict status (pull_request_target) Successful in 11s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 10s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 8s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Skipped
Build ErsatzTV Image / Functional E2E (curl + UI contracts) (pull_request) Successful in 8s
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (pull_request) Successful in 7s
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (pull_request) Successful in 5s
PR Gates / Script tests (pytest) (pull_request) Successful in 2m14s
docs(773): root-cause the recurring defect shapes across the full closed-issue corpus
Analysis over all 349 closed issues (95 carry a `## Closing record`), classified
by five independent raters against a written taxonomy, with an inter-rater control
(12/15 blind agreement) and a backward-generalization check over the 254
pre-convention issues.

Findings that change the picture the issue started from:

- The ranking reverses. Vacuous verification is the most common shape (17/69),
  not twin-missed (14/69), over the full corpus vs the issue's 50-issue sample.
- The issue's central hypothesis holds and extends: twin-missed, vacuous-by-
  sampling and symptom-keyed guards are one error (reasoning about a
  representative instead of the population) — ~32/69 (46%), one detector.
- The shapes predate the closing-record convention (#1, #215, #232, #403), so
  they are not an artifact of recent guard-building work.
- A class the taxonomy missed entirely: check-and-use races over mutable state
  (#536, #622, #632, #706, #707) — five instances, proposed independently by
  three raters and re-derived by a fourth, blind.
- Overclaim drops to 4% as a primary cause; it is a modifier, not a class.

Part 2 (tooling audit), all measured rather than assumed: csharp-lsp cannot
initialize and typescript-lsp cannot resolve typescript, the `LSP` tool has 0
calls across 811 transcripts, ruff/pyright are enforced nowhere despite the
global instruction, and PreToolUse/PostToolUse hook execution leaves no durable
trace — so we cannot currently tell whether our own guards fire.

Names the classes where no mechanical detector is plausible rather than
inventing weak ones. Spawns #774-#781; this issue is analysis, not implementation.

Refs #773

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-13 20:01:25 +02:00
..

docs/ — task-signal map

Purpose: route a fresh contributor/agent to the minimal set of docs for the task at hand, instead of a mandatory front-to-back read. Update this doc in the same PR that adds, removes, or retitles a doc below, or that changes which sections a task signal points to.

Start here, always

  • CLAUDE.md (repo root) — project intro: architecture, layout, dev commands, conventions, Task Completion Protocol.
  • docs/contributing.md — established code patterns (CQRS/MediatR, LanguageExt, the ChicoryTV SPA, EF Core dual-provider migrations, FFmpeg pipeline, analyzers, testing). Read before any non-trivial change.

Task signal → minimal sections

Signal Read
Session startup / "what's next" (no issue named) docs/handoffs/chicorytv-issue-queue.md (standing kickoff — two concurrent tracks: orientation ‖ scripts/select-queue.sh 5)
Named-issue pickup Skip queue selection; go straight to focused retrieval — see "Knowledge retrieval" below, then the issue body
Adding/changing a /api/* endpoint docs/api-conventions.md checklist + docs/endpoint-index.md
Adding a ChicoryTV SPA screen docs/spa-conventions.md
Scheduling / playout engine work docs/domain-model.md + decisions catalog rows keyed sched.* (docs/decisions/README.md)
Concurrency / optimistic-locking work docs/api-conventions.md §7a/b/c + docs/decisions/optimistic-concurrency.md
Auth / security-surface work docs/decisions/api-auth-security.md
CI / release pipeline work docs/ci-cd.md + docs/decisions/release-ci-governance.md
Proposing a new guard / CI check / regression test convention docs/defect-shapes-773.md §4 (detector menu + the classes where no detector is plausible)
Live local run / Playwright-MCP verification docs/e2e-local.md + scripts/e2e-local.sh
Adding/changing a UI-E2E browser flow docs/e2e-local.md → "UI-E2E harness" + scripts/e2e-ui.sh
What does a test suite cover docs/testing.md
Legacy Blazor route lookup docs/blazor-route-parity.md (historical #91 phase (b) inventory)
"Why do we do X this way" / challenging a convention Catalog-first: docs/decisions/README.md (active rows) → follow the row's link to docs/decisions/records/<area>/<topic>.md for full rationale. docs/decisions/archive/<area>/ only for "what did the rule used to be."

Knowledge retrieval (MemPalace + catalog + Gitea)

These four rules are the seam agreed with server-management#642 (the Gitea→MemPalace exporter). They apply whether the question comes up via MemPalace, a grep, or a stale comment:

  1. Current conventions/decisions → catalog-first. Start at docs/decisions/README.md; discover via the ErsatzTV-Decisions wing (active) / ErsatzTV-Decisions-Archive (superseded/retired). Resolve by topic/key, never by chasing a file path.
  2. Issue history → evidence, not authority. The Gitea-ErsatzTV wing is historical narrative that may be stale; it never overrides current Markdown.
  3. The breadcrumb rule (the crux behavior change). A file path named inside a historical issue comment (e.g. "grep docs/decisions.md 2026-07-17", "see …") is a breadcrumb, not a live pointer. Find the current rule via the catalog / active wing by concept; do not treat the named path as current. (Why it's safe: still-current → in the active wing, breadcrumb resolves; superseded → the active wing returns the successor and a literal follow lands on a record that announces its own status: superseded; retired → the active wing returns nothing, which is itself the signal. The validator-enforced move-to-archive/ is what prevents the catastrophic "superseded rule read as current" case.)
  4. Fallback when MemPalace is stale/down: docs/decisions/README.md catalog, then rg '^`key: <dotted.key>`' docs/decisions/. MemPalace is never authority nor sole fallback.

MemPalace is candidate discovery only — every passage is verified against its cited Markdown/Gitea source before use. Never derive live queue state from MemPalace, #237, or historical comments; queue state is live Gitea state, retrieved via scripts/select-queue.sh (see docs/handoffs/chicorytv-issue-queue.md). Full retrieval contract (altitude/precedence, staleness bounds, what's mined per issue): docs/handoffs/chicorytv-issue-queue.md → "Knowledge retrieval".

Also present in docs/

  • docs/domain-model.md — what the app IS: entity glossary, channel→playout→schedule/block concept map, where each concept is edited in the SPA.
  • docs/api-conventions.md — checklist for adding/changing a /api/* endpoint (controllers, DTOs, error mapping, auth, OpenAPI regen, tests).
  • docs/spa-conventions.md — playbook for adding a screen to the ChicoryTV React SPA.
  • docs/e2e-local.md (+ scripts/e2e-local.sh) — how to run a live local instance for manual or Playwright-MCP verification.
  • docs/testing.md — testing map: what each *.Tests project / web suite covers, golden-file nets, the timezone-independence rule, how to run subsets, the per-PR verification gate.
  • docs/blazor-route-parity.md — historical record of the completed #91 phase (b) cutover: the Blazor Server UI is removed and every legacy route now 302-redirects to its SPA equivalent (or falls through to the catch-all → /app). Read it for the full legacy→SPA route inventory.
  • docs/decisions/records/<area>/<topic>.md — one active decision record per file, YAML frontmatter (key/title/status/since/supersedes/superseded-by, plus optional stale-after/sources — ersatztv#603), rationale prose in the body. The filename is the key, so one-active-record-per-key is a filesystem property (ersatztv#610). docs/decisions.md and the topic files remain as the lifecycle-schema narrative plus a "Records formerly in this file" index, which is what keeps older date-based pointers resolvable. Generated active view: docs/decisions/README.md (catalog / task router) — start there. Superseded/retired records live in docs/decisions/archive/ and are read only for history, never for "what is the current rule."
  • docs/ci-cd.md — build/test/release pipeline, versioning, dependency management.
  • docs/rest-api.md — REST API design doc for ersatztv#2 (goals, conventions, per-slice plan). Largely superseded day-to-day by docs/api-conventions.md; read this for the original rationale.
  • docs/mcp.md — the ErsatzTV.Mcp stdio JSON-RPC MCP server (#58): how it wraps /api/v1 as read + cautious-write tools, its config/env vars, auth, security posture, and the tool catalog.
  • docs/channels.md — Channel entity field reference.
  • docs/m3u-xmltv.md — M3U/XMLTV generation overview (ChannelPlaylist, GetChannelGuideHandler).
  • docs/fork-strategy.md — divergence policy vs upstream ErsatzTV.
  • docs/design-sync.md — Claude Design ↔ repo screen workflow (#92).
  • docs/endpoint-index.md — generated REST endpoint index (method/path/operationId/summary per OpenAPI tag). Do not edit by hand; regenerated by scripts/generate-endpoint-index.py / scripts/update-openapi.sh.
  • docs/handoffs/chicorytv-issue-queue.md — static session kickoff prompt + workflow lore. Queue state is live Gitea state, retrieved each session via scripts/select-queue.sh — see that file's standing kickoff for the two concurrent tracks (orientation ‖ selection). ersatztv#237 is a closed, archival historical tracker (superseded by startup.parallel-orientation in docs/decisions.md) — not a live pointer.
  • docs/defect-shapes-773.md — root-cause analysis of the recurring defect shapes across the whole closed-issue corpus (#773): the measured class ranking, the four families they consolidate into, the cheapest mechanical detector per class, the classes where no detector is plausible, and an audit of which configured hooks/MCP servers/LSPs are actually invoked. Read it before proposing a new guard or CI check — §4 is the detector menu, and it argues against enumerating cases one incident at a time.
  • docs/tracker-retrofit-triage-237.md — audit trail for the #524 triage of ersatztv#237's 111 comments (method, per-comment classification, totals). Evidence for the docs.tracker-comment-retrofit decision; read it only when triaging another over-cap tracker.
  • docs/handoffs/rest-api.md — original handoff prompt for kicking off the REST API work (#2).