docs(293): note the pageNum upper clamp (MaxAllItemsPageNum) in the decision + api-conventions
Build ErsatzTV Image / CI image pin matches docker/ci (pull_request) Successful in 5s
Build ErsatzTV Image / Docs update reminder (pull_request) Successful in 5s
Build ErsatzTV Image / decisions.md append-only (pull_request) Successful in 6s
Build ErsatzTV Image / Functional E2E (curl contracts) (pull_request) Successful in 14m16s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 19m30s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 18m32s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (pull_request) Successful in 12m24s
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (pull_request) Successful in 13m20s

Fix delta re-review flagged the decision entry + §5 note still described the
pre-fix pageNum = Math.Max(0, pageNum); the shipped code clamps the upper bound
too (0..2_000_000) to stop pageNum*pageSize overflowing int to a 500.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-18 13:40:20 +02:00
co-authored by Claude Opus 4.8
parent ac7965dee4
commit c57fbf9826
2 changed files with 9 additions and 5 deletions
+3 -2
View File
@@ -367,8 +367,9 @@ enum fields) as `List<SearchFieldResponseModel>`. Drives the SmartCollection rul
introspectable by MCP; no query parameters.
**Param + DTO expansion (#293, cap `search/all-items`)**: no new endpoint — `GET /api/v1/search/all-items`
gained two **optional** query params (`pageNum` 0-based, `pageSize` default 500, clamped 11000 via the §1
Logs `Math.Clamp` precedent) so a broad query can't materialize the whole index in one response, and one
gained two **optional** query params (`pageSize` default 500, clamped 11000 via the §1 Logs `Math.Clamp`
precedent; `pageNum` 0-based, clamped `0..2_000_000` so `pageNum * pageSize` can't overflow `int` to a 500)
so a broad query can't materialize the whole index in one response, and one
**additive** response field, `Totals` (`SearchResultAllItemsTotalsResponseModel`, ten per-kind `…Count`
ints), so a client can page to completeness. The clamp is per media kind, so one response is bounded to
≤ 10 × `pageSize` ids. The SPA add-all flow (`getAllSearchItemIds` in `web/src/api/search.ts`) pages until
+6 -3
View File
@@ -1783,9 +1783,12 @@ page to completeness** — rather than option (b) (a generous cap + truncation s
`GET /api/v1/channels/auto-tune/members` (#384) paging convention already in the codebase.
- **Endpoint (additive).** `SearchAllItems` gains optional `pageNum` (0-based) + `pageSize`, clamped exactly
like the §1 Logs / sibling `Search` precedent: `pageNum = Math.Max(0, pageNum)`,
`pageSize = Math.Clamp(pageSize, 1, MaxAllItemsPageSize)` with `MaxAllItemsPageSize = 1000`,
`DefaultAllItemsPageSize = 500`. The clamp is applied per media kind (a page returns ≤ `pageSize` ids of
like the §1 Logs / sibling `Search` precedent: `pageSize = Math.Clamp(pageSize, 1, MaxAllItemsPageSize)`
with `MaxAllItemsPageSize = 1000`, `DefaultAllItemsPageSize = 500`. `pageNum` is clamped
`Math.Clamp(pageNum, 0, MaxAllItemsPageNum)` with `MaxAllItemsPageNum = 2_000_000` — the upper bound keeps
`pageNum * pageSize` (the search skip) inside `int` range so an absurd page number can't overflow to a 500
(the sibling `Search` only floors at 0; the all-items endpoint hardens the upper bound too since this is a
DoS-hardening change). The clamp is applied per media kind (a page returns ≤ `pageSize` ids of
*each* of the ten kinds), so one response is bounded to ≤ 10 × `pageSize` ids. `QuerySearchIndexAllItems`
carries `PageNum`/`PageSize`; the handler passes `skip = PageNum × PageSize`, `limit = PageSize` into
`ISearchIndex.Search` (native skip/limit) and reads `SearchResult.TotalCount` (the true total, free) per