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>
11 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), 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→ generateddocs/endpoint-index.md, hooked intoscripts/update-openapi.sh(guarded on a successful spec build). - PR #187 → #184 CLOSED:
ApiControllerSecurityTestsnow ASSEMBLY-SCANS theErsatzTV.Controllers.Apinamespace (no hand-maintained registry;>=20min-count guard; intentionally NOT filtered onControllerBaseso non-ControllerBasecontrollers like the exemptScannerControllerstay in scope). Quick wins in the same PR: Trakt matched-items link → SPA/app/search;GET /api/searchparallelized (Task.WhenAll, eachForKindgets its ownTvContextviaIDbContextFactory); 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 — reusesPagedLibraryBrowseItemsResponseModel; the per-kind projection + rooted-artwork logic was extracted into a sharedErsatzTV.Application/LibraryBrowse/LibraryBrowseItemMapper.cs(browse handler unchanged). SPACollectionsScreennow lists real members (Load-more pager); honest-banner +getCollectionItemsPreviewremoved. POST-items 500 sub-item confirmed ALREADY fixed (fb3f2856ValidateMediaItems→ 422); not re-added. - PR #188 → #151/#152 STILL OPEN (backend only):
MultiCollectionController+RerunCollectionControllerCRUD over existing handlers + thinweb/src/api/{multiCollections, rerunCollections}.ts. Rerun request DTO takesCollectionType+SelectedIdand builds a minimal id-only VM (handlers read only.Id/.MediaItemId); a guard rejects unsupportedCollectionType(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
SelectedIdcan 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, andmain-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_modulesfrom a sibling worktree (cp -R) into NEW worktrees instead ofnpm 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.shwhich also regenerates endpoint-index.md, thennpm 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(overallstate+ per-context). PR runs skip the imagebuildjob (showsskipped);Build & test (.NET)+EF migration integrityare 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/PlaylistGroupResponseModelalready exist on main (partial #153 groundwork);PlaylistControlleris 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_modulesfrom 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) andErsatzTV/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:
PlaylistControlleris GET-only; response DTOs (PlaylistResponseModel,PlaylistGroupResponseModel) already exist on main. Needs playlist-group + playlist CRUD + item management (+ probably a preview endpoint viaPreviewPlayout), then a SPA editor (Blazor refsPlaylists.razorgroup 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
- Verify main green (post-#188) + confirm v26.6.0 image built (tags list / registry).
- #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.
- #153 playlists [M, API+SPA] — CRUD backend (copy CollectionController pattern; DTOs partly exist) + SPA editor; full routine; close #153.
- Optionally interleave #190 (CI NuGet cache) as a standalone S PR early.
- Do NOT start #145 late — own session.
- Consider filing the deferred rerun existence-check hardening issue while in #151/#152.
- Update THIS handoff, commit to main, print the next prompt in a fenced block.
Issue queue (work top-down)
- #151 + #152 SPA editors — multi/rerun collection editor screens (backend merged) [M, pair]
- #153 playlists/playlist-groups CRUD (API GET-only today) + SPA editor [M]
- #190 CI NuGet cache (+ Docker openapi-jar, shallow checkout) [S, standalone]
- #145 playback troubleshooting screen [L, OWN SESSION — the last phase-(b) functional gate]
- #91 phase (b): Step 1 redirect sweep [S, independent]; Steps 2–3 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.