# UI sweep coverage (plan ยง7.5) Gate: every line below executes for BOTH personas unless marked "admin-only". Status: โœ… swept+green ยท ๐Ÿ”ฒ pending (future sweep runs). | # | Page / control | admin | restricted | |---|---|---|---| | 1 | Login: bad password rejected; good login lands authed; logout | โœ… | โœ… | | 2 | Dashboard: sections render (Recently Added / Not Started) | โœ… | โœ… (hidden lib absent) | | 3 | Dashboard: hidden library visibility (Audiobooks) | โœ… visible | โœ… absent | | 4 | Search: results scoped (`/api/media-items/search`) | โœ… | โœ… no leaks | | 5 | Media list: no hidden items in payloads | โœ… | โœ… | | 6 | Library browse grid + pagination | ๐Ÿ”ฒ | ๐Ÿ”ฒ | | 7 | Library create / edit / delete (admin) | ๐Ÿ”ฒ | n/a | | 8 | Admin visibility toggle roundtrip (hide โ†’ restricted loses โ†’ unhide) | ๐Ÿ”ฒ | ๐Ÿ”ฒ | | 9 | Media detail: edit metadata / archive / delete | ๐Ÿ”ฒ | n/a | | 10 | Reader: open, page turn, TOC, bookmark, highlight, note, settings | ๐Ÿ”ฒ | ๐Ÿ”ฒ | | 11 | Collections: CRUD, add/remove items, smart-rule editor | ๐Ÿ”ฒ | ๐Ÿ”ฒ | | 12 | Series: list/detail | ๐Ÿ”ฒ | ๐Ÿ”ฒ | | 13 | Stats screens + range filters | ๐Ÿ”ฒ | ๐Ÿ”ฒ | | 14 | Admin: users CRUD, visibility matrix, settings toggles, processing issues | ๐Ÿ”ฒ | n/a | | 15 | Upload: EPUB generated at runtime, upload โ†’ appears โ†’ delete | ๐Ÿ”ฒ | n/a | | 16 | Auth edges: restricted โ†’ admin URL; anonymous โ†’ media URL | ๐Ÿ”ฒ | โœ… (detail/404) | | 17 | OPDS / KOReader | API-covered (invariant test) | API-covered | | 18 | Podcasts: page renders (empty state before any feed) | ๐Ÿ”ฒ | ๐Ÿ”ฒ | | 19 | Podcasts: add-feed modal โ†’ feed page (member flow) | ๐Ÿ”ฒ | ๐Ÿ”ฒ | | 20 | Podcasts: feed detail โ€” episode list lifecycle (download/queue/failed+retry states inline), Download All, gap banner | ๐Ÿ”ฒ | ๐Ÿ”ฒ | | 21 | Podcasts: cross-user invisibility โ€” own feed only (RLS ยง20 surfaces) | ๐Ÿ”ฒ | ๐Ÿ”ฒ | | 22 | Podcasts: order selector re-renders episode list; serial suggestion shown only for serial/audiobook feeds | ๐Ÿ”ฒ | ๐Ÿ”ฒ | | 23 | Podcasts: audio reader "Ep N/M" + prev/next episode; chain-advance to next episode | ๐Ÿ”ฒ | ๐Ÿ”ฒ | ### Podcast-specific sweep notes (plan task 1.10) - The download lifecycle needs a fetchable enclosure: sweep with a local feed server fixture (the integration tests use `swapFeedServer`; the Playwright run needs the same trick) โ€” otherwise episodes stay pending and rows 20's queue/failed states can't render. - Row 21 rides `TestPodcastRLSSurfaces` (API level) until the sweep lands; the page-level check is the 404 render for a foreign feed id. - Row 23 chains by page navigation โ€” assert the URL becomes the next episode's reader and progress carries over. ## 2026-10-30 โ€” round-3 regression probes (live-server, env-gated) Two specs added against a RUNNING dev server (skip unless `BH_FEED=` is set for the first): - `confirm_probe.spec.ts` โ€” every `hx-confirm` must open the GLOBAL confirm modal, never a native dialog. Pins the htmx-2 detail-shape fix (`detail.question`, not `detail.element`) and the modal's presence on signed-in pages (it used to live inside SidebarSignIn). - `add_order_probe.spec.ts` โ€” the add-modal "Download order" select reveals when "Download all episodes now" is checked (CSS sibling selector; the checkbox must stay a sibling of `.podcast-add-order`). ## 2026-10-30 โ€” episode collections (plan item 2.3) โ€” sweep candidates New controls the Playwright sweep should cover once it lands: - Collection picker modal: Books/Episodes tab pair โ€” episodes tab loads `?scope=episodes`, selection persists across tab switches and htmx swaps (shared bookPicker store). - Collection detail: episode rows (play link carries `?queue=collection:`; chain hops keep the param), "Not downloaded" badge, "Unavailable / Remove entry" hint row for collected-but-unsubscribed feeds (All Libraries view), header "Play as Sequence" button. - Player (collection mode): order dropdown + reverse button ABSENT (feed-mode only); "Ep N/M" reflects collection order; auto-advance follows the collection chain, and back-to-detail exits to the collection page. - API-level pins live in `TestPodcastEpisodeCollections` (7 subtests incl. the family-lens auditor case) + `TestPodcastPlayerOrderControl`. ## 2026-10-30 โ€” browser sweep executed (manual, OpenChamber panel) All controls above plus the item-3 builder/editor surfaces were driven in a real browser against the dev stack. Outcomes + reusable gotchas: - Fixed during the sweep: templ has no `continue` STATEMENT (codegen emits it as literal text โ€” the library switcher's podcast exclusion never worked); CSP attribute grammar (no backticks, no `?.`, no if-statements in Alpine attrs); rules editor double-encoded payloads; store hook must use the IMPORTED Alpine (window.Alpine?.store silently no-ops). Pins: TestLibrarySwitcherExcludesPodcasts, templates CSP source scan, TestPodcastEpisodeCollections/TestEpisodeCollectionsFilterTree. - Panel limitation for future automated specs: `selectOption`-equivalent via this panel sets the value WITHOUT a change event โ€” htmx change-triggers (player order dropdown, library switcher) must be driven with Playwright-native interactions, not value assignment. - Episode flows confirmed: picker Episodes tab โ†’ Add Selected โ†’ cards with queue=collection: play links โ†’ chain hops keep the param; order controls appear ONLY in feed mode (player + feed page share the persisted override).