Files
ersatztv/docs/handoffs/chicorytv-issue-queue.md
T
timothyandClaude Opus 4.8 d20b240a1a
Build ErsatzTV Image / Build & test (.NET) (push) Successful in 4m9s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (push) Successful in 6m21s
Build ErsatzTV Image / Build & push image (amd64) (push) Successful in 3m51s
docs: advance ChicoryTV handoff past the collections/API-gap + v26.6.0 release session
Merged #186(#185)/#187(#184)/#189(#155)/#188(#151-152 backend); tagged v26.6.0.
Next: #151/#152 SPA editors → #153 playlists → #145. Filed #190 (CI cache).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 19:11:48 +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), parity pass 2 (#140/#142/#143/#146/#147), the FULL scheduling parity #144/#162 (PRs #170#175/#179), the media/troubleshooting parity #141/#161 + #158 + #180 (PRs #181/#182/#183), onboarding docs (part 1 PR #~183-era, part 2 #185 PR #186), and the collections/API-gap batch #155/#151/#152-backend + #184 quick wins (PRs #187/#189/#188) are MERGED. v26.5.0 in prod; v26.6.0 TAGGED 2026-07-08 (first release carrying the full SPA-parity feature set — awaiting the Komodo pin bump 26.5.0→26.6.0 in server-management). Blazor removal (#91 phase b) is now gated ONLY on: #151/#152 SPA editors (backend APIs done), #153 (playlists CRUD+editor), and #145 (playback troubleshooting).

