Files
ersatztv/docs/handoffs/chicorytv-issue-queue.md
T
timothyandClaude Fable 5 22fa3ecb08
Build ErsatzTV Image / Build & test (.NET) (push) Successful in 4m33s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (push) Successful in 4m55s
Build ErsatzTV Image / Build & push image (amd64) (push) Failing after 43s
docs: advance ChicoryTV queue past parity #140/#146/#147 (PRs #150/#154/#156); gaps #151-#153/#155 filed; next prompt = parity #141-#145
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 12:57:51 +02:00

9.2 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) and the cutover root-flip (#91 phase a) are MERGED. v26.5.0 tagged + DEPLOYED to prod 2026-07-07. Blazor removal (#91 phase b) is blocked on parity issues; #140/#146/#147 closed this pass, #141–#145 remain.

Session state (2026-07-07, post parity kickoff): main = d58deddc. This session merged:

  • #147 → PR #150 (39455a96): "Classic UI" link in Settings → System About card (plain <a href="/system/health">) + "Opens in ChicoryTV" MudTooltip cue on exactly the 11 redirecting Blazor sidebar links (from LegacyUiRedirects.Map). Removal markers for #91 phase (b): grep "Classic UI" (SPA) + ersatztv#147 (MainLayout.razor @code).
  • #146 → PR #154 (1f3385a2): dedicated ChannelEditScreen at /app/edit-channel/{id} (allowSubPaths + keyed render), hydrate-then-PUT on GET/PUT /api/channels/{id}, full ChannelEditor.razor field parity. Builder hydration rejected (scope comment on issue). /channels/numbers drag-reorder DEFERRED — existing Renumber toolbar accepted as parity.
  • #140 → PR #156 (5995707c): CollectionsScreen (web/src/screens/) + web/src/api/collections.ts — manual collections CRUD + UseCustomPlaybackOrder + items add(picker)/remove; smart collections CRUD with live browse preview. getCollections/getSmartCollections moved out of schedules.ts.
  • Gap issues FILED: #151 (multi-collections API), #152 (rerun collections API), #153 (playlists API), #155 (no GET for a manual collection's items + POST /items 500s on unknown media id). #151–#153+#155 now ALSO gate full Blazor parity → #91 phase (b).
  • All three PRs: adversarial fork review (SHIP) + CI green before merge; #146/#140 live-E2E'd against a real server. Worktrees parity-147/146/140 removed. Main post-merge CI green.

Lessons for all remaining prompts (accumulated):

  • The main checkout (/Users/timothy/ersatztv) sits on the STALE docs/59-ui-redesign-brief branch. NEVER recon/edit there — point subagents at a worktree pinned to origin/main.
  • Gitea 1.24 has no rerun-run API; retrigger CI with an empty commit. Concurrent migration jobs collide on host port 3306 until #149 lands.
  • GET /api/collections returns ONLY manual collections — GetAllCollectionsHandler queries the Collection table and the mapper hardcodes CollectionType.Collection. No read-only fallback for multi/rerun/playlist types (that's why #151–#153 exist).
  • GET /api/library/browse search hits are restricted to Movie/Show/Season/Artist (MediaTypesFor) — episode/song/MV/image/other/remote-stream items are NOT enumerable via search; matters for #141 (media browse) and any picker UI. For those four kinds, browse id == mediaItemId (verified in GetLibraryBrowseItemsHandler).
  • SPA screen pattern for sub-path routes: route entry with allowSubPaths + screen parses window.location.pathname itself + popstate listener + key={window.location.pathname} on the render branch (SettingsScreen, ChannelEditScreen precedents).
  • New extracted screens go in web/src/screens/ (keep App.tsx footprint to import + one ScreenContent branch); screen tests mock fetch by URL path (App.test.tsx pattern), API client tests follow channelTemplates.test.ts (assert exact URLs + full toEqual bodies).
  • Backend quirk: isEnabled=false && showInEpg=true 422s on PUT /api/channels/{id} (and the handler silently stores isEnabled && showInEpg) — UI must gate the EPG switch.
  • DTO records in ErsatzTV.Core/Api MUST get file-scoped #nullable enable (else OpenAPI emits ["null","string"]). ErsatzTV.Application has NO nullable context — string? trips CS8632.
  • NSubstitute + ConfigElementKey: stub with Arg.Any<ConfigElementKey>() + generic <T>.
  • Option<T>.ToNullable() doesn't exist; use MatchUnsafe(v => (T?)v, () => null).
  • ./scripts/update-openapi.sh needs a prior normal dotnet build ErsatzTV/ErsatzTV.csproj.
  • Id-taking child-collection GETs 404 on unknown parent via pre-check + ApiResults + an OpenApiErrorResponseContractTests [TestCase] entry.
  • Backlog nits: pageSize unclamped on paged endpoints; artwork content-type trusted (#66); GET /api/guide 21-include eager-load per channel per request; fillerKind almost always None in JSON guide; UpdateChannelHandler.cs:144–151 dead null-clear (pre-existing); ExternalLogoUrl missing from ChannelViewModel/UpdateChannelRequest (Blazor-only field); languages-list endpoint still unimplemented (free-text language codes in SPA); #156 review nits: Lucene name-quote lacks \ escaping, picker silently caps at 50 (totalCount unused), delete dialog doesn't clear stale dialogError, one toMatchObject.

PROMPT — Parity continuation: #145 logs/troubleshooting → #143 ffmpeg/filler/watermarks → #142 trakt → #141 media browse → #144 scheduling blocks

You are Fable, the ORCHESTRATOR in the main Claude Code session (Claude Code only). Fable is EXPENSIVE: delegate (recon → Explore/haiku; mechanical → sonnet; judgment-heavy code → opus; fable forks for review). Read CLAUDE.md + the Lessons above first.

HARD CONSTRAINTS:

  • Work in worktrees off origin/main; NEVER touch /Users/timothy/ersatztv (stale branch). cd web && npm ci in any NEW worktree.
  • Max 2–3 concurrent builds; ONE dotnet build at a time. NEVER set ETV_UPDATE_GOLDENS.
  • Merge consent in-conversation per PR (user may pre-approve). CI reruns = empty commit.
  • Live-E2E new screens per the #93 recipe (curl localhost, NOT 127.0.0.1 — host guard; wait for "Done migrating search index").
  • Adversarial review fork over each PR diff before asking merge consent; apply should-fixes.

Known facts (2026-07-07; RECON EACH ISSUE before implementing — unlike the last pass,

API coverage for these screens is largely UNKNOWN and gaps must be filed as issues first)

  • #145 logs & troubleshooting (/system/logs, /system/troubleshooting/*): likely NO log/ troubleshooting API endpoints — check Controllers/Api. If absent, file gap issue(s) and decide whether backend work fits in-session or gets queued.
  • #143 ffmpeg profiles / filler presets / watermarks editors: read endpoints exist (GET /api/ffmpeg/profiles(+/{id}), resolution by-name; filler/watermark LISTS exist — DB order, client-sort). Editor CRUD (POST/PUT/DELETE) coverage unknown — recon.
  • #142 trakt lists (/media/trakt/lists): API coverage unknown; Trakt auth/device flows live in Blazor dialogs — recon both the API and how the flow maps to the SPA.
  • #141 media browse/search/trash (/media/movies|tv|music|other, /search, trash): remember the library/browse 4-kind search restriction (Lessons) — full media browse likely needs new/wider endpoints; #155's items-GET may share design. Biggest recon surface.
  • #144 scheduling blocks (blocks/decos/templates + playout detail editors): biggest build; recon which of blocks/decos/templates/playout-detail have API CRUD.
  • Suggested order: #145 → #143 → #142 → #141 → #144 (small→large; re-order after recon if gaps invert the sizes). It is FINE for a session to output "gap issues filed + what was buildable now" — parity needs the API gaps surfaced early anyway.

Task

  1. RECON [Explore agents, parallel, read-only, worktree off origin/main]: per issue above, map Blazor pages → required operations → existing API endpoints → gaps. Product per issue: buildable-now scope + gap list.
  2. File API gap issues (pattern: #151–#153/#155 — reference #91 phase b + epic #59).
  3. Implement buildable-now scope per issue (sonnet for small screens, opus for big ones), one worktree per issue, tests + live E2E, PR, fork review, CI, consent, merge — in the suggested order. Stop when the session runs long; leave clean state.
  4. Update THIS handoff: merged PRs + main SHA, pop done items, next prompt = whatever remains (#141–#145 leftovers, then #91 phase b readiness check: #151–#153/#155 gate it too now). Commit to main. Print the next prompt in a fenced block.

Issue queue (work top-down)

  1. #145 logs & troubleshooting (likely smallest; API recon first) ← PROMPT above
  2. #143 ffmpeg profiles / filler presets / watermarks editors
  3. #142 trakt lists
  4. #141 media browsing, search & trash (big; shares design with #155 items-GET)
  5. #144 scheduling building blocks + playout detail editors (biggest)
  6. API gaps gating #91b: #151 multi-collections, #152 rerun collections, #153 playlists, #155 collection items GET (+ POST /items 500 fix) — slot into sessions as backend work.
  7. #91 phase (b): remove Blazor once #141–#145 + #151–#153/#155 close; also remove the #147 Classic-UI link + ersatztv#147 cue then.
  8. MCP PR #76 (#58): refresh tool catalog against the full API surface, review, merge.
  9. #149 CI flake (migrations job host-port collision) — small, slot into any session. Cross-refs: #99 (TS/HLS-Direct sessions) stays backlog. Done this pass: #147 (PR #150), #146 (PR #154), #140 (PR #156); gap issues #151/#152/#153/#155 filed; prod remains v26.5.0 (next release = tag + bump Komodo pin per CLAUDE.md Deployment).