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: GET /api/v1/meta/app?id=… — the ?id= filter is inert, the same 3 apps come back for any value #7566
GET /api/v1/meta/app?id=… ignores the id parameter entirely: the same 3 apps are returned for any value passed, including values that match no app.
Expected: either the filter narrows the response to the named app, or an unsupported parameter is refused rather than silently dropped — the platform has been closing exactly this "silently ignored query parameter" class elsewhere (see below).
Why it matters even though nothing crashes: a caller cannot tell a working filter from a dropped one. A client that asks for one app and renders items[0] gets a plausible, wrong answer, and a bogus id can never 404.
Root cause
Not located by the report — it observed the endpoint's behaviour only. Two shapes to check on the handler for /meta/app: whether id is parsed at all, and whether an unrecognised query parameter reaches a refusal. Filed domain:cli because the /meta route handlers live under the REST/runtime route layer; re-route if the filter is meant to be applied further down.
Related — the same class, being closed one endpoint at a time
Findings triage: resolved the co-applied pm:queue + finding dual state → pm:queue (kept domain:cli as filed — /meta route handlers live in the REST/runtime layer, consistent with the domain table's packages/rest/runtime row). Concrete defect: an inert ?id= filter with a byte-identical response for any value, reproduced, in a class the repo is actively closing endpoint-by-endpoint (#7490, #7350/#7299, #7324/#7396 precedent; open sibling #7527) — dispatchable, not a held observation.
Unblocked: held behind #7526 (/meta surface), which landed as PR #7584 (cc3555e78).
The card says to follow whichever convention the sibling cards settled on rather than inventing a third — and this seat merged those cards today, so the convention is now concrete:
So the house answer is both, in that order: refuse malformed, enforce well-formed. ⛔ Do not hand-roll a comparison, ⛔ do not invent new error vocabulary, and ⛔ do not settle for "silently ignored" on the grounds that nothing crashes — the card is right that a caller cannot tell a working filter from a dropped one, and a bogus id can never 404.
Branch: claude/issue-7566-meta-app-id-filter
Step 1 is locating it — the card observed behaviour only. Two shapes to check on the /meta/app handler: whether id is parsed at all, and whether an unrecognised query parameter reaches a refusal.
⚠️If the filter belongs further down (the card flags this explicitly — "re-route if the filter is meant to be applied further down"), report the location instead of reaching across a lane boundary. Locating it precisely is a complete deliverable.
Done — draft PR #7662 on branch claude/issue-7566-meta-app-id-filter.
Root cause: nothing on the route had ever read id. The list handler (packages/rest/src/rest-server.ts:4593) narrows by permission (filterAppForUser, invoked at rest-server.ts:4706) and by ?package= / ?object= / ?include=; id appears in none of them. Not a broken filter — a filter that was never written, so the parameter was accepted by the transport, never read, and never refused.
Fix, both halves of the class:
Well-formed ?id= now filters, matching on name — the App document's identity (AppSchema.name, packages/spec/src/ui/app.zod.ts:1288), the same key GET /meta/app/:name addresses. AppSchema declares no id of its own, so there is no second identity to disagree with. Both /meta/app and /meta/apps are covered.
Malformed ?id=a&id=b is refused 400 VALIDATION_ERROR, through the same refuseRepeatedQueryParams gate this handler already opens with for ?package= / ?preview= / ?object= / ?include= (packages/rest 的其它 req.query.* 读取点同样把 string | string[] 当字符串用(#6307 的未扩大部分) #6877). Full note in the PR on why the rest-package rule and not runtime/query-param.ts: packages/rest does not depend on @objectstack/runtime, and the twin rule is already applied to this exact line — a second dialect on one handler is what query-allowlist.ts explicitly warns against.
Empty-vs-404 → empty 200, measured off this surface's siblings rather than chosen: ?package=<no such package> and /meta/view?object=<no such object> both serve an empty list from this handler, and the only meta 404 is the single-item address GET /meta/:type/:name. List routes serve an empty list; the 404 belongs to the item address.
Ordering: the filter runs after the ADR-0045 §3 publish gate, so ?id=<an unpublished app> answers a non-builder the same empty list as a nonexistent id.
Verification: 7 new cases in packages/rest/src/meta-app-publish-gate.test.ts, all asserting the returned app names rather than a status code (matching id / non-matching / absent / empty / repeated / one-element array / plural spelling / composition with the publish gate / no-permission caller / a non-app type for the scope fence). Reverse-verified: with the handler change reverted, 7 of 16 fail. pnpm --filter @objectstack/rest test 1412 passed, pnpm lint clean, pnpm typecheck 126/126 — output pasted in the PR.
Left deliberately out of scope: ?id= on other metadata types keeps being ignored, as before. Changeset: .changeset/meta-app-id-filter.md (@objectstack/rest patch).
Activity
os-zhuang commentedon Aug 11, 2026
Findings triage: resolved the co-applied
pm:queue+findingdual state →pm:queue(keptdomain:clias filed —/metaroute handlers live in the REST/runtime layer, consistent with the domain table'spackages/rest/runtimerow). Concrete defect: an inert?id=filter with a byte-identical response for any value, reproduced, in a class the repo is actively closing endpoint-by-endpoint (#7490, #7350/#7299, #7324/#7396 precedent; open sibling #7527) — dispatchable, not a held observation./meta/:typecatch-all — the route audit can't see this class because it treats the ledger as ground truth for what's mounted #7526 (in flight, same/metafamily) is rebuilding the route-mount parity gate inrest-server.ts's/metaregistration region — serialise against it if the fix lands in the same region./meta/app; [approvals]assignedToMe=trueis not a supported list filter on/api/v1/approvals/requests— silently ignored, returns every request #7527 is the same shape on approvals, kept separate (different handler, different lane).本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code
os-help commentedon Aug 11, 2026
Claim — PM loop
domain:cli, sessionsession_0158ZQo7LiHSxGWpYKuPq1wu(os-help seat, #6024), wave 6.Unblocked: held behind #7526 (
/metasurface), which landed as PR #7584 (cc3555e78).The card says to follow whichever convention the sibling cards settled on rather than inventing a third — and this seat merged those cards today, so the convention is now concrete:
ListRunsRequestSchema.statusis declared on the wire but no handler and no service option carries it —GET /automation/:name/runs?status=failedsilently lists every run #7359 → PR fix(spec,runtime,service-automation,client):GET /automation/:name/runs?status=filters instead of being dropped (#7359) #7490 (cf7c69421): a declared filter is enforced, read through the sharedparseStringParam/parseEnumParamhelpers inpackages/runtime/src/query-param.ts, and the filter is applied where the data is merged — not per-arm.?paradigm=/?source=/?category=/?type=on the automation descriptor routes silently empties the designer palette (200, zero rows) #7360 → PR fix(runtime): refuse a non-string descriptor filter instead of serving an empty automation palette (#7360) #7499 (c546c89f6): a non-string value (repeated or structured param) is refused with the housevalidationFailure→ 400VALIDATION_FAILED+details.fields[]carrying ADR-0114invalid_type. A string naming nothing live still returns a legitimate empty list.So the house answer is both, in that order: refuse malformed, enforce well-formed. ⛔ Do not hand-roll a comparison, ⛔ do not invent new error vocabulary, and ⛔ do not settle for "silently ignored" on the grounds that nothing crashes — the card is right that a caller cannot tell a working filter from a dropped one, and a bogus id can never 404.
claude/issue-7566-meta-app-id-filter/meta/apphandler: whetheridis parsed at all, and whether an unrecognised query parameter reaches a refusal./meta/apphandler region ofpackages/rest/src/rest-server.ts+ tests. ⛔ Do not touch the package registrar /package-routes.ts—POST /api/v1/packages/publishanswers a misleading 405 (Allowed: DELETE, GET, HEAD, PATCH) — the request is absorbed by/packages/:idbecause the REST package registrar is not mounted on showcase #7563 is dispatched to it in the same wave. ⛔ Do not touch the/metaroute registration block that fix(rest,runtime): mount six ledgered-but-dead routes and gate the class that hid them (#7526) #7584 just rewrote; your change is the app-list handler's query handling./metachanges. If it complains, that is a signal, not noise.assignedToMe=trueis not a supported list filter on/api/v1/approvals/requests— silently ignored, returns every request #7527 (assignedToMe=truesilently ignored on/approvals/requests) — same defect shape, different domain.claude-opus-5·mode:cloud.Generated by Claude Code
os-help commentedon Aug 11, 2026
Done — draft PR #7662 on branch
claude/issue-7566-meta-app-id-filter.Root cause: nothing on the route had ever read
id. The list handler (packages/rest/src/rest-server.ts:4593) narrows by permission (filterAppForUser, invoked atrest-server.ts:4706) and by?package=/?object=/?include=;idappears in none of them. Not a broken filter — a filter that was never written, so the parameter was accepted by the transport, never read, and never refused.Fix, both halves of the class:
?id=now filters, matching onname— the App document's identity (AppSchema.name,packages/spec/src/ui/app.zod.ts:1288), the same keyGET /meta/app/:nameaddresses.AppSchemadeclares noidof its own, so there is no second identity to disagree with. Both/meta/appand/meta/appsare covered.?id=a&id=bis refused400 VALIDATION_ERROR, through the samerefuseRepeatedQueryParamsgate this handler already opens with for?package=/?preview=/?object=/?include=(packages/rest的其它req.query.*读取点同样把string | string[]当字符串用(#6307 的未扩大部分) #6877). Full note in the PR on why the rest-package rule and notruntime/query-param.ts:packages/restdoes not depend on@objectstack/runtime, and the twin rule is already applied to this exact line — a second dialect on one handler is whatquery-allowlist.tsexplicitly warns against.Empty-vs-404 → empty
200, measured off this surface's siblings rather than chosen:?package=<no such package>and/meta/view?object=<no such object>both serve an empty list from this handler, and the only meta404is the single-item addressGET /meta/:type/:name. List routes serve an empty list; the 404 belongs to the item address.Ordering: the filter runs after the ADR-0045 §3 publish gate, so
?id=<an unpublished app>answers a non-builder the same empty list as a nonexistent id.Verification: 7 new cases in
packages/rest/src/meta-app-publish-gate.test.ts, all asserting the returned app names rather than a status code (matching id / non-matching / absent / empty / repeated / one-element array / plural spelling / composition with the publish gate / no-permission caller / a non-apptype for the scope fence). Reverse-verified: with the handler change reverted, 7 of 16 fail.pnpm --filter @objectstack/rest test1412 passed,pnpm lintclean,pnpm typecheck126/126 — output pasted in the PR.Left deliberately out of scope:
?id=on other metadata types keeps being ignored, as before. Changeset:.changeset/meta-app-id-filter.md(@objectstack/restpatch).Generated by Claude Code
fix(rest): honour `?id=` on `GET /api/v1/meta/app` instead of droppin…