SchedulesScreen loaded the rerun-collection picker with getRerunCollections({ pageNum: 0, pageSize: 1000 }). RerunCollectionController clamps pageSize to MaxPageSize = 100, so the request was always served 100 rows. Past 100 rerun collections the picker silently omitted the rest — no error, no truncation indicator, and a schedule item simply could not be pointed at a rerun collection that exists.
Replaced with loadAllRerunCollections(), which pages to completeness against totalCount at pageSize: 100, mirroring CollectionsScreen.enterReorder. The server cap is untouched: api.search-allitems-paging set the precedent that the client pages and the server stays bounded.
Done-when box 3 — the other loadPickerData fetches
Audited. getPlaylistGroups, getWatermarks, getGraphicsElements, getLanguages and getFillerPresetsByKind declare no paging parameters at all server-side and return plain arrays, so they are not truncatable and were left alone (a comment records why). This was confirmed twice independently — once against the controllers directly, and once against the full enumeration of paged /api/v1 operations built for #633.
But the class does not stop here. The cold review found, and grep confirmed, seven further call sites that ask for pageSize 500/1000 against endpoints capped at 100 — including RerunCollectionsScreen.tsx:136, which means this PR lets a schedule reference rerun collection #120 while the screen that creates and edits it still cannot show it. Deliberately not widened into this PR, whose test net is scoped to the schedules picker: filed as #644.
Verification
npx vitest run src/screens/SchedulesScreen.test.tsx → 27 passed; full web suite → 997 passed. tsc -b and eslint clean.
Mutation-verified: forcing the loop to stop after page 0 reddens the new test (expected 1 to be 2).
The new test pins the exact 150-element option set with toEqual and asserts exactly 2 requests — not a non-empty check, which cannot see items that are missing.
A latent trap this fixes on the way past
The existing #616 regression test looped over every rerun-collection request asserting pageNum === '0'. Correct when exactly one request was ever issued — but this branch makes the loader legitimately walk pages 1, 2, …, so that assertion now describes something the correct code does not do. It passed only because the shared fixture's totalCount fits in one page; raising that default would have failed the #616 test with a misleading "picker requested page 1" signal for what is proper paging. Narrowed to the first request, which is the offset #616 actually cared about.
The independent reviewer mutation-checked that narrowing rather than accepting it: reintroducing the exact #616 defect still fails the #616 test with the #616 message (and the #634 test too), and the rerunRequests[0] index fails cleanly via the preceding length assertion rather than throwing a TypeError.
Review
Independent cold review (process.independent-review-rubric: pure-SPA leaf, below every mandatory trigger, run anyway): MERGEABLE, twice — once on the implementation, then again on the fix commit at the current head. Two declined nits are recorded in the review thread: the concurrent-insert duplicate-row window (inherent to offset paging, identical in the mirrored precedent) and the seven sibling call sites (#644).
Docs
None required — no convention, route, endpoint or decision changed. The api.paging-zero-based contract this upholds is unchanged and is documented by #633.
fixes #634
## What
`SchedulesScreen` loaded the rerun-collection picker with `getRerunCollections({ pageNum: 0, pageSize: 1000 })`. `RerunCollectionController` clamps `pageSize` to `MaxPageSize = 100`, so the request was always served 100 rows. Past 100 rerun collections the picker silently omitted the rest — no error, no truncation indicator, and a schedule item simply could not be pointed at a rerun collection that exists.
Replaced with `loadAllRerunCollections()`, which pages to completeness against `totalCount` at `pageSize: 100`, mirroring `CollectionsScreen.enterReorder`. The server cap is untouched: `api.search-allitems-paging` set the precedent that the client pages and the server stays bounded.
## Done-when box 3 — the other `loadPickerData` fetches
Audited. `getPlaylistGroups`, `getWatermarks`, `getGraphicsElements`, `getLanguages` and `getFillerPresetsByKind` declare **no** paging parameters at all server-side and return plain arrays, so they are not truncatable and were left alone (a comment records why). This was confirmed twice independently — once against the controllers directly, and once against the full enumeration of paged `/api/v1` operations built for #633.
**But the class does not stop here.** The cold review found, and grep confirmed, **seven** further call sites that ask for `pageSize` 500/1000 against endpoints capped at 100 — including `RerunCollectionsScreen.tsx:136`, which means this PR lets a schedule *reference* rerun collection #120 while the screen that creates and edits it still cannot show it. Deliberately **not** widened into this PR, whose test net is scoped to the schedules picker: filed as **#644**.
## Verification
- `npx vitest run src/screens/SchedulesScreen.test.tsx` → 27 passed; full web suite → 997 passed. `tsc -b` and `eslint` clean.
- **Mutation-verified**: forcing the loop to stop after page 0 reddens the new test (`expected 1 to be 2`).
- The new test pins the **exact** 150-element option set with `toEqual` and asserts exactly 2 requests — not a non-empty check, which cannot see items that are missing.
## A latent trap this fixes on the way past
The existing #616 regression test looped over **every** rerun-collection request asserting `pageNum === '0'`. Correct when exactly one request was ever issued — but this branch makes the loader legitimately walk pages 1, 2, …, so that assertion now describes something the correct code does not do. It passed only because the shared fixture's `totalCount` fits in one page; raising that default would have failed the #616 test with a misleading "picker requested page 1" signal for what is proper paging. Narrowed to the first request, which is the offset #616 actually cared about.
The independent reviewer mutation-checked that narrowing rather than accepting it: reintroducing the exact #616 defect still fails the #616 test with the #616 message (and the #634 test too), and the `rerunRequests[0]` index fails cleanly via the preceding length assertion rather than throwing a `TypeError`.
## Review
Independent cold review (`process.independent-review-rubric`: pure-SPA leaf, below every mandatory trigger, run anyway): MERGEABLE, twice — once on the implementation, then again on the fix commit at the current head. Two declined nits are recorded in the review thread: the concurrent-insert duplicate-row window (inherent to offset paging, identical in the mirrored precedent) and the seven sibling call sites (#644).
## Docs
None required — no convention, route, endpoint or decision changed. The `api.paging-zero-based` contract this upholds is unchanged and is documented by #633.
SchedulesScreen loaded the rerun-collection picker with getRerunCollections({
pageNum: 0, pageSize: 1000 }). The server (RerunCollectionController) clamps
pageSize via Math.Clamp(pageSize, 1, MaxPageSize) with MaxPageSize=100, so
the request was silently served only the first 100 rows regardless of what
was asked for. With >100 rerun collections, the picker omitted the rest with
no error and no truncation indicator — a schedule item couldn't be pointed
at a rerun collection past the 100th.
Fix: page the client to completeness against totalCount, mirroring
CollectionsScreen.enterReorder (fetch page 0, keep requesting subsequent
pages while accumulated < totalCount, break early if a page returns zero
rows to guard against a non-terminating loop on a server-side anomaly).
Per api.search-allitems-paging precedent, the client pages rather than
raising the server's MaxPageSize cap.
Audited the other loadPickerData fetches (getPlaylistGroups, getWatermarks,
getGraphicsElements, getLanguages, getFillerPresetsByKind): their endpoints
return a plain, unpaged array server-side with no pageNum/pageSize params
and no clamp, so they aren't subject to the same silent-truncation defect
and don't need the same treatment.
Adds a vitest case pinning the exact expected option set (150 rerun
collections across two pages) rather than a non-empty/truthy check.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The #616 comment this call site carried recorded WHY it reads `pageNum: 0` — a
previous version passed 1 and skipped the whole first page. Rewriting the call for
#634 dropped it. Restore it next to the new paging loop, which also starts its
follow-up requests at 1 and is only correct because the first page is 0.
Cold review finding. The #616 regression test looped over EVERY rerun-collection
request asserting pageNum === '0'. That was right when exactly one request was ever
issued, but since this branch the loader legitimately walks pageNum 1, 2, … to page to
completeness — so the assertion now describes something the correct code does not do.
It passes today only because the shared fixture's totalCount fits in a single page.
Raising that default would have failed the #616 test with a "picker requested page 1"
signal for what is proper paging, sending the next reader after a defect that isn't
there. Narrow it to the first request, which is the offset #616 actually cared about.
Also corrects the new comment's history: the `pageNum: 1` it describes is pre-#616,
not the previous commit.
Independent cold review, twice: implementation (MERGEABLE) then the fix commit at this head (MERGEABLE, no findings at any severity). Reviewer mutation-verified the narrowed #616 guard itself. Two nits declined with reasons; the sibling truncation class filed as #644.
Review-verdict: MERGEABLE @ f9380eb
Independent cold review, twice: implementation (MERGEABLE) then the fix commit at this head (MERGEABLE, no findings at any severity). Reviewer mutation-verified the narrowed #616 guard itself. Two nits declined with reasons; the sibling truncation class filed as #644.
timothy
merged commit 5f3623b321 into main2026-07-26 12:20:28 +02:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
fixes #634
What
SchedulesScreenloaded the rerun-collection picker withgetRerunCollections({ pageNum: 0, pageSize: 1000 }).RerunCollectionControllerclampspageSizetoMaxPageSize = 100, so the request was always served 100 rows. Past 100 rerun collections the picker silently omitted the rest — no error, no truncation indicator, and a schedule item simply could not be pointed at a rerun collection that exists.Replaced with
loadAllRerunCollections(), which pages to completeness againsttotalCountatpageSize: 100, mirroringCollectionsScreen.enterReorder. The server cap is untouched:api.search-allitems-pagingset the precedent that the client pages and the server stays bounded.Done-when box 3 — the other
loadPickerDatafetchesAudited.
getPlaylistGroups,getWatermarks,getGraphicsElements,getLanguagesandgetFillerPresetsByKinddeclare no paging parameters at all server-side and return plain arrays, so they are not truncatable and were left alone (a comment records why). This was confirmed twice independently — once against the controllers directly, and once against the full enumeration of paged/api/v1operations built for #633.But the class does not stop here. The cold review found, and grep confirmed, seven further call sites that ask for
pageSize500/1000 against endpoints capped at 100 — includingRerunCollectionsScreen.tsx:136, which means this PR lets a schedule reference rerun collection #120 while the screen that creates and edits it still cannot show it. Deliberately not widened into this PR, whose test net is scoped to the schedules picker: filed as #644.Verification
npx vitest run src/screens/SchedulesScreen.test.tsx→ 27 passed; full web suite → 997 passed.tsc -bandeslintclean.expected 1 to be 2).toEqualand asserts exactly 2 requests — not a non-empty check, which cannot see items that are missing.A latent trap this fixes on the way past
The existing #616 regression test looped over every rerun-collection request asserting
pageNum === '0'. Correct when exactly one request was ever issued — but this branch makes the loader legitimately walk pages 1, 2, …, so that assertion now describes something the correct code does not do. It passed only because the shared fixture'stotalCountfits in one page; raising that default would have failed the #616 test with a misleading "picker requested page 1" signal for what is proper paging. Narrowed to the first request, which is the offset #616 actually cared about.The independent reviewer mutation-checked that narrowing rather than accepting it: reintroducing the exact #616 defect still fails the #616 test with the #616 message (and the #634 test too), and the
rerunRequests[0]index fails cleanly via the preceding length assertion rather than throwing aTypeError.Review
Independent cold review (
process.independent-review-rubric: pure-SPA leaf, below every mandatory trigger, run anyway): MERGEABLE, twice — once on the implementation, then again on the fix commit at the current head. Two declined nits are recorded in the review thread: the concurrent-insert duplicate-row window (inherent to offset paging, identical in the mirrored precedent) and the seven sibling call sites (#644).Docs
None required — no convention, route, endpoint or decision changed. The
api.paging-zero-basedcontract this upholds is unchanged and is documented by #633.SchedulesScreen loaded the rerun-collection picker with getRerunCollections({ pageNum: 0, pageSize: 1000 }). The server (RerunCollectionController) clamps pageSize via Math.Clamp(pageSize, 1, MaxPageSize) with MaxPageSize=100, so the request was silently served only the first 100 rows regardless of what was asked for. With >100 rerun collections, the picker omitted the rest with no error and no truncation indicator — a schedule item couldn't be pointed at a rerun collection past the 100th. Fix: page the client to completeness against totalCount, mirroring CollectionsScreen.enterReorder (fetch page 0, keep requesting subsequent pages while accumulated < totalCount, break early if a page returns zero rows to guard against a non-terminating loop on a server-side anomaly). Per api.search-allitems-paging precedent, the client pages rather than raising the server's MaxPageSize cap. Audited the other loadPickerData fetches (getPlaylistGroups, getWatermarks, getGraphicsElements, getLanguages, getFillerPresetsByKind): their endpoints return a plain, unpaged array server-side with no pageNum/pageSize params and no clamp, so they aren't subject to the same silent-truncation defect and don't need the same treatment. Adds a vitest case pinning the exact expected option set (150 rerun collections across two pages) rather than a non-empty/truthy check. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>Review-verdict: MERGEABLE @
f9380ebIndependent cold review, twice: implementation (MERGEABLE) then the fix commit at this head (MERGEABLE, no findings at any severity). Reviewer mutation-verified the narrowed #616 guard itself. Two nits declined with reasons; the sibling truncation class filed as #644.