Skip to content

Commit 0d536d6

Browse files
committed
Merge remote-tracking branch 'origin/main' into claude/issue-14423-loadmany-consumer-census
2 parents eabffe3 + a4e4d2d commit 0d536d6

8 files changed

Lines changed: 459 additions & 26 deletions

File tree

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
'@objectstack/rest': patch
3+
---
4+
5+
`GET /api/v1/meta/diagnostics?type=` now states the caller's organization
6+
7+
The cross-type spec-validation sweep behind the Studio governance directory named no
8+
organization, so an organization's own metadata overlays were absent from it — clean tiles
9+
rendered over a partition the sweep never read. The protocol implementation already
10+
declares and reads `organizationId`; only the REST call site never supplied one.
11+
12+
The `?type=` arm now resolves the request's memoised execution context and passes
13+
`organizationIdForMetaRead(canonicalMetaUrlType(type), ctx.tenantId)` — the same
14+
registry-gated predicate the list, single-item, `/layers`, `/history` and `/diff` doors
15+
already use, so read scope and write scope cannot drift: a type the registry declares
16+
`allowOrgOverride: false` keeps reading environment-wide, and an anonymous or
17+
organization-less caller reads exactly what it read before.
18+
19+
The untyped whole-registry sweep is deliberately unchanged and remains environment-wide:
20+
it spans types with different `allowOrgOverride` while the request carries a single
21+
`organizationId`, which cannot express a per-type scope. That gap is tracked on the card.

