Skip to content

Metadata API: no batch by-names read, so the Console roster gate costs one /meta/object request per name #29236

Closed

Description

@objectstack-fleet

domain:ui#1 · zhuangjianguo · session_01QsR2jUJ19MstFvFhjgiYTu

Ruled: 6580261740 · letter A · 2026-11-02T14:56Z

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.

Links back: #29121, PR #29229.

Activity

  1. added
    enhancementNew feature or request
    pm:queueReady for the PM dispatch loop
    domain:serverDomain lane — seat card indexed by label:pm:seat
    on Nov 2, 2026
  2. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: p2 · pm:queue · 2026-11-02T11:07Z

    ⛔ Not a claim.


    Generated by Claude Code

  3. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    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 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/main 31826d3318)
    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.

  4. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Nov 2, 2026
  5. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    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 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/main 31826d3318)
    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.

  6. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    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

  7. added
    needs-user-decisionBlocked on a maintainer decision — do not dispatch; decision cards only, never on a PR
    and removed
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    on Nov 2, 2026
  8. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    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 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.
    • C: widen ?id= to every type and accept a list. This changes ?id='s meaning on app and 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.
    • 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.

  9. zhuangjianguo commented on Nov 2, 2026

    @zhuangjianguo
    Collaborator

    Brief-claimed-by: session_01QsR2jV5sBSzCYNEDgpYLJw · batch #458 · 2026-11-02T14:50Z


    Generated by Claude Code

  10. 8 remaining items

  11. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    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 on bb07931c), landing now. Two things the server PR on this card inherits; the next domain:server seat's claim should name both.

    1. 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.
    2. Declaration. The spec PR declares Metadata-protocol: added (the authorable-surface/api.json shard moved by one key; check-changeset-no-major refuses none there, 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 as none from the card body.

    Card stays pm:blocked until #29722 merges; nothing here changes the ruling.

  12. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#2 · os-support-ai · session_01WGufzhJG3tKnksHVa1krBz

    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.

  13. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:blockedBlocked by another issue/PR — body carries Blocked-by: #N
    on Nov 5, 2026
  14. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#3 · os-elon-musk · session_016WV4cytQjG9X1CrCgytUM5

    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/main 66a8822b: 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)

  15. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    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 to claude/issue-<n>-<slug>)
    Session: session_016WV4cytQjG9X1CrCgytUM5 (seat) · dev card thread session_016WV4cyaiN5dg5cw1zSyihP
    Every other line of 6670429730 stands.

  16. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    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 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.

  17. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#3 · os-elon-musk · session_016WV4cytQjG9X1CrCgytUM5

    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/main 66a8822b: 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)

  18. objectstack-fleet commented on Nov 5, 2026

    @objectstack-fleet
    ContributorAuthor

    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

  19. objectstack-fleet commented on Nov 6, 2026

    @objectstack-fleet
    ContributorAuthor

    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.

    Reading Value
    PR state merged, closed this card via Fixes #29236
    Final head 621212ae
    Deviation (1) maintainer ruled 「同意,七个键落地」 (2026-11-06T03:49Z): locale joins the list door's closed query set (seven keys)
    Queue dequeued twice (a cli timeout flake, #30807; a same-group spec-liveness red from #30716, fixed there at 81d1ccf), re-armed, merged on the third run

    pm:dispatched removed; the card is closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

domain:serverDomain lane — seat card indexed by label:pm:seatenhancementNew feature or requestpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions