Skip to content

projector: parseLimit still reinterprets non-decimal spellings — limit=1e2 / 0x10 / 5.0 / +5 are honoured instead of falling back to the default (#1547 residual) #2971

Closed

Description

@dezren39

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

  • parseLimit honours 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.ts gains 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

  1. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    priority/lowNice to have; do when convenient
    queue/queuedHas a queued task in the Supabase agent queue
    source/creatorFiled by the new-issue-creator job
    task/triageQueue packet kind: verify, reproduce, and route this item
    app/pm-stackpm-stack (Pad/Grist) in developing-today/code
    effort/xsTrivial: expected under 30 minutes of work
    on Oct 31, 2026
  2. dezren39 commented on Oct 31, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

    • Agent: new-issue-creator (lane B, new-issue-creator-code-b)
    • Session / ID: new-issue-creator-code-b run 2026-10-31T06:50Z (America/Chicago scheduled run)
    • Found via: filed this run
    • Task: Triage the parseLimit non-decimal spelling reinterpretation (projector read API, projector: read-API limit is never validated — ?limit=-1 returns the whole table and ?limit=2.7 500s the request #1547 residual) and route the strict-spelling fix
    • Expectation: effort/xs — done looks like: only plain decimal spellings honoured, coercible spellings fall back to the endpoint default, limit.test.ts gains the spelling matrix
    • Links: probe on laptop ~/git/fleet/probe-2026-10-31-laneB-projector/ (real parseLimit, md5-matched main 9b689eb)
  3. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Oct 31, 2026
  4. dezren39 commented on Oct 31, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done (triage)

  5. 33 remaining items

  6. added
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    status/parkedDeliberately paused with a recorded resume condition
    and removed
    queue/claimedQueue worker lifecycle state
    on Oct 31, 2026
  7. dezren39 commented on Oct 31, 2026

    @dezren39
    MemberAuthor

    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.

  8. added
    queue/claimedQueue worker lifecycle state
    and removed
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    on Oct 31, 2026
  9. dezren39 commented on Oct 31, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  10. added a commit that references this issue on Oct 31, 2026
  11. dezren39 commented on Oct 31, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done

    • Agent: queue worker (repo-worker-code), lane C shift
    • Session / ID: queue task 4275
    • Found via: queue claim (resume)
    • Task: PR 3077 merged — merge commit 7946d8f. Codex review clean on head 132543d (no findings, all rounds dispositioned); no CI runs exist for pm-stack paths (only CodeRabbit neutral); laptop verification on the merged head: projector suite 44 pass / 0 fail, limit.test.ts 13/13. Issue closed by the merge. Task completed as fixed_merged.
    • Expectation: done — no follow-up.
    • Links: PR fix(projector): parseLimit honours only decimal-digit spellings (#2971) #3077
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

app/pm-stackpm-stack (Pad/Grist) in developing-today/codeeffort/xsTrivial: expected under 30 minutes of workkind/bugSomething isn't working (prefixed form of the classic bug label)priority/lowNice to have; do when convenientsource/creatorFiled by the new-issue-creator jobtask/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions