Cold adversarial review (external, zero shared context) returned GATE: BLOCKED. blazor-route-parity.md now embeds per-cluster mutation-depth verdicts; schedules + media-sources rows moved to Section 3 (disproven SPA-READY). Handoff queue reordered: #210/#211 -> #208/#209 -> #207/#212 -> #202 -> removal PR. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
9.6 KiB
ChicoryTV issue-queue handoff (living document)
Paste the prompt below into a fresh session to work the next item. Each session ends by UPDATING THIS FILE in place (rewrite the state section and the queue for the next item) so it always holds the current handoff. History: created 2026-07-02 after the plan audit (#59 epic); all backend gap issues (#100–#111), all SPA screens (#84–#89, #93, #109), the rebrand (#90), the cutover root-flip (#91 phase a), full scheduling parity (#144/#162), media/troubleshooting parity (#141/#161/#158/#180), onboarding docs (#185), the collections/API-gap batch (#155/#151/#152-backend/#184), the multi/rerun/playlist SPA editors (#151/#152 PR #194, #153 PR #195), CI speedups (#190 PR #192), #145 playback troubleshooting (PR #199), #198 OpenAPI casing (PR #201) + #193 rerun existence-check (PR #200) are MERGED. v26.5.0 in prod; v26.6.0 tagged (awaiting Komodo pin bump in server-management).
Session state (2026-07-09 night, #91 gate session): the cold adversarial review gate for
#91 phase (b) RAN and returned GATE: BLOCKED (3 must-fix) — findings filed as review-labeled
issues #202–#206. The review ran correctly cold: fresh headless session from
~/adversarial-reviewer, zero shared context, brief verbatim from the #91 gate comment. All
claims were then verified in code. The #203 MUST-FIX (parity doc untrustworthy) was resolved
in-session: a 7-agent mutation-depth sweep re-verified every Section-2 row; results embedded
in docs/blazor-route-parity.md (verdict table + schedules/media-sources rows moved to
Section 3); gaps promoted to issues #207–#213; #203 CLOSED. #204 (exact-match-only
redirects) has an agreed pattern+catch-all strategy on the issue; #205 (blazor-final tag) and
#206 (auth posture) are folded into the future removal-PR routine. Main is green
(post-#200/#201 run all success). No code changed this session — docs + issues only.
Blazor removal (#91 phase b) is BLOCKED on MUST-FIX feature gates, in this planned order:
- #210 + #211 (+#213 nits) — playouts delete/reset wiring (endpoints EXIST), erase/context endpoints, collections custom-order + add-item kinds, copy/trash/logs nits ← NEXT (prompt below)
- #208 + #209 — shared "Add to collection/playlist/schedule" component: search-screen mutations + media browse/detail mutations, per-show scan wiring, episode info/troubleshoot entries
- #207 (+#212) — schedules editor full mutation depth (endpoints exist; needs languages enumeration endpoint shared with #212 channel-editor pickers)
- #202 — media-source management (write REST API + SPA screens; largest, riskiest)
- #91 phase (b) removal PR — pattern redirects + catch-all (#204 plan), blazor-final tag
(#205), auth posture note (#206), delete Pages/Shared/ViewModels/Validators + 6 packages
(MudBlazor, MediatR.Courier.DependencyInjection, Blazored.FluentValidation, BlazorSortable,
Heron.MudCalendar, Chronic.Core). Removal recon is DONE (this session): Courier consumers
are 100% Blazor (
AddCourierStartup.cs:394 dies too); the StartupMapWhen"blazor" branch (736–795) CO-HOSTS MapControllers/OpenAPI/Scalar — surgical removal only (MapBlazorHub:775, MapFallbackToPage:776, services 379–398);wwwroot/lib/*+css/site.cssare_Host-only; checkLocals/*.resxconsumers before deleting; keepExtensions/exceptNavigationManagerExtensions.cs.
Lessons for all remaining prompts (conventions live in docs/; this is workflow lore):
- READ docs/README.md → the convention docs FIRST; point recon/implementer agents at specific doc sections. Only recon the task-specific delta.
- blazor-route-parity.md now carries mutation-depth verdicts (2026-07-09 sweep table at the top of Section 2). A row is only trustworthy if its cluster verdict is PARITY-OK; the sweep evidence lives in the issues #207–#213. Keep the verdict table updated as gates close.
- "Screen exists" ≠ parity: the root cause of the false SPA-READY rows was same-session verification that never diffed capabilities against the Blazor page. Per-capability diff vs the Blazor page is the standard for any future parity claim.
- Several gaps are UNWIRED EXISTING endpoints (playout delete/reset, block copy, scan-show, collections add-item kinds) — check the endpoint index before building new API surface.
- Keep the MAIN checkout's
web/node_modulesfresh (npm installafter pulling a PR that adds a dep) — worktrees copy it, and a stale copy broke typecheck in a #198 worktree. - Playwright-MCP E2E: never open tabs/window.open for file-download endpoints — curl them.
If browser tools stall repeatedly,
pkill -f ms-playwright-mcpand drive a fresh session. - The user's main checkout (/Users/timothy/ersatztv) stays ON main and pulled each session.
Feature work in worktrees off origin/main; copy
web/node_modulesfrom the main checkout. - Subagent connection drops = laptop sleep/transient; re-resume via SendMessage (work survives).
- Build/verify locally, then trust it; CI (VM 127) confirms (~9 min warm). Watch by commit
status:
/api/v1/repos/timothy/ersatztv/commits/{sha}/status. - PR routine (works): worktree off origin/main → implement (opus judgment-heavy / sonnet
mechanical; doc pointers + exact facts; csharp-lsp for C#) → API changes: build app project
FIRST then
./scripts/update-openapi.shthennpm run generate:api→ full local test pass → push, PR → fork adversarial review (SCOPED "review only") + live-E2E for UI changes (scripts/e2e-local.sh) → review fixes as follow-up COMMITS (never amend/force-push) → CI green → merge (consent per session) → structured close comments per CLAUDE.md protocol. - Never run TWO committing agents on one worktree concurrently. Read-only review forks are fine.
- Reusable API facts: DTO records in ErsatzTV.Core/Api need file-scoped
#nullable enable; ErsatzTV.Application has NO nullable context (CS8632);Option<T>→nullable =MatchUnsafe(v => (T?)v, () => null);LanguageExtensions.Applycollapses NotFoundError→422, so real 404s need a controller pre-check; id-taking child GETs get an OpenApiErrorResponseContractTests [TestCase].
PROMPT — #210 + #211 (+#213): playouts/collections mutation gaps + parity nits
You are Fable, the ORCHESTRATOR in the main Claude Code session. Fable is EXPENSIVE: delegate (recon → Explore/haiku; mechanical → sonnet; judgment-heavy → opus; fable forks for review). FIRST read CLAUDE.md, docs/README.md + the convention docs it indexes, and the Lessons above.
HARD CONSTRAINTS:
- Work in worktrees off origin/main. Copy web/node_modules from the main checkout.
- Up to 3 concurrent builds; never 5+. NEVER set ETV_UPDATE_GOLDENS.
- Merge consent in-conversation per session (prior pre-approvals do NOT carry over).
- Live-E2E via scripts/e2e-local.sh; NEVER exercise download endpoints via browser tabs (curl them). Adversarial review fork per PR diff, SCOPED "review only".
Task — close the first #91 phase (b) feature gates
Read issues #210, #211, #213 (bodies carry exact file:line evidence from the #203 sweep).
- #210 playouts: wire the EXISTING
DELETE /api/playouts/{id}andPOST /api/channels/{channelNumber}/playout/resetinto the SPA (delete UI + enable the disabled Reset button; fix its stale wrong comment App.tsx:3279-3283). Add NEW endpoints for erase-items / erase-items-and-history (per playout kind; MediatR handlers exist Blazor-side — reuse) + SPA buttons; scheduling-context dialog needs a decode endpoint (follow the decode-by-row-id decision) or explicit deferral with decision entry. Preview calendar: decide build-vs-decision-entry. - #211 collections: new custom-order endpoint (
PUT /api/collections/{id}/custom-order, Index-from-array-order convention) + reorder UI; widenADDABLE_TYPE_LISTto all 10 kinds (backend already accepts them). - #213 nits (as far as the session allows): block-copy button (client fn exists), watermark
copy via
/add?from=prefill, trash select-all/see-all, Trakt stale note, decisions.md entries (yaml paste, channel-numbers renumber, deco-templates calendar). Full PR routine; one worktree, one PR (or split #210/#211 into two PRs if cleaner). Update blazor-route-parity.md verdict table rows you close + api-conventions checklist + OpenAPI regen for new endpoints. Comment + close #210/#211 (and #213 if fully done) per protocol.
On completion — REQUIRED last step
Update THIS handoff (pop the done items, promote #208+#209 to next with a fresh prompt), commit to main, print the next prompt in a fenced code block.
Issue queue (work top-down)
- #210 + #211 (+#213) playouts/collections gaps ← PROMPT above.
- #208 + #209 search + media mutation surface (shared "Add to…" component).
- #207 (+#212) schedules editor depth + channel-editor gaps (shared languages endpoint).
- #202 media-source management (write API + SPA) — largest.
- #91 phase (b) Blazor removal PR (gate cleared once 1–4 close; #204/#205/#206 fold in; removal recon in session state above).
- #197 cold API contract+security review — HARD GATE on #58 close/go-live and MANDATORY before any remote exposure.
- Backlog: #99 (TS/HLS-Direct session tracking), #66 (artwork magic-byte sniffing), backlog
nits (unclamped pageSize, 30 MB bare 413, PlayoutController route Name=/lightweight
exists-check, guide 21-include eager-load + fillerKind notes — see #85/#102 comments).
Cross-refs: v26.6.0 deploy = Komodo pin bump (server-management). Real-transcode E2E of the
playback screen: once on the test container (
ersatztv-testruns:latest) — local ffmpeg 8.1.2 lacks subtitles/zscale filters.