Skip to content

Commit a8b75f9

Browse files
committed
Merge remote-tracking branch 'origin/main' into claude/issue-18915-published-readme-examples-compile
2 parents bbc20f3 + 89c6ec5 commit a8b75f9

8 files changed

Lines changed: 762 additions & 34 deletions

File tree

‎content/docs/deployment/environment-variables.mdx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ OS_MCP_STDIO_ENABLED=true OS_MCP_STDIO_API_KEY=osk_... os start # start the lo
257257
|:---|:---|:---|:---|
258258
| `OS_MCP_SERVER_ENABLED` | boolean | `true` | The MCP **HTTP** surface (`/api/v1/mcp`) is a core capability and defaults **on**. Set `false` to disable it (endpoint 404s, the Connect-an-Agent page disappears). |
259259
| `OS_MCP_STDIO_ENABLED` | boolean | `false` | Auto-start the long-lived **stdio** transport at boot. Opt-in and **stricter** than the HTTP surface. **Requires `OS_MCP_STDIO_API_KEY`** — stdio runs as that key's identity with RLS/FLS/tenant applied; if the key is missing or invalid, boot **fails closed** (stdio refuses to start). See ADR-0101. |
260-
| `OS_MCP_STDIO_API_KEY` | string | — | The `osk_...` API key the **stdio** transport runs as. Resolved through the same verify chain as the HTTP/REST surfaces, so reads are scoped to that identity's permissions. Mint one from **Setup → Connect an Agent** (or `POST /api/v1/keys`). For full authority, mint a key on a platform-admin or dedicated **service** identity — there is deliberately no `system`/unscoped bypass. |
260+
| `OS_MCP_STDIO_API_KEY` | string | — | The `osk_...` API key the **stdio** transport runs as. Resolved through the same verify chain as the HTTP/REST surfaces, so reads are scoped to that identity's permissions. Mint one from the **Connect an Agent** page — **Account → Developer** for any signed-in user, **Setup → Connect an Agent** for platform admins — or `POST /api/v1/keys`. For full authority, mint a key on a platform-admin or dedicated **service** identity — there is deliberately no `system`/unscoped bypass. |
261261
| `OS_MCP_SERVER_NAME` | string | `objectstack` | Server name advertised to MCP clients. |
262262
| `OS_MCP_SERVER_TRANSPORT` | enum | `stdio` | `stdio` \| `http`. Use `http` (Streamable HTTP) for a remote client; `stdio` for a local one. |
263263

‎content/docs/permissions/tenant-audit-census.mdx‎

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,27 @@ cannot read, and they are neither in nor out.
217217
| object name is an `object: string` parameter | 19 |
218218
| object name is some other run-time expression | 57 |
219219

