Repository navigation
Description
Filing gate: ① a defect with named landing sites and a measured repro. Finding class (b). This is a class-closure card: the family's first members were #20061 and #20062, closed by PR #20137, and this is the family's second occurrence, so under the fold rule (#20110) it gets ONE card covering every remaining site, with an enumeration pin.
Found by the os-dev round on #20061/#20062 (PR #20137) and filed by the domain:cli execution seat (#6024, session_01TnPAC1UsTGfHPXVUCL6iLn). ⛔ Filed bare: routing and grading belong to triage. ⛔ Not a claim.
The family
A published REST door reads a numeric query parameter with a bare Number(). A value the door cannot read becomes NaN, 0 or a fallback, and the door answers 200 with a widened or substituted window. It should refuse with 400 VALIDATION_FAILED, the way the doors PR #20137 fixed now do through its private reader readDeclaredQueryNumber.
Measured members
Reach: real RestServer routes with a spy protocol on origin/main 6780e34a. Each answered 200; line numbers are at PR #20137's head 74898ed5.
| door | parameter | site | today |
|---|---|---|---|
GET /meta/:type/:name/history |
?sinceSeq=abc |
rest-server.ts:8139 |
dropped; the log is read from the start |
GET /meta/:type/:name/audit |
?limit=abc |
rest-server.ts:8318 |
dropped; the producer default 100 is served |
GET /search |
?perObject=abc |
rest-server.ts:10709 |
NaN is handed to searchAll |
The declarations exist for the first two: HistoryMetaItemRequestSchema.sinceSeq and AuditMetaItemRequestSchema.limit are both z.number(), which refuses NaN. perObject has no declared schema.
Read-only members (not driven; include them in the census, measure them in the round)
GET /data/approvals/requestslimit/offset(rest-server.ts:13601): a non-numeric value is dropped and the unpaged list is served.- export
?page=(:10297): falls back to the 500-row chunk. This is chunking only.
What closes the class
- Every member reads through
readDeclaredQueryNumber(the reader PR fix(rest): refuse a ?limit= the door cannot read on import jobs, export, meta history and search (#20061, #20062) #20137 added), against its own declaration where one exists, else as a whole number. - An enumeration pin: a census test that finds every
Number(read of a request query value inpackages/rest/src/rest-server.tsand fails on any not routed through the reader, or through a ledgered exemption with a reason. The family then cannot reopen one site at a time. - The same test style PR fix(rest): refuse a ?limit= the door cannot read on import jobs, export, meta history and search (#20061, #20062) #20137 uses:
400 VALIDATION_FAILED,fields[0].field/.code, the service never called, and a lit control per door.
⛔ No position on the bounds themselves. HistoryMetaItemRequestSchema.limit admitting 1.5 / 0 / negatives is the spec seat's question, noted in PR #20137's Acceptance notes.
Related
The field code a numeric query failure carries is invalid_type through rest's ADR-0114 D3 mapper, but invalid_number through runtime's parseIntegerParam. That was answered for #20061/#20062 as keep invalid_type. Converging them, if ever wanted, belongs to the spec seat's D3 mapping, not to this card.
Dedupe: MCP issue search in this repository (REST query parameter bare Number sinceSeq history audit limit perObject NaN dropped class closure): 0 hits. Dedupe words: sinceSeq NaN dropped history · audit limit abc dropped · perObject NaN searchAll · bare Number query param rest-server
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/src/rest-server.ts(/history ?sinceSeq:8139,/audit ?limit:8318,/search ?perObject:10709, plus the read-only members) ⇒domain:cli; rationale: the class-closure card for the bare-Number()family whose first members (#20061, #20062) PR #20137 closed; one card, one census pin, under the closure rule (#20088). Runs but answers wrong ⇒ p2, as its members.Triage seat #6015 ·
session_01CRZSc7dU8oDStbTbSwhuZe· 2026-09-25T10:09Z. ⛔ Not a claim, ⛔ not a dispatch. Read: this card and its full thread, andorigin/main.Execution note: every member reads through PR #20137's
readDeclaredQueryNumberagainst its own declaration; the census test fails on anyNumber(read of a request query value not routed through the reader or a ledgered exemption. ⛔ No position on the bounds.objectstack-fleet commentedon Sep 27, 2026
Claim: PM loop round 3, fifteenth slot (batch 3; the
rest-server.tsfence holds no live work: PR #20337 (#20290) is complete and parked for a maintainer decision on its own card; beside #20215 on a disjoint surface)Session:
session_01UYBdGBzWSrAMzpW8ah3GbPAccount:
os-litantBranch:
claude/issue-20139-rest-query-number-censusWorktree:
objectstack-issue-20139Domain:
domain:cliSeat:
domain:cli#1File surface:
packages/rest/src/rest-server.ts, only these sites (measured ona78f731ad):/history?sinceSeqread (about :7489);/audit?limitread (about :7681);?page=chunk read (about :9816);/search?perObjectread (about :10228);?limit/?offsetreads (about :12780-:12781);readDeclaredQueryNumber(about :736), only if a member needs it widened;404 [no_draft](about :7754), which becomes404NO_DRAFT;rest-server.tsand outside both fences:/diffdoor'sfrom/to(andfromVersion/toVersion) reads, a family member the census found one frame fromreq.query;UNDECLARED_ROW_COUNT_PARAM→UNDECLARED_WHOLE_NUMBER_PARAMrename and its docblock;readDeclaredQueryNumber's docblock (the body is unchanged);AuditMetaItemRequestSchemaimport;packages/rest/src/, plus per-door tests there;.changeset/20139-*.md.⛔ Not the plain read's
?state=draftbranch (about :6921-:6946) or theSTORED_VERSION_DOOR_POLICYdocblock (about :3463-:3467): PR #20337 holds both. ⛔ Not theGET /meta/:typelist handler: #20320 waits on it.packages/spec/**is read-only. Stop on breach and explain in the reportContainer & model:
M,mode:subagent,model: default tier.Clause-②: no
Thread-read: 5830651452
Serial constraints cleared:
The file lists of all 14 open PRs were read in this act. Only PR #20337 (#20290) touches rest-server.ts, in two hunks: the docblock at about :3463 and the plain-read draft branch at about :6921-:6946. That PR is complete, contract-reviewed PASS (5860832731) and parked on a needs-user-decision (5860841580). This card's sites are all outside those hunks, and the later lander merges main. #20320 (p3) waits behind this card: its list-projection move would re-home query reads this card's census scans (serial note 5860608324). Fold-or-serial with #20290 is SERIAL, because fold gate ① fails. R3's other in-flight slot is #20215 (packages/cli), which is disjointTaken 2026-09-27T23:33Z,
origin/maina78f731ad.Clause-②: no: doors that answered 200 on an unreadable value now refuse, which narrows an accept set, so the claim line readsno. The changeset carriesClause-②: no (narrowing)+minor+ BREAKING + the ADR-0087 marker, in the family precedent's form (.changeset/20061-rest-limit-parsing.md, PR #20137).Generated by Claude Code
test(rest): pin the remaining numeric query reads' refusals (red on b…
objectstack-fleet commentedon Sep 28, 2026
os-dev-report
{
"issue": 20139,
"status": "done",
"branch": "claude/issue-20139-rest-query-number-census",
"pr": "#20345",
"session": "session_01UYBdGBzWSrAMzpW8ah3GbP — this run's harness-stamped Claude-Session id (the claim of record names the same)",
"premise_still_valid": true,
"summary": "Every remaining numeric query read in packages/rest/src/rest-server.ts now goes through readDeclaredQueryNumber and refuses an unreadable value with 400 VALIDATION_FAILED + fields[] (service never called), where it used to drop it or hand on NaN and answer 200: /history ?sinceSeq and /audit ?limit against HistoryMetaItemRequestSchema.sinceSeq / AuditMetaItemRequestSchema.limit, and /search ?perObject, /approvals/requests ?limit/?offset and /diff ?from/?to (plus fromVersion/toVersion) as whole numbers. The census (rest-server-query-number-census.test.ts) classifies EVERY numeric coercion in the file via the TS AST (Number/parseInt/parseFloat called, new-ed or passed as a value, unary +) as reader / not-a-query-value / exempt, and it found one member the card did not list — /diff read Number(raw) inside a local parseV helper, one frame from req.query — so it counts every coercion rather than query-looking ones; export ?page= (chunk size only: streamed rows byte-identical for every page value, unreadable = absent) and rollback toVersion (already refused 400 INVALID_REQUEST before the verb) are the two ledgered, pinned exemptions. The approvals door's catch answers every throw 500, so its reads sit in a scoped try handed to handleRouteError; the publish route comment now names 404
NO_DRAFT. Zone-2 measured: all five listed doors red on a78f731 (30/30 refusal rows 200); no hunk in either PR #20337 fence or the GET /meta/:type list handler (no numeric query read lives there); worktree and node_modules removed after the PR opened.","tests": "Red first, on the unfixed source (pins committed alone as 54658aa over a78f731): rest-server-query-number-reads.test.ts → Tests 30 failed | 25 passed (55), every failure 'expected a 400 refusal … got 200'; a throwaway spy probe (deleted, never committed) recorded what each service received (e.g. search perObject NaN, approvals limit dropped → unpaged no total, diff from=abc&to=3 → only toVersion 3). Fix at HEAD d07bbaa (fix 5ef104d + merge of origin/main d3958ba, no rebase, no conflict): family files 112 passed (reads 55 + census 14 + precedent 43); full rest suite
pnpm --filter @objectstack/rest exec vitest run --project local --maxWorkers=2→ Test Files 206 passed (206), Tests 3747 passed | 2 skipped (3749); test:repo → 8 passed; typecheck exit 0 with check:test-typecheck OK 0 file(s) / 0 error(s). Ablations, fix committed first, each through scripts/ablation-replace.mjs WRAP mode (EXIT/INT/TERM restore), on-disk marker count proven before the run, no dist involved (relative src import; census reads the file): (A) search perObject back to bare Number(req.query.perObject): anchor 1→0, marker 1, blob 9505bebc→0b580156 → Tests 5 failed | 64 passed = the 4 perObject refusal rows + census naming rest-server.ts:10283 GET ${basePath}/search » Number(req.query.perObject); (A′) /diff back to parseV: blob→85ca1f0e → 10 failed | 59 passed = 9 diff refusal rows + census naming GET ${metaPath}/:type/:name/diff » Number(raw); (B) new const extra = Number(req.query.extra): blob→1d6d2ea5 → 1 failed | 68 passed = the census alone. Every restore: blob 9505bebc == HEAD, git diff HEAD empty, marker 0. B's FIRST attempt was a no-op (replacement contained its anchor; tool refused 1→1 and restored, no test ran) — re-anchored on a comment line and re-run. Gates: dispatch-gates --commands from merge base d3958ba → 62; --ran → 62 derived, 60 run, 2 NOT-MEASURED, 0 UNRUN. NOT MEASURED: check:dual-build-cjs-loads and check:type-check-debt (exit 3, PREREQUISITE NOT MET — 43 packages without dist); declared narrowing: rest dist built (check-dts-emitted 2/2), require(dist/index.cjs).RestServer and import('@objectstack/rest').RestServer both function; diff moves no export. pnpm lint full union at d07bbaa exit 0 (119s). Board check --base origin/main exit 0 (13 citations resolve).","mcp_calls": "0 — no MCP GitHub tool called; reads went through single-card REST GETs (card #20139 + comments, PR #20137 + files, #20061/#20062 threads for the report form, the PR lookup/read-back of #20345)",
"api_writes": "3 — REST proxy writes, each a POST /repos/objectstack-ai/objectstack/dispatches to the fleet-write relay, executed as objectstack-fleet[bot]: (1) pr_create → POST /repos/objectstack-ai/objectstack/pulls (draft #20345, body read back byte-identical, 18531 bytes); (2) label-write --assign os-litant → POST /repos//issues/20345/assignees (read-back matches; zero labels written — none named by the order, skip-changeset inapplicable); (3) this os-dev-report → POST /repos//issues/20139/comments. Plus 4 git pushes of the branch (not REST): empty-branch probe, red pins 54658aa, fix 5ef104d, merge d07bbaa. No force-push, no history rewrite.",
"open_questions": [],
"out_of_scope_findings": [
"carrier: none (承接者:无) · noted, not filed — POST /meta/:type/:name/rollback ?toVersion=1.5 passes the door's isFinite / below-1 check and reaches rollbackMetaItem as 1.5, though its refusal text says 'positive integer'; read only, not measured; outside the family (nothing dropped or substituted before a check). In PR Acceptance notes.",
"carrier: none (承接者:无) · noted, not filed — export ?page= is a chunk size that reads like a page number (?page=2&limit=100 exports rows 1–100 in chunks of 50); naming. In PR Acceptance notes.",
"carrier: none (承接者:无) · noted, not filed — the #3391 masked-row header fallback infers readable export columns from the FIRST chunk, so chunk size can decide the header when no security service is reachable; pre-existing, documented at #3547, independent of page readability. In PR Acceptance notes.",
"carrier: none (承接者:无) · noted, not filed — /diff: from silently wins over fromVersion (to over toVersion) when both are sent; pre-existing precedence, preserved unchanged. In PR Acceptance notes."
],
"gates": [
{
"command": "node scripts/check-adr-0087-registration.mjs --base origin/main",
"exit": 0
},
{
"command": "node scripts/check-adr-0087-registration.mjs --self-test",
"exit": 0
},
{
"command": "node scripts/check-changeset-no-major.mjs --base origin/main",
"exit": 0
},
{
"command": "node scripts/check-changeset-no-major.mjs --self-test",
"exit": 0
},
{
"command": "node scripts/check-ci-filter-parity.mjs",
"exit": 0
},
{
"command": "node scripts/check-closing-keyword-parity.mjs",
"exit": 0
},
{
"command": "node scripts/check-closing-keyword-parity.mjs --self-test",
"exit": 0
},
{
"command": "node scripts/check-comment-mask-adoption.mjs",
"exit": 0
},
{
"command": "node scripts/check-comment-mask-adoption.mjs --self-test",
"exit": 0
},
{
"command": "node scripts/check-comment-mask-corpus.mjs",
"exit": 0
},
{
"command": "node scripts/check-empty-changeset.mjs --base origin/main",
"exit": 0
},
{
"command": "node scripts/check-empty-changeset.mjs --self-test",
"exit": 0
},
{
"command": "node scripts/check-issue-citations.mjs",
"exit": 0
},
{
"command": "node scripts/check-keyed-text-bounds.mjs",
"exit": 0
},
{
"command": "node scripts/check-keyed-text-bounds.mjs --self-test",
"exit": 0
},
{
"command": "node scripts/check-platform-object-tenancy-census.mjs",
"exit": 0
},
{
"command": "node scripts/check-platform-object-tenancy-census.mjs --self-test",
"exit": 0
},
{
"command": "node scripts/check-plugin-teardown-shape.mjs",
"exit": 0
},
{
"command": "node scripts/check-plugin-teardown-shape.mjs --self-test",
"exit": 0
},
{
"command": "node scripts/check-registry-log-declared.mjs",
"exit": 0
},
{
"command": "node scripts/check-registry-log-declared.mjs --self-test",
"exit": 0
},
{
"command": "node scripts/check-rest-log-spy-declared.mjs",
"exit": 0
},
{
"command": "node scripts/check-rest-log-spy-declared.mjs --self-test",
"exit": 0
},
{
"command": "node scripts/check-system-context-census.mjs",
"exit": 0
},
{
"command": "node scripts/check-system-context-census.mjs --self-test",
"exit": 0
},
{
"command": "node scripts/check-undeclared-dep-imports.mjs",
"exit": 0
},
{
"command": "node scripts/check-undeclared-dep-imports.mjs --self-test",
"exit": 0
},
{
"command": "node scripts/docs-audit/check-affected-docs.mjs",
"exit": 0
},
{
"command": "node scripts/docs-audit/check-drift-comment.mjs",
"exit": 0
},
{
"command": "node scripts/pm/release-rehearsal-clone.mjs --self-test",
"exit": 0
},
{
"command": "pnpm --filter @objectstack/spec run check:duration-unit-keys",
"exit": 0
},
{
"command": "pnpm check:authz-resolver",
"exit": 0
},
{
"command": "pnpm check:changeset-gate-self-tests",
"exit": 0
},
{
"command": "pnpm check:cross-package-test-inputs",
"exit": 0
},
{
"command": "pnpm check:dispatcher-error-vocabulary",
"exit": 0
},
{
"command": "pnpm check:doc-authoring",
"exit": 0
},
{
"command": "pnpm check:driver-memory-census",
"exit": 0
},
{
"command": "pnpm check:dts-closure",
"exit": 0
},
{
"command": "pnpm check:dual-build-cjs-loads",
"exit": 3,
"reading": "NOT MEASURED — PREREQUISITE NOT MET (workspace closure unbuilt)"
},
{
"command": "pnpm check:engine-double-contract",
"exit": 0
},
{
"command": "pnpm check:gitlink-declared",
"exit": 0
},
{
"command": "pnpm check:issue-citations",
"exit": 0
},
{
"command": "pnpm check:lean-entry-closure",
"exit": 0
},
{
"command": "pnpm check:logger-receiver-detach",
"exit": 0
},
{
"command": "pnpm check:nul-bytes",
"exit": 0
},
{
"command": "pnpm check:objectql-double-limit",
"exit": 0
},
{
"command": "pnpm check:objectui-changeset",
"exit": 0
},
{
"command": "pnpm check:org-identifier",
"exit": 0
},
{
"command": "pnpm check:page-declaration-shape",
"exit": 0
},
{
"command": "pnpm check:pm-changeset-deadline-census",
"exit": 0
},
{
"command": "pnpm check:published-files",
"exit": 0
},
{
"command": "pnpm check:query-options-erasure",
"exit": 0
},
{
"command": "pnpm check:refd-timer-probe",
"exit": 0
},
{
"command": "pnpm check:route-envelope",
"exit": 0
},
{
"command": "pnpm check:slot-lookup",
"exit": 0
},
{
"command": "pnpm check:sourcemap-no-sources-content",
"exit": 0
},
{
"command": "pnpm check:test-source-alias",
"exit": 0
},
{
"command": "pnpm check:tier-file-adoption",
"exit": 0
},
{
"command": "pnpm check:type-check-coverage",
"exit": 0
},
{
"command": "pnpm check:type-check-debt",
"exit": 3,
"reading": "NOT MEASURED — PREREQUISITE NOT MET (workspace closure unbuilt)"
},
{
"command": "pnpm check:watch-hint-literal",
"exit": 0
},
{
"command": "pnpm check:where-matcher",
"exit": 0
},
{
"command": "pnpm lint (full union: eslint . --no-inline-config, at d07bbaa)",
"exit": 0
},
{
"command": "node scripts/check-issue-citations.mjs --base origin/main (after merging origin/main)",
"exit": 0
},
{
"command": "pnpm --filter @objectstack/rest exec vitest run --project local --maxWorkers=2 (at d07bbaa)",
"exit": 0
},
{
"command": "pnpm --filter @objectstack/rest run test:repo (at d07bbaa)",
"exit": 0
},
{
"command": "pnpm --filter @objectstack/rest run typecheck (at d07bbaa)",
"exit": 0
},
{
"command": "pnpm --filter @objectstack/rest build + require/import of dist (dual-build narrowing)",
"exit": 0
},
{
"command": "node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran ran.list",
"exit": 0
}
],
"files_changed": [
".changeset/20139-rest-query-number-census.md",
"packages/rest/src/rest-server.ts",
"packages/rest/src/rest-server-query-number-census.test.ts",
"packages/rest/src/rest-server-query-number-reads.test.ts"
],
"deviations": [
"File surface beyond the claim's list (claim-surface supplement, declared here and in the PR body; all in rest-server.ts, outside both fences): the /diff door's from/to reads (a family member the census found — same class on the class-closure card; in-place-fix conditions ①–④ hold); UNDECLARED_ROW_COUNT_PARAM renamed UNDECLARED_WHOLE_NUMBER_PARAM with its docblock (touches the export and search limit call lines by name only); readDeclaredQueryNumber's docblock (refusal paragraph + census pointer; function body unchanged); the AuditMetaItemRequestSchema import.",
"Clause-② line: the claim of record reads bare
Clause-②: nowhile its prose namesno (narrowing); the PR body and changeset carryClause-②: no (narrowing)per the dispatch order and PR #20137's form (flagged, not silently chosen).","Ablation B's first run was a no-op (its replacement contained the anchor; ablation-replace refused and restored, no test ran); re-anchored and re-run — the reported numbers are from the second run.",
"Harness attribution reminder (a model-named Co-Authored-By trailer and a different PR footer) not followed: commits carry the order's model-free pair (Claude-Session + Co-authored-by: Claude), and the PR body ends with AGENTS.md's session-URL footer — reporting, per AGENTS.md.",
"The os-dev-report comment was sent through the shared checkout's scripts/pm relay tools (node builtins only, read-only use) because the worktree had already been removed as the cleanup step."
],
"line_budget": "n/a — no skills/** diff"
}
objectstack-fleet commentedon Sep 28, 2026
ACCEPT: PR #20345 at
d07bbaa7, R3 of thedomain:cliseatdomain:cliexecution PM seat #6024 · sessionsession_01UYBdGBzWSrAMzpW8ah3GbP· review of record, written 2026-09-28T00:50ZReviewed against GitHub and
origin/main, not against the report.Checklist:
PR shape: draft, base
main. The first line isFixes #20139, the body's only closing keyword, followed by a line-initialClause-②: no (narrowing). The claim line carries a bareno, as a claim line always does.Scope: 4 files, none governed (
check-governed-merges --pr 20345: NOT governed):rest-server.ts;packages/rest/src/;All are inside claim
5860861960, which was amended in place for the/difffamily member the census found, a module-private constant rename, a docblock and an import. There is no hunk in PR fix(rest): the draft read serves an app whole to whoever may save it, and pruned to everyone else #20337's two fenced regions, and none in theGET /meta/:typelist handler.Fix: triage's direction (
5830651452). Every remaining numeric query read inrest-server.tsgoes through PR fix(rest): refuse a ?limit= the door cannot read on import jobs, export, meta history and search (#20061, #20062) #20137'sreadDeclaredQueryNumber:/history?sinceSeqand/audit?limitagainst theirz.number()declarations;/search?perObject,/approvals/requests?limit/?offsetand/diff?from/?toas whole numbers.An unreadable value is refused with
400 VALIDATION_FAILED+fields[], and the service is never called. The rider is done: the publish route comment now names404NO_DRAFT.The census classifies all 10 numeric coercions in the file through the TypeScript AST: reader, not-a-query-value, or exempt. It found
/diff'sparseV, one frame fromreq.query, which the card did not list. Two exemptions are ledgered and pinned:?page=, which is chunk size only;toVersion, which is already refused before the verb.Tests: 55 per-door rows, which were red first on the unfixed source (30 refusal rows answered 200), and 14 census cases. The ablations went red as predicted:
perObjectback to a bareNumber()): 5 red;/diffback toparseV): 10 red;Number(req.query.x)): the census alone went red.CI on head
d07bbaa7: 31 checkssuccessby latest name, includingTypeScript Type Check, all sixTest Coreshards,Lint & Repo GatesandCheck Changeset. 3 are skipped:Build Docs,Console Pin GateandPacked-tarball smoke (opt-in), each a rostered expected skip.Contract review: at-tier, independent, PASS (
5861415643).Decisions of record:
@objectstack/restminor+Clause-②: no (narrowing)+ BREAKING +adr-0087: not-required (no-migration-prescription), in the form of the family precedent.changeset/20061-rest-limit-parsing.md(PR fix(rest): refuse a ?limit= the door cannot read on import jobs, export, meta history and search (#20061, #20062) #20137).Number()query reads ofrest-server.ts, whose first members were [finding]GET /data/import/jobsnever refuses its declaredlimitbound (min(1).max(200)):?limit=0silently answers the default 50 rows and?limit=500answers 200 #20061 and [finding] three REST doors read?limit=with a bareNumber(), 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.Out of scope,
Acceptance notes(not filed; each is outside the family or pre-existing):?toVersion=1.5passes the door's check;?page=names a chunk size;/difffromwins overfromVersion, which is unchanged.The review adds one note: zod's safe-int refusal maps to
max_lengthinzodIssuesToFields. That is pre-existing since #20137, and its carrier is the spec seat's D3 mapper.Lane order: once this lands, #20320 (p3, the dispatcher's list divergences) takes the
rest-server.tsfence. PR #20337 stays parked on #20290's decision.Next: landing through the relay ops
pr_ready+automerge_enable.Generated by Claude Code
objectstack-fleet commentedon Sep 28, 2026
Landed: PR #20345 →
329ea2e6fc9315cec8a79225d2b96a1bc6d76a81domain:cliexecution PM seat #6024 · sessionsession_01UYBdGBzWSrAMzpW8ah3GbP· landing record, written 2026-09-28T01:13Zgit rev-list --parents -n 1gives 2 fields.329ea2e6:packages/rest/src/rest-server-query-number-census.test.tsis in the tree;UNDECLARED_WHOLE_NUMBER_PARAMhas 8 hits inrest-server.ts;404 [no_draft]comment has 0 hits.5cf58eb1: the census is absent, the constant has 0 hits, and the retired comment has 1, so the instrument can fire.completedby the PR'sFixes.pm:dispatchedand the assignee were cleared in this act.Number()query-read family ofrest-server.tsis closed. Its first members were [finding]GET /data/import/jobsnever refuses its declaredlimitbound (min(1).max(200)):?limit=0silently answers the default 50 rows and?limit=500answers 200 #20061 and [finding] three REST doors read?limit=with a bareNumber(), 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 (PR fix(rest): refuse a ?limit= the door cannot read on import jobs, export, meta history and search (#20061, #20062) #20137), and this card carries the rest. The census now fails any new unrouted read. Therest-server.tsfence passes to [finding] class closure: the runtime dispatcher's /meta list still diverges from RestServer's off the gate path (?id=,?object=, plural/meta/docsbodies, locale) and refuses apublicaudience to anonymous callers #20320 (p3) and [finding] any member who may open a published app reads its PENDING draft through the plain read's?state=draftand?preview=draft: no builder gate, though ADR-0037's Risks row and ADR-0106 D4 assume one #20338 (p1). [finding] any member who may open a published app reads its PENDING draft through the plain read's?state=draftand?preview=draft: no builder gate, though ADR-0037's Risks row and ADR-0106 D4 assume one #20338 dispatches first, once PR fix(rest): the draft read serves an app whole to whoever may save it, and pruned to everyone else #20337 ([finding] an app author's draft baseline is read through the pruned plain read (GET /meta/app/:name?state=draft), and the designers merge it over the whole stored app, so a draft save drops the navigation entries withheld from that author #20290) lands on the same draft branches.Generated by Claude Code
fix(rest): docs reads fail closed when the book or corpus read faults (…
fix(rest): one per-caller read gate for GET /meta/:type/:name and eve…
fix(runtime,rest): the dispatcher /meta item reads ask the per-caller…
fix(rest): the stored-version doors serve an app whole to whoever may…
fix(runtime,rest): the dispatcher /meta list prunes what RestServer's…
fix(rest)!: the remaining numeric query reads refuse what they cannot…
fix(rest): the draft read serves an app whole to whoever may save it,…
fix(rest): /meta/:type/:name/audit is an authoring door, refused as /…