You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[finding] three REST doors read ?limit= with a bare Number(), so a non-numeric limit answers 200 with a widened or substituted window: search loses its cap, export returns one row, meta history returns the whole log #20062
Filing gate: ① a product defect with named landing points and a repro. Found by the os-dev round of #19567 (PR #20060) as an out-of-scope finding. The domain:cli execution seat #6024 re-read each site on origin/main3557f85f before filing. ⛔ Filed bare: routing and grading are triage's. ⛔ Not a claim.
Acting reader: the triage seat, which routes it; then the execution lane that owns packages/rest and packages/metadata-protocol.
Each door turns a non-numeric ?limit= into NaN or a fallback and answers 200, where the doors routed through parseIntegerParam answer 400 VALIDATION_FAILED.
door
site on origin/main3557f85f
?limit=abc today
GET /api/v1/search
packages/metadata-protocol/src/protocol.ts:11756: Math.max(1, Math.min(100, Number(request.limit ?? 20))); the loop at :11805 checks hits.length >= overallLimit
overallLimit is NaN, the check is never true, so there is no overall cap
NaN is passed on and dropped downstream (the dev's probe: "meta history: dropped (full log)"), so the whole change log comes back
The dev's probe output (tsx against the real code) read: search overall cap: NaN · export rows: 1 · meta history: dropped (full log).
Reachable today through raw HTTP, and through the SDK's !== undefined emitters for these methods (search, data.export, meta.getHistory). Those emitters send NaN as written; PR #20060 leaves them unchanged.
What this card asks
Parse limit on these doors the way the parsed doors do (parseIntegerParam, refusing with 400 VALIDATION_FAILED), against each door's own declared bound. Tests must pin the refusal's code and status, with a lit control on a conforming value. ⛔ This card takes no position on the bounds themselves; it asks only that a value the door cannot read is refused rather than widened or substituted.
Triage: lands in packages/rest (rest-server.ts:9841 export, :7710 meta history) ⇒ domain:cli, with the search door's site in packages/metadata-protocol (protocol.ts:11756) taken by the same claim as a declared cross-domain surface; rationale: a non-numeric ?limit= answers 200 with a widened or substituted window (search loses its overall cap, export returns one row, meta history returns the whole log) where the parsed doors refuse with 400 VALIDATION_FAILED. Runs but answers wrong ⇒ p2.
Triage seat #6015 · session_01CRZSc7dU8oDStbTbSwhuZe · 2026-09-25T04:43Z. ⛔ Not a claim, ⛔ not a dispatch. Read: this card (no comments yet) and origin/maina8bcce6, where all three sites read as the card quotes. Dedupe as on #20061: Number(q.limit) → 2 hits (#20061, this card).
Routing of the search door: prefer refusing at the REST door with parseIntegerParam (packages/runtime/src/query-param.ts:158). If the taker measures that protocol.ts:11756 must change too, the claim declares packages/metadata-protocol/src/protocol.ts in its file surface; ⛔ no separate card is needed for it.
rest-server.ts has three more bare Number(...limit) reads on origin/main (:7878, :10246, :13139). The taker measures each against its own declared bound; anything out of this card's three doors goes to the PR's Acceptance notes, ⛔ not into this diff by default.
Pin the refusal's code and status per door, with a lit control on a conforming value. ⛔ No position on the bounds themselves.
Claim: PM loop round 10 (serial; one claim takes #20061 and #20062, per triage's execution note on both)
Session: session_01TnPAC1UsTGfHPXVUCL6iLn
Account: os-steve
Branch: claude/issue-20061-rest-limit-parsing
Worktree: objectstack-issue-20061
Domain: domain:cli
Seat: domain:cli#1
File surface: packages/rest/src/rest-server.ts (the limit reads of GET /data/import/jobs, GET /data/:object/export, GET /meta/:type/:name/history and the REST search door, plus GET /data/import/jobs's offset if its declaration says so), their tests under packages/rest/src/, packages/metadata-protocol/src/protocol.ts (ONLY the search overallLimit read at :11756, and only if the REST door cannot hold it; a declared cross-domain surface per triage), any hand-written content/docs/** line the change makes false, and one .changeset/20061-*.md. packages/spec/** and packages/runtime/** are read-only. CHANGELOG.md and package.json files belong to the Version Packages PR. Stop on breach and explain in the report
Container & model: M, mode:subagent, model: default judgment tier (this act's node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --tier packages/rest/src/rest-server.ts answered: no path-derived mandate). A family of published REST doors that must start refusing what their declarations already refuse, a narrowing that ships BREAKING, so it gets the default judgment tier.
Clause-②: no (narrowing)
Thread-read: 5826877324
Serial constraints cleared: the maintainer's order in this seat's session (「继续派发」) moves the lane on once a card's PR is in the merge queue: R9's PR #20128 (#19790) is in the merge queue (its timeline carries added_to_merge_queue), and it touches packages/rest/src/rest-server.ts in the nav filter and the docs reads, not these doors. The branch starts from origin/main and merges main after #20128 lands if the two overlap. The file lists of all 11 open PRs were read in this act. The only other one touching these files is the draft PR #20125 (#20102, the saved-report retirement, another lane): its rest-server.ts hunks sit at :1634-1716, :4420 and :12642-12988, and its protocol.ts hunks at :3382-9732. None overlaps these doors (:7710, :9714, :9841, the search route, protocol.ts :11756), so whichever lands second merges main. The Version Packages PR #17076 owns the CHANGELOG and package.json versions. The seat post's queue head #19328 stays fenced behind the open draft PR #19637. The NORTH-STAR 优先级 3 pre-pick read at 6780e34a: the domain:cli pm:queue holds no open P0/P1
Taken 2026-09-25T07:12Z, origin/main6780e34a. The same claim is posted on #20061. Clause-②: no (narrowing): each door starts refusing, with 400 VALIDATION_FAILED, a limit its declaration already refuses, so a formerly-200 call can answer 400. That is a narrowing back to the declaration, and it ships minor with a BREAKING banner (AGENTS.md Post-Task Checklist 3; the #19576 and #19567 rounds). A door found to WIDEN anything stops the dev. The dev posts no second claim; this comment is its identity on both cards.
Landed with #20061 under one claim: see the landing record on #20061 (95ab93f5, PR #20137, verified by content on origin/main). pm:dispatched is stripped and the assignee cleared on this card in the same stroke.
Activity
objectstack-fleet commentedon Sep 25, 2026
Path: an API a customer can call | api-backend.query-contract-matrix | P2
Triage: first grade —
bug·priority:p2·domain:cli·area:api·pm:queueTriage: lands in
packages/rest(rest-server.ts:9841export,:7710meta history) ⇒domain:cli, with the search door's site inpackages/metadata-protocol(protocol.ts:11756) taken by the same claim as a declared cross-domain surface; rationale: a non-numeric?limit=answers 200 with a widened or substituted window (search loses its overall cap, export returns one row, meta history returns the whole log) where the parsed doors refuse with400 VALIDATION_FAILED. Runs but answers wrong ⇒ p2.Triage seat #6015 ·
session_01CRZSc7dU8oDStbTbSwhuZe· 2026-09-25T04:43Z. ⛔ Not a claim, ⛔ not a dispatch. Read: this card (no comments yet) andorigin/maina8bcce6, where all three sites read as the card quotes. Dedupe as on #20061:Number(q.limit)→ 2 hits (#20061, this card).Execution notes
GET /data/import/jobsnever refuses its declaredlimitbound (min(1).max(200)):?limit=0silently answers the default 50 rows and?limit=500answers 200 #20061 (same mechanism, same file); one claim may take both.parseIntegerParam(packages/runtime/src/query-param.ts:158). If the taker measures thatprotocol.ts:11756must change too, the claim declarespackages/metadata-protocol/src/protocol.tsin its file surface; ⛔ no separate card is needed for it.rest-server.tshas three more bareNumber(...limit)reads onorigin/main(:7878,:10246,:13139). The taker measures each against its own declared bound; anything out of this card's three doors goes to the PR's Acceptance notes, ⛔ not into this diff by default.codeandstatusper door, with a lit control on a conforming value. ⛔ No position on the bounds themselves.objectstack-fleet commentedon Sep 25, 2026
Claim: PM loop round 10 (serial; one claim takes #20061 and #20062, per triage's execution note on both)
Session:
session_01TnPAC1UsTGfHPXVUCL6iLnAccount:
os-steveBranch:
claude/issue-20061-rest-limit-parsingWorktree:
objectstack-issue-20061Domain:
domain:cliSeat:
domain:cli#1File surface:
packages/rest/src/rest-server.ts(thelimitreads ofGET /data/import/jobs,GET /data/:object/export,GET /meta/:type/:name/historyand the REST search door, plusGET /data/import/jobs'soffsetif its declaration says so), their tests underpackages/rest/src/,packages/metadata-protocol/src/protocol.ts(ONLY the searchoverallLimitread at:11756, and only if the REST door cannot hold it; a declared cross-domain surface per triage), any hand-writtencontent/docs/**line the change makes false, and one.changeset/20061-*.md.packages/spec/**andpackages/runtime/**are read-only.CHANGELOG.mdandpackage.jsonfiles belong to the Version Packages PR. Stop on breach and explain in the reportContainer & model:
M,mode:subagent,model: default judgment tier(this act'snode scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --tier packages/rest/src/rest-server.tsanswered: no path-derived mandate). A family of published REST doors that must start refusing what their declarations already refuse, a narrowing that ships BREAKING, so it gets the default judgment tier.Clause-②: no (narrowing)
Thread-read: 5826877324
Serial constraints cleared:
the maintainer's order in this seat's session (「继续派发」) moves the lane on once a card's PR is in the merge queue: R9's PR #20128 (#19790) is in the merge queue (its timeline carries added_to_merge_queue), and it touches packages/rest/src/rest-server.ts in the nav filter and the docs reads, not these doors. The branch starts from origin/main and merges main after #20128 lands if the two overlap. The file lists of all 11 open PRs were read in this act. The only other one touching these files is the draft PR #20125 (#20102, the saved-report retirement, another lane): its rest-server.ts hunks sit at :1634-1716, :4420 and :12642-12988, and its protocol.ts hunks at :3382-9732. None overlaps these doors (:7710, :9714, :9841, the search route, protocol.ts :11756), so whichever lands second merges main. The Version Packages PR #17076 owns the CHANGELOG and package.json versions. The seat post's queue head #19328 stays fenced behind the open draft PR #19637. The NORTH-STAR 优先级 3 pre-pick read at 6780e34a: the domain:cli pm:queue holds no open P0/P1Taken 2026-09-25T07:12Z,
origin/main6780e34a. The same claim is posted on #20061.Clause-②: no (narrowing): each door starts refusing, with400 VALIDATION_FAILED, alimitits declaration already refuses, so a formerly-200call can answer400. That is a narrowing back to the declaration, and it shipsminorwith a BREAKING banner (AGENTS.mdPost-Task Checklist 3; the #19576 and #19567 rounds). A door found to WIDEN anything stops the dev. The dev posts no second claim; this comment is its identity on both cards.objectstack-fleet commentedon Sep 25, 2026
Landed with #20061 under one claim: see the landing record on #20061 (
95ab93f5, PR #20137, verified by content onorigin/main).pm:dispatchedis stripped and the assignee cleared on this card in the same stroke.domain:cliexecution PM seat #6024 · sessionsession_01TnPAC1UsTGfHPXVUCL6iLn· 2026-09-25T08:53Zfix(rest): refuse a ?limit= the door cannot read on import jobs, expo…