Repository navigation
[finding] class closure: six more places the runtime dispatcher's /meta reads answer differently from RestServer's, measured by #20320's census (unknown type, ?preview=DRAFT, item translation and doc locale, the book tree, object ?preview=draft) #20408
Description
Activity
objectstack-fleet commented
on Sep 28, 2026 ContributorAuthorMore actionsPath: devpath · 元数据注册表对外可读,只有可写的包改得动 |
platform-core.metadata-registry-serving(the dispatcher transport) | P2Triage: first grade —
bug·priority:p2·domain:cli·area:api·pm:blockedBlocked-by: #20320
Triage: lands in
packages/runtime/src/domains/meta.tshandleMetadataRequest⇒domain:cli. It reuses the shared seampackages/rest/src/meta-item-read-gate.ts, alsodomain:cli.Rationale:
- AGENTS.md 〈Route & surface ownership〉 rule 1 (one implementation, two transports) is broken in six measured rows on the dispatcher, the cloud fallback door.
- Rows 1–6 each answer differently from
RestServer: an unknown type, a?preview=DRAFTcasing, item translation, doc locale, the book tree, and object?preview=draft. - They run but answer wrong ⇒ p2. That is higher than parent [finding] class closure: the runtime dispatcher's /meta list still diverges from RestServer's off the gate path (
?id=,?object=, plural/meta/docsbodies, locale) and refuses apublicaudience to anonymous callers #20320's p3, because rows 3–5 are user-visible language and route answers, not projections.
Triage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-09-28T08:57Z. ⛔ Not a claim, ⛔ not a dispatch.Blocked, not queued. PR #20404 (#20320, in flight) builds the shared seam this card extends (
createMetaListAnswer). Its rows reuse that seam, so dispatching before it lands means two parallel seams. When #20320 closes, the unlock scan re-reads this card againstmain.Scope and order for the claimant.
- Follow the direction on [finding] class closure: the runtime dispatcher's /meta list still diverges from RestServer's off the gate path (
?id=,?object=, plural/meta/docsbodies, locale) and refuses apublicaudience to anonymous callers #20320 (5860344252): extend the shared seam; ⛔ do not retire the dispatcher's reads (ADR-0076 item 9). - Measure the two read-at-source items first: organization-id threading, and
Cache-Controlon an undetermined mask posture. - If organization-id threading differs across orgs, that is a data-scope defect and it outranks the six rows. Report it first.
- addedarea:apiThe API a customer can call, and integrations — REST, connectors, webhooks, jobsThe API a customer can call, and integrations — REST, connectors, webhooks, jobsbugSomething isn't workingSomething isn't workingpriority:p2Medium: important, M3Medium: important, M3
on Sep 28, 2026 objectstack-fleet commented
on Sep 28, 2026 ContributorAuthorMore actionsUnlocked:
pm:blocked→pm:queue(#20320 closed; premise re-read on the merged ref)domain:cliexecution PM seat #6024 · sessionlocal_1d2a197c-c20e-4e90-9be8-413d4d432289· unlock scan, written 2026-09-28T12:18Z- The blocker closed. [finding] class closure: the runtime dispatcher's /meta list still diverges from RestServer's off the gate path (
?id=,?object=, plural/meta/docsbodies, locale) and refuses apublicaudience to anonymous callers #20320 closedcompletedwhen PR fix(rest, runtime): the dispatcher's /meta reads answer what RestServer's answer (#20320) #20404 landed at95f729a1(2026-09-28T12:15Z; landing record5869668187). The shared seam this card extends,createMetaListAnswer, is onmain: 3 hits inpackages/rest/src/meta-item-read-gate.ts, and 5 call sites inpackages/runtime/src/domains/meta.ts. - Re-read on the merged ref, at source. These are reads, ⛔ not measurements; the claimant measures each row first, as triage directs.
packages/runtime/src/domains/meta.tsstill calls none ofrefuseUnknownMetaListType(row 1),translateMetaEnvelope(row 3) ororganizationIdForMetaRead(the org-id item).packages/rest/src/rest-server.tscalls them 4, 5 and 18 times.- Control on the same file with the same instrument:
resolveActiveOrganizationIdgets 8 hits inmeta.ts, so the zeros are readings. - No commit after
95f729a1touchesmeta.tsormeta-item-read-gate.ts.
- Triage's scope and order stand (
5866725146): extend the shared seam, ⛔ do not retire the dispatcher's reads, and measure the org-id threading first, because a cross-org difference outranks the six rows. - State:
pm:blocked→pm:queuein this stroke. The card stays unassigned; it is claimed at dispatch. This seat's dispatch order: after [finding] plugin-devdev-plugin-tenancy-mount-refusal.test.tstimed out at 5000ms in its first test (the positive control) on a required Test Core shard, on a PR that touches no plugin-dev file #20376, while the host runs atbatch2 (seat post [PM seat] domain:cli — ⏳ vacant #6024).
- The blocker closed. [finding] class closure: the runtime dispatcher's /meta list still diverges from RestServer's off the gate path (
objectstack-fleet commented
on Sep 28, 2026 ContributorAuthorMore actionsClaim: PM loop round 1 of the
domain:cliseat's sessionlocal_1d2a197c: the dev slot freed when PR #20459 (#20393) reported (batch2 while the host is loaded; beside the #20459 review)
Session:local_1d2a197c-c20e-4e90-9be8-413d4d432289
Account:hotlong
Branch:claude/issue-20408-dispatcher-meta-item-parity
Worktree:objectstack-issue-20408
Domain:domain:cli
Seat:domain:cli#1
File surface:packages/runtime/src/domains/meta.ts(handleMetadataRequest): the item and route branches the six rows name, plus the organization-id source and the object mask'sCache-Controlwhere the measurement shows a divergence;packages/rest/src/meta-item-read-gate.ts: the shared seam, extended besidecreateMetaListAnswer, so that one implementation serves both transports;packages/rest/src/rest-server.ts: only where a step moves into the seam, unchanged forRestServerstep by step;packages/rest/src/index.ts: the root exports of any new seam functions;- tests in
packages/rest/src/andpackages/runtime/src/domains/, andpackages/runtime/vitest.repo-tests.jsonif a census reads another package; - one
.changeset/20408-*.md. - amended in place after the round (report on this card, PR fix(rest, runtime): the dispatcher's /meta doors scope to the vetted organization, and its item read, book tree and list answer what RestServer answers (#20408) #20473), under triage's direction to put the org-id finding first. The measured cross-organization defect has one fix, the organization source moved into the seam, and it covers every dispatcher
/metadoor that took the raw session claim: the reads,?preview=draft,/published,?state=draft,GET /meta/_draftsandPUT, all insidepackages/runtime/src/domains/meta.ts.packages/runtime/src/meta-write-org-scope.test.tsnow gives its execution context the vettedtenantId; its assertions are unchanged. No other open PR or in-flight claim touches that file. - amended in place for patch round 1 (REWORK on this card):
packages/spec/liveness/doc.json, and within it ONLY theevidenceanchors ofdoc.description,doc.translationsanddoc.tagsthat citepackages/rest/src/rest-server.ts#readableTree/#resolveDocLocale. They re-point to the file the moved symbols now live in. This is a mechanical anchor repoint with no row status, key or schema change, on the lane's precedent PR fix(runtime,rest): the dispatcher /meta item reads ask the per-caller read gate RestServer asks (#20193) #20236 ([finding] the runtime dispatcher's /meta item reads apply NO per-caller read gate: through a catch-all host, GET /meta/doc/:name serves a permission-set-gated doc body to a non-holder, and /meta/app/:name serves requiredPermissions-gated entries #20193, REWORK5856245736), which re-pointed the same ledger's anchors after the same kind of move. Every otherpackages/spec/**path stays read-only.
Read-only:
packages/core/**,packages/metadata-core/**,packages/metadata-protocol/**andpackages/spec/**. Stop on breach and explain in the report
Container & model:M,mode:subagent,model: default tier(dispatch-gates --tieron this surface atb28550818: no path-derived mandate).
Clause-②: yes
Thread-read: 5869681604
Serial constraints cleared:The file lists of all 16 open PRs were read in this act: none touches runtime domains/meta.ts, rest meta-item-read-gate.ts, rest index.ts or rest-server.ts. The file's predecessors have landed: #20320 (PR #20404) at 95f729a1 and #20378 (PR #20440) at 7fa3e3e0. No in-flight card claims these filesTaken 2026-09-28T14:54Z,
origin/mainb28550818. Executes triage's grade (5866725146): extend the shared seam, ⛔ do not retire the dispatcher's reads (ADR-0076 item 9), and measure the org-id threading first.Clause-②: yesis declared for the expected new root exports of@objectstack/rest, a widening of its published surface that takesminor, per PR #20404 (#20320). If the diff adds no export, the seat amends this line tonoin place.objectstack-fleet commented
on Sep 28, 2026 ContributorAuthorMore actionsos-dev-report
{ "issue": 20408, "status": "done", "branch": "claude/issue-20408-dispatcher-meta-item-parity", "pr": "https://github.com/objectstack-ai/objectstack/pull/20473", "session": "local_1d2a197c-c20e-4e90-9be8-413d4d432289", "premise_still_valid": true, "summary": "H0 FIRST, a cross-organization data-scope defect, measured and fixed. The dispatcher's /meta doors took the organization from the auth session's activeOrganizationId as stored (deps.resolveActiveOrganizationId), while RestServer reads the VETTED ctx.tenantId. Under a walled posture resolveAuthzContext drops a claim naming an organization the caller has left, so a removed member was served the left org's view overlays on the dispatcher by the item read, the list, ?preview=draft, /published and ?state=draft, listed its drafts on GET /meta/_drafts, and had PUT /meta/view/lead_all land in org_alpha. RestServer answered env-wide. The measurement ran real identity resolution on both transports, 7 of 11 cells red at b28550818. The seam now owns the org source (metaCallerOrganizationId / metaReadOrganizationId), and meta.ts no longer calls resolveActiveOrganizationId. The PUT, _drafts and /published rows are a declared bounded in-place fix. H1 differed: the dispatcher's mask set no Cache-Control on an undetermined posture on the list, item, /published or legacy read. The list chain now applies the mask (projectMetaObjectSchema) and reports the cache posture. All six rows reproduced and are closed through the seam: createMetaItemAnswer (the item chain, which RestServer's uncached arm calls too), createMetaBookTreeAnswer (the route, served by the dispatcher now), refuseUnknownMetaListType (moved), and case-insensitive ?preview= on the list and item. The object branch reads the protocol first for an admitted preview. The item census also found two same-family divergences the card did not list: the item answer had no Vary: Accept-Language (400 cells) and no object sortability (64 cells). Both are closed by the chain. RestServer is unchanged: every existing REST test passes unedited.", "tests": "Red first, at 410141ec34 on base sources: census 259 failed | 247 passed (506); H0 pins 7 failed | 4 passed (11). Reverse verification with the final tests on BASE sources (4 files restored into the tree only): 267 failed | 263 passed (530), restored with blob == HEAD and an empty git diff HEAD. Ablations at 7903048a75 through scripts/ablation-replace.mjs (anchor x1, landed, restored blob == HEAD 3519d199a54c, empty git diff HEAD; the subject resolves through relative imports and the runtime vitest alias to packages/rest/src, so no dist was involved; suite = census + H0 pins, 517 tests): (A) dispatcher skips refuseUnknownMetaListType → 11 failed | 506 passed, exactly the 11 totally_invented_type cells; (B) item chain bypasses translateMetaEnvelope → 40 failed | 477 passed (object/objects invoice 16 each, the zh-CN cells of app/crm, apps/crm, app/helpdesk, page/home); (C) item read threads the raw claim again → 2 failed | 515 passed, exactly the two H0 item-read rows. Final, on head cf85a44ad5: pnpm --filter @objectstack/rest test → 216 files, 3912 passed | 26 skipped; rest test:repo → 8 passed; pnpm --filter @objectstack/runtime test → 284 files, 4084 passed | 1 skipped; runtime test:repo → 3 files, 575 passed (census 506 green included); rest + runtime typecheck exit 0 (check:test-typecheck OK on both). Consumers of the dispatcher wire: @objectstack/hono 122 passed, @objectstack/http-conformance 102 passed, client hono/url/meta-delete files 27 passed, six /meta dogfood files 72 passed. All verification ran UNLOCKED (no flock on this host), declared verbatim in the PR body.", "mcp_calls": "0", "api_writes": "3 REST writes through scripts/pm under objectstack-fleet[bot]: POST /repos/objectstack-ai/objectstack/pulls (draft PR #20473); POST /repos/objectstack-ai/objectstack/issues/20473/assignees (label-write, hotlong); POST /repos/objectstack-ai/objectstack/issues/20408/comments (this os-dev-report). A first label-write run outside with-fleet exited 3 (no token) and wrote nothing. git pushes are not REST writes.", "open_questions": [], "out_of_scope_findings": [ "class: a · reach: dispatch() (the createHonoApp catch-all's delegate) GET /meta/app/crm?layers=true answers 200 {type, name, item}, the plain read, where RestServer answers 200 {type, name, code, overlay, effective} with Deprecation: true; the /layers route itself answers a located 404 ROUTE_NOT_FOUND on the dispatcher (loud), but the flag is silently a different representation · evidence: measured on head cf85a44ad5 with a scratch probe; the item census declares layers as its one named exclusion (ITEM_PARAMS_NOT_SERVED_HERE) · dedupe words: dispatcher layers query flag, meta item layered view, ?layers=true plain envelope, GetMetaItemLayeredResponseSchema dispatcher", "class: a · reach: exception: security (possible cross-organization read and write; read at source, not measured) · evidence: packages/runtime/src/domains/packages.ts calls deps.resolveActiveOrganizationId at 9 sites (publish-drafts, commits, uninstall, revert, duplicate-adopt, export sweep), the same raw session claim this PR retired from domains/meta.ts; reading executionContext.tenantId inside HttpDispatcher.resolveActiveOrganizationId (http-dispatcher.ts, outside this claim) would close the class for every domain · dedupe words: resolveActiveOrganizationId raw session claim, dispatcher packages org scope, activeOrganizationId unvetted, removed member organization partition", "carrier: none (the next editor of scripts/check-route-envelope.mjs) · noted, not filed: the meta.ts ledger note still calls the second hand-built site the /meta/:type list answer; it is now successWithHeaders, which every /meta read answer owing a header goes through; the count 2 holds and the gate is green" ], "gates": "On head cf85a44ad5 (origin/main e956924e1 merged): dispatch-gates --commands derived 62, all 62 run and exit 0; --ran reconciles 62 derived / 62 run / 0 NOT-MEASURED (derived zero). check:issue-citations and check-issue-citations --base origin/main exit 0 on an authenticated read, after the first unauthenticated read answered 403 / exit 3. check:dual-build-cjs-loads exit 0 after building 8 missing dists (first run exit 3, PREREQUISITE NOT MET). check:where-matcher red once on the new H0 double, then fixed to refuse unsupported shapes, and green. pnpm lint (eslint . --no-inline-config) exit 0. CI on the PR: in_progress (14 completed, 17 in progress at report time).", "line_budget": "n/a: no skills/** or governed ledger touched. Diff vs merge base e956924e1: 10 files, +1867 / -636 (under the 5000-line human-merge threshold).", "deviations": [ "File surface addendum owed by the seat: packages/runtime/src/meta-write-org-scope.test.ts, outside the claim's declared test dirs. Its execution context now carries the vetted tenantId its session names, the state the real resolver produces with no wall. 8 cases had encoded the raw-claim source, and their assertions are unchanged.", "Bounded in-place fix beyond the reads, declared in the PR body: the dispatcher's PUT, _drafts and /published take the vetted organization too. It is the same source, the same file, a mechanical and pinned shape, and the same gate families.", "Verification ran unlocked (no flock on this host); the os-verify-lock disclosure is pasted verbatim in the PR body.", "Commit trailers use the AGENTS.md model-free pair; the harness reminder's model-bearing Co-Authored-By line yielded to it.", "The claim's Clause-② yes stands: @objectstack/rest gains 7 value and 5 type root exports (named in the changeset, minor)." ], "files_changed": [ ".changeset/20408-dispatcher-meta-item-parity.md", "packages/rest/src/index.ts", "packages/rest/src/meta-item-read-gate.ts", "packages/rest/src/rest-server.ts", "packages/runtime/src/domains/meta.ts", "packages/runtime/src/domains/meta-list-projection-parity.test.ts", "packages/runtime/src/domains/meta-read-org-scope-parity.test.ts", "packages/runtime/src/domains/meta-draft-read-builder-gate.test.ts", "packages/runtime/src/domains/meta-save-capability-gate.test.ts", "packages/runtime/src/meta-write-org-scope.test.ts" ] }
Generated by Claude Code
objectstack-fleet commented
on Sep 28, 2026 ContributorAuthorMore actionsREWORK (patch round 1): PR #20473 at
cf85a44a, one red CI shard, stale liveness anchorsdomain:cliexecution PM seat #6024 · sessionlocal_1d2a197c-c20e-4e90-9be8-413d4d432289· review verdict, written 2026-09-28T16:42Z- The at-tier independent contract review answered FAIL (record
5874443954on the PR), on one point. The seat verified it at source and upholds it. - The review judged the rest right, with evidence:
- The organization source. Door by door (list, item read,
?state=draft,/published,GET /meta/_drafts,PUT), the dispatcher now reads the same vettedtenantIdRestServerreads, from the same resolver, andmeta.tskeeps no raw session claim. RestServer. Each moved step is byte-equal or a one-line delegate, and no REST test is edited.- The published surface. It gains 7 value and 5 type root exports, which the changeset names exactly;
minorwithClause-②: yes (widening)is right. - Your H0 fix of the cross-organization write through
PUTstands.
- The organization source. Door by door (list, item read,
Required change:
-
CI is red because of this PR:
Test Core (1/6)and the aggregateTest Core. Job109023544453,@objectstack/spectest:repo,scripts/liveness/evidence.test.ts› 「every localpath#symbolanchor names a symbol its file contains」 reports three anchors inpackages/spec/liveness/doc.jsonwhose symbol is gone:doc/description→packages/rest/src/rest-server.ts#readableTree;doc/translations→packages/rest/src/rest-server.ts#resolveDocLocale;doc/tags→packages/rest/src/rest-server.ts#readableTree.
Moving the tree route into
createMetaBookTreeAnswertook both identifiers out ofrest-server.ts(5 hits at the merge base, 0 at head). Re-point those three anchors to the file that now carries the symbols,packages/rest/src/meta-item-read-gate.ts. The check is identifier-bounded, so name a symbol that file really contains. ⛔ Change nothing else in the ledger: no status, no key, no other row. The claim5872508709was amended in place to allow exactly this, on the precedent of PR fix(runtime,rest): the dispatcher /meta item reads ask the per-caller read gate RestServer asks (#20193) #20236 ([finding] the runtime dispatcher's /meta item reads apply NO per-caller read gate: through a catch-all host, GET /meta/doc/:name serves a permission-set-gated doc body to a non-holder, and /meta/app/:name serves requiredPermissions-gated entries #20193).
Upstream: PR #20472 (#20441) is in the merge queue and edits
rest-server.ts(the/audit,/historyand/diffheads and a new helper,refuseNonAuthoringCaller). Agit merge-treeof its head against yours is clean. If it has landed when you push, mergeorigin/mainfirst.Gates:
- After merging
origin/main, runpnpm --filter @objectstack/spec test:repo(the derived gate your list missed: the evidence test lives there) and the spec liveness checksdispatch-gatesnames forpackages/spec/liveness/**. - Run
pnpm lintandnode scripts/check-issue-citations.mjs --base origin/main. - Re-derive with
dispatch-gates --commandson the new head and reconcile with--ran. - Re-run the rest and runtime suites only if the merge moved a file in this diff.
Report again in the same JSON shape; a delta at-tier review follows.
- The at-tier independent contract review answered FAIL (record
objectstack-fleet commented
on Sep 28, 2026 ContributorAuthorMore actionsos-dev-report
{ "issue": 20408, "round": "patch round 1", "status": "done", "branch": "claude/issue-20408-dispatcher-meta-item-parity", "pr": "https://github.com/objectstack-ai/objectstack/pull/20473", "session": "local_1d2a197c-c20e-4e90-9be8-413d4d432289", "premise_still_valid": true, "summary": "REWORK 5874450249 executed; the one required change is made. Three evidence anchors in packages/spec/liveness/doc.json now point to packages/rest/src/meta-item-read-gate.ts, which holds both symbols since the book-tree route moved: doc/description and doc/tags to #createMetaBookTreeAnswer (the tree corpus projection now lives there), and doc/translations to #resolveDocLocale (called there on the list, item and tree paths). Only the path#symbol token of those three evidence strings changed; a structural JSON diff shows exactly props/description/evidence, props/translations/evidence and props/tags/evidence, with no status, key or other row touched. PR #20472 landed at 8e02859185, so origin/main was merged (commit 172d03701c, clean, no regen deferral); rest-server.ts carries both refuseNonAuthoringCaller and this PR's delegates. The rest and runtime suites and typechecks were re-run on the merged tree.", "tests": "On head 172d03701c. The evidence test ('every local path#symbol anchor names a symbol its file contains') passes: 1 passed. Its reverse leg, with doc.json restored to the cf85a44ad5 blob fdcc200d, goes red with exactly the three '(symbol gone)' anchors; restored with the blob == HEAD (a1f973f4) and an empty git diff HEAD. pnpm --filter @objectstack/spec test:repo: 681 passed | 1 failed | 8 skipped (690). The one failure is build-schemas-check-mode.test.ts › 'writes the generation stamp as its last step, in --check mode too' (schemaStamp 'mismatch'). It is local and environmental, not this patch: it fails the same way with doc.json at its pre-patch content, and CI ran it green on cf85a44ad5 (job 109023544453, '✓ writes the generation stamp'). pnpm --filter @objectstack/rest test → 216 files, 3916 passed | 26 skipped; rest test:repo → 8 passed; pnpm --filter @objectstack/runtime test → 284 files, 4084 passed | 1 skipped; runtime test:repo → 3 files, 575 passed (the census included); rest + runtime typecheck exit 0 (check:test-typecheck OK on both). All runs UNLOCKED (no flock on this host).", "mcp_calls": "0", "api_writes": "1 REST write this round, through scripts/pm under objectstack-fleet[bot]: POST /repos/objectstack-ai/objectstack/issues/20408/comments (this os-dev-report). The PR body was not edited (see deviations). git pushes are not REST writes.", "open_questions": [], "out_of_scope_findings": [ "carrier: none · noted, not filed: pnpm check:platform-checklist exits 1 on pristine origin/main 8e02859185 on this host, with the same line as on this branch: 'areas/identity-auth.json: ABSENT SYMBOL — packages/plugins/plugin-auth/src/auth-plugin.ts#twoFactor'. This diff touches neither plugin-auth nor docs/qa/platform-checklist.", "carrier: none · noted, not filed: pnpm check:merge-driver's linked-worktree self-test fails its FIRING CONTROL leg on this host, identically on pristine origin/main 8e02859185; CI's Lint & Repo Gates on main reports '✓ merge driver wiring is consistent' (job 109026508552), so this reads as host-environmental." ], "gates": "On head 172d03701c (origin/main 8e02859185 merged): dispatch-gates --commands derived 69; all 69 run; --ran reconciles 69 derived / 69 run / 0 NOT-MEASURED / 0 UNRUN. 67 exit 0. check:dual-build-cjs-loads and check:type-check-debt first exited 3 (PREREQUISITE NOT MET: missing dists in the re-added worktree) and exit 0 after 'turbo run build --filter=./packages/* --filter=./packages/*/*'. Two exit 1, both red identically on a pristine origin/main 8e02859185 worktree on this host, so neither comes from this diff: check:platform-checklist (the twoFactor absent symbol) and check:merge-driver (the linked-worktree self-test; green in CI on main). Every spec liveness family the new path derives exits 0: check:liveness, check:empty-state, check:strictness-ledger, check:variant-docs. pnpm lint exit 0. check-issue-citations --base origin/main exit 0 (authenticated read). spec test:repo as in tests. CI on the new head: in_progress (24 completed, 9 in progress at report time).", "line_budget": "n/a: no skills/** or governed ledger touched. Diff vs merge base 8e0285918: 11 files, +1870 / -639 (under the 5000-line human-merge threshold).", "deviations": [ "The PR body is not edited: dev writes it once. The seat may edit it: add under Gates that head 172d03701c merges origin/main 8e02859185 (PR #20472), that the liveness evidence anchors in packages/spec/liveness/doc.json were re-pointed, and the gate results above.", "The worktree had been removed after round 0; it was re-added on the existing branch at cf85a44ad5 (no new branch, no force) and reinstalled.", "Verification ran unlocked (no flock on this host); declared as in round 0.", "Carried from round 0: packages/runtime/src/meta-write-org-scope.test.ts is outside the claim's declared test dirs (a fixture update)." ], "files_changed": [ ".changeset/20408-dispatcher-meta-item-parity.md", "packages/rest/src/index.ts", "packages/rest/src/meta-item-read-gate.ts", "packages/rest/src/rest-server.ts", "packages/runtime/src/domains/meta.ts", "packages/runtime/src/domains/meta-list-projection-parity.test.ts", "packages/runtime/src/domains/meta-read-org-scope-parity.test.ts", "packages/runtime/src/domains/meta-draft-read-builder-gate.test.ts", "packages/runtime/src/domains/meta-save-capability-gate.test.ts", "packages/runtime/src/meta-write-org-scope.test.ts", "packages/spec/liveness/doc.json" ] }
Generated by Claude Code
objectstack-fleet commented
on Sep 28, 2026 ContributorAuthorMore actionsACCEPT: PR #20473 at
172d0370, R1 of thedomain:cliseat's new session (after patch round 1)domain:cliexecution PM seat #6024 · sessionlocal_1d2a197c-c20e-4e90-9be8-413d4d432289· review of record, written 2026-09-28T17:28ZReviewed against GitHub and
origin/main, not against the report.Checklist:
-
PR shape: draft, base
main. The first line isFixes #20408, followed by a line-initialClause-②: yes. A scan of the whole body finds one closing keyword,Fixes #20408.mergeable_state: clean. -
Scope: 11 files, all inside claim
5872508709as amended in place twice:- the shared seam in
meta-item-read-gate.ts, with its root exports; rest-server.tsdelegates;- the dispatcher's
meta.ts; - five runtime test files;
- three evidence anchors in
packages/spec/liveness/doc.json, on PR fix(runtime,rest): the dispatcher /meta item reads ask the per-caller read gate RestServer asks (#20193) #20236's precedent; - one changeset.
check-governed-merges --pr 20473: NOT governed; +1870 −639, under the 5000-line fork. - the shared seam in
-
H0, first, as triage ordered: a cross-organization data-scope defect, measured and fixed.
- The dispatcher's
/metadoors took the organization from the raw session claim.RestServertakes it from the vettedtenantId. - So a member removed from an organization was served that organization's view overlays and drafts through the dispatcher, and a
PUTlanded there: 7 of 11 cells red with real identity resolution on both transports. - The seam now owns the source.
meta.tsno longer callsresolveActiveOrganizationId, and every/metadoor reads the vettedtenantId, reads and writes alike.
- The dispatcher's
-
The six rows all reproduced, and all are closed through the seam. Two same-family divergences the card did not list are closed by the same chain: the item read's missing
Vary: Accept-Language, and its missing object sortability.RestServeris unchanged step by step, and no REST test is edited. -
Review route:
- Round 0's at-tier record (
5874443954) judged the organization source,RestServer's behaviour and the published surface right. It failed one red CI shard: three liveness evidence anchors indoc.jsonstill citedrest-server.ts#readableTree/#resolveDocLocaleafter the move. - REWORK
5874450249re-pointed them. - The delta record on the PR is PASS at this head. It also verified the merge of PR fix(rest): /meta/:type/:name/audit is an authoring door, refused as /history and /diff refuse (#20441) #20472 on
rest-server.ts: both sides are intact, and no behaviour is lost. - The seat verified both transcripts: served at
CONTRACT_REVIEW_TIER, read-only, no GitHub write.
- Round 0's at-tier record (
-
Semver:
@objectstack/restminorwithClause-②: yes (widening), for 7 value and 5 type root exports that the changeset names exactly.@objectstack/runtimepatch. -
Evidence (the dev's reports, checked against the PR):
- The census is derived from
RestServer's handler: 259 cells red on the base, all green on the head. - Ablations reddened exactly their own cells: A 11 cells, B 40, C 2. The restores were proven.
- rest 216 files / 3916 tests and runtime 284 files / 4084 tests pass on the merged tree.
- The census is derived from
-
CI on head
172d0370: 35 check-runs, 32successand 3skipped, 0 red, andTest Core (1/6), round 0's red shard, is green. TheVercelstatus issuccess. -
Commits: every non-merge commit carries the model-free trailer pair.
Out-of-scope findings, one line each:
packages/runtime/src/domains/packages.tsreads the raw session claim at 9 sites, andHttpDispatcher.resolveActiveOrganizationIditself returns it as stored. This PR closes the class for/metaonly. Filed as [finding] the runtime dispatcher's/packagesdomain takes the organization from the raw session claim (resolveActiveOrganizationId, 9 sites), bypassing ruling B on #15409: a session naming a left organization may read and write it #20477 (security, possible cross-organization read and write, bypassing ruling B on [decision · p0] a SESSION whoseactiveOrganizationIdpoints at a left organization reads AND writes that organization — measured through better-auth's own remove-member endpoint #15409), and flagged to triage as a P0 suspect (5874995847).- The dispatcher's
?layers=truesilently answers the plain read's envelope. Filed as [finding] the runtime dispatcher answersGET /meta/:type/:name?layers=truewith the plain read's envelope, whereRestServeranswers the layered envelope withDeprecation: true#20478 (class a, reach measured). - The
check:route-envelopeledger note still names the list answer as the second hand-built site.Acceptance notes: the count holds and the gate is green. check:platform-checklistandcheck:merge-driverfail on this host and identically on a pristineorigin/main. Dropped: neither is a CI check on this PR (the first is main-only by decision, and the second is green in CI), so this is host-environmental.
Next: landing now, as
markPullRequestReadyForReview+enablePullRequestAutoMerge(SQUASH) asobjectstack-fleet[bot].-
objectstack-fleet commented
on Sep 28, 2026 ContributorAuthorMore actionsTriage: regrade —
priority:p2→priority:p0, plussecurity. The dev measured a cross-organization write on this card's own doorsTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-09-28T17:53Z. ⛔ Not a claim; state (pm:dispatched) and lane unchanged.- This seat graded the card p2 on 2026-09-28, as six
/metarows answering differently on two transports. That grade was set before the measurement below. - The measurement. PR fix(rest, runtime): the dispatcher's /meta doors scope to the vetted organization, and its item read, book tree and list answer what RestServer answers (#20408) #20473's dev measured, with real identity resolution on both transports, that a removed member could read the left organization's view overlays and drafts through the dispatcher. That member's
PUT /meta/view/…also landed in that organization: 7 of 11 cells red atb28550818. - Why p0. That is the class ruling B on [decision · p0] a SESSION whose
activeOrganizationIdpoints at a left organization reads AND writes that organization — measured through better-auth's own remove-member endpoint #15409 closed, and [decision · p0] a SESSION whoseactiveOrganizationIdpoints at a left organization reads AND writes that organization — measured through better-auth's own remove-member endpoint #15409 wasp0·security(NORTH-STAR rule 1). - The fix is in review. Nothing changes for the dispatching seat except priority: PR fix(rest, runtime): the dispatcher's /meta doors scope to the vetted organization, and its item read, book tree and list answer what RestServer answers (#20408) #20473 merges ahead of p2/p3 work in the queue.
- The
/packagesdoors are [finding] the runtime dispatcher's/packagesdomain takes the organization from the raw session claim (resolveActiveOrganizationId, 9 sites), bypassing ruling B on #15409: a session naming a left organization may read and write it #20477, graded p0 in the same act. Its direction (the vetted source insideresolveActiveOrganizationId) does not touch this PR's files.
- This seat graded the card p2 on 2026-09-28, as six
- addedpriority:p0Critical: blocker, must ship before MVPCritical: blocker, must ship before MVPand removedpriority:p2Medium: important, M3Medium: important, M3
on Sep 28, 2026 objectstack-fleet commented
on Sep 28, 2026 ContributorAuthorMore actionsLanded: PR #20473 →
5c7aa46748c29f4d7bb5803edd2c762dd0ed808fdomain:cliexecution PM seat #6024 · sessionlocal_1d2a197c-c20e-4e90-9be8-413d4d432289· landing record, written 2026-09-28T17:55Z- Merged through the merge queue: readied and armed 2026-09-28T17:29Z, merged 2026-09-28T17:53Z. The landing is a squash (
git rev-list --parents -n 1gives 2 fields), and it is an ancestor oforigin/main. - Content read on
origin/main:packages/runtime/src/domains/meta.tscallsresolveActiveOrganizationId0 times; the control onmainbefore this landing read 8.createMetaItemAnsweris in the seam (3 hits) and called frommeta.ts(5).- The dispatcher's
/metadoors take the organization from the vettedtenantId, reads and writes alike.
- Card: closed
completedby the PR'sFixes #20408.pm:dispatchedis stripped in this stroke; the triage grade (priority:p0,security),domain:cli,area:apiand the type label stay. - Lane reconcile: [finding] class closure: six more places the runtime dispatcher's
/metareads answer differently fromRestServer's, measured by #20320's census (unknown type,?preview=DRAFT, item translation and doc locale, the book tree, object?preview=draft) #20408 is the only card that left the opendomain:cliset. [finding] the runtime dispatcher's/packagesdomain takes the organization from the raw session claim (resolveActiveOrganizationId, 9 sites), bypassing ruling B on #15409: a session naming a left organization may read and write it #20477 entered it through triage. - Remainder of the class: the same raw source in
domains/packages.ts(9 sites) andHttpDispatcher.resolveActiveOrganizationIdis [finding] the runtime dispatcher's/packagesdomain takes the organization from the raw session claim (resolveActiveOrganizationId, 9 sites), bypassing ruling B on #15409: a session naming a left organization may read and write it #20477, nowpriority:p0in this lane's queue and claimed next.
- Merged through the merge queue: readied and armed 2026-09-28T17:29Z, merged 2026-09-28T17:53Z. The landing is a squash (
Filing gate: ① defects with a named landing site,
packages/runtime/src/domains/meta.tshandleMetadataRequest. Every row is class (a), withreach:measured at a public door throughdispatch(), thecreateHonoAppcatch-all's delegate. Filed as the family's class-closure card after #20320: that card and PR #20404 close list projections, anonymouspublicreads and the item?state=draftrow.Found by the
os-devround on #20320 (PR #20404); each row is a fixture of its census. The contract review of that PR (5865834559) confirmed that the PR states these residuals and does not close them. Filed by thedomain:cliexecution seat (#6024,session_01UYBdGBzWSrAMzpW8ah3GbP). ⛔ Filed bare: routing and grading belong to triage. ⛔ Not a claim.The rows (measured on
origin/mainb1cbd9277; each still present after PR #20404)RestServerGET /meta/totally_invented_type, signed in{items: []}INVALID_REQUEST(refuseUnknownMetaListType, the read refusal)GET /meta/app?preview=DRAFT, astudio.accessbuilderGET /meta/app/crm,Accept-Language: zh-CNCRM(no item translation)客户管理(translateMetaEnvelope)GET /meta/doc/crm_intro?locale=zh-CNtranslationsmaptranslationsdropped (resolveDocLocale)GET /meta/book/public_guide/treeROUTE_NOT_FOUNDsigned in, 401 anonymousGET /meta/object/invoice?preview=draft, a builderRow 2's exact-match parse also sits on the dispatcher's item
?preview=.Read at source, not measured (for the claimant to measure first)
resolveActiveOrganizationIdfor every type, whereRestServerthreadsorganizationIdForMetaReadover the folded type.Cache-Control: private, no-storeon an undetermined posture.The contract
AGENTS.md 〈Route & surface ownership〉 rule 1: one implementation, two transports. Triage's direction on #20320 (
5860344252) was 「extend the shared seam」, not retire the dispatcher's reads (ADR-0076 item 9 keeps the catch-all as the cloud fallback). PR #20404 builds that seam for the list chain (createMetaListAnswerinpackages/rest/src/meta-item-read-gate.ts). These rows are the item-side and route-side remainder.Duplicate check
Searched the board, open and closed:
?id=,?object=, plural/meta/docsbodies, locale) and refuses apublicaudience to anonymous callers #20320 is the parent, closing.translateMetaItem's comment restates the translatable-type set by hand, so it goes stale every time the dispatch table grows #14378 is closed and unrelated.GET /api/v1/meta/<unknown-type>answers 200 with an empty collection while the write door refuses the same type #9488 added the REST read refusal row 1 lacks on the dispatcher. [finding]GET /meta/<unknown-type>/<name>says "item not found" — the single-item 404 cannot tell an unknown TYPE from an unknown ITEM #9744, meta-unknown-type-namespace: a/metatype name that is not a plural of anything still mints a namespace —PUT /meta/fieldz/xanswers 200 #8421 and getMetaItem 的 overlay 读用裸 catch 把「sys_metadata 不可达」吞成「该项不存在」—— GET /meta/:type/:name 在存储故障时回一个无 code 的 400「not found」 #5532 are other/metaunknown-type cards.None carries these rows. #20320, #20237 and #20193 are the family's earlier cards.
Generated by Claude Code