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
Metadata API: GET /api/v1/meta/app?id[]=NAME (bracketed array spelling) ignores the filter and answers the caller's full app list #28930
QA-source: #28927 · platform-core.builtin-apps-nav-render · observed beside the clauses
What happens
GET /api/v1/meta/app?id[]=setup (and ?id[0]=setup) answers 200 with the caller's unfiltered app list. A client that serialises arrays qs-style silently gets every app back instead of one app or a refusal. This is the sibling of #28548 (empty ?id=), which is fixed at this subject: ?id= now answers 400 "Query parameter 'id' names no app", and a repeated id answers VALIDATION_ERROR.
Not an authorization issue: the member's unfiltered list is still pruned (setup never appears in it).
Measured at framework 7fa9873f (main, 2026-11-02) on a stock showcase boot.
Reproduction
Boot the stock showcase: OS_PORT=PORT pnpm -C examples/app-showcase exec objectstack dev --ui --seed-admin --no-compile -p PORT -d file:/tmp/x/data.db.
As admin: GET /api/v1/meta/app?id[]=setup → 200, items [showcase_app, setup, account].
As the seeded member phone.demo@example.com (password showcase123): the same → 200, [showcase_app, account].
Expected: the one named app (as ?id=setup answers), or a 400 like the empty and repeated spellings get.
Actual: the unfiltered list.
Controls: ?id=setup → that one app; ?id= → 400; a repeated id → VALIDATION_ERROR; ?id=SETUP, ?id=setup%20, ?id=* → 200 items:[] (exact-name match).
Where (a guess, not traced)
RUNNER places the /meta/app?id= filter in packages/rest/src/rest-server.ts (a.name === id). The #28548 fix refuses an empty and a repeated id; a bracketed key presumably reaches the handler under another key name, so the filter is never applied.
Read fresh. The /meta/app?id= filter in packages/rest (rest-server.ts, the same place as the Metadata API: GET /api/v1/meta/app?id= with an empty value ignores the filter and answers the caller's full app list #28548 fix) is skipped for the qs-style id[]= / id[0]= spellings, which answer the unfiltered list. The card notes that list is still pruned per caller, so it is not an authorization issue. It is a user-visible behaviour defect, so it is p2 in domain:server, and it goes to pm:queue.
Claim: PM loop round 4 · card thread · 2026-11-02T05:20Z
Session: session_0186vfjHHMsRXC9EUT9hTFMo (the seat); the card thread is session_01FEkQ5o6bowfKzFDhW76JZ3
Account: os-project-manager (the seat's linked user; the card's assignee)
Branch: claude/project-thread-vh6ns8 (the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)
Worktree: the card thread's own container checkout
Domain: domain:server
Seat: domain:server#2
Ruling-ref: the maintainer, 2026-11-01T03:46Z: 「server 车道现在就是你负责,任务有一大堆啊,都可以派,包括 p3」, with 2026-10-26T10:29Z 「p1 p2 处理完了,就可以处理 p3」. With 2026-11-01T12:11Z 「定级你可以自己决定」 (triage graded this card) and 2026-11-02T05:15Z 「队列进了很多任务,抓紧派发」; seat 1 split the queue and gave this card to seat 2. Seat's route: refuse, with one answer. A bracketed id key gets the same 400 VALIDATION_ERROR as a repeated id (#28548's words), never the unfiltered list.
File surface: the /meta list ?id= filter in packages/rest/src/rest-server.ts (and any /meta/:type door sharing that seam); its tests; one dogfood pin; changeset
Container & model: M, mode:thread, model: opus (--tier names no path mandate: PM's call, default), effort: medium
Clause-②: yes (narrowing) expected: a query answered 200 is now refused; the dev measures and declares; CONTRACT_REVIEW_TIER review
Metadata-protocol: none (expected; ruling A #25105 ships a non-protocol narrowing at patch with the BREAKING banner; the dev measures and declares)
Responsibility: the dev extends #28548's refusal to bracketed key spellings, red first with ablation; the seat reviews and lands
Thread-read: none
Premise: measured by triage (6569547911) on main
Serial constraints cleared: none; overlap re-read of open PRs on rest-server.ts before pr_create
Resume-from: none — fresh from origin/main
State: → pm:dispatched, assigned to os-project-manager, recorded by this claim.
domain:server#2 · os-project-manager · session_01FEkQ5o6bowfKzFDhW76JZ3
os-dev-report
{
"issue": 28930,
"status": "done",
"branch": "claude/project-thread-vh6ns8",
"pr": "#29046",
"session": "session_01FEkQ5o6bowfKzFDhW76JZ3",
"premise_still_valid": true,
"summary": "GET /meta/app (and /meta/apps) now refuses any query key that opens id[ (?id[]=NAME, ?id[0]=NAME, ?id[x]=) with 400 VALIDATION_ERROR naming the key, no list, in the empty ?id= refusal's sentence frame (#28548). Both refusals go through one builder; the empty id/object messages are byte-identical. The step lives in createMetaListAnswer step 3 (packages/rest/src/meta-item-read-gate.ts, not rest-server.ts as the card guessed), after the per-caller gate, so RestServer and the runtime dispatcher answer it identically. Only the app list reads id, so the fix is /meta/app only; ?object[]= on the view list is the same class, measured and reported, not fixed. Declared Clause-② no (narrowing), not the order's expected yes: nothing published is widened (same as #28548's own declaration); Metadata-protocol none, patch, BREAKING banner, FROM ?id[]=NAME TO ?id=NAME. The bracketed refusal does not reuse repeatedQueryParamMessage, whose 'supplied N times' would be false for a key sent once.",
"tests": "HEAD 2055ce2. rest: pnpm --filter @objectstack/rest test exit 0, Test Files 366 passed (366), Tests 6940 passed | 332 skipped; rest typecheck exit 0. runtime parity (repo-project file, run directly): 991/991 exit 0; runtime typecheck exit 0. dogfood meta-read-doors-live: 14/14. Ablation: call replaced with 'void refuseBracketedAppIdFilter;' via ablation-replace (anchor 1->0, blob 9c8674a8->b9866803), rest rebuilt exit 0, dist-preflight --absent exit 0 (marker 'refuseBracketedAppIdFilter(query);' absent from 6 built files); reds exactly the new cases: rest 3 failed|28 passed (BRACKETED id[]/id[0]/id[name]), runtime parity 1 failed|990 (reference-moves test; row A stays equal since both transports gave the same unfiltered list), dogfood 2 failed|12 (?id[]=setup and ?id[0]=setup got 200 with [showcase_app]). Restore: blob==HEAD, git diff HEAD empty, rebuild exit 0, preflight present in 2 files, tree clean. A first ablation that deleted the line made the unused function fail the rest DTS build (exit 1); discarded. Dogfood stack has no setup app (only showcase_app for both callers), so the control narrows on showcase_app and ?id=setup -> [].",
"gates": "Local derived set (dispatch-gates --commands, 64 commands) all exit 0 at 2055ce2; --ran: '64 derived famil(ies) accounted for — 64 run, 0 NOT-MEASURED'. First-pass exit 3s were prerequisites, re-run green: check-plugin-teardown-shape --self-test after git fetch --depth=1 origin 621a487; check:dual-build-cjs-loads after building 7 missing dists (studio, client-react, embedder-openai, knowledge-memory, knowledge-ragflow, service-cluster-redis, service-knowledge). Record: /mnt/project-files/pm-orders/server/28930-gates-ran.txt. CI check-runs at report time (PR #29046): all in_progress or queued (Check Changeset, Type Check x4, Lint x9, PR-body guards, Governed Surface Queue Guard, Spec property liveness, Check PR Size, Flag docs affected); skipped: 18.x upgrade harness, Schedule gate, Packed-tarball smoke. Not run locally: test:repo beyond the one edited parity file, pnpm lint (CI-owned).",
"dogfood_battery": "2055ce23 · os-verify-lock: VERDICT command-exit 0 · Test Files 383 passed | 3 skipped (386) · Tests 3166 passed | 28 skipped (3194) · no failures",
"mcp_calls": "8 — issue_read x3 (get, get_comments x2), pull_request_read x3 (get_files #28602, get_files #28731, get_check_runs #29046), list_pull_requests x1; no write tools",
"api_writes": "1 — fleet-write relay pr_create (POST /repos/objectstack-ai/objectstack/pulls, run 41399602096) → #29046; plus this os-dev-report comment (POST /repos//issues/28930/comments via post-stamped)",
"open_questions": [],
"out_of_scope_findings": [
"class: a · reach: RestServer GET /meta/:type route handler, view list with a three-view fixture: ?object[]=lead -> 200 [all_leads, acct_view, loose_view] where ?object=lead -> 200 [all_leads]; the adapters hand the bracketed key through as spelled, as measured for id[] over HTTP on the dogfood stack · evidence: createMetaListAnswer step 4 reads query.object only · same family as #28930 (qs-style array key bypasses a one-value list filter); package[] on the list doors not measured · dedupe words: view object[] bracketed filter, meta view list object array, qs array key meta list",
"carrier: none · noted in PR #29046 Acceptance notes: open PR #28850 also edits meta-read-doors-live.dogfood.test.ts (header comment and acceptance[2] setup); this PR appends a describe at the end, hunks disjoint"
]
}
Release: session_0186vfjHHMsRXC9EUT9hTFMo · cause: the maintainer's wrap-up (「进展中的开发先提交代码然后暂停,先确保已有的pr都合并」, 「草稿的也交给下一任,在座位帖写清楚」); seat 2 signs off · next: PR #29046 is ACCEPTed (6570953324) with review PASS (6570942095) and is in the merge queue; Fixes #28930 closes this card on merge. Next: the next seat posts the landing record and files the ?object[]= view-list follow-up card. ⛔ Do not re-dispatch while #29046 is queued.
Resume-from: claude/project-thread-vh6ns8@2055ce2324552f66a7654791d750177a9859837d
State: pm:dispatched → pm:queue, assignee cleared, in this same relay stroke. Seat hand-off: mailbox #28284 comment 6571506250; seat post #20966.
Claim: PM loop round 1 · seat takeover · 2026-11-02T08:10Z
Session: session_01ADHkmQxwoGb5fSnrFkpxmt (the seat)
Account: os-steve (the seat's linked user; the card's assignee)
Branch: claude/project-thread-vh6ns8 (continued from the released claim; PR #29046)
Worktree: the card thread's own container checkout
Domain: domain:server
Seat: domain:server#2
Ruling-ref: the maintainer, verbatim: 「开 server 2、3、5 号席位, 前任已经下班,接手所有开发,包括跟进之前未完成的开发落地。」 (os-steve project "objectstack spec"). Takes over the hand-back Release: 6571737801 of seat 2's previous term (session_0186vfjHHMsRXC9EUT9hTFMo).
File surface: the /meta list ?id= filter in packages/rest/src/rest-server.ts; its tests; one dogfood pin; changeset (unchanged from claim 6569718113)
Container & model: M, mode:thread, model: opus (as the previous claim), effort: medium
Clause-②: yes (narrowing) — as declared on PR #29046; CONTRACT_REVIEW_TIER review PASS 6570942095 on record
Metadata-protocol: none — as declared on PR #29046
Responsibility: the dev extended #28548's refusal to bracketed key spellings (claim 6569718113); the seat follows PR #29046 to MERGED and files the ?object[]= view-list follow-up
Thread-read: 6571737801
Premise: holds (measured by the previous term's dev; re-read on the PR head before ACCEPT)
Serial constraints cleared: none new; the PR's file list is re-read against live claims before landing
Resume-from: claude/project-thread-vh6ns8@2055ce2324552f66a7654791d750177a9859837d
Status: PR #29046 is ACCEPTed (6570953324) and in the merge queue; no new dev work. ⛔ No re-dispatch while it is queued.
State: pm:queue → pm:dispatched, assigned to os-steve, recorded by this claim.
Activity
objectstack-fleet commentedon Nov 2, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: platform-core.builtin-apps-nav-render
Triage: priority:p2 · domain:server · pm:queue · 2026-11-02T05:06Z
⛔ Not a claim.
/meta/app?id=filter in packages/rest (rest-server.ts, the same place as the Metadata API: GET /api/v1/meta/app?id= with an empty value ignores the filter and answers the caller's full app list #28548 fix) is skipped for the qs-styleid[]=/id[0]=spellings, which answer the unfiltered list. The card notes that list is still pruned per caller, so it is not an authorization issue. It is a user-visible behaviour defect, so it is p2 indomain:server, and it goes topm:queue.Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:server#2 · os-project-manager · session_0186vfjHHMsRXC9EUT9hTFMo
Claim: PM loop round 4 · card thread · 2026-11-02T05:20Z
Session:
session_0186vfjHHMsRXC9EUT9hTFMo(the seat); the card thread issession_01FEkQ5o6bowfKzFDhW76JZ3Account:
os-project-manager(the seat's linked user; the card's assignee)Branch:
claude/project-thread-vh6ns8(the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)Worktree: the card thread's own container checkout
Domain:
domain:serverSeat:
domain:server#2Ruling-ref: the maintainer, 2026-11-01T03:46Z: 「server 车道现在就是你负责,任务有一大堆啊,都可以派,包括 p3」, with 2026-10-26T10:29Z 「p1 p2 处理完了,就可以处理 p3」. With 2026-11-01T12:11Z 「定级你可以自己决定」 (triage graded this card) and 2026-11-02T05:15Z 「队列进了很多任务,抓紧派发」; seat 1 split the queue and gave this card to seat 2. Seat's route: refuse, with one answer. A bracketed
idkey gets the same 400VALIDATION_ERRORas a repeatedid(#28548's words), never the unfiltered list.File surface: the
/metalist?id=filter inpackages/rest/src/rest-server.ts(and any/meta/:typedoor sharing that seam); its tests; one dogfood pin; changesetContainer & model:
M,mode:thread,model: opus(--tiernames no path mandate: PM's call, default),effort: mediumClause-②: yes (narrowing) expected: a query answered 200 is now refused; the dev measures and declares; CONTRACT_REVIEW_TIER review
Metadata-protocol: none (expected; ruling A #25105 ships a non-protocol narrowing at patch with the BREAKING banner; the dev measures and declares)
Responsibility: the dev extends #28548's refusal to bracketed key spellings, red first with ablation; the seat reviews and lands
Thread-read: none
Premise: measured by triage (
6569547911) on mainSerial constraints cleared: none; overlap re-read of open PRs on rest-server.ts before pr_create
Resume-from: none — fresh from
origin/mainState: →
pm:dispatched, assigned toos-project-manager, recorded by this claim.Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:server#2 · os-project-manager · session_01FEkQ5o6bowfKzFDhW76JZ3
os-dev-report
{
"issue": 28930,
"status": "done",
"branch": "claude/project-thread-vh6ns8",
"pr": "#29046",
"session": "session_01FEkQ5o6bowfKzFDhW76JZ3",
"premise_still_valid": true,
"summary": "GET /meta/app (and /meta/apps) now refuses any query key that opens id[ (?id[]=NAME, ?id[0]=NAME, ?id[x]=) with 400 VALIDATION_ERROR naming the key, no list, in the empty ?id= refusal's sentence frame (#28548). Both refusals go through one builder; the empty id/object messages are byte-identical. The step lives in createMetaListAnswer step 3 (packages/rest/src/meta-item-read-gate.ts, not rest-server.ts as the card guessed), after the per-caller gate, so RestServer and the runtime dispatcher answer it identically. Only the app list reads id, so the fix is /meta/app only; ?object[]= on the view list is the same class, measured and reported, not fixed. Declared Clause-② no (narrowing), not the order's expected yes: nothing published is widened (same as #28548's own declaration); Metadata-protocol none, patch, BREAKING banner, FROM ?id[]=NAME TO ?id=NAME. The bracketed refusal does not reuse repeatedQueryParamMessage, whose 'supplied N times' would be false for a key sent once.",
"tests": "HEAD 2055ce2. rest: pnpm --filter @objectstack/rest test exit 0, Test Files 366 passed (366), Tests 6940 passed | 332 skipped; rest typecheck exit 0. runtime parity (repo-project file, run directly): 991/991 exit 0; runtime typecheck exit 0. dogfood meta-read-doors-live: 14/14. Ablation: call replaced with 'void refuseBracketedAppIdFilter;' via ablation-replace (anchor 1->0, blob 9c8674a8->b9866803), rest rebuilt exit 0, dist-preflight --absent exit 0 (marker 'refuseBracketedAppIdFilter(query);' absent from 6 built files); reds exactly the new cases: rest 3 failed|28 passed (BRACKETED id[]/id[0]/id[name]), runtime parity 1 failed|990 (reference-moves test; row A stays equal since both transports gave the same unfiltered list), dogfood 2 failed|12 (?id[]=setup and ?id[0]=setup got 200 with [showcase_app]). Restore: blob==HEAD, git diff HEAD empty, rebuild exit 0, preflight present in 2 files, tree clean. A first ablation that deleted the line made the unused function fail the rest DTS build (exit 1); discarded. Dogfood stack has no setup app (only showcase_app for both callers), so the control narrows on showcase_app and ?id=setup -> [].",
"gates": "Local derived set (dispatch-gates --commands, 64 commands) all exit 0 at 2055ce2; --ran: '64 derived famil(ies) accounted for — 64 run, 0 NOT-MEASURED'. First-pass exit 3s were prerequisites, re-run green: check-plugin-teardown-shape --self-test after git fetch --depth=1 origin 621a487; check:dual-build-cjs-loads after building 7 missing dists (studio, client-react, embedder-openai, knowledge-memory, knowledge-ragflow, service-cluster-redis, service-knowledge). Record: /mnt/project-files/pm-orders/server/28930-gates-ran.txt. CI check-runs at report time (PR #29046): all in_progress or queued (Check Changeset, Type Check x4, Lint x9, PR-body guards, Governed Surface Queue Guard, Spec property liveness, Check PR Size, Flag docs affected); skipped: 18.x upgrade harness, Schedule gate, Packed-tarball smoke. Not run locally: test:repo beyond the one edited parity file, pnpm lint (CI-owned).",
"dogfood_battery": "2055ce23 · os-verify-lock: VERDICT command-exit 0 · Test Files 383 passed | 3 skipped (386) · Tests 3166 passed | 28 skipped (3194) · no failures",
"mcp_calls": "8 — issue_read x3 (get, get_comments x2), pull_request_read x3 (get_files #28602, get_files #28731, get_check_runs #29046), list_pull_requests x1; no write tools",
"api_writes": "1 — fleet-write relay pr_create (POST /repos/objectstack-ai/objectstack/pulls, run 41399602096) → #29046; plus this os-dev-report comment (POST /repos//issues/28930/comments via post-stamped)",
"open_questions": [],
"out_of_scope_findings": [
"class: a · reach: RestServer GET /meta/:type route handler, view list with a three-view fixture: ?object[]=lead -> 200 [all_leads, acct_view, loose_view] where ?object=lead -> 200 [all_leads]; the adapters hand the bracketed key through as spelled, as measured for id[] over HTTP on the dogfood stack · evidence: createMetaListAnswer step 4 reads query.object only · same family as #28930 (qs-style array key bypasses a one-value list filter); package[] on the list doors not measured · dedupe words: view object[] bracketed filter, meta view list object array, qs array key meta list",
"carrier: none · noted in PR #29046 Acceptance notes: open PR #28850 also edits meta-read-doors-live.dogfood.test.ts (header comment and acceptance[2] setup); this PR appends a describe at the end, hunks disjoint"
]
}
Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:server#2 · os-project-manager · session_0186vfjHHMsRXC9EUT9hTFMo
Release:
session_0186vfjHHMsRXC9EUT9hTFMo· cause: the maintainer's wrap-up (「进展中的开发先提交代码然后暂停,先确保已有的pr都合并」, 「草稿的也交给下一任,在座位帖写清楚」); seat 2 signs off · next: PR #29046 is ACCEPTed (6570953324) with review PASS (6570942095) and is in the merge queue;Fixes #28930closes this card on merge. Next: the next seat posts the landing record and files the?object[]=view-list follow-up card. ⛔ Do not re-dispatch while #29046 is queued.Resume-from:
claude/project-thread-vh6ns8@2055ce2324552f66a7654791d750177a9859837dState:
pm:dispatched→pm:queue, assignee cleared, in this same relay stroke. Seat hand-off: mailbox #28284 comment 6571506250; seat post #20966.Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:server#2 · os-steve · session_01ADHkmQxwoGb5fSnrFkpxmt
Claim: PM loop round 1 · seat takeover · 2026-11-02T08:10Z
Session:
session_01ADHkmQxwoGb5fSnrFkpxmt(the seat)Account:
os-steve(the seat's linked user; the card's assignee)Branch:
claude/project-thread-vh6ns8(continued from the released claim; PR #29046)Worktree: the card thread's own container checkout
Domain:
domain:serverSeat:
domain:server#2Ruling-ref: the maintainer, verbatim: 「开 server 2、3、5 号席位, 前任已经下班,接手所有开发,包括跟进之前未完成的开发落地。」 (os-steve project "objectstack spec"). Takes over the hand-back
Release:6571737801 of seat 2's previous term (session_0186vfjHHMsRXC9EUT9hTFMo).File surface: the
/metalist?id=filter inpackages/rest/src/rest-server.ts; its tests; one dogfood pin; changeset (unchanged from claim 6569718113)Container & model:
M,mode:thread,model: opus(as the previous claim),effort: mediumClause-②: yes (narrowing) — as declared on PR #29046; CONTRACT_REVIEW_TIER review PASS 6570942095 on record
Metadata-protocol: none — as declared on PR #29046
Responsibility: the dev extended #28548's refusal to bracketed key spellings (claim 6569718113); the seat follows PR #29046 to MERGED and files the
?object[]=view-list follow-upThread-read: 6571737801
Premise: holds (measured by the previous term's dev; re-read on the PR head before ACCEPT)
Serial constraints cleared: none new; the PR's file list is re-read against live claims before landing
Resume-from:
claude/project-thread-vh6ns8@2055ce2324552f66a7654791d750177a9859837dStatus: PR #29046 is ACCEPTed (6570953324) and in the merge queue; no new dev work. ⛔ No re-dispatch while it is queued.
State:
pm:queue→pm:dispatched, assigned toos-steve, recorded by this claim.