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: no batch by-names read, so the Console roster gate costs one /meta/object request per name #29236
Filing gate: ② out-of-scope finding, class a, from #29121 (PR #29229; report card comment 6574295250) · filed by domain:ui#1 · ⛔ Not a claim. No grade: triage sets it.
Business reason. After #29121, Console Home stops downloading the whole object registry. Instead it reads each object the app roster requires by name, one request per name: 8 requests on app-crm on every Home visit outside an app. A larger app means more round trips, and each one costs a full latency on a phone link. A single batch read would make it one request.
Measured (the #29121 dev, on the production Console with app-crm, at PR #29229 head d8b43ffa). The branch sends 28 requests in total, with no unscoped object or view list. 11 of them are by-name reads, 70 KB in all, and 8 of those are the roster gate's requiresObject union.
Wanted. The metadata list endpoint for a type (/meta/object, and generically /meta/:type) accepts a names filter, for example ?names=a,b,c, and answers only those items. The UI can then fold the roster gate's reads into one request. If this adds a query parameter to the published API, the change is a spec and API matter, so the reader decides the protocol declaration.
Reader. Server metadata API (domain:server); the Console adopts it as a follow-up in domain:ui.
Claim: PM loop round 8 · card thread · 2026-11-02T11:40Z
Session: session_01ADHkmQKwKFCp1m6Pb6Q8c1 (the seat); the card thread is named in a follow-up claim once it reports its branch
Account: os-steve (the seat's linked user; the card's assignee)
Branch: pending — the card thread's harness-pinned branch, written into a follow-up claim before the dev starts
Worktree: the card thread's own container checkout
Domain: domain:server
Seat: domain:server#5
Ruling-ref: no maintainer ruling on this card; triage grade p2 (6575623583: first check whether the existing list filter already serves a by-names read; a new query key is a protocol addition whose name goes to the maintainer before any code).
File surface: measurement of the /api/v1/meta/:type list door (packages/rest, packages/metadata-protocol); at most one test pinning an existing filter spelling. ⛔ No new query key or route, no packages/spec/**: a new key stops with needs_decision.
Container & model: S, mode:thread, model: the thread's default judgement tier, effort: medium (p2)
Clause-②: no
Metadata-protocol: none
Responsibility: the code is the metadata list door · the Console roster gate reads each required object by name, one request per name, because no batch by-names read is known · reached by every Console Home visit outside an app
Thread-read: 6575623583
Premise: holds as filed (PR #29046, merged, refuses bracketed ?id[]= on GET /meta/app; whether another spelling selects by names is what the dev measures on origin/main31826d3318)
Serial constraints cleared: measurement only; a pin-only PR touches no source.
Resume-from: none — fresh from origin/main
State: pm:queue → pm:dispatched, assigned to os-steve, recorded by this claim.
Claim: PM loop round 8 · card thread · branch named · 2026-11-02T11:45Z (supersedes 6576235563, which had the branch pending)
Session: session_01ADHkmQKwKFCp1m6Pb6Q8c1 (the seat); the card thread is session_01ADHkmNqzH9zZjokhM7K3u3
Account: os-steve (the seat's linked user; the card's assignee)
Branch: claude/project-thread-ddr31t (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#5
Ruling-ref: no maintainer ruling on this card; triage grade p2 (6575623583: first check whether the existing list filter already serves a by-names read; a new query key is a protocol addition whose name goes to the maintainer before any code).
File surface: measurement of the /api/v1/meta/:type list door (packages/rest, packages/metadata-protocol); at most one test pinning an existing filter spelling. ⛔ No new query key or route, no packages/spec/**: a new key stops with needs_decision.
Container & model: S, mode:thread, model: the thread's default judgement tier, effort: medium (p2)
Clause-②: no
Metadata-protocol: none
Responsibility: the code is the metadata list door · the Console roster gate reads each required object by name, one request per name, because no batch by-names read is known · reached by every Console Home visit outside an app
Thread-read: 6576235563
Premise: holds as filed (PR #29046, merged, refuses bracketed ?id[]= on GET /meta/app; whether another spelling selects by names is what the dev measures on origin/main31826d3318)
Serial constraints cleared: measurement only; a pin-only PR touches no source.
Resume-from: none — fresh from origin/main
State: pm:queue → pm:dispatched, assigned to os-steve, recorded by this claim.
{
"issue": 29236,
"status": "needs_decision",
"branch": "claude/project-thread-ddr31t",
"pr": null,
"session": "session_01ADHkmNqzH9zZjokhM7K3u3",
"premise_still_valid": true,
"summary": "Measured on origin/main a19759ac (code) and a showcase boot of that tree: no existing spelling on the GET /meta/:type list door selects items by name for object or any type but app. The list door reads exactly five keys (META_QUERY_ARITY_DOORS.list: package, preview, object, include, id); id narrows only metaType app, to exactly one name; object narrows only view (by bound object, not by item name). Every other key is silently ignored (the route declares no closed set), so ?names= / ?name= / ?ids= / ?filter= / ?id[]= on /meta/object all answer the full 115-item, 746 KB list with 200; repeated ?id= is a 400 arity refusal on every type. The store read (getMetaItems -> readFlattenedMetaItems) loads the whole type list; GetMetaItemsRequestSchema has no names member. A batch by-names read therefore needs a new query key: stopping with needs_decision, no code, no PR.",
"tests": "Showcase boot (examples/app-showcase `objectstack dev --seed-admin --fresh -p 38917`, signed in as the seeded admin), each GET /api/v1/meta/...: object -> 200 746514B n=115; object?id=showcase_account -> same 746514B n=115; object?name=, ?names=showcase_account,showcase_contact, ?ids=, ?id[]=, ?filter= -> each 200 746514B n=115; object?id=a&id=b -> 400 VALIDATION_ERROR (id supplied 2 times); view -> 200 24009B n=36, view?names=x and view?id=x -> same n=36; app -> n=3; app?id=showcase_app -> 200 7368B n=1; app?id=a&id=b -> 400; app?id[]=showcase -> 400 bracketed-id refusal; app?names=showcase -> n=3 (ignored). By-name reads for comparison: object/showcase_account 10174B, object/showcase_contact 5875B. App bundle /meta/app/showcase_app/bundle 301937B. Build: turbo build --filter=@objectstack/example-showcase... under os-verify-lock, VERDICT command-exit 0 (132s). Server killed by its recorded PID, port confirmed free.",
"gates": "none: no diff, no PR (dispatch-gates not run: empty change set).",
"dogfood_battery": "n/a: no PR",
"mcp_calls": "2: mcp__github__issue_read get, mcp__github__issue_read get_comments (reads only)",
"api_writes": "1: this os-dev-report comment on #29236 via post-stamped.mjs",
"files_changed": [],
"line_budget": "n/a: no diff",
"deviations": [
"Booted the showcase through its own package dev script (cd examples/app-showcase; pnpm dev --fresh -p 38917) instead of root `pnpm dev`: root dev's check-dev-prereqs refuses until all 106 workspace packages (35 ui/ packages) have dist; the showcase closure itself was built by turbo first. Measurement only, no code ran from an unbuilt package."
],
"open_questions": [
{
"question": "Which spelling serves a batch by-names list read on GET /meta/:type (protocol addition, maintainer names it)?",
"options": [
"A ?names=a,b,c on every /meta/:type list: one comma-separated value (fits the existing arity rule that refuses a repeated key; machine names are snake_case so a comma never occurs in a name). Narrowing step in createMetaListAnswer after the per-caller gate and before the object mask, so masking and translation run only on the named items; empty value refused 400 like ?id=; unknown names simply absent (no 404). Pushed down to the store read as GetMetaItemsRequest.names so the protocol filters before decorating. Files: packages/spec/src/api/protocol.zod.ts (GetMetaItemsRequestSchema + gen:schema/gen:docs/api-surface artifacts), packages/rest/src/meta-item-read-gate.ts (META_QUERY_ARITY_DOORS.list, the chain step, the empty refusal), packages/rest/src/meta-collection-routes.ts (listRequest), packages/runtime/src/domains/meta.ts (dispatcher twin pass-through; meta-list-projection-parity.test.ts census), packages/metadata-protocol/src/protocol.ts (readFlattenedMetaItems filter), packages/client/src/index.ts (meta.getItems options). Size ~150-250 src lines + tests; minor changeset on spec/rest/metadata-protocol/client; Metadata-protocol: none (API, not authorable metadata) but Clause-2 wording to be set by the seat.",
"B Same key, chain-only: narrow in createMetaListAnswer (rest + runtime parity), no spec/store change. Smaller (~60 src lines + tests) and fixes the wire cost (746 KB -> only the named items), but the server still reads the full type list per request.",
"C Generalise the existing ?id= to every type and accept a comma list: reuses a known key but changes its meaning on app (today exactly one name) and collides with the bracketed-id refusal PR #29046 just shipped.",
"D Add no key: the Console keeps one by-name read per required object (8 on app-crm)."
],
"recommendation": "A, because it fixes both the round trips and the server-side full-list read, keeps one spelling for every type, fits the arity and empty-value rules the door already has, and leaves ?id='s just-shipped one-app meaning alone. If the maintainer wants the smallest step first, B now and the store push-down later is a clean split."
}
],
"security_findings": "none",
"out_of_scope_findings": [
"carrier: the names decision on this card · noted, not filed: GET /meta/:type declares no closed query-parameter set (AGENTS.md Route & surface ownership 5; existing routes convert per lane), so a misspelt filter (?names= today, or ?id= on any type but app) answers the full list with 200, indistinguishable from a real answer. Adding the new key is the natural moment to declare the list's closed set (refuseUnknownQueryParams with package, preview, object, include, id, the new key)."
]
}
The dev measured first and stopped with needs_decision (report 6576480506, at 2026-11-02T11:53Z). No existing spelling on GET /meta/:type selects list items by name, except ?id= on app, which takes exactly one name. A batch by-names read therefore needs a new public query key. Naming a public API key is the maintainer's call. The card thread is parked on claude/project-thread-ddr31t with no diff and no PR.
The question (maintainer):
A (seat recommends): add ?names=a,b,c on every /meta/:type list, as one comma-separated value. Narrow after the per-caller gate and push the filter down to the store read (GetMetaItemsRequest.names), so masking and translation run only on the named items. An empty value is refused with 400, and an unknown name is simply absent. This adds to the protocol: a spec, rest, metadata-protocol and client minor, about 150–250 source lines plus tests. The spec part goes to the spec lane first.
B: the same key, narrowed in the rest chain only, with no spec or store change (about 60 lines). It fixes the wire cost, but the server still reads the full list.
D: add no key. The Console keeps one request per name (8 on app-crm).
Why A: one spelling for every type. It fits the door's existing arity and empty-value rules, fixes both the round trips and the server's full-list read, and leaves ?id= alone. Adding the key is also the natural moment to declare the list door's closed set of query parameters (the dev's out-of-scope note).
State: pm:dispatched → needs-user-decision. The card thread stays parked until the ruling.
Spec half of ruling A (6580261740): PR #29722 for #29441, contract review PASS (6594380969 on 064d4e01, delta on bb07931c), landing now. Two things the server PR on this card inherits; the next domain:server seat's claim should name both.
Drop the marker in the serving change.GetMetaItemsRequestSchema.names ships with a describe that opens [PLANNED — not yet served] and ends "No list door reads it yet: until one does, a request carrying it is answered as if it were absent." A pin in packages/spec/src/api/protocol.test.ts asserts that prefix, so the PR that serves ?names= must, in the same change, remove the prefix and the trailing sentence, delete that one it(...), and run gen:docs (moves content/docs/references/api/protocol.mdx). That is one packages/spec edit outside the rest / runtime / metadata-protocol / client workload the ruling lists.
Blocker landed.#29441 closed: PR #29722 merged (6f094645), so GetMetaItemsRequestSchema.names is on main with the [PLANNED — not yet served] marker. This card's Blocked-by: #29441 (6591626191) is met; the pm:blocked → pm:queue flip and the pm:blocking sweep on #29441 are the triage sweep's. The serving PR carries the two items in 6594515725.
Claim: PM loop round 1 · 2026-11-05T21:47Z
Session: session_016WV4cytQjG9X1CrCgytUM5
Account: os-elon-musk (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/issue-29236-meta-names-read
Worktree: objectstack-issue-29236
Domain: domain:server
Seat: domain:server#3
File surface: ruling A's server workload (6580261740): packages/rest/src/meta-item-read-gate.ts (META_QUERY_ARITY_DOORS.list, the narrowing chain step after the per-caller gate, the empty-value 400, the list door's closed query set via refuseUnknownQueryParams), packages/rest/src/meta-collection-routes.ts (listRequest), packages/runtime/src/domains/meta.ts (dispatcher twin + meta-list-projection-parity census), packages/metadata-protocol (readFlattenedMetaItems names filter), packages/client/src/index.ts (meta.getItems options), tests beside each; plus the one inherited packages/spec edit named in 6594515725 (drop the [PLANNED — not yet served] prefix and trailing sentence on GetMetaItemsRequestSchema.names in packages/spec/src/api/protocol.zod.ts, delete the one marker it(...) in protocol.test.ts, gen:docs moving content/docs/references/api/protocol.mdx); root .changeset/ files (stop on breach; explain in the report)
Container & model: M, mode:thread, model: default build (dispatch-gates --tier: no path-derived mandate; floor sonnet · default opus · ceiling fable), contract review at CONTRACT_REVIEW_TIER before the queue (the closed query set narrows the published list door, and the PR edits a packages/spec describe), effort: high
Clause-②: no
Metadata-protocol: none
Responsibility: the /meta/:type list door (packages/rest) reads no names filter and declares no closed query set, so the Console roster gate pays one request per name and a misspelt filter answers the full list with 200 | none | every Console Home visit outside an app (8 reads on app-crm, measured in 6576480506)
Thread-read: 6595098031
Premise: holds — unblocked: the wait was on #29441, closed 2026-11-03T03:58Z (PR #29722 merged 6f094645); re-derived on origin/main66a8822b: protocol.zod.ts still carries the [PLANNED — not yet served] marker on names, so nothing serves it yet
Serial constraints cleared: open PR #30459 (#30391, ACCEPTed, awaiting the maintainer) touches packages/rest/src/meta-item-read-gate.ts in another region (the plural-label read); disjoint by region, the later lander merges main. No other open PR or in-flight claim names the files above (19 open non-mailbox PRs read at claim time)
Claim amendment to 6670429730 · 2026-11-05T21:51Z
Branch: claude/project-thread-ibfnsp (the card thread's designated push branch, the recorded platform exception to claude/issue-<n>-<slug>)
Session: session_016WV4cytQjG9X1CrCgytUM5 (seat) · dev card thread session_016WV4cyaiN5dg5cw1zSyihP
Every other line of 6670429730 stands.
Claim amendment to 6670429730 · 2026-11-05T22:20Z
Clause-②: yes
The dev re-derived it from the diff: the list door's closed query set is the narrowing ruling 6580261740 names, and serving the declared names key plus meta.getItems({ names }) and three new @objectstack/rest exports the dispatcher twin needs (META_LIST_QUERY_PARAMS, metaListQueryRefusal, metaListNames) is the widening half. The card stays in this lane because the ruling assigns this workload to the domain:server PR; the contract-review-tier review before the queue covers both halves.
File surface adds: content/docs/protocol/kernel/http-protocol.mdx (one paragraph: ?names= and the closed set). Skills-docs: follow-up owed for skills/objectstack-api/SKILL.md (the seat files it before ACCEPT).
Every other line stands.
Claim: PM loop round 1 · 2026-11-05T22:46Z
Session: session_016WV4cytQjG9X1CrCgytUM5 (seat) · dev card thread session_016WV4cyaiN5dg5cw1zSyihP
Account: os-elon-musk (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/project-thread-ibfnsp (the card thread's designated push branch, the recorded platform exception to claude/issue-<n>-<slug>)
Worktree: objectstack-issue-29236
Supersedes: claim 6670429730 and its amendments 6670501210, 6671057079 (re-posted whole so the closing-target guard reads the live branch)
Domain: domain:server
Seat: domain:server#3
File surface: ruling A's server workload (6580261740): packages/rest/src/meta-item-read-gate.ts (META_QUERY_ARITY_DOORS.list, the narrowing chain step after the per-caller gate, the empty-value 400, the list door's closed query set via refuseUnknownQueryParams), packages/rest/src/meta-collection-routes.ts (listRequest), packages/runtime/src/domains/meta.ts (dispatcher twin + meta-list-projection-parity census), packages/metadata-protocol (readFlattenedMetaItems names filter), packages/client/src/index.ts (meta.getItems options), tests beside each; plus the one inherited packages/spec edit named in 6594515725 (drop the [PLANNED — not yet served] prefix and trailing sentence on GetMetaItemsRequestSchema.names in packages/spec/src/api/protocol.zod.ts, delete the one marker it(...) in protocol.test.ts, gen:docs moving content/docs/references/api/protocol.mdx); root .changeset/ files; content/docs/protocol/kernel/http-protocol.mdx (one paragraph: ?names= and the closed set) (stop on breach; explain in the report)
Container & model: M, mode:thread, model: default build (dispatch-gates --tier: no path-derived mandate; floor sonnet · default opus · ceiling fable), contract review at CONTRACT_REVIEW_TIER before the queue (the closed query set narrows the published list door, and the PR edits a packages/spec describe), effort: high
Clause-②: yes
Metadata-protocol: none
Responsibility: the /meta/:type list door (packages/rest) reads no names filter and declares no closed query set, so the Console roster gate pays one request per name and a misspelt filter answers the full list with 200 | none | every Console Home visit outside an app (8 reads on app-crm, measured in 6576480506)
Thread-read: 6671057079
Premise: holds — unblocked: the wait was on #29441, closed 2026-11-03T03:58Z (PR #29722 merged 6f094645); re-derived on origin/main66a8822b: protocol.zod.ts still carries the [PLANNED — not yet served] marker on names, so nothing serves it yet
Serial constraints cleared: open PR #30459 (#30391, ACCEPTed, awaiting the maintainer) touches packages/rest/src/meta-item-read-gate.ts in another region (the plural-label read); disjoint by region, the later lander merges main. No other open PR or in-flight claim names the files above (19 open non-mailbox PRs read at claim time)
{
"issue": 29236,
"status": "done",
"branch": "claude/project-thread-ibfnsp",
"pr": "https://github.com/objectstack-ai/objectstack/pull/30709",
"session": "session_016WV4cyaiN5dg5cw1zSyihP",
"premise_still_valid": true,
"summary": "Ruling A (6580261740) served. GET /meta/:type (REST and the runtime dispatcher, both scopes) reads ?names=a,b,c: one comma-separated value, trimmed/deduped (metaListNames); an empty value is a located 400 VALIDATION_ERROR (param names) before the store read; an unknown name is simply absent. The names are pushed down as GetMetaItemsRequest.names (getMetaItems/readFlattenedMetaItems filter after the merge, before nav contributions/locks/governance), and chain step 2a in createMetaListAnswer narrows after the per-caller gate and before the object mask/translation. The list declares its closed query set META_LIST_QUERY_PARAMS (package, preview, object, include, id, names, locale) judged by unknownQueryParamRefusalMessage before arity (metaListQueryRefusal); the bracketed keys with a located refusal keep it (package[ always, id[ on app, object[ on view). names joins META_QUERY_ARITY_DOORS.list. client meta.getItems (unscoped + scoped) takes { names }. Spec: the [PLANNED — not yet served] marker on GetMetaItemsRequestSchema.names retired, marker test deleted, gen:docs. One paragraph in http-protocol.mdx.",
"tests": "New: rest meta-list-names-filter.test.ts (reading, chain step on object with mask+translation seeing only named items, unknown absent, empty rejected before mask, app narrowed after the gate; door push-down, non-filtering store on object/view(+object=), absent names not sent, empty 400 with no store read, unknown 200 empty); rest meta-query-arity-doors.test.ts closed-set describe (recognition before arity, declared keys accepted, undeclared and bracketed refused, ?locale=zh-CN 200); metadata-protocol protocol.meta-list-names.test.ts (5); runtime dispatcher-query-arity.test.ts (recognition, push-down, locale, empty) and meta-list-projection-parity.test.ts (5 new probes + META_LIST_QUERY_PARAMS equals the derived read set); client.test.ts names URL unscoped/scoped. Two meta-app-publish-gate.test.ts controls (id[] on view, object[] on app) flip 200 -> 400. Ablations, each red: rest recognition off (12), locale dropped (3), chain step off (5), chain step after the mask (3), rest empty refusal off (5), rest push-down off (1), dispatcher recognition off (census red), dispatcher push-down off, dispatcher empty refusal off, protocol filter off (4), client names off. Suites at c2b596eb (pre-merge): rest 394 files green; census + dispatcher 1330; protocol 12; client 228; spec protocol.test green. typecheck exit 0: rest, metadata-protocol, client, runtime, spec (spec with an 8 GB heap).",
"gates": "After git merge origin/main (4bf9a2d7, includes #30459) + pnpm install --frozen-lockfile + whole-tree turbo build (119/119): node scripts/pm/dispatch-gates.mjs --commands at 5f55d49c derives 106 families (identical list to the pre-merge round at c2b596eb); all 106 + 6 extras (check:meta-url-spelling, check:authz-resolver, check:changeset-fixed, check:error-code-casing, check:route-ledger-census, pnpm lint) exit 0, run with NODE_OPTIONS=--max-old-space-size=8192 (spec check:test-typecheck OOMs at the default heap, environmental). --ran reconcile: 106 derived, 106 run, 0 NOT-MEASURED, 0 UNRUN. Round 1 at c2b596eb (pre-merge, no whole-tree build): 109/112 exit 0; check:generated OOM (green on rerun with the heap), check:skill-examples and check:dual-build-cjs-loads exit 3 (needed the whole-tree build; both 0 in round 2). CI on PR #30709 at 5f55d49c: 57 success, 8 skipped, 0 failed.",
"line_budget": "+783 / -43 over 19 files (source +283/-24, tests +500/-19; under 3000)",
"files_changed": [
".changeset/29236-meta-list-names-filter.md",
"content/docs/protocol/kernel/http-protocol.mdx (one paragraph)",
"content/docs/references/api/protocol.mdx (generated)",
"packages/client/src/index.ts",
"packages/client/src/client.test.ts",
"packages/metadata-protocol/src/protocol-meta-list-reads.ts",
"packages/metadata-protocol/src/protocol.ts",
"packages/metadata-protocol/src/protocol.meta-list-names.test.ts",
"packages/rest/src/index.ts",
"packages/rest/src/meta-collection-routes.ts",
"packages/rest/src/meta-item-read-gate.ts",
"packages/rest/src/meta-list-names-filter.test.ts",
"packages/rest/src/meta-query-arity-doors.test.ts",
"packages/rest/src/meta-app-publish-gate.test.ts",
"packages/runtime/src/domains/meta.ts",
"packages/runtime/src/domains/dispatcher-query-arity.test.ts",
"packages/runtime/src/domains/meta-list-projection-parity.test.ts",
"packages/spec/src/api/protocol.zod.ts (describe)",
"packages/spec/src/api/protocol.test.ts (marker test deleted)"
],
"deviations": [
"locale joins the closed set (seat-accepted, veto point at ACCEPT). The ruling's line: \"The same server PR declares the list door's closed set of query parameters (`package, preview, object, include, id, names`)\". The list door already reads ?locale= (extractLocale in the translation step), so a six-key set would refuse ?locale=zh-CN, which answers 200 today; keeping it is keeping behaviour, not widening. Pinned on both transports; the census derives locale from source.",
"Patch levels, not the ruling's minor (seat-accepted): check-changeset-no-major requires patch on every entry when the PR declares Metadata-protocol: none.",
"content/docs/protocol/kernel/http-protocol.mdx paragraph is outside the ruling's file list; the seat added it to the claim.",
"Two existing controls in meta-app-publish-gate.test.ts (bracketed id[] on view, object[] on app) flip from 200 (ignored) to 400 recognition refusals, as the closed set requires.",
"package list items carry no name, so ?names= on /meta/package matches none (200, empty list). Noted, not changed."
],
"clause_2": "yes (narrowing + widening) — narrowing: the list refuses any query name outside the seven with 400 VALIDATION_ERROR where it ignored it (BREAKING section + adr-0087: not-required (no-migration-prescription) on the changeset); widening: ?names= served, client meta.getItems { names }, and three new @objectstack/rest exports META_LIST_QUERY_PARAMS, metaListQueryRefusal, metaListNames. The ruling assigns both halves to this server PR. Metadata-protocol: none (an API query key, not authorable metadata).",
"skills_docs": "follow-up #30710",
"acceptance_notes": "ui follow-up is #29444 (Console Home roster gate folds its by-name reads into one ?names= request); ui/** untouched.",
"dogfood_battery": "run at head 5f55d49c, full (unsharded): pnpm turbo run test --filter=@objectstack/dogfood after the whole-tree build and rm -rf packages/runtime/.objectstack; exit 0; 421 files passed / 3 skipped (424), 3513 tests passed / 36 skipped (3549). No red to fix or report. (The ERROR/WARN log lines in the run, hook sandbox capability, locale validation, UNIQUE constraint, come from a run in which every test passed.)",
"mcp_calls": "0 — no MCP GitHub calls (reads via gh api GET; subscribe_pr_activity is a session subscription, not a GitHub write)",
"api_writes": "git push x2 to claude/project-thread-ibfnsp; relay writes 2: pr_create (fw-20261105T225448Z-501626, PR #30709, 10934 bytes identical) and this report comment",
"open_questions": [],
"security_findings": "none",
"out_of_scope_findings": []
}
Activity
objectstack-fleet commentedon Nov 2, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: p2 ·
pm:queue· 2026-11-02T11:07Z⛔ Not a claim.
?id[]=, see Metadata API: GET /api/v1/meta/app?id[]=NAME (bracketed array spelling) ignores the filter and answers the caller's full app list #28930 / PR fix(rest)!: GET /meta/app refuses a bracketed id key (?id[]=, ?id[0]=) instead of answering every app #29046) already serves this. Only if a new query key is needed does it become a protocol addition: then p1, and the new name goes to the maintainer before any code.Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:server#5 · os-steve · session_01ADHkmQKwKFCp1m6Pb6Q8c1
Claim: PM loop round 8 · card thread · 2026-11-02T11:40Z
Session:
session_01ADHkmQKwKFCp1m6Pb6Q8c1(the seat); the card thread is named in a follow-up claim once it reports its branchAccount:
os-steve(the seat's linked user; the card's assignee)Branch: pending — the card thread's harness-pinned branch, written into a follow-up claim before the dev starts
Worktree: the card thread's own container checkout
Domain:
domain:serverSeat:
domain:server#5Ruling-ref: no maintainer ruling on this card; triage grade p2 (6575623583: first check whether the existing list filter already serves a by-names read; a new query key is a protocol addition whose name goes to the maintainer before any code).
File surface: measurement of the
/api/v1/meta/:typelist door (packages/rest,packages/metadata-protocol); at most one test pinning an existing filter spelling. ⛔ No new query key or route, nopackages/spec/**: a new key stops with needs_decision.Container & model:
S,mode:thread, model: the thread's default judgement tier,effort: medium(p2)Clause-②: no
Metadata-protocol: none
Responsibility: the code is the metadata list door · the Console roster gate reads each required object by name, one request per name, because no batch by-names read is known · reached by every Console Home visit outside an app
Thread-read: 6575623583
Premise: holds as filed (PR #29046, merged, refuses bracketed
?id[]=onGET /meta/app; whether another spelling selects by names is what the dev measures onorigin/main31826d3318)Serial constraints cleared: measurement only; a pin-only PR touches no source.
Resume-from: none — fresh from
origin/mainState:
pm:queue→pm:dispatched, assigned toos-steve, recorded by this claim.objectstack-fleet commentedon Nov 2, 2026
domain:server#5 · os-steve · session_01ADHkmQKwKFCp1m6Pb6Q8c1
Claim: PM loop round 8 · card thread · branch named · 2026-11-02T11:45Z (supersedes 6576235563, which had the branch pending)
Session:
session_01ADHkmQKwKFCp1m6Pb6Q8c1(the seat); the card thread issession_01ADHkmNqzH9zZjokhM7K3u3Account:
os-steve(the seat's linked user; the card's assignee)Branch:
claude/project-thread-ddr31t(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#5Ruling-ref: no maintainer ruling on this card; triage grade p2 (6575623583: first check whether the existing list filter already serves a by-names read; a new query key is a protocol addition whose name goes to the maintainer before any code).
File surface: measurement of the
/api/v1/meta/:typelist door (packages/rest,packages/metadata-protocol); at most one test pinning an existing filter spelling. ⛔ No new query key or route, nopackages/spec/**: a new key stops with needs_decision.Container & model:
S,mode:thread, model: the thread's default judgement tier,effort: medium(p2)Clause-②: no
Metadata-protocol: none
Responsibility: the code is the metadata list door · the Console roster gate reads each required object by name, one request per name, because no batch by-names read is known · reached by every Console Home visit outside an app
Thread-read: 6576235563
Premise: holds as filed (PR #29046, merged, refuses bracketed
?id[]=onGET /meta/app; whether another spelling selects by names is what the dev measures onorigin/main31826d3318)Serial constraints cleared: measurement only; a pin-only PR touches no source.
Resume-from: none — fresh from
origin/mainState:
pm:queue→pm:dispatched, assigned toos-steve, recorded by this claim.objectstack-fleet commentedon Nov 2, 2026
domain:server#5 · os-steve · session_01ADHkmNqzH9zZjokhM7K3u3
os-dev-report
{ "issue": 29236, "status": "needs_decision", "branch": "claude/project-thread-ddr31t", "pr": null, "session": "session_01ADHkmNqzH9zZjokhM7K3u3", "premise_still_valid": true, "summary": "Measured on origin/main a19759ac (code) and a showcase boot of that tree: no existing spelling on the GET /meta/:type list door selects items by name for object or any type but app. The list door reads exactly five keys (META_QUERY_ARITY_DOORS.list: package, preview, object, include, id); id narrows only metaType app, to exactly one name; object narrows only view (by bound object, not by item name). Every other key is silently ignored (the route declares no closed set), so ?names= / ?name= / ?ids= / ?filter= / ?id[]= on /meta/object all answer the full 115-item, 746 KB list with 200; repeated ?id= is a 400 arity refusal on every type. The store read (getMetaItems -> readFlattenedMetaItems) loads the whole type list; GetMetaItemsRequestSchema has no names member. A batch by-names read therefore needs a new query key: stopping with needs_decision, no code, no PR.", "tests": "Showcase boot (examples/app-showcase `objectstack dev --seed-admin --fresh -p 38917`, signed in as the seeded admin), each GET /api/v1/meta/...: object -> 200 746514B n=115; object?id=showcase_account -> same 746514B n=115; object?name=, ?names=showcase_account,showcase_contact, ?ids=, ?id[]=, ?filter= -> each 200 746514B n=115; object?id=a&id=b -> 400 VALIDATION_ERROR (id supplied 2 times); view -> 200 24009B n=36, view?names=x and view?id=x -> same n=36; app -> n=3; app?id=showcase_app -> 200 7368B n=1; app?id=a&id=b -> 400; app?id[]=showcase -> 400 bracketed-id refusal; app?names=showcase -> n=3 (ignored). By-name reads for comparison: object/showcase_account 10174B, object/showcase_contact 5875B. App bundle /meta/app/showcase_app/bundle 301937B. Build: turbo build --filter=@objectstack/example-showcase... under os-verify-lock, VERDICT command-exit 0 (132s). Server killed by its recorded PID, port confirmed free.", "gates": "none: no diff, no PR (dispatch-gates not run: empty change set).", "dogfood_battery": "n/a: no PR", "mcp_calls": "2: mcp__github__issue_read get, mcp__github__issue_read get_comments (reads only)", "api_writes": "1: this os-dev-report comment on #29236 via post-stamped.mjs", "files_changed": [], "line_budget": "n/a: no diff", "deviations": [ "Booted the showcase through its own package dev script (cd examples/app-showcase; pnpm dev --fresh -p 38917) instead of root `pnpm dev`: root dev's check-dev-prereqs refuses until all 106 workspace packages (35 ui/ packages) have dist; the showcase closure itself was built by turbo first. Measurement only, no code ran from an unbuilt package." ], "open_questions": [ { "question": "Which spelling serves a batch by-names list read on GET /meta/:type (protocol addition, maintainer names it)?", "options": [ "A ?names=a,b,c on every /meta/:type list: one comma-separated value (fits the existing arity rule that refuses a repeated key; machine names are snake_case so a comma never occurs in a name). Narrowing step in createMetaListAnswer after the per-caller gate and before the object mask, so masking and translation run only on the named items; empty value refused 400 like ?id=; unknown names simply absent (no 404). Pushed down to the store read as GetMetaItemsRequest.names so the protocol filters before decorating. Files: packages/spec/src/api/protocol.zod.ts (GetMetaItemsRequestSchema + gen:schema/gen:docs/api-surface artifacts), packages/rest/src/meta-item-read-gate.ts (META_QUERY_ARITY_DOORS.list, the chain step, the empty refusal), packages/rest/src/meta-collection-routes.ts (listRequest), packages/runtime/src/domains/meta.ts (dispatcher twin pass-through; meta-list-projection-parity.test.ts census), packages/metadata-protocol/src/protocol.ts (readFlattenedMetaItems filter), packages/client/src/index.ts (meta.getItems options). Size ~150-250 src lines + tests; minor changeset on spec/rest/metadata-protocol/client; Metadata-protocol: none (API, not authorable metadata) but Clause-2 wording to be set by the seat.", "B Same key, chain-only: narrow in createMetaListAnswer (rest + runtime parity), no spec/store change. Smaller (~60 src lines + tests) and fixes the wire cost (746 KB -> only the named items), but the server still reads the full type list per request.", "C Generalise the existing ?id= to every type and accept a comma list: reuses a known key but changes its meaning on app (today exactly one name) and collides with the bracketed-id refusal PR #29046 just shipped.", "D Add no key: the Console keeps one by-name read per required object (8 on app-crm)." ], "recommendation": "A, because it fixes both the round trips and the server-side full-list read, keeps one spelling for every type, fits the arity and empty-value rules the door already has, and leaves ?id='s just-shipped one-app meaning alone. If the maintainer wants the smallest step first, B now and the store push-down later is a clean split." } ], "security_findings": "none", "out_of_scope_findings": [ "carrier: the names decision on this card · noted, not filed: GET /meta/:type declares no closed query-parameter set (AGENTS.md Route & surface ownership 5; existing routes convert per lane), so a misspelt filter (?names= today, or ?id= on any type but app) answers the full list with 200, indistinguishable from a real answer. Adding the new key is the natural moment to declare the list's closed set (refuseUnknownQueryParams with package, preview, object, include, id, the new key)." ] }Stamped 2026-11-02T11:53Z.
Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:server#5 · os-steve · session_01ADHkmQKwKFCp1m6Pb6Q8c1
Needs decision · #29236 · 2026-11-02T14:37Z
The dev measured first and stopped with
needs_decision(report 6576480506, at 2026-11-02T11:53Z). No existing spelling onGET /meta/:typeselects list items by name, except?id=onapp, which takes exactly one name. A batch by-names read therefore needs a new public query key. Naming a public API key is the maintainer's call. The card thread is parked onclaude/project-thread-ddr31twith no diff and no PR.The question (maintainer):
?names=a,b,con every/meta/:typelist, as one comma-separated value. Narrow after the per-caller gate and push the filter down to the store read (GetMetaItemsRequest.names), so masking and translation run only on the named items. An empty value is refused with 400, and an unknown name is simply absent. This adds to the protocol: a spec, rest, metadata-protocol and client minor, about 150–250 source lines plus tests. The spec part goes to the spec lane first.?id=to every type and accept a list. This changes?id='s meaning onappand collides with the bracketed-id refusal fix(rest)!: GET /meta/app refuses a bracketed id key (?id[]=, ?id[0]=) instead of answering every app #29046 just shipped.Why A: one spelling for every type. It fits the door's existing arity and empty-value rules, fixes both the round trips and the server's full-list read, and leaves
?id=alone. Adding the key is also the natural moment to declare the list door's closed set of query parameters (the dev's out-of-scope note).State:
pm:dispatched→needs-user-decision. The card thread stays parked until the ruling.zhuangjianguo commentedon Nov 2, 2026
Brief-claimed-by: session_01QsR2jV5sBSzCYNEDgpYLJw · batch #458 · 2026-11-02T14:50Z
Generated by Claude Code
8 remaining items
objectstack-fleet commentedon Nov 3, 2026
domain:spec#2 · os-support-ai · session_01WGufzhJG3tKnksHVa1krBz
Spec half of ruling A (6580261740): PR #29722 for #29441, contract review PASS (6594380969 on
064d4e01, delta onbb07931c), landing now. Two things the server PR on this card inherits; the nextdomain:serverseat's claim should name both.GetMetaItemsRequestSchema.namesships with a describe that opens[PLANNED — not yet served]and ends "No list door reads it yet: until one does, a request carrying it is answered as if it were absent." A pin inpackages/spec/src/api/protocol.test.tsasserts that prefix, so the PR that serves?names=must, in the same change, remove the prefix and the trailing sentence, delete that oneit(...), and rungen:docs(movescontent/docs/references/api/protocol.mdx). That is onepackages/specedit outside the rest / runtime / metadata-protocol / client workload the ruling lists.Metadata-protocol: added(theauthorable-surface/api.jsonshard moved by one key;check-changeset-no-majorrefusesnonethere, precedents feat(spec): the package export manifest declares withheldMaps, classified door for the unmanaged import #29521 and feat(spec): declare the whole-deployment export, every installed package as installable packages in one read (PackageExportBundleSchema) #29100). The server PR's own declaration is judged on its own diff; it is not inherited asnonefrom the card body.Card stays
pm:blockeduntil #29722 merges; nothing here changes the ruling.objectstack-fleet commentedon Nov 3, 2026
domain:spec#2 · os-support-ai · session_01WGufzhJG3tKnksHVa1krBz
Blocker landed. #29441 closed: PR #29722 merged (
6f094645), soGetMetaItemsRequestSchema.namesis onmainwith the[PLANNED — not yet served]marker. This card'sBlocked-by: #29441(6591626191) is met; thepm:blocked→pm:queueflip and thepm:blockingsweep on #29441 are the triage sweep's. The serving PR carries the two items in 6594515725.objectstack-fleet commentedon Nov 5, 2026
domain:server#3 · os-elon-musk · session_016WV4cytQjG9X1CrCgytUM5
Claim: PM loop round 1 · 2026-11-05T21:47Z
Session:
session_016WV4cytQjG9X1CrCgytUM5Account:
os-elon-musk(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-29236-meta-names-readWorktree:
objectstack-issue-29236Domain:
domain:serverSeat:
domain:server#3File surface: ruling A's server workload (6580261740):
packages/rest/src/meta-item-read-gate.ts(META_QUERY_ARITY_DOORS.list, the narrowing chain step after the per-caller gate, the empty-value 400, the list door's closed query set viarefuseUnknownQueryParams),packages/rest/src/meta-collection-routes.ts(listRequest),packages/runtime/src/domains/meta.ts(dispatcher twin +meta-list-projection-paritycensus),packages/metadata-protocol(readFlattenedMetaItemsnames filter),packages/client/src/index.ts(meta.getItemsoptions), tests beside each; plus the one inheritedpackages/specedit named in 6594515725 (drop the[PLANNED — not yet served]prefix and trailing sentence onGetMetaItemsRequestSchema.namesinpackages/spec/src/api/protocol.zod.ts, delete the one markerit(...)inprotocol.test.ts,gen:docsmovingcontent/docs/references/api/protocol.mdx); root.changeset/files (stop on breach; explain in the report)Container & model:
M,mode:thread,model: defaultbuild (dispatch-gates --tier: no path-derived mandate; floor sonnet · default opus · ceiling fable), contract review atCONTRACT_REVIEW_TIERbefore the queue (the closed query set narrows the published list door, and the PR edits apackages/specdescribe),effort: highClause-②: no
Metadata-protocol: none
Responsibility: the
/meta/:typelist door (packages/rest) reads no names filter and declares no closed query set, so the Console roster gate pays one request per name and a misspelt filter answers the full list with 200 | none | every Console Home visit outside an app (8 reads on app-crm, measured in 6576480506)Thread-read: 6595098031
Premise: holds — unblocked: the wait was on #29441, closed 2026-11-03T03:58Z (PR #29722 merged
6f094645); re-derived onorigin/main66a8822b:protocol.zod.tsstill carries the[PLANNED — not yet served]marker onnames, so nothing serves it yetSerial constraints cleared: open PR #30459 (#30391, ACCEPTed, awaiting the maintainer) touches
packages/rest/src/meta-item-read-gate.tsin another region (the plural-label read); disjoint by region, the later lander mergesmain. No other open PR or in-flight claim names the files above (19 open non-mailbox PRs read at claim time)objectstack-fleet commentedon Nov 5, 2026
domain:server#3 · os-elon-musk · session_016WV4cytQjG9X1CrCgytUM5
Claim amendment to 6670429730 · 2026-11-05T21:51Z
Branch:
claude/project-thread-ibfnsp(the card thread's designated push branch, the recorded platform exception toclaude/issue-<n>-<slug>)Session:
session_016WV4cytQjG9X1CrCgytUM5(seat) · dev card threadsession_016WV4cyaiN5dg5cw1zSyihPEvery other line of 6670429730 stands.
feat(rest)!: serve ?names= on the /meta/:type list and close its quer…
objectstack-fleet commentedon Nov 5, 2026
domain:server#3 · os-elon-musk · session_016WV4cytQjG9X1CrCgytUM5
Claim amendment to 6670429730 · 2026-11-05T22:20Z
Clause-②: yes
The dev re-derived it from the diff: the list door's closed query set is the narrowing ruling 6580261740 names, and serving the declared
nameskey plusmeta.getItems({ names })and three new@objectstack/restexports the dispatcher twin needs (META_LIST_QUERY_PARAMS,metaListQueryRefusal,metaListNames) is the widening half. The card stays in this lane because the ruling assigns this workload to thedomain:serverPR; the contract-review-tier review before the queue covers both halves.File surface adds:
content/docs/protocol/kernel/http-protocol.mdx(one paragraph:?names=and the closed set).Skills-docs:follow-up owed forskills/objectstack-api/SKILL.md(the seat files it before ACCEPT).Every other line stands.
objectstack-fleet commentedon Nov 5, 2026
domain:server#3 · os-elon-musk · session_016WV4cytQjG9X1CrCgytUM5
Claim: PM loop round 1 · 2026-11-05T22:46Z
Session:
session_016WV4cytQjG9X1CrCgytUM5(seat) · dev card threadsession_016WV4cyaiN5dg5cw1zSyihPAccount:
os-elon-musk(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/project-thread-ibfnsp(the card thread's designated push branch, the recorded platform exception toclaude/issue-<n>-<slug>)Worktree:
objectstack-issue-29236Supersedes: claim 6670429730 and its amendments 6670501210, 6671057079 (re-posted whole so the closing-target guard reads the live branch)
Domain:
domain:serverSeat:
domain:server#3File surface: ruling A's server workload (6580261740):
packages/rest/src/meta-item-read-gate.ts(META_QUERY_ARITY_DOORS.list, the narrowing chain step after the per-caller gate, the empty-value 400, the list door's closed query set viarefuseUnknownQueryParams),packages/rest/src/meta-collection-routes.ts(listRequest),packages/runtime/src/domains/meta.ts(dispatcher twin +meta-list-projection-paritycensus),packages/metadata-protocol(readFlattenedMetaItemsnames filter),packages/client/src/index.ts(meta.getItemsoptions), tests beside each; plus the one inheritedpackages/specedit named in 6594515725 (drop the[PLANNED — not yet served]prefix and trailing sentence onGetMetaItemsRequestSchema.namesinpackages/spec/src/api/protocol.zod.ts, delete the one markerit(...)inprotocol.test.ts,gen:docsmovingcontent/docs/references/api/protocol.mdx); root.changeset/files;content/docs/protocol/kernel/http-protocol.mdx(one paragraph:?names=and the closed set) (stop on breach; explain in the report)Container & model:
M,mode:thread,model: defaultbuild (dispatch-gates --tier: no path-derived mandate; floor sonnet · default opus · ceiling fable), contract review atCONTRACT_REVIEW_TIERbefore the queue (the closed query set narrows the published list door, and the PR edits apackages/specdescribe),effort: highClause-②: yes
Metadata-protocol: none
Responsibility: the
/meta/:typelist door (packages/rest) reads no names filter and declares no closed query set, so the Console roster gate pays one request per name and a misspelt filter answers the full list with 200 | none | every Console Home visit outside an app (8 reads on app-crm, measured in 6576480506)Thread-read: 6671057079
Premise: holds — unblocked: the wait was on #29441, closed 2026-11-03T03:58Z (PR #29722 merged
6f094645); re-derived onorigin/main66a8822b:protocol.zod.tsstill carries the[PLANNED — not yet served]marker onnames, so nothing serves it yetSerial constraints cleared: open PR #30459 (#30391, ACCEPTed, awaiting the maintainer) touches
packages/rest/src/meta-item-read-gate.tsin another region (the plural-label read); disjoint by region, the later lander mergesmain. No other open PR or in-flight claim names the files above (19 open non-mailbox PRs read at claim time)docs(protocol): document ?names= and the list's closed query set; cha…
objectstack-fleet commentedon Nov 5, 2026
domain:server#3 · os-elon-musk · session_016WV4cyaiN5dg5cw1zSyihP
os-dev-report
{ "issue": 29236, "status": "done", "branch": "claude/project-thread-ibfnsp", "pr": "https://github.com/objectstack-ai/objectstack/pull/30709", "session": "session_016WV4cyaiN5dg5cw1zSyihP", "premise_still_valid": true, "summary": "Ruling A (6580261740) served. GET /meta/:type (REST and the runtime dispatcher, both scopes) reads ?names=a,b,c: one comma-separated value, trimmed/deduped (metaListNames); an empty value is a located 400 VALIDATION_ERROR (param names) before the store read; an unknown name is simply absent. The names are pushed down as GetMetaItemsRequest.names (getMetaItems/readFlattenedMetaItems filter after the merge, before nav contributions/locks/governance), and chain step 2a in createMetaListAnswer narrows after the per-caller gate and before the object mask/translation. The list declares its closed query set META_LIST_QUERY_PARAMS (package, preview, object, include, id, names, locale) judged by unknownQueryParamRefusalMessage before arity (metaListQueryRefusal); the bracketed keys with a located refusal keep it (package[ always, id[ on app, object[ on view). names joins META_QUERY_ARITY_DOORS.list. client meta.getItems (unscoped + scoped) takes { names }. Spec: the [PLANNED — not yet served] marker on GetMetaItemsRequestSchema.names retired, marker test deleted, gen:docs. One paragraph in http-protocol.mdx.", "tests": "New: rest meta-list-names-filter.test.ts (reading, chain step on object with mask+translation seeing only named items, unknown absent, empty rejected before mask, app narrowed after the gate; door push-down, non-filtering store on object/view(+object=), absent names not sent, empty 400 with no store read, unknown 200 empty); rest meta-query-arity-doors.test.ts closed-set describe (recognition before arity, declared keys accepted, undeclared and bracketed refused, ?locale=zh-CN 200); metadata-protocol protocol.meta-list-names.test.ts (5); runtime dispatcher-query-arity.test.ts (recognition, push-down, locale, empty) and meta-list-projection-parity.test.ts (5 new probes + META_LIST_QUERY_PARAMS equals the derived read set); client.test.ts names URL unscoped/scoped. Two meta-app-publish-gate.test.ts controls (id[] on view, object[] on app) flip 200 -> 400. Ablations, each red: rest recognition off (12), locale dropped (3), chain step off (5), chain step after the mask (3), rest empty refusal off (5), rest push-down off (1), dispatcher recognition off (census red), dispatcher push-down off, dispatcher empty refusal off, protocol filter off (4), client names off. Suites at c2b596eb (pre-merge): rest 394 files green; census + dispatcher 1330; protocol 12; client 228; spec protocol.test green. typecheck exit 0: rest, metadata-protocol, client, runtime, spec (spec with an 8 GB heap).", "gates": "After git merge origin/main (4bf9a2d7, includes #30459) + pnpm install --frozen-lockfile + whole-tree turbo build (119/119): node scripts/pm/dispatch-gates.mjs --commands at 5f55d49c derives 106 families (identical list to the pre-merge round at c2b596eb); all 106 + 6 extras (check:meta-url-spelling, check:authz-resolver, check:changeset-fixed, check:error-code-casing, check:route-ledger-census, pnpm lint) exit 0, run with NODE_OPTIONS=--max-old-space-size=8192 (spec check:test-typecheck OOMs at the default heap, environmental). --ran reconcile: 106 derived, 106 run, 0 NOT-MEASURED, 0 UNRUN. Round 1 at c2b596eb (pre-merge, no whole-tree build): 109/112 exit 0; check:generated OOM (green on rerun with the heap), check:skill-examples and check:dual-build-cjs-loads exit 3 (needed the whole-tree build; both 0 in round 2). CI on PR #30709 at 5f55d49c: 57 success, 8 skipped, 0 failed.", "line_budget": "+783 / -43 over 19 files (source +283/-24, tests +500/-19; under 3000)", "files_changed": [ ".changeset/29236-meta-list-names-filter.md", "content/docs/protocol/kernel/http-protocol.mdx (one paragraph)", "content/docs/references/api/protocol.mdx (generated)", "packages/client/src/index.ts", "packages/client/src/client.test.ts", "packages/metadata-protocol/src/protocol-meta-list-reads.ts", "packages/metadata-protocol/src/protocol.ts", "packages/metadata-protocol/src/protocol.meta-list-names.test.ts", "packages/rest/src/index.ts", "packages/rest/src/meta-collection-routes.ts", "packages/rest/src/meta-item-read-gate.ts", "packages/rest/src/meta-list-names-filter.test.ts", "packages/rest/src/meta-query-arity-doors.test.ts", "packages/rest/src/meta-app-publish-gate.test.ts", "packages/runtime/src/domains/meta.ts", "packages/runtime/src/domains/dispatcher-query-arity.test.ts", "packages/runtime/src/domains/meta-list-projection-parity.test.ts", "packages/spec/src/api/protocol.zod.ts (describe)", "packages/spec/src/api/protocol.test.ts (marker test deleted)" ], "deviations": [ "locale joins the closed set (seat-accepted, veto point at ACCEPT). The ruling's line: \"The same server PR declares the list door's closed set of query parameters (`package, preview, object, include, id, names`)\". The list door already reads ?locale= (extractLocale in the translation step), so a six-key set would refuse ?locale=zh-CN, which answers 200 today; keeping it is keeping behaviour, not widening. Pinned on both transports; the census derives locale from source.", "Patch levels, not the ruling's minor (seat-accepted): check-changeset-no-major requires patch on every entry when the PR declares Metadata-protocol: none.", "content/docs/protocol/kernel/http-protocol.mdx paragraph is outside the ruling's file list; the seat added it to the claim.", "Two existing controls in meta-app-publish-gate.test.ts (bracketed id[] on view, object[] on app) flip from 200 (ignored) to 400 recognition refusals, as the closed set requires.", "package list items carry no name, so ?names= on /meta/package matches none (200, empty list). Noted, not changed." ], "clause_2": "yes (narrowing + widening) — narrowing: the list refuses any query name outside the seven with 400 VALIDATION_ERROR where it ignored it (BREAKING section + adr-0087: not-required (no-migration-prescription) on the changeset); widening: ?names= served, client meta.getItems { names }, and three new @objectstack/rest exports META_LIST_QUERY_PARAMS, metaListQueryRefusal, metaListNames. The ruling assigns both halves to this server PR. Metadata-protocol: none (an API query key, not authorable metadata).", "skills_docs": "follow-up #30710", "acceptance_notes": "ui follow-up is #29444 (Console Home roster gate folds its by-name reads into one ?names= request); ui/** untouched.", "dogfood_battery": "run at head 5f55d49c, full (unsharded): pnpm turbo run test --filter=@objectstack/dogfood after the whole-tree build and rm -rf packages/runtime/.objectstack; exit 0; 421 files passed / 3 skipped (424), 3513 tests passed / 36 skipped (3549). No red to fix or report. (The ERROR/WARN log lines in the run, hook sandbox capability, locale validation, UNIQUE constraint, come from a run in which every test passed.)", "mcp_calls": "0 — no MCP GitHub calls (reads via gh api GET; subscribe_pr_activity is a session subscription, not a GitHub write)", "api_writes": "git push x2 to claude/project-thread-ibfnsp; relay writes 2: pr_create (fw-20261105T225448Z-501626, PR #30709, 10934 bytes identical) and this report comment", "open_questions": [], "security_findings": "none", "out_of_scope_findings": [] }Generated by Claude Code
objectstack-fleet commentedon Nov 6, 2026
domain:server#3 · os-elon-musk · session_016WV4cytQjG9X1CrCgytUM5
Landed · 2026-11-06T05:17Z · PR #30709 merged through the queue as
c17719dd6c. ACCEPT 6673684157, ruling record 6676369627.Fixes #29236621212aelocalejoins the list door's closed query set (seven keys)pm:dispatchedremoved; the card is closed.