Session state (2026-07-08, collections/API-gap + release session): main = 1c035cc9 + this docs commit. Merged FOUR PRs (all fork-reviewed + CI-green before merge):

  • PR #186 → #185 CLOSED: onboarding docs part 2 — docs/testing.md (authoritative testing map; contributing.md §8 shrunk to a pointer) + scripts/generate-endpoint-index.py → generated docs/endpoint-index.md, hooked into scripts/update-openapi.sh (guarded on a successful spec build).
  • PR #187 → #184 CLOSED: ApiControllerSecurityTests now ASSEMBLY-SCANS the ErsatzTV.Controllers.Api namespace (no hand-maintained registry; >=20 min-count guard; intentionally NOT filtered on ControllerBase so non-ControllerBase controllers like the exempt ScannerController stay in scope). Quick wins in the same PR: Trakt matched-items link → SPA /app/search; GET /api/search parallelized (Task.WhenAll, each ForKind gets its own TvContext via IDbContextFactory); dead "New Group" header buttons removed.
  • PR #189 → #155 CLOSED: GET /api/collections/{id}/items (paged) returns a manual collection's FULL contents across all kinds — reuses PagedLibraryBrowseItemsResponseModel; the per-kind projection + rooted-artwork logic was extracted into a shared ErsatzTV.Application/LibraryBrowse/LibraryBrowseItemMapper.cs (browse handler unchanged). SPA CollectionsScreen now lists real members (Load-more pager); honest-banner + getCollectionItemsPreview removed. POST-items 500 sub-item confirmed ALREADY fixed (fb3f2856 ValidateMediaItems → 422); not re-added.
  • PR #188 → #151/#152 STILL OPEN (backend only): MultiCollectionController + RerunCollectionController CRUD over existing handlers + thin web/src/api/{multiCollections, rerunCollections}.ts. Rerun request DTO takes CollectionType+SelectedId and builds a minimal id-only VM (handlers read only .Id/.MediaItemId); a guard rejects unsupported CollectionType (Playlist/RerunFirstRun/RerunRerun/SearchQuery/Fake*) with 422 (IsSupportedSelectionType). SPA editor screens are the remaining work → keep #151/#152 open.
  • New issues: #190 (CI speed — cache NuGet packages + Docker/checkout wins, S). Deferred review nit (NOT yet filed): rerun create/update doesn't existence-check the selected id (a bad SelectedId can dangling-FK-row or 500 on SaveChanges) — file a small hardening issue when touching #151/#152 SPA work; consistent with api-conventions §3 deep-FK precedent.
  • Tests on main: ErsatzTV.Tests ~870, web 330 (40 files), Core.Tests 493(+1 skip), Architecture 5 — all green. main CI (test+migrations+image) green at 1c035cc9.
  • Worktrees to remove (all merged): .worktrees/feat-185, feat-quickwins, feat-collections, feat-multirerun, and main-handoff (after this doc commit).

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 instead of re-explaining. Only recon what the docs don't cover.
  • The main checkout (/Users/timothy/ersatztv) sits on a STALE branch. NEVER recon/edit there — worktrees off origin/main only; copy web/node_modules from a sibling worktree (cp -R) into NEW worktrees instead of npm ci (faster). Docs-only worktrees need none.
  • Subagent connection drops = the laptop went to sleep, NOT a turn-length problem. The agent's context AND on-disk work survive. Re-resume with SendMessage ("you dropped when the laptop slept; git status shows X on disk; continue from step N"). Multiple resumes are fine. This session lost zero work across ~5 drops.
  • 3 build slots authorized (user, 2026-07-08): up to 3 concurrent dotnet builds machine-wide is fine now (was 1). Still don't do 5+/wide fan-outs.
  • Scope review-fork prompts to "review only; do not answer unrelated questions". A user question injected into the session context once derailed a review fork into answering it (zero review done). State the task is the only job.
  • PR routine (works): worktree → implement (opus agent for judgment-heavy code, sonnet for mechanical; give doc pointers + exact facts) → merge origin/main into branch before PR (v1.json/endpoint-index/blazor-route-parity conflicts → resolve route-parity by hand, REGENERATE v1.json authoritatively via ./scripts/update-openapi.sh which also regenerates endpoint-index.md, then npm run generate:api; full test pass; a sonnet reconcile agent handles this well) → push, PR → fork adversarial review (+ sonnet live-E2E for UI-visible changes) → CI green → merge (session pre-approval: user OK'd auto-merge on CI-green + review-clean this session; RE-ASK each new session) → structured close comments per the CLAUDE.md protocol. Apply review should-fixes as a follow-up COMMIT (not amend+force — auto-mode blocks the force-push).
  • Gitea 1.24: no rerun-run API — retrigger CI with an empty commit; poll by commit: /api/v1/repos/timothy/ersatztv/commits/{sha}/status (overall state + per-context). PR runs skip the image build job (shows skipped); Build & test (.NET) + EF migration integrity are the gating checks. Tag push (v*) builds :prod+:<version>+:<sha>.
  • Live E2E: scripts/e2e-local.sh (see docs/e2e-local.md) — single port 8409 for UI+API; mutating verbs need no API key locally; Playwright MCP screenshots land in cwd (tolerated).
  • Reusable API facts (from PR #188/#189): collection-item listings → reuse PagedLibraryBrowseItemsResponseModel + LibraryBrowseItemMapper.HydrateMediaItemsByIds; MediaItem ids are globally unique across kinds. multi/rerun/playlist Application handlers ALL exist — API work is controller+DTO+tests only. PlaylistResponseModel/ PlaylistGroupResponseModel already exist on main (partial #153 groundwork); PlaylistController is GET-only today.

PROMPT — #151/#152 SPA editors, then #153 playlists (API+SPA), toward #91 phase (b)

You are Fable, the ORCHESTRATOR in the main Claude Code session (Claude Code only). Fable is EXPENSIVE: delegate (recon → Explore/haiku; mechanical/reconciles → sonnet; judgment-heavy code → opus; fable forks for review). FIRST read CLAUDE.md, docs/README.md and the convention docs it indexes, and the Lessons above.

HARD CONSTRAINTS:

  • Work in worktrees off origin/main; NEVER touch /Users/timothy/ersatztv (stale branch). Copy web/node_modules from a sibling worktree into NEW web worktrees.
  • Up to 3 concurrent builds OK; never 5+/wide fan-outs. NEVER set ETV_UPDATE_GOLDENS.
  • Subagent drops = laptop sleep; re-resume via SendMessage (work survives).
  • Merge consent in-conversation per session (last session's pre-approval does NOT carry over). CI reruns = empty commit. Apply review should-fixes as a follow-up commit (no force-push).
  • Live-E2E new screens via scripts/e2e-local.sh (docs/e2e-local.md).
  • Adversarial review fork over each PR diff before merge; SCOPE it to "review only".
  • Any PR that changes a convention/route/decision updates the relevant doc in the SAME PR (esp. docs/blazor-route-parity.md rows).

Known facts (2026-07-08 — re-verify cheaply)

  • main = 1c035cc9 + the handoff doc commit; all green. v26.6.0 tagged (deploy = user bumps Komodo pin in server-management).
  • #151/#152 backend APIs are LIVE (/api/multi-collections, /api/rerun-collections, thin api-clients in web/src/api/). The remaining work is the SPA EDITOR SCREENS. Blazor refs: ErsatzTV/Pages/MultiCollectionEditor.razor (Name + dual add-pickers over collections / smart-collections + per-item ScheduleAsGroup/PlaybackOrder) and ErsatzTV/Pages/RerunCollectionEditor.razor (CollectionType select → conditional single autocomplete over collections/multi/smart/shows/seasons/artists + first-run/rerun PlaybackOrders; note the API rejects Playlist/internal types). Mirror the existing SPA collections editors (web/src/screens/CollectionsScreen.tsx + smart-collection editor) for the three-touch-point pattern (ScreenId union / ScreenRoute / mediaNavIds).
  • #153 playlists: PlaylistController is GET-only; response DTOs (PlaylistResponseModel, PlaylistGroupResponseModel) already exist on main. Needs playlist-group + playlist CRUD + item management (+ probably a preview endpoint via PreviewPlayout), then a SPA editor (Blazor refs Playlists.razor group tree + PlaylistEditor.razor). [M — API+SPA]
  • #145 playback troubleshooting = the last functional gate. L, OWN SESSION, do NOT start late.
  • #190 CI NuGet cache = independent S quick win (changes CI itself → its own PR, watch it land).

Task

  1. Verify main green (post-#188) + confirm v26.6.0 image built (tags list / registry).
  2. #151/#152 SPA editors [M, mirror pair] — build the multi/rerun collection editor screens on the merged APIs; live-E2E via e2e-local.sh; full PR routine; update docs/blazor-route-parity.md rows to "SPA DONE"; CLOSE #151/#152 per protocol.
  3. #153 playlists [M, API+SPA] — CRUD backend (copy CollectionController pattern; DTOs partly exist) + SPA editor; full routine; close #153.
  4. Optionally interleave #190 (CI NuGet cache) as a standalone S PR early.
  5. Do NOT start #145 late — own session.
  6. Consider filing the deferred rerun existence-check hardening issue while in #151/#152.
  7. Update THIS handoff, commit to main, print the next prompt in a fenced block.

Issue queue (work top-down)

  1. #151 + #152 SPA editors — multi/rerun collection editor screens (backend merged) [M, pair]
  2. #153 playlists/playlist-groups CRUD (API GET-only today) + SPA editor [M]
  3. #190 CI NuGet cache (+ Docker openapi-jar, shallow checkout) [S, standalone]
  4. #145 playback troubleshooting screen [L, OWN SESSION — the last phase-(b) functional gate]
  5. #91 phase (b): Step 1 redirect sweep [S, independent]; Steps 23 Blazor deletion + verification [M-L, own session, after #151/#152/#153/#145 close] Backlog (non-blocking): rerun-create existence-check hardening (file it), #172 API hardening, #163 playout goldens, #164 health UX, #176 PseudoTV-style creation (post-phase-b), #177/#178 Jellyfin, #66 artwork sniffing.