.claude/skills/pm-dispatch/references/dispatch-runbook.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,9 @@ monitor 按自己的 deadline 触发;身份 = 三元组 `(issue, 分支, PR head
243243
- **文件面两句原文**:「预期落点是 X;若实测表明真正的生产者在别包,报备后按生产者侧修
244244
(落点与理由写进报告和 PR 正文),⛔ 不在消费者侧打补丁」—— 只写一个路径名,
245245
是要求 dev 在守约与修对之间二选一;跨包常等于跨车道,PM 事后补跨座位声明。
246+
- **模型标识只禁内容工件**(维护者 2026-09-03 裁):PR 标题/正文、代码注释、文档、changeset、
247+
issue/PR 评论;两条豁免同属规则 —— harness 写在 commit 的 `Co-Authored-By` 尾注(含 session 链接),
248+
`.claude/agents/*` frontmatter 的 `model:`(`check:agent-model-declared` 要求);⛔ 不再申报为偏差。
246249
- **Same-day churn 行与在飞重叠**:派发时 `git log origin/main --oneline -20 -- <paths>`
247250
见当天合并 ⇒ 加一行「基于合并后的代码工作,issue 引用的片段可能已变,
248251
先核对当前 main」(dev 的 worktree 切出后不会自己更新)。

content/docs/permissions/system-context.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ The largest single consumer — **17 of the 106 sites**.
158158
|:--|:---|:---|:---|:---|
159159
| 48 | Object API-exposure gate bypassed (`apiEnabled` / `apiMethods`) | runtime | Get: internal self-writes ignore exposure declarations — these govern **external** exposure, not engine self-writes | `action-execution.ts:138` |
160160
| 49 | Action `requiredPermissions` bypassed | runtime | Get: engine self-invocation runs any action | `action-execution.ts:401` |
161-
| 50 | `manage_metadata` bypassed on metadata writes | runtime, rest | Get: schema writes without the capability | `domains/meta.ts:471`, `:874`, `rest-server.ts:4715`, `:6078`, `:6326`, `:6757`, `:6950` |
161+
| 50 | `manage_metadata` bypassed on metadata writes | runtime, rest | Get: schema writes without the capability | `domains/meta.ts:471`, `:874`, `rest-server.ts:4789`, `:6203`, `:6451`, `:6882`, `:7075` |
162162
| 51 | The shared metadata-write verdict itself returns `allowed` | metadata-core | Get: the one function all of row 50's doors consult answers yes before any capability is examined | `meta-write-capability.ts:134` |
163163
| 52 | Anonymous-deny seam satisfied on the domain dispatchers and the package/federation routes | runtime, rest | Get: passes with no `userId` | `domains/actions.ts:411`, `domains/ai.ts:60`, `domains/automation.ts:989`, `domains/meta.ts:232`, `domains/security.ts:78`, `domains/packages.ts:326`, `external-datasource-routes.ts:302`, `package-routes.ts:97` |
164164
| 53 | MCP principal check satisfied | runtime | Get: MCP surface reachable with no user | `domains/mcp.ts:61` |

docs/qa/platform-checklist/SWEEP.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,12 @@ single reader would not have covered.
6262
5. **Reconcile `coverage.json` centrally** (a single writer): un-waive any kind a hunter
6363
proved has a stock fixture, map new items to their kinds, pin `enumSource` on any new
6464
variants matrix.
65-
6. **Validate** `node scripts/check-platform-checklist.mjs` until green, then land the
66-
run record under `runs/` and surface product defects / docs drift to the maintainer
67-
in `FOLLOW-UPS.md`.
65+
6. **Validate** `node scripts/check-platform-checklist.mjs` until green, then surface
66+
product defects / docs drift to the maintainer in `FOLLOW-UPS.md` — with the authored
67+
items and the reconciled `coverage.json`, that register is the sweep's whole durable
68+
output. A sweep files **no run record**: that artifact belongs to `checklist-test`,
69+
and it never lands under `runs/` (git-ignored) but as one `qa-run` GitHub issue —
70+
[runs/README.md](./runs/README.md), body contract in [RUNNER.md](./RUNNER.md).
6871

6972
## Discipline that made the 2026-08 sweep trustworthy
7073

packages/rest/src/execctx-consumer-census.test.ts

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,28 @@ describe('[#13160] §1 the production supplier fulfils with `undefined` rather t
309309
// ---------------------------------------------------------------------------
310310

311311
describe('[#13160] §2 the consumer surface, counted from the tree', () => {
312-
it('75 invocation sites, 95 mentions — the thread\'s two control numbers hold', () => {
312+
it('76 invocation sites, 97 mentions — the thread\'s two control numbers hold', () => {
313+
// [#13753] 75 → 76 sites / 95 → 97 mentions. `GET /meta/diagnostics`
314+
// resolved NO identity, so the Studio governance sweep could not state
315+
// which organization's partition it was reading and reported clean
316+
// tiles over one it never read. It joins as a LOCALLY CAUGHT site (the
317+
// continuation-line `.catch(rethrowAuthzStoreUnavailable)` spelling),
318+
// like the `/history` and `/diff` doors before it: this door does not
319+
// sit behind the shared anonymous floor either.
320+
//
321+
// ⚠️ +1 and +2 again, for the same reason as below: one call site, and
322+
// one prose mention in the door's new comment recording that
323+
// `resolveExecCtx` is memoised per request so this is not a new
324+
// org-resolution seam.
325+
//
326+
// ⚠️ The site is resolved INSIDE an `if (diagnosticsType)` block rather
327+
// than in a ternary, and the shape is load-bearing for this census: a
328+
// ternary puts the `.catch(…)` on a continuation line with NO trailing
329+
// `;`, which is a THIRD layout {@link catchArguments} cannot read — it
330+
// would have counted 23 caught sites and found 22 arguments, i.e. the
331+
// §7 CONTROL failing rather than a silent hole. Conforming to the
332+
// house spelling was preferred over teaching the reader a layout.
333+
//
313334
// [#13406] 73 → 75 sites / 92 → 95 mentions. The `/meta/:type/:name/
314335
// history` and `/diff` read doors resolved NO identity, so neither
315336
// could state which organization's `sys_metadata_history` partition it
@@ -340,11 +361,11 @@ describe('[#13160] §2 the consumer surface, counted from the tree', () => {
340361
// `enforceAuth` was measured NOT to be the repair). A mention count
341362
// that tracked the site count exactly would be measuring one thing
342363
// twice.
343-
expect(SITES.length).toBe(75);
344-
expect(SOURCE.split('resolveExecCtx').length - 1).toBe(95);
364+
expect(SITES.length).toBe(76);
365+
expect(SOURCE.split('resolveExecCtx').length - 1).toBe(97);
345366
});
346367

347-
it('the split is 22 locally caught / 53 bare — NOT 16 / 53, which does not add to 75', () => {
368+
it('the split is 23 locally caught / 53 bare — NOT 16 / 53, which does not add to 76', () => {
348369
// 16 sites spell the catch on the invocation line; 4 more spell it on
349370
// the continuation line. A single-line grep sees 16 and the arithmetic
350371
// silently loses four sites.
@@ -354,12 +375,12 @@ describe('[#13160] §2 the consumer surface, counted from the tree', () => {
354375
// be the first of its kind and would break the structural claim below.
355376
const sameLine = CAUGHT.filter((s) => SOURCE.split('\n')[s.line - 1].includes('.catch('));
356377
expect(sameLine.length).toBe(16);
357-
expect(CAUGHT.length).toBe(22);
378+
expect(CAUGHT.length).toBe(23);
358379
expect(BARE.length).toBe(53);
359380
expect(CAUGHT.length + BARE.length).toBe(SITES.length);
360381
});
361382

362-
it('⭐ every one of the 53 bare sites is guarded on the VERY NEXT LINE, and none of the 22 caught ones is', () => {
383+
it('⭐ every one of the 53 bare sites is guarded on the VERY NEXT LINE, and none of the 23 caught ones is', () => {
363384
// This inverts the reason the thread gave for doing the bare sites
364385
// first ("no local signal that a fault becomes an anonymous subject").
365386
// The bare sites are bare BECAUSE the shared anonymous floor is the

0 commit comments

Comments
 (0)