fix(boundary): detect item-type arrays anywhere in src/ (DR-094)
check:boundary passed on the very leak it was written for. The pattern was anchored to `includeItemTypes:` at the query site, so searchScope.ts assigning the same array to a named const and dereferencing it one indirection away was invisible — through every green CI run. The check now matches an array literal naming two or more Jellyfin item types anywhere in src/, catching a const, a Record value, a function return, and an inline query alike. Deliberate limits kept: two adjacent literals required (single-type presentation stays legal), string literals required (item.type === "Audio" is display logic), explicit type list (so ["High","Low"] produces no noise). Verified all five cases: reintroducing the original SCOPE_ITEM_TYPES fails; a new const ["Movie","Series"] fails; the same array in a .test.ts passes; itemType: "Movie" / item.type === / ["High","Low"] pass; a 5th allowlist entry fails on the new cap. Allowlist 1→3 entries, capped at 4 so the next exception forces a conversation rather than a one-line append: - GenericMediaListPage: grid styling over a self-declared itemType — presentation, changes only with a UI redesign. - DownloadedBrowse: borderline, leans domain (the container set grows when Jellyfin adds a container type). Allowlisted with a TODO for a backend MediaItem.isContainer flag. The header now names what the check still cannot see — run-time-built sets, types split across variables, switch/|| taxonomy — and CLAUDE.md states that a green check:boundary is not proof. That matters given this check passed on its own founding violation for months. Also: both gates wired into test-all.sh, which called `bun run test` without --run and would have hung in watch mode. Corrected the Dockerfile comment describing the Windows toolchain as mingw/GNU — it is MSVC via cargo-xwin (GNU cannot bundle NSIS from Linux).
This commit is contained in:
@@ -220,7 +220,7 @@ Internal architecture, components, and application logic.
|
||||
| DR-060 | Multi-server store and active-account selection: save/get/delete server, save/get user, set/get active user (per-server), active-session resolution | Storage | UR-047 | Partial (store done; server-switcher UI pending) |
|
||||
| DR-061 | Episode Focus View: episode hero followed *immediately* by the "More Episodes" strip — a forward-biased window (~3 before / ~6 after) around the current episode, spanning season boundaries in series order, with the current episode present and badged, per-card resume progress and watched state, and click-to-swap focus (no playback) | UI | UR-048 | Done |
|
||||
| DR-062 | Detail-page section ordering: continuation content precedes discovery content — Episode Focus View renders hero → episode strip → cast → similar; Series renders hero → seasons/episodes → cast → similar | UI | UR-048 | Done |
|
||||
| DR-063 | Search scope resolver mapping the originating route to an `includeItemTypes` set (All / Music / Movies / TV), defaulting to All for Home, `/library`, and the search tab | UI | UR-049 | Implemented |
|
||||
| DR-063 | Search scope taxonomy owned by Rust: `SearchScope` (All / Music / Movies / TV) crosses IPC as an opaque enum and `SearchScope::item_types()` expands it to Jellyfin item types, resolved once in `repository_search` before the cache and server paths diverge so online and offline filter identically; `All` expands to *no* filter rather than the union of the other scopes (which would drop People and folders). The frontend maps the originating route to a scope (`resolveSearchScope`, presentation) and never names an item type for search | Backend | UR-049 | Implemented |
|
||||
| DR-064 | Scope chip row rendered under the search bar on both the search page and the in-library header search: preselected from context, horizontally scrollable, re-runs the search preserving the query on change | UI | UR-049 | Implemented |
|
||||
| DR-065 | Thread `SearchOptions.includeItemTypes` through `library.search()` so the global/header search honours scope (backend online + offline paths already support it) | UI | UR-049 | Implemented |
|
||||
| DR-066 | Persisted search result group order with a drag-and-drop settings list, keyboard-accessible reordering, a shipped default (see DR-091 for the current group set and order), and empty-group omission | Settings | UR-050 | Implemented |
|
||||
@@ -247,6 +247,8 @@ Internal architecture, components, and application logic.
|
||||
| DR-090 | Relevance ranking in Rust (`domain/search_rank.rs`): results sort by match position (prefix → word-start → mid-word substring → no name match) then by media kind (containers before their contents), stably so the backend's own relevance breaks ties. Applied in `repository_search` to both the instant cache result and the merged cache+server union, so the list does not reshuffle when server results land | Backend | UR-060 | Done |
|
||||
| DR-091 | Search result groups split TV into separate Shows and Episodes groups and add a People group (default order: Shows → Episodes → Movies → Songs → Albums → Artists → People); a stored `tvShows` order from before the split expands in place to shows+episodes so an upgrading user keeps their arrangement | UI | UR-060 | Done |
|
||||
| DR-092 | Video tap gestures resolve in `tapGestures.ts` (pure, unit-tested) rather than inline in `VideoPlayer.svelte`: `registerTap` returns `pending` for a first tap — the component defers `togglePlayPause` behind a `DOUBLE_TAP_WINDOW_MS` (300 ms) timer that a second tap cancels — or `seek` (+30 s right / −10 s left) for a second tap inside the window; a consumed second tap resets the state so a third tap starts fresh, and a swipe cancels the pending tap. The compatibility `click` the browser synthesizes after a touch tap is filtered in `handleVideoClick` so it cannot bypass the deferral. `resolveSeekTarget` converts the delta to the absolute position the facade requires, clamped to `[0, duration]` and chained off a still-in-flight `pendingSeekTarget` so back-to-back skips accumulate instead of all resolving against a not-yet-updated position | UI | UR-061 | Done |
|
||||
| DR-094 | Frontend boundary tripwire (`scripts/check-frontend-boundary.sh`) detects Jellyfin item-type array literals **anywhere** in `src/` rather than only inline at an `includeItemTypes:` query site, so a category→type mapping cannot evade the check by being assigned to a named const (the evasion that let the `scoped-search` leak pass CI); requires two adjacent type literals so single-type presentation and `item.type ===` inspection stay legal, and caps the allowlist to force taxonomy into Rust instead of accumulating exceptions | Tooling | - | Done |
|
||||
| DR-093 | Traceability coverage gate derives its requirement denominators from `requirements.md` at run time rather than hardcoded literals: `countDefinedRequirements` counts an ID only where it leads a markdown table row (ignoring the "Traces To" column and prose) and deduplicates IDs listed both in the definition tables and in the §3 traceability matrix; `computeCoverage` reports the *intersection* of traced and defined IDs so an ID traced in code but absent from `requirements.md` is surfaced as `orphaned` instead of inflating the ratio past 100%. UT/IT test identifiers are excluded as a separate taxonomy. CI and `bun run traces:coverage` share this computation and fail on both a sub-threshold and an impossible >100% result | Tooling | - | Done |
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user