220+
### Subtractions the census could NOT defend — enforced
221+
222+
A same-named call on something that is not a data engine is subtracted, and the
223+
subtraction is DEFENSIBLE when this census can name why: the receiver is a `node:`
224+
builtin, a value it watched being constructed, a language global, a type THIS
225+
corpus declares and the door rule rejected, or an `UNTYPED_RECEIVERS` row.
226+
227+
⚠️ Counted below are the subtractions it can name no such fact for — the
228+
receiver carries a declared type the engine type index does not hold, and that
229+
index is built from TRACKED sources only, deliberately. An untracked, generated
230+
or dependency-owned declaration is one this census never saw, and «never saw it»
231+
must not be spelled the same way as «read it, not an engine».
232+
233+
| what | count |
234+
| :--- | ---: |
235+
| write calls subtracted with no defensible reason | **3** |
236+
| …whose declared type text states an engine door anyway | **2** |
237+
238+
Every one of them is listed, by receiver and by the type text that could not be
239+
placed, in [`docs/audits/2026-08-tenant-audit-write-call-sites.counts.md`](https://github.com/objectstack-ai/objectstack/blob/main/docs/audits/2026-08-tenant-audit-write-call-sites.counts.md).
240+
220241
The corpus walked is every tracked non-test source under `packages/services/`
221242
and `packages/plugins/`; calls to a same-named method on something that is not
222243
a data engine were subtracted. Every site is listed in
@@ -232,11 +253,11 @@ holds still. They are required to be HERE and to say WHEN they were true;
232253
their values are not compared. The reasoning, and the measurement behind it,
233254
are in `scripts/check-tenant-audit-census.mjs`.
234255

235-
Measured on 2026-09-16 at `11daf7f69`.
256+
Measured on 2026-09-18 at `02bdeaaf2`.
236257

237258
| corpus scale (not enforced) | count |
238259
| :--- | ---: |
239-
| tracked non-test sources scanned | 570 |
260+
| tracked non-test sources scanned | 573 |
240261
| engine-shaped types recognised | 63 |
241262
| declared objects in the registry | 117 |
242263
| same-named calls subtracted as non-engine | 146 |

‎docs/audits/2026-08-tenant-audit-write-call-sites.counts.md‎

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,30 @@ silent, and `node scripts/tenant-audit-census.mjs --write` is the resolution.
4343
| Threading a decidably non-elevated context | 0 |
4444
| Threading a context of undecidable elevation | 102 |
4545

46+
## Subtractions the census could NOT defend — enforced
47+
48+
A same-named call on something that is not a data engine is subtracted, and the
49+
subtraction is DEFENSIBLE when this census can name why: the receiver is a `node:`
50+
builtin, a value it watched being constructed, a language global, a type THIS
51+
corpus declares and the door rule rejected, or an `UNTYPED_RECEIVERS` row.
52+
53+
⚠️ Counted below are the subtractions it can name no such fact for — the
54+
receiver carries a declared type the engine type index does not hold, and that
55+
index is built from TRACKED sources only, deliberately. An untracked, generated
56+
or dependency-owned declaration is one this census never saw, and «never saw it»
57+
must not be spelled the same way as «read it, not an engine».
58+
59+
| what | count |
60+
| :--- | ---: |
61+
| write calls subtracted with no defensible reason | **3** |
62+
| …whose declared type text states an engine door anyway | **2** |
63+
64+
| file | receiver | verb | why | declared type | door | n |
65+
|---|---|---|---|---|---|---:|
66+
| `packages/plugins/plugin-auth/src/audience-gate-test-support.ts` | `engine` | `insert` | anonymous-type | `{ insert: (name: string, data: any, options?: any) => Promise<unknown> } \| null` | ⚠️ yes | 1 |
67+
| `packages/plugins/plugin-auth/src/sso-client-secret.ts` | `e` | `update` | anonymous-type | `{ find(object: string, query: unknown): Promise<Record<string, unknown>[]>; update(object: string, data: unknown, options?: unknown): Promise<unknown>; }` | ⚠️ yes | 1 |
68+
| `packages/plugins/plugin-hono-server/src/adapter.ts` | `this.app` | `delete` | type-not-in-corpus | `Hono` | no | 1 |
69+
4670
## Corpus scale — present and dated, ⛔ NOT enforced
4771

4872
⛔ These four describe the CORPUS this census walked, not the population it
@@ -52,11 +76,11 @@ holds still. They are required to be HERE and to say WHEN they were true;
5276
their values are not compared. The reasoning, and the measurement behind it,
5377
are in `scripts/check-tenant-audit-census.mjs`.
5478

55-
Measured on 2026-09-16 at `11daf7f69`.
79+
Measured on 2026-09-18 at `02bdeaaf2`.
5680

5781
| corpus scale (not enforced) | count |
5882
| :--- | ---: |
59-
| tracked non-test sources scanned | 570 |
83+
| tracked non-test sources scanned | 573 |
6084
| engine-shaped types recognised | 63 |
6185
| declared objects in the registry | 117 |
6286
| same-named calls subtracted as non-engine | 146 |

‎packages/spec/src/api/batch.test.ts‎

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,19 @@ describe('BatchUpdateRequestSchema', () => {
107107

108108
// [#3939] The count bounds moved OUT of the schema. They were a second source
109109
// of truth that never matched reality: the schema said 1..200 while the routes
110-
// enforced nothing, and the one route that did cap read the deployment's
111-
// configured `batch.maxBatchSize` (1..1000) instead. The cap is now enforced
112-
// at the route from that config, and the schema carries shape only.
110+
// enforced nothing, and the one route that did cap read the constructed
111+
// `RestServerConfig.batch.maxBatchSize` (1..1000, default 200) instead. The
112+
// cap is now enforced at the route from that config, and the schema carries
113+
// shape only.
114+
//
115+
// Reachability: EMBEDDER-ONLY (#15543, #16801). ⛔ That config is NOT
116+
// deployment policy: it is written only by a host that constructs the
117+
// `RestServerConfig` itself, never by `os serve` or the dev plugin, so a
118+
// CLI-started deployment always gets the default of 200 and no flag, config
119+
// file or CLI option moves it. Same posture as the schema this file pins
120+
// (`BatchUpdateRequestSchema` in `batch.zod.ts`) and
121+
// `RestServer#enforceBatchSize`; the per-key record is the REACHABILITY row
122+
// in `packages/spec/liveness/batch_endpoints.json`.
113123
it('accepts an empty record list — an empty batch is a no-op, not a client error', () => {
114124
expect(() =>
115125
BatchUpdateRequestSchema.parse({

‎pnpm-lock.yaml‎

Lines changed: 5 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎pnpm-workspace.yaml‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,3 +394,38 @@ overrides:
394394
'@xmldom/xmldom@>=0.8.0 <0.9.0': '^0.8.15'
395395
'@xmldom/xmldom@>=0.9.0 <0.10.0': '^0.9.12'
396396
'qs@>=6.0.0 <7.0.0': '^6.16.0'
397+
# OSV 2026-09-18 (#18930) — one advisory, and it names a fixed version, so
398+
# this is the "take the fix" path osv-scanner.toml's own header prescribes
399+
# and NOT an exemption; that ledger stays at ZERO entries.
400+
# devalue GHSA-9rgm-9g3h-6x36 (5.3 medium) — flagged at the single resolved
401+
# line 5.9.0, fixed 5.9.2. It turned `Validate Package Dependencies` red
402+
# on `main` itself (scheduled run 35301766597, step 13), so every PR
403+
# touching any package.json inherited a red that was not its own.
404+
# Transitive-only: no workspace manifest declares devalue, so there is no
405+
# publishable declared range to keep in lockstep and
406+
# check-override-consistency.mjs lists it as an override it cannot
407+
# cross-check against a declared range — correct for this shape, and a
408+
# report, never a failure. Reached through svelte@5.56.9, which declares
409+
# `devalue: ^5.8.1` — a range that ALREADY admits 5.9.2, so this is a
410+
# dedupe onto the patched line rather than a forced upgrade past what the
411+
# dependent supports (the dompurify / nanoid shape above).
412+
# Why the pin rather than a bare resolver refresh: the lockfile sat on
413+
# 5.9.0 purely through lockfile inertia — 5.9.0 satisfied ^5.8.1, so
414+
# nothing re-resolved it when 5.9.1 and 5.9.2 published, the same
415+
# mechanism the hono note above records. `pnpm update devalue -r --depth
416+
# Infinity` does clear it, but it re-resolves the whole tree and moved
417+
# twelve unrelated packages (type-fest, seroval, postcss, nanoid, knex,
418+
# picomatch, ip-address, isbot, node-abi, use-sync-external-store …) in
419+
# one 107/87-line lockfile churn; the override moves devalue alone and
420+
# leaves a floor behind, so a future transitive reintroduction lands on
421+
# the patched line instead of silently re-arming the advisory.
422+
# ONE resolved copy in the whole tree (measured, `pnpm why devalue`), so
423+
# the floorless selector forces nothing else onto the 5.x line.
424+
# Bound at the 6.0.0 major boundary per this block's header rule, never
425+
# `<5.9.2`, which would self-invalidate the day 5.9.2 is itself flagged
426+
# (the undici 7.28.0 / brace-expansion 5.0.8 specimens, #4961 / #5032).
427+
# ⚠️ The advisory's CONTENT is NOT characterised here: api.osv.dev and
428+
# GitHub's /advisories endpoint are both refused by the authoring
429+
# container's egress proxy, so the severity and the fixed version above
430+
# are read off the scanner's own output line and nothing else.
431+
'devalue@<6.0.0': '^5.9.2'

0 commit comments

Comments
 (0)