Repository navigation
Description
projector: parseLimit still reinterprets non-decimal spellings — limit=1e2, 0x10, 5.0, +5, 5 are honoured as numbers instead of falling back to the default
Evidence (verified this run, main 9b689eb5)
pm-stack/projector/src/server.ts:50-56 — the fix for #1547:
export function parseLimit(raw: string | null, defaultLimit: number, maxLimit: number): number {
if (raw === null) return defaultLimit;
const n = Number(raw);
if (!Number.isInteger(n) || n < 1) return defaultLimit;
return Math.min(n, maxLimit);
}Its own doc comment (:42-49) says "Only a positive integer is honoured" and that negative/fractional/non-numeric values fall back to the endpoint default. But the check is on the Number()-coerced value, not the spelling, so any spelling Number() coerces to an integer passes:
Probe (laptop, ~/git/fleet/probe-2026-10-31-laneB-projector/, real parseLimit imported from the md5-matched server.ts of main 9b689eb5, defaults 200/1000):
| raw | result | expected per the #1547 contract |
|---|---|---|
"1e3" |
1000 | default 200 (scientific spelling) |
"1e2" |
100 (same mechanism) | default 200 |
"0x10" |
16 | default 200 (hex spelling) |
"5.0" |
5 | default 200 (fractional spelling — 2.7 falls back, 5.0 does not) |
"+5" |
5 | default 200 |
" 5" |
5 | default 200 |
"5" |
5 | 5 (control, honoured) |
"2.7", "abc" |
200 | 200 (controls, fall back) |
Used by both read endpoints: /items (server.ts:139) and /comments (server.ts:148). The existing test matrix (pm-stack/projector/test/limit.test.ts) covers -1, 0, 2.7, abc, "", NaN, Infinity — none of the coercible spellings above.
Why it matters
This is the exact reinterpretation class the repo keeps removing site by site (#2789/#2791/#2743 for measurement parsers, #832 for world seeds, the digits-only rule in bin/proxy-port.mjs): a client that sends limit=0x10 or limit=1e2 gets a silently different page size than the API contract states, and 5.0 vs 2.7 behaving differently is an inconsistency inside the fix's own test matrix. The bound itself still holds (results are clamped), so this is correctness/contract drift, not an unbounded-read hole — priority/low.
Acceptance criteria
-
parseLimithonours only a plain decimal positive-integer spelling (digits only, e.g./^[0-9]+$/after the absent-parameter check);1e2,1e3,0x10,5.0,+5, leading/trailing-whitespace, and empty spellings fall back to the endpoint default. - Well-formed values behave exactly as today: honoured exactly, over-max clamped to the per-endpoint maximum, absent parameter keeps the default.
-
test/limit.test.tsgains the coercible-spelling matrix above for both endpoints' defaults/maxima; existing projector: read-API limit is never validated — ?limit=-1 returns the whole table and ?limit=2.7 500s the request #1547 tests pass unchanged. - No change to the endpoints, defaults (items 200/1000, comments 500/1000), or the store layer.
Activity
dezren39 commentedon Oct 31, 2026
🤖 Agent note · filed
dezren39 commentedon Oct 31, 2026
🤖 Agent note · done (triage)
pm-stack/projector/src/server.tsparseLimit(L50–56) isconst n = Number(raw); if (!Number.isInteger(n) || n < 1) return defaultLimit; return Math.min(n, maxLimit)— soNumber("1e2")=100,Number("0x10")=16,Number("5.0")=5,Number("+5")=5, andNumber(" 5")=5all pass the integer gate and are honoured/clamped instead of falling back to the default. Both call sites verified:/items(L139, default 200 / max 1000) and/comments(L148, default 500 / max 1000).test/limit.test.tscovers the projector: read-API limit is never validated — ?limit=-1 returns the whole table and ?limit=2.7 500s the request #1547 negative/fractional/non-numeric/zero cases but has no coercible-spelling cases./^[0-9]+$/spellings (parse digits, ≥1, clamp to max as today); absent parameter still defaults; every other spelling falls back to the endpoint default. Fix packet requires the coercible-spelling matrix (1e2,0x10,5.0,+5,5,5) intest/limit.test.tsfor both endpoints, existing projector: read-API limit is never validated — ?limit=-1 returns the whole table and ?limit=2.7 500s the request #1547 tests unchanged. No endpoint/default/store changes.repo-health:v1:fix:developing-today/code:issue:2971). Issue stays open for the fix.33 remaining items
dezren39 commentedon Oct 31, 2026
agent-note:v1
event: parked
task: 4275
pr: #3077
note: Parked 20m awaiting the Codex review just requested. No CI runs exist for pm-stack paths (check-runs API verified); laptop suite on PR head 132543d: 44 pass / 0 fail. Resume condition: Codex clean -> merge -> close.
dezren39 commentedon Oct 31, 2026
🤖 Agent note · picked up
Merge pull request #3077 from developing-today/queue/4275-2971-projec…
dezren39 commentedon Oct 31, 2026
🤖 Agent note · done