Files
ersatztv/docs/handoffs/chicorytv-issue-queue.md
T
timothyandClaude Fable 5 cfabd6f33f
Build ErsatzTV Image / Build & test (.NET) (push) Successful in 8m14s
Build ErsatzTV Image / Docs update reminder (push) Has been skipped
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (push) Successful in 10m9s
Build ErsatzTV Image / Build & push image (amd64) (push) Successful in 7m58s
docs: advance ChicoryTV queue past #210/#211 (PR #214); next = #208+#209 shared add-to component
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 23:40:43 +02:00

11 KiB
Raw Blame History

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), and the first #91-gate batch #210/#211/#213-partial (PR #214) are MERGED. v26.5.0 in prod; v26.6.0 tagged (awaiting Komodo pin bump in server-management).

Session state (2026-07-09 late night, #210/#211/#213 session): #210 + #211 CLOSED via PR #214 (merged; main green). New API surface: POST /api/playouts/{id}/erase-items + .../erase-items-and-history (reuse Blazor's ErasePlayoutItems/ErasePlayoutHistory commands; controller 404 pre-check + per-kind 422 guards), GET /api/playouts/items/{id}/scheduling-context (decode-by-row-id; PlayoutItemResponseModel gained id null-for-gap-rows + hasSchedulingContext; PlayoutListItemResponseModel gained playoutMode), PUT /api/collections/{id}/custom-order (Index from array order; GetCollectionItems now orders by CustomIndex when the flag is on — array order carries it, DTO unchanged). SPA: playout Reset/Delete/erase-by-kind wired, scheduling-context dialog, templates preview month-grid (TS port of AlternateScheduleSelector.GetScheduleForDate in web/src/screens/playoutTemplateCalendar.ts), OnDemand alternate-schedules gating, collections reorder mode (loads ALL pages then move up/down; any-kind, not movies-only — decisions.md), 10-kind add picker, block-copy dialog, watermark /add?from= prefill, trash select-all + pageSize 100. #213 stays OPEN (reduced scope: logs sort/page-size persistence, block-history page-size/gating, blocks/templates list filter — read-only conveniences or API-gap-blocked). Adversarial review fork returned APPROVE-WITH-FIXES: watermark mode-from-state fixed in-PR; erase/reset EntityLocker lock-gating race filed as #215 (systemic API posture, all playout mutations lock-free — not a #214 regression). Flake note: App.test.tsx builder collections fan-out test deflaked (passive-effect flush let the mount fan-out leak past mockClear on slow CI).

Blazor removal (#91 phase b) remaining MUST-FIX gates, in order:

  1. #208 + #209 — shared "Add to collection/playlist/schedule" component: search-screen mutations + media browse/detail mutations, per-show scan wiring, episode info/troubleshoot entries ← NEXT (prompt below)
  2. #207 (+#212) — schedules editor full mutation depth (endpoints exist; needs languages enumeration endpoint shared with #212 channel-editor pickers)
  3. #202 — media-source management (write REST API + SPA screens; largest, riskiest)
  4. #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 (2026-07-09 gate session): Courier consumers are 100% Blazor (AddCourier Startup.cs:394 dies too); the Startup MapWhen "blazor" branch (736795) CO-HOSTS MapControllers/OpenAPI/Scalar — surgical removal only (MapBlazorHub:775, MapFallbackToPage:776, services 379398); wwwroot/lib/*+css/site.css are _Host-only; check Locals/*.resx consumers before deleting; keep Extensions/ except NavigationManagerExtensions.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_modules fresh (npm install after 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-mcp and 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_modules from 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.sh then npm 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.Apply collapses NotFoundError→422, so real 404s need a controller pre-check; id-taking child GETs get an OpenApiErrorResponseContractTests [TestCase].

PROMPT — #208 + #209: search + media mutation surface (shared "Add to…" component)

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.
  • PARALLELIZE BY DEFAULT: split the task into disjoint slices up front and run 34 implementer agents concurrently (recon agents are free — always fan those out). 34 concurrent dotnet/npm builds are fine on this Mac (M4, 10 cores, 16 GB); check uptime before a big fan-out — if 1-min load > ~6, drop to 23. Never 5+ builds (the historic crash was an 89-way fan-out). NEVER set ETV_UPDATE_GOLDENS.
  • Never two committing agents on ONE worktree — give each parallel slice its own worktree branched off the feature branch and merge back (worked well for #213 alongside #211). Sequence only where a slice genuinely depends on another's output (e.g. SPA needs the backend's regenerated OpenAPI types — consider stubbing types or splitting backend-first narrow, SPA-wide after).
  • 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 #208 + #209 gates

Read issues #208 and #209 (bodies carry exact file:line evidence from the #203 sweep).

  1. #208 search screen: the SPA search screen is display-only; Blazor's search page mutates (add result → collection/playlist/schedule). Build the shared "Add to collection/playlist/schedule" component ONCE (design for reuse by #209) and wire it into search results. Check the endpoint index first — several add-item endpoints already exist (collections add-items accepts all 10 kinds since PR #214).
  2. #209 media browse/detail: the same component on browse tiles + detail pages; per-show scan wiring (endpoint exists — check index); episode info + troubleshoot entry points (playback troubleshooting takes ?mediaItem={id}; MediaDetailScreen.tsx:524 carries a stale "#153/#155" pointer to fix). Decide component placement per spa-conventions (shared component location) and record any new convention in decisions.md. Full PR routine; update blazor-route-parity.md verdict rows (#208/#209 clusters), OpenAPI regen if any new endpoint. Comment + close #208/#209 per protocol.

On completion — REQUIRED last step

Update THIS handoff (pop the done items, promote #207+#212 to next with a fresh prompt), commit to main, print the next prompt in a fenced code block.


Issue queue (work top-down)

  1. #208 + #209 search + media mutation surface (shared "Add to…" component) ← PROMPT above.
  2. #207 (+#212) schedules editor depth + channel-editor gaps (shared languages endpoint).
  3. #202 media-source management (write API + SPA) — largest.
  4. #91 phase (b) Blazor removal PR (gate cleared once 13 close; #204/#205/#206 fold in; removal recon in session state above).
  5. #197 cold API contract+security review — HARD GATE on #58 close/go-live and MANDATORY before any remote exposure.
  6. Backlog: #215 (API playout mutations skip EntityLocker gating — from #214 review), #213 remainder (logs sort/page-size persistence, block-history page-size/gating, list filters), #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-test runs :latest) — local ffmpeg 8.1.2 lacks subtitles/zscale filters.