From c57fbf982645c859ca6300dbd7da2a8dc1f62c1d Mon Sep 17 00:00:00 2001 From: Timothy Date: Sat, 18 Jul 2026 13:40:20 +0200 Subject: [PATCH] docs(293): note the pageNum upper clamp (MaxAllItemsPageNum) in the decision + api-conventions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- docs/api-conventions.md | 5 +++-- docs/decisions.md | 9 ++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/docs/api-conventions.md b/docs/api-conventions.md index 1635b1c59..6cc198d29 100644 --- a/docs/api-conventions.md +++ b/docs/api-conventions.md @@ -367,8 +367,9 @@ enum fields) as `List`. 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 1–1000 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 1–1000 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 diff --git a/docs/decisions.md b/docs/decisions.md index 368af4dde..962dbbd9f 100644 --- a/docs/decisions.md +++ b/docs/decisions.md @@ -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