Skip to content

Commit fbaacfe

Browse files
docs(spec): correct the Virtual ObjectQL retirement wording (context arms, readonly-writes docblock, ledger row) (#27408)
<!-- claude-projects-attribution: {"github_login":"os-support-ai"} --> _Requested by **Yibo Wang** · [project thread](https://claude.ai/code/project/chan_01BVUyyPie8gHwoPM18iABwB?thread=cmsg_01BVUyyPie8gHwoPM18iABwB2JfLyoXowwaMTotLmArPu2)_ Fixes #27346 ## What changes The three prose should-fixes from contract review 6485025305 on the merged #27324 (#27028): 1. `packages/spec/src/contracts/data-engine.ts`, the `strictReadonlyWrites` docblock: no longer says the option does not "cross the RPC / Virtual Data Engine boundary" (that boundary is retired). It now says, as the `WriteObservabilityOptions` docblock already does, that nothing here can be serialized and none of it is reachable from a REST/wire body. 2. The D3 reason of `data-engine-rpc-protocol-retired` (`packages/spec/src/migrations/entries/semantic/18.data-engine-rpc-protocol-retired.ts`): "every arm admitted a caller-supplied `context`" becomes "every read and write arm …". The `execute` arm carried an untyped options record and `vectorFind` had no `context`. The same sentence in the retirement comment in `packages/spec/src/data/data-engine.zod.ts` gets the same correction. 3. `docs/audits/2026-07-unknown-key-strictness-ledger.md`, the `data-engine.zod.ts` row note: records that ten more sites (`DataEngineRequestSchema` and its nine arms) left with #27028. The pending `.changeset/27028-data-engine-rpc-protocol-retired.md` is **not** edited (check-empty-changeset). A new `.changeset/27346-data-engine-rpc-retirement-wording.md` (`@objectstack/spec` patch) carries a "Supersedes, in the same release:" paragraph naming that note's sentence and giving the corrected wording. Generated outputs the D3 reason feeds are regenerated where they move. ## Why The released wording overstated the claim (two of the nine arms had no `context` key) and the docblock pointed at a boundary that no longer exists in the spec. Prose only: no schema, export or runtime behaviour changes. ## Verification Readings are posted on the PR once the local runs finish (spec build, `check:generated`, spec `test:repo`, spec test under os-verify-lock, derived gates). Clause-②: no Metadata-protocol: none ## Human Minimum - [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic. - [x] 2. Every name I added uses the casing for its kind. - [x] 3. No formatter ran; `pnpm lint` passes. - [x] 4. One issue, one branch off an up-to-date `main`, one pull request. - [x] 5. A change that publishes carries a changeset, and both declaration lines are filled in here and in the changeset. - [x] 6. `packages/spec` touched: its generated artifacts are regenerated and committed. - [x] 7. No hand edits to `content/docs/references/`, `packages/*/CHANGELOG.md` or `content/docs/releases/`. - [x] 8. Title, body and comments are in English. - [x] The *Before Submitting* list in CONTRIBUTING.md is done. --- _Generated by [Claude Code](https://claude.ai/code/session_01WGufziSEJnb5QGLZRcRJua)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 86edcaf commit fbaacfe

6 files changed

Lines changed: 19 additions & 8 deletions

File tree

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@objectstack/spec': patch
3+
---
4+
5+
docs(spec): the Virtual ObjectQL retirement's D3 reason says which request arms admitted a caller-supplied `context`
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
Supersedes, in the same release, one sentence of the `feat(spec)!: retire the unserved Virtual ObjectQL request protocol from data/data-engine.zod.ts` note: "every arm admitted a caller-supplied `context` (`isSystem` included)". The corrected wording is: every read and write arm (`find`, `findOne`, `insert`, `update`, `delete`, `count`, `aggregate`) admitted a caller-supplied `context` (`isSystem` included). The `execute` arm carried an untyped options record rather than a `context` key, and the `vectorFind` arm had no `context` at all. The D3 semantic entry `data-engine-rpc-protocol-retired` carries the same correction, so `os migrate meta` and the upgrade guide read it. The `strictReadonlyWrites` docblock on `WriteObservabilityOptions` no longer names the retired "Virtual Data Engine" boundary: the option cannot be serialized and is not reachable from a REST/wire body. No schema, export or runtime behaviour changes.

‎content/docs/protocol/objectql/security.mdx‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -390,8 +390,8 @@ which the engine computes on every read and no driver has a column for, is dropp
390390
every write in every context, `isSystem` included. The vocabulary is
391391
open — it grows as the write path gains legal strips — so branch on `reason`
392392
exhaustively rather than treating "not `readonly_when`" as "read-only". The listener is an in-process
393-
callback: it is delivered by the local engine, and does **not** cross the RPC / Virtual
394-
Data Engine boundary, so a remote caller never receives these events. Without a listener,
393+
callback: it is delivered by the local engine, it cannot be serialized, and no REST/wire
394+
body reaches it, so a remote caller never receives these events. Without a listener,
395395
the only trace is a server-side `WARN` naming the object, the field, and both remedies.
396396

397397
---

‎docs/audits/2026-07-unknown-key-strictness-ledger.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -715,7 +715,7 @@ column does not move and the `strip` column falls by the count of what left.
715715
| File | Class | Note |
716716
|---|---|---|
717717
| `object.zod.ts` | authorable | top-level already guarded (#1535); **all 14 inner blocks strict** — 13 at 批 20, and the held 14th (`IndexSchema`) closed 2026-08-16 once its hold's evidence was spent: the hold was the #5114 class caught pre-ship (objectui's `FALLBACK_SCHEMAS.index` had drifted, offering `where`/`brin`, and the editor PUT the whole object through `saveMetaItem`), gated on the objectui rename (#5247) and an ADR-0049 answer for `type`/`partial` (#5248). #5248 answered remove (PR #5842, `retiredKey` tombstones + protocol-17 migration); **objectui#4772 then converged the editor to the declared `name`/`fields`/`unique` surface**, so the close shipped with a curated `where` guidance entry (database-layer prescription — deliberately NOT a rename onto the retired `partial` tombstone, which would be finding 7) and per-key pins that the tombstones' own prescriptions survive the strict path. Semantic entry `object-index-unknown-keys-refused` (protocol 18). The file's row left the remaining-strip map by reaching zero; the hold's full history is preserved in that map's section prose and in `object-strictness-batch20.test.ts` §4, which flipped from pinning the strip to pinning the close |
718-
| `data-engine.zod.ts` | wire (p) | engine contract shapes (was 14 — `DataEngineBatchRequestSchema` retired with `IDataEngine.batch?`, #4618) |
718+
| `data-engine.zod.ts` | wire (p) | engine contract shapes (was 14 — `DataEngineBatchRequestSchema` retired with `IDataEngine.batch?`, #4618; ten more sites — `DataEngineRequestSchema` and its nine arms — retired with the Virtual ObjectQL request protocol, #27028) |
719719
| `seed-loader.zod.ts` | wire | **re-verdicted 2026-08-14 (#4001 batch D)** — the `(p)` split's "authored" half dissolved under measurement. The seed FILE shape this file's old note meant is `SeedSchema` (`seed.zod.ts`, a registered type, strict since the registered-types batch) — it enters this file only as the `seeds[]` VALUE inside `SeedLoaderRequestSchema`, so the authored half was never one of these 12 sites. Every producer of the request/config halves is framework code, enumerated: `runtime/app-plugin.ts` ×3 (org replay / inline seed / hot-reload), `runtime/domains/packages.ts`, `metadata-protocol/protocol.ts` `applySeedBodies`, `metadata-protocol/seed-loader.ts` `validate()`, `cloud-connection` marketplace install — all `.parse()`/`.safeParse()` over config LITERALS written in code; no `defineStack` key, no metadata type, no Studio form, no CLI flag writes a loader config. `SeedIdentity` is server-constructed by design (`execution-context.zod.ts`: "never client-supplied"); graph/resolution/result/error shapes are built by the loader itself (`buildDependencyGraph`, `buildResult`). BFS from all 26 metadata-type roots + `ObjectStackSchema` (6689 nodes; `ObjectSchema` positive control REACHABLE, fresh uncarried shape negative control UNREACHABLE, synthetic-carrier flip green, same run): all 12 UNREACHABLE. Same class as `data-engine.zod.ts` — an internal service contract (`ISeedLoaderService`), machine-fed at every door |
720720
| `field.zod.ts` | authorable | partially strict |
721721
| `filter.zod.ts` | open | query dialect — user data flows through the predicate values; validated semantically elsewhere |

‎packages/spec/src/contracts/data-engine.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,8 +169,8 @@ export interface WriteObservabilityOptions {
169169
*
170170
* This is an IN-PROCESS option, exactly like its neighbour above, and for the
171171
* same structural reason: `WriteObservabilityOptions` is not the serializable
172-
* `EngineUpdateOptionsSchema` bag, so nothing here crosses the RPC / Virtual
173-
* Data Engine boundary or is reachable from a REST/wire body. A remote caller
172+
* `EngineUpdateOptionsSchema` bag, so nothing here can be serialized, and
173+
* none of it is reachable from a REST/wire body. A remote caller
174174
* cannot set it, and gets NEITHER behaviour: its write is stripped and
175175
* committed, silently from its side, exactly as before this option existed —
176176
* a 200 whose read-only columns kept their stored values. That is deliberate

‎packages/spec/src/data/data-engine.zod.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1343,8 +1343,8 @@ export type QueryWithTransportParsed = z.infer<typeof QueryWithTransportSchema>;
13431343
// `ctx.api.object(name).find(...)` and parses no request schema; the wire batch
13441344
// validates with `CrossObjectBatchRequestSchema` / `BatchUpdateRequestSchema`
13451345
// from `../api/batch.zod.ts`. As published the protocol was also unsafe to
1346-
// implement: every arm admitted a caller-supplied `context` (`isSystem`
1347-
// included), and `execute` carried a raw driver command. Its private helpers
1346+
// implement: every read and write arm admitted a caller-supplied `context`
1347+
// (`isSystem` included), and `execute` carried a raw driver command. Its private helpers
13481348
// (`RpcQueryOptionsSchema` and the `filter`-only fold) went with it;
13491349
// `RPC_QUERY_ALIAS_SLOTS` above stays, since the transport dialect and the
13501350
// engine fold by it.

‎packages/spec/src/migrations/entries/semantic/18.data-engine-rpc-protocol-retired.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ export const entry: SemanticMigration = {
3636
+ 'against controls of 311, 2095 and 74 files importing `@objectstack/spec`. The one real '
3737
+ 'boundary engine calls cross, the QuickJS hook and action sandbox, speaks '
3838
+ '`ctx.api.object(name)` and parses no request schema. As published the protocol was also '
39-
+ 'unsafe to implement: every arm admitted a caller-supplied `context` (`isSystem` included) '
39+
+ 'unsafe to implement: every read and write arm admitted a caller-supplied `context` '
40+
+ '(`isSystem` included) '
4041
+ 'and the `execute` arm carried a raw driver command, so enforcing it would first have '
4142
+ 'meant narrowing it and building a second data door beside REST, batch, MCP and the '
4243
+ 'sandbox. `DataEngineContractSchema` restated the engine methods as `z.function()` '

0 commit comments

Comments
 (0)