From 9d214ed97e4c524293eb601c75a817854ba7cb3e Mon Sep 17 00:00:00 2001 From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com> Date: Fri, 4 Sep 2026 02:42:56 +0000 Subject: [PATCH 1/4] feat(spec): retire MetadataChangedEventPayloadSchema, the metadata:changed payload nothing ever emitted or consumed (ADR-0049) WIP: schema + orphan enum removed, ADR-0087 registrations (two retired-def entries, the D3 semantic entry, registry regenerated), retirement pins in cluster.test.ts, the two isomorphic alias pins, cluster.mdx prose, the metadata-manager doc-comment and the changeset. Generated artifacts follow in the next commit. Claude-Session: https://claude.ai/code/session_0174WZTU6XcFcS7g2kykC53i Co-authored-by: Claude --- .../metadata-changed-event-payload-retired.md | 68 +++++++++++ content/docs/kernel/cluster.mdx | 106 ++++++++-------- packages/metadata/src/metadata-manager.ts | 12 +- packages/spec/src/kernel/cluster.test.ts | 61 +++++----- packages/spec/src/kernel/cluster.zod.ts | 87 ++++---------- .../18.kernel__MetadataChangeOperation.ts | 23 ++++ .../18.kernel__MetadataChangedEventPayload.ts | 36 ++++++ ....metadata-changed-event-payload-retired.ts | 62 ++++++++++ packages/spec/src/migrations/registry.ts | 113 ++++++++++++++++++ .../src/type-alias-convention.pin.test.ts | 21 +++- 10 files changed, 429 insertions(+), 160 deletions(-) create mode 100644 .changeset/metadata-changed-event-payload-retired.md create mode 100644 packages/spec/src/migrations/entries/retired-defs/18.kernel__MetadataChangeOperation.ts create mode 100644 packages/spec/src/migrations/entries/retired-defs/18.kernel__MetadataChangedEventPayload.ts create mode 100644 packages/spec/src/migrations/entries/semantic/18.metadata-changed-event-payload-retired.ts diff --git a/.changeset/metadata-changed-event-payload-retired.md b/.changeset/metadata-changed-event-payload-retired.md new file mode 100644 index 0000000000..61d30433f1 --- /dev/null +++ b/.changeset/metadata-changed-event-payload-retired.md @@ -0,0 +1,68 @@ +--- +"@objectstack/spec": minor +--- + +feat(spec): retire `MetadataChangedEventPayloadSchema` — the `metadata:changed` payload nothing ever emitted or consumed (#14180, ADR-0049) + + + +**BREAKING** export removal, landing after the v17.0.0 cut (the lockstep +launch-window convention ships it as `minor`; the prescription is registered +under protocol major 18 — `RETIRED_DEFS_BY_MAJOR[18]` + the D3 semantic entry +`metadata-changed-event-payload-retired` — where `os migrate meta` users will +look). + +`kernel/cluster.zod.ts` declared a "canonical payload for the +`metadata:changed` event" and said every metadata persistence layer MUST emit +it after any successful write and every reader MUST subscribe and compare its +`version` before invalidating. Nothing ever did either: zero runtime emitters, +zero subscribers, zero imports outside `packages/spec` (its own unit test, the +isomorphic alias pin and the generated artifacts), in objectstack and in +objectui at the pinned sha. It could not have been honoured as declared — the +`version` field is `z.bigint()`, which the standard JSON serializer refuses, so +the payload could not cross any pubsub transport without a codec no driver +ships. The three cluster channels that do run (`metadata.changed`, +`metadata.mutated`, `datasource.mutated`) all carry an address-only signal +whose receiver re-reads its own store — the opposite of the declared +version-compare receipt — so the one plausible future consumer was decided +against (2026-09-01 ruling), and the triage ruling (2026-09-02) chose removal +over "make a consumer". + +FROM → TO: + +- `MetadataChangedEventPayloadSchema` / `MetadataChangedEventPayload` → + *(removed)* — no replacement type is declared. Subscribe to one of the lanes + documented in `content/docs/kernel/cluster.mdx` §6.2 instead: + `metadata.changed` (`ClusterMetadataChangedPayload`, `@objectstack/metadata`), + `metadata.mutated` (`ClusterMetadataMutationPayload`, + `@objectstack/metadata-protocol`) or `datasource.mutated` + (`ClusterDatasourceMutationPayload`, `@objectstack/service-datasource`). +- `MetadataChangeOperationSchema` / `MetadataChangeOperation` → *(removed)* — + the orphan value schema of the payload's `operation` field; it had no other + consumer. + +One-line fix: delete the import — every one of the four names is TS2305 after +upgrade, and no runtime path ever produced or read a value of these types. A +host that used the retired type for a transport of its own keeps a local type. + +The retirement kit: + +- **whole-def deletion** (route 3 — not an authorable surface: no metadata-type + binding, stack collection or manifest embed ever carried it, and nothing + parsed it outside its own unit test, so there is no authored document to + rewrite and nobody who could receive a parse-time tombstone): + `kernel/MetadataChangedEventPayload` and `kernel/MetadataChangeOperation` in + `RETIRED_DEFS_BY_MAJOR[18]` plus the D3 semantic entry. The payload def was + never in `json-schema.manifest/` (the JSON Schema build skips `bigint`); the + enum was, so the manifest deletion gate adjudicates it against the entry. +- **retirement pins** in `kernel/cluster.test.ts`: runtime namespace probes + assert both names are absent from `kernel/cluster.zod` and from the + `@objectstack/spec/kernel` entry, with `ClusterCapabilityConfigSchema` as + the positive control; the two isomorphic alias pins left with the schemas. +- **docs**: `content/docs/kernel/cluster.mdx` no longer describes a planned + version-stamped payload or a version-compare reader contract — the shipped + address-only lanes and their re-read receipt are the contract; the + `ClusterMetadataChangedPayload` doc-comment in `@objectstack/metadata` no + longer claims to "align with" the retired schema (it never did). +- zero in-tree consumers, so no in-repo source changes ride along; runtime + behaviour is unchanged. diff --git a/content/docs/kernel/cluster.mdx b/content/docs/kernel/cluster.mdx index 2935677a10..93af82e1bb 100644 --- a/content/docs/kernel/cluster.mdx +++ b/content/docs/kernel/cluster.mdx @@ -296,31 +296,31 @@ they declare scope and strategy, and the runtime does the rest. Metadata is the most cache-hot data in the system. Every read path — ObjectQL planning, REST routing, UI rendering, permission checks — -touches it. Making it correct across a cluster requires two things the -current protocol lacks: a **monotonic version per item** and a -**well-defined invalidation event**. +touches it. Making it correct across a cluster needs a well-defined +invalidation signal per state owner — the three lanes of §6.2 — and, in this +protocol, deliberately **no** per-item version on the wire (§6.1). ### 6.1 Monotonic version A `version` column is already present on every persisted metadata record in `system/metadata-persistence.zod.ts` (`version: z.number()`, used today for -optimistic concurrency). This ADR proposes formalising it as a monotonic -per-item version and **widening it to `bigint`** so caches can compare -freshness across long-running clusters without overflow. - -> **Status: planned.** The column is still `version: number` in the schema; -> the widening and the cache-comparison contract below describe the target -> design, not current runtime behaviour. - -Once wired, caches store `{value, version}`. On any incoming change -notification the cache compares the incoming version with the stored one: - -- Incoming version `>` stored → invalidate (apply new value or evict) -- Incoming version `≤` stored → ignore (out-of-order notification, already - superseded) - -This eliminates a whole class of bugs where a slow-arriving "old" -invalidation evicts a "newer" value the node has already learned about. +optimistic concurrency). Earlier revisions of this page proposed formalising +it as a monotonic per-item version, widening it to `bigint`, and having every +cache compare it on receipt. + +> **Status: not declared.** The column is `version: number` in the schema, +> and nothing in the protocol carries a version across nodes. The +> version-compare invalidation this section once described as the target +> design — caches storing `{value, version}` and ignoring a notification whose +> version is not strictly greater than the cached one — went with the retired +> `MetadataChangedEventPayloadSchema` (§6.2, lane 1; ADR-0049 +> enforce-or-remove, ADR-0087 entry `metadata-changed-event-payload-retired`). +> The shipped lanes are address-only signals whose receiver re-reads its own +> store, and a re-ordered or duplicated delivery converges to the same state as +> a single one — which is what removes the "old invalidation evicts a newer +> value" class of bug without a version to compare. A version-stamped protocol +> returns only via the ENFORCE route of ADR-0049: the emitter and the reader +> first, the declaration with them. ### 6.2 The cluster-invalidation family @@ -394,30 +394,23 @@ the pre-write set (#5109). The registry entry is **deleted, never pre-filled** from the payload — the peer re-reads the shared store, which is the source of truth. -At the payload's top level there is still **no** `version` / `name` / -`tenantId` / `operation` field and **no** version comparison; the item's name -is carried only inside the replayed `event`. - -**Target spec (planned).** The richer, version-stamped payload below is -defined as `MetadataChangedEventPayloadSchema` in `kernel/cluster.zod.ts` -but is **not yet wired** into the runtime: - -```ts -// MetadataChangedEventPayloadSchema — target shape, not yet emitted -{ - type: 'object' | 'view' | 'flow' | …, - name: '', - tenantId?: '', - version: , - operation: 'create' | 'update' | 'delete' | 'publish', -} -``` - -When wired with `scope: 'cluster'` + `deliverySemantics: 'at-least-once'` -and a `partitionKey` of `` `${type}:${name}` ``, the partition key would -guarantee that two rapid updates to the same item are applied to every -node's cache in order, and the at-least-once guarantee would let a briefly -partitioned node catch up on reconnect. +At the payload's top level there is **no** `version` / `name` / `tenantId` +/ `operation` field and **no** version comparison — by design, not by +omission; the item's name is carried only inside the replayed `event`. + +**No richer payload is declared.** The spec once carried a version-stamped +target shape for this lane — `MetadataChangedEventPayloadSchema` in +`kernel/cluster.zod.ts` (`type` / `name` / `tenantId` / `version: bigint` / +`operation` / `correlationId`), whose docblock said every persistence layer +MUST emit it and every reader MUST compare `version` on receipt. Nothing ever +emitted or subscribed to it, and its `bigint` version could not have crossed a +JSON transport without a codec no driver ships, so it was retired under +ADR-0049 enforce-or-remove (ADR-0087 entry +`metadata-changed-event-payload-retired`, `RETIRED_DEFS_BY_MAJOR[18]`, +together with the `MetadataChangeOperationSchema` enum that typed its +`operation` field). The shape above **is** the lane-1 contract, and its +receipt semantics are the family's: drop the cache entry, re-read the shared +store, no version comparison. #### Lane 2 — `metadata.mutated` (the ObjectQL object registry) @@ -485,16 +478,18 @@ all; the admin service publishes on the write doors it already owns. ### 6.3 Reader contract -> **Status: planned.** Today readers are invalidated by the `metadata.changed` -> PubSub fan-out described in §6.2, which replays watch events verbatim -> without version comparison. The contract below is the target design that -> goes with the version-stamped payload. - -All metadata readers (registry, loader, query engine) should: +The reader contract is the one §6.2 states for the family, and it is what +ships — there is no version-stamped variant behind it (the payload that +carried one was retired, §6.1). A metadata reader that keeps its own +long-lived cache: -1. Subscribe to the metadata change channel on startup. -2. Compare incoming `version` with cached `version` before evicting. -3. Treat missing `version` as `0` (legacy compatibility). +1. Subscribes to the lane whose state it mirrors — `metadata.changed` for a + mirror of the metadata service's own caches; lanes 2 and 3 already keep + ObjectQL's object and driver registries converged (§7.3). +2. On receipt drops its own `originNode` messages, then evicts — never + pre-fills from the payload. +3. Re-reads the shared store on the next access; a duplicate or re-ordered + delivery converges to the same state as a single one. ## 7. Plugin author guidance @@ -572,8 +567,9 @@ cluster.pubsub.subscribe('metadata.changed', (msg) => { > already keep those registries converged across replicas, and a second > subscription would be redundant. -A higher-level cache factory (with automatic version comparison) is part of -the Phase 4 / §6 target design but is **not yet implemented**. No +There is no higher-level cache factory and no version comparison to +automate — the version-stamped payload was retired (§6.1) and the lanes are +address-only, so the subscribe-and-evict shape above is the whole contract. No `if (cluster)` branches are needed either way — the `memory` driver makes the subscribe call a no-op-equivalent local fan-out on a single node. diff --git a/packages/metadata/src/metadata-manager.ts b/packages/metadata/src/metadata-manager.ts index 042f99b9c7..a29a87e3d5 100644 --- a/packages/metadata/src/metadata-manager.ts +++ b/packages/metadata/src/metadata-manager.ts @@ -230,8 +230,16 @@ function generateEventUuid(): string { * Payload format for cluster-wide metadata change broadcasts. * * Published on channel `metadata.changed` by any node mutating metadata - * and consumed by peers to invalidate their local caches. Aligns with - * `MetadataChangedEventPayload` in `cluster-semantics.mdx` §5. + * and consumed by peers to invalidate their local caches + * (`content/docs/kernel/cluster.mdx` §6.2, lane 1). This shape IS the whole + * contract: the origin node for loopback suppression, the metadata type, and + * the local watch event replayed verbatim — an address-only signal. There is + * no `version`, `name`, `tenantId` or `operation` at the top level and no + * version comparison on receipt; a peer drops its cache entry and re-reads + * the shared store. The spec once declared a richer, version-stamped + * `metadata:changed` payload that this shape was said to align with; it never + * did, and that schema was retired (ADR-0087 entry + * `metadata-changed-event-payload-retired`). */ export interface ClusterMetadataChangedPayload { /** Origin nodeId — used for loopback suppression. */ diff --git a/packages/spec/src/kernel/cluster.test.ts b/packages/spec/src/kernel/cluster.test.ts index 082c087bcb..639bcf2b83 100644 --- a/packages/spec/src/kernel/cluster.test.ts +++ b/packages/spec/src/kernel/cluster.test.ts @@ -10,7 +10,6 @@ import { ServiceClusterAnnotationsSchema, ClusterDriverSchema, ClusterCapabilityConfigSchema, - MetadataChangedEventPayloadSchema, } from './cluster.zod'; import { EventMetadataSchema } from './events/core.zod'; import { ServiceMetadataSchema, ServiceFactoryRegistrationSchema } from './service-registry.zod'; @@ -193,38 +192,38 @@ describe('cluster.zod', () => { }); }); - describe('MetadataChangedEventPayload', () => { - it('parses a canonical change payload', () => { - const parsed = MetadataChangedEventPayloadSchema.parse({ - type: 'object', - name: 'account', - version: 42n, - operation: 'update', - }); - expect(parsed.type).toBe('object'); - expect(parsed.version).toBe(42n); - expect(parsed.operation).toBe('update'); - }); - - it('accepts tenant-scoped overlay changes', () => { - const parsed = MetadataChangedEventPayloadSchema.parse({ - type: 'view', - name: 'account_list', - tenantId: 'tnt_abc', - version: 7n, - operation: 'publish', - }); - expect(parsed.tenantId).toBe('tnt_abc'); + describe('MetadataChangedEventPayload retirement (ADR-0049 enforce-or-remove)', () => { + // Runtime namespace probes, the registry-retirement.test.ts pattern: a + // removed export cannot be imported by name (would not compile), so the + // pin asks the namespace object. The payload schema declared a MUST-emit / + // MUST-subscribe `metadata:changed` contract that nothing ever produced or + // consumed, and its `z.bigint()` version could not cross a JSON transport; + // the `MetadataChangeOperationSchema` enum existed only to type its + // `operation` field and left with it as the orphan value schema. ADR-0087: + // `RETIRED_DEFS_BY_MAJOR[18]` + the D3 entry + // `metadata-changed-event-payload-retired`. Anti-vacuity guard on each + // probe: a neighbour that stayed. + const RETIRED = [ + 'MetadataChangedEventPayloadSchema', + 'MetadataChangeOperationSchema', + ] as const; + const SURVIVOR = 'ClusterCapabilityConfigSchema'; + + it('the payload schema and its orphan operation enum are no longer exported from kernel/cluster.zod', async () => { + const mod = (await import('./cluster.zod')) as unknown as Record; + for (const name of RETIRED) { + expect(Object.prototype.hasOwnProperty.call(mod, name)).toBe(false); + } + // Anti-vacuity: the sibling that deliberately stayed still resolves. + expect(Object.prototype.hasOwnProperty.call(mod, SURVIVOR)).toBe(true); }); - it('rejects payload without a version', () => { - expect(() => - MetadataChangedEventPayloadSchema.parse({ - type: 'object', - name: 'account', - operation: 'update', - }), - ).toThrow(); + it('nor from the `@objectstack/spec/kernel` entry', async () => { + const kernel = (await import('./index')) as unknown as Record; + for (const name of RETIRED) { + expect(Object.prototype.hasOwnProperty.call(kernel, name)).toBe(false); + } + expect(Object.prototype.hasOwnProperty.call(kernel, SURVIVOR)).toBe(true); }); }); }); diff --git a/packages/spec/src/kernel/cluster.zod.ts b/packages/spec/src/kernel/cluster.zod.ts index 37fdc590c1..61538d29e2 100644 --- a/packages/spec/src/kernel/cluster.zod.ts +++ b/packages/spec/src/kernel/cluster.zod.ts @@ -327,71 +327,24 @@ export type ClusterCapabilityConfig = z.input; // ========================================================================== -// Metadata Change Event Payload +// Retired: the `metadata:changed` event payload (ADR-0049 enforce-or-remove) // ========================================================================== - -/** - * Operation that triggered a `metadata:changed` event. - */ -export const MetadataChangeOperationSchema = z.enum([ - 'create', - 'update', - 'delete', - 'publish', -]).describe('Persistence operation that triggered the change.'); - -export type MetadataChangeOperation = z.input; - -/** - * Canonical payload for the `metadata:changed` event. - * - * All metadata persistence layers MUST emit this event after any successful - * write. Readers (registry caches, query engines, REST routers) MUST - * subscribe to it and compare `version` with their cached value before - * applying the invalidation — out-of-order older versions are ignored. - * - * @see content/docs/kernel/cluster.mdx §6 - */ -export const MetadataChangedEventPayloadSchema = lazySchema(() => z.object({ - /** - * Metadata type — e.g. `'object'`, `'view'`, `'flow'`, `'agent'`. - * Matches the `MetadataTypeSchema` enum. - */ - type: z.string().min(1).describe('Metadata type (e.g. "object", "view").'), - - /** - * Machine name of the changed item. - */ - name: z.string().min(1).describe('Machine name of the metadata item.'), - - /** - * Tenant scope when the change is tenant-overlaid. Absent for - * platform-default metadata. - */ - tenantId: z.string().optional().describe('Tenant id when the change is overlay-scoped.'), - - /** - * Monotonic version of the record after the change. Readers compare - * this with their cached value; only strictly greater versions - * invalidate. - * - * Modelled as `bigint` in the schema to support long-running clusters - * without 32-bit wraparound concerns; persisted as `numeric` / `int8` - * in storage. - */ - version: z.bigint().describe('Monotonic version of the record after the change.'), - - /** - * The operation that produced this version. - */ - operation: MetadataChangeOperationSchema, - - /** - * Optional correlation id for tracing the change back to a request / - * deploy / migration that produced it. - */ - correlationId: z.string().optional() - .describe('Trace correlation id of the originating request.'), -}).describe('Canonical payload for the metadata:changed cluster event.')); - -export type MetadataChangedEventPayload = z.input; +// +// `MetadataChangedEventPayloadSchema` (`type` / `name` / `tenantId` / +// `version: z.bigint()` / `operation` / `correlationId`) and the +// `MetadataChangeOperationSchema` enum that existed only to type its +// `operation` field were removed whole. The ADR-0087 registry is the +// declaration: `kernel/MetadataChangedEventPayload` and +// `kernel/MetadataChangeOperation` in `RETIRED_DEFS_BY_MAJOR[18]` plus the D3 +// semantic entry `metadata-changed-event-payload-retired`. The docblock said +// every metadata persistence layer MUST emit it and every reader MUST +// subscribe and version-compare; nothing ever did either, and the `bigint` +// version field could not have crossed a JSON transport without a codec no +// pubsub driver ships. The cluster channels that actually run are documented +// in `content/docs/kernel/cluster.mdx` §6.2: `metadata.changed` +// (`ClusterMetadataChangedPayload`, `@objectstack/metadata`), +// `metadata.mutated` (`ClusterMetadataMutationPayload`, +// `@objectstack/metadata-protocol`) and `datasource.mutated` — address-only +// signals whose receivers re-read their own store rather than compare +// versions. A version-stamped payload returns only via the ENFORCE route of +// ADR-0049: the emitter and the reader first, the declaration with them. diff --git a/packages/spec/src/migrations/entries/retired-defs/18.kernel__MetadataChangeOperation.ts b/packages/spec/src/migrations/entries/retired-defs/18.kernel__MetadataChangeOperation.ts new file mode 100644 index 0000000000..4e005290be --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.kernel__MetadataChangeOperation.ts @@ -0,0 +1,23 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #14180 — kernel/cluster.zod.ts `MetadataChangeOperationSchema` / +// `MetadataChangeOperation` (the `create` / `update` / `delete` / `publish` +// enum), the orphan value schema of the retired +// `kernel/MetadataChangedEventPayload` def registered beside it: it existed +// only to type that payload's `operation` field and had no other consumer +// anywhere — measured at the retirement's base commit 2cc461030, every hit +// was the payload itself, its own isomorphic alias pin and the generated +// artifacts; nothing in objectui at the pinned sha. An exported value schema +// with no consumer reads as a capability to whoever finds it (#3950), so it +// leaves with the payload (the playbook's orphan-value-schema rule, the +// `kernel/DistributedStateConfig` precedent). Unlike the payload this enum +// serializes, so it WAS in `json-schema.manifest/kernel.json` and the +// manifest deletion gate adjudicates its removal against this entry. Route 3, +// same declaration: this table plus the D3 semantic entry +// `metadata-changed-event-payload-retired`. +// +// Registered under 18, not 17: v17.0.0 was cut before this landed, so the +// removal ships on the 17.x line (launch-window convention: accept-set +// narrowings ride minor releases) and the prescription lives at the major +// boundary where `migrate meta` users look. +export const entry = 'kernel/MetadataChangeOperation'; diff --git a/packages/spec/src/migrations/entries/retired-defs/18.kernel__MetadataChangedEventPayload.ts b/packages/spec/src/migrations/entries/retired-defs/18.kernel__MetadataChangedEventPayload.ts new file mode 100644 index 0000000000..9aa792ebbb --- /dev/null +++ b/packages/spec/src/migrations/entries/retired-defs/18.kernel__MetadataChangedEventPayload.ts @@ -0,0 +1,36 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +// #14180 — kernel/cluster.zod.ts `MetadataChangedEventPayloadSchema` / +// `MetadataChangedEventPayload`, retired whole (ADR-0049 enforce-or-remove; +// triage ruling 2026-09-02: remove via the ADR-0087 route, ⛔ not "make a +// consumer" — that is contract growth with no pull). The docblock declared a +// MUST-emit / MUST-subscribe contract for a `metadata:changed` event — `type` +// / `name` / `tenantId` / `version: z.bigint()` / `operation` / +// `correlationId`, readers comparing `version` before invalidating — that +// nothing in the tree ever produced or consumed: zero runtime emitters, zero +// subscribers, zero imports outside `packages/spec` (its own unit test, the +// isomorphic alias pin and the generated artifacts), measured at the +// retirement's base commit 2cc461030 with positive controls in objectstack +// and objectui (pinned sha). It was unenforceable by construction: the +// `bigint` version field cannot cross a JSON transport (the standard +// serializer throws on it) without a codec no pubsub driver ships, so no +// conforming emitter could ever have existed. The three cluster channels that +// DO run — `metadata.changed` (`ClusterMetadataChangedPayload`, +// `@objectstack/metadata`), `metadata.mutated` +// (`ClusterMetadataMutationPayload`, `@objectstack/metadata-protocol`) and +// `datasource.mutated` — all carry an address-only signal whose receiver +// re-reads its own store (ruled 2026-09-01 for the registry lane), the +// opposite of the declared version-compare receipt, so the one plausible +// future consumer was decided against. Never in `json-schema.manifest/` (the +// JSON Schema build skips `bigint`), so the manifest deletion gate has nothing +// to adjudicate for this def; the entry is the declaration the retirement +// route requires. Route 3: not an authorable surface — no metadata-type +// binding, stack collection or manifest embed ever carried it — so no +// tombstone and no D2 conversion; this table plus the D3 semantic entry +// `metadata-changed-event-payload-retired` ARE the declaration. +// +// Registered under 18, not 17: v17.0.0 was cut before this landed, so the +// removal ships on the 17.x line (launch-window convention: accept-set +// narrowings ride minor releases) and the prescription lives at the major +// boundary where `migrate meta` users look. +export const entry = 'kernel/MetadataChangedEventPayload'; diff --git a/packages/spec/src/migrations/entries/semantic/18.metadata-changed-event-payload-retired.ts b/packages/spec/src/migrations/entries/semantic/18.metadata-changed-event-payload-retired.ts new file mode 100644 index 0000000000..0dfbbdbab8 --- /dev/null +++ b/packages/spec/src/migrations/entries/semantic/18.metadata-changed-event-payload-retired.ts @@ -0,0 +1,62 @@ +// Copyright (c) 2026 ObjectStack. Licensed under the Apache-2.0 license. + +import type { SemanticMigration } from '../../types.js'; + +export const entry: SemanticMigration = { + id: 'metadata-changed-event-payload-retired', + surface: + 'kernel.cluster metadata change event payload (`MetadataChangedEventPayloadSchema` ' + + 'in kernel/cluster.zod.ts — 2 defs, 4 exported names: ' + + '`MetadataChangedEventPayloadSchema`, `MetadataChangedEventPayload`, ' + + '`MetadataChangeOperationSchema`, `MetadataChangeOperation`)', + replacement: + 'Nothing to migrate to, because nothing ever emitted or consumed it. The ' + + 'cluster invalidation channels that actually run are the three lanes ' + + 'documented in content/docs/kernel/cluster.mdx §6.2: `metadata.changed` ' + + '(`ClusterMetadataChangedPayload` in `@objectstack/metadata` — the origin ' + + 'node, the metadata type and the replayed watch event), `metadata.mutated` ' + + '(`ClusterMetadataMutationPayload` in `@objectstack/metadata-protocol`) and ' + + '`datasource.mutated` (`ClusterDatasourceMutationPayload` in ' + + '`@objectstack/service-datasource`). A host that needs cross-node cache ' + + 'invalidation subscribes to one of those; a host that held the retired type ' + + 'for a transport of its own keeps a local type — the spec no longer declares ' + + 'one.', + reason: + 'ADR-0049 enforce-or-remove (triage ruling 2026-09-02 on the spec seat: ' + + 'remove via the ADR-0087 route, not "make a consumer" — that is contract ' + + 'growth with no pull). The docblock declared that all metadata persistence ' + + 'layers MUST emit a `metadata:changed` event with this payload and that ' + + 'every reader MUST subscribe and compare `version` before invalidating. ' + + "Measured at the retirement's base commit with positive controls: zero " + + 'runtime producers, zero subscribers, zero imports outside packages/spec ' + + '(its own unit test, the isomorphic alias pin and the generated artifacts) ' + + 'in objectstack, and nothing in objectui at the pinned sha. It was ' + + 'unenforceable by construction — the `version` field is `z.bigint()`, ' + + 'which the standard JSON serializer refuses, so the payload as declared ' + + 'could not cross any pubsub transport without a codec no driver ships: a ' + + 'MUST-emit contract no conforming emitter could satisfy. The shipped ' + + 'channels all carry an address-only signal whose receiver re-reads its own ' + + 'store (the 2026-09-01 ruling for the registry lane), the opposite of the ' + + 'declared version-compare receipt, so the one plausible future consumer was ' + + 'decided against; the 2026-08-27 ruling on transitions removes a staged ' + + "window. `MetadataChangeOperationSchema` existed only to type the payload's " + + '`operation` field and leaves with it as its orphan value schema (the ' + + '`DistributedStateConfig` precedent). Route 3: not an authorable surface — ' + + 'no metadata-type binding, stack collection or manifest embed ever carried ' + + 'it, and nothing parsed it outside its own unit test — so no tombstone and ' + + 'no D2 conversion; `RETIRED_DEFS_BY_MAJOR[18]` ' + + '(`kernel/MetadataChangedEventPayload`, `kernel/MetadataChangeOperation`) ' + + 'plus this entry ARE the declaration.', + acceptanceCriteria: + 'No code imports `MetadataChangedEventPayloadSchema`, ' + + '`MetadataChangedEventPayload`, `MetadataChangeOperationSchema` or ' + + '`MetadataChangeOperation` from `@objectstack/spec` or ' + + '`@objectstack/spec/kernel` — every one is TS2305 after upgrade (pinned by ' + + 'runtime namespace probes in kernel/cluster.test.ts, with ' + + '`ClusterCapabilityConfigSchema` as the positive control). No metadata ' + + 'document needs editing: the schema was reachable from no metadata-type ' + + 'binding, stack collection or /meta door. ⚠️ Runtime behaviour is ' + + 'deliberately UNCHANGED: no emitter or subscriber ever existed, and the ' + + 'three shipped cluster lanes publish the same bytes before and after — the ' + + 'retirement removes a false declaration, not behaviour.', +}; diff --git a/packages/spec/src/migrations/registry.ts b/packages/spec/src/migrations/registry.ts index c74366d3b1..30697e3d0b 100644 --- a/packages/spec/src/migrations/registry.ts +++ b/packages/spec/src/migrations/registry.ts @@ -6908,6 +6908,64 @@ const step18: MigrationStep = { '`persistence.key`; `initialData` record values containing literal `${…}` keep parsing ' + 'byte-identically.', }, + { + id: 'metadata-changed-event-payload-retired', + surface: + 'kernel.cluster metadata change event payload (`MetadataChangedEventPayloadSchema` ' + + 'in kernel/cluster.zod.ts — 2 defs, 4 exported names: ' + + '`MetadataChangedEventPayloadSchema`, `MetadataChangedEventPayload`, ' + + '`MetadataChangeOperationSchema`, `MetadataChangeOperation`)', + replacement: + 'Nothing to migrate to, because nothing ever emitted or consumed it. The ' + + 'cluster invalidation channels that actually run are the three lanes ' + + 'documented in content/docs/kernel/cluster.mdx §6.2: `metadata.changed` ' + + '(`ClusterMetadataChangedPayload` in `@objectstack/metadata` — the origin ' + + 'node, the metadata type and the replayed watch event), `metadata.mutated` ' + + '(`ClusterMetadataMutationPayload` in `@objectstack/metadata-protocol`) and ' + + '`datasource.mutated` (`ClusterDatasourceMutationPayload` in ' + + '`@objectstack/service-datasource`). A host that needs cross-node cache ' + + 'invalidation subscribes to one of those; a host that held the retired type ' + + 'for a transport of its own keeps a local type — the spec no longer declares ' + + 'one.', + reason: + 'ADR-0049 enforce-or-remove (triage ruling 2026-09-02 on the spec seat: ' + + 'remove via the ADR-0087 route, not "make a consumer" — that is contract ' + + 'growth with no pull). The docblock declared that all metadata persistence ' + + 'layers MUST emit a `metadata:changed` event with this payload and that ' + + 'every reader MUST subscribe and compare `version` before invalidating. ' + + "Measured at the retirement's base commit with positive controls: zero " + + 'runtime producers, zero subscribers, zero imports outside packages/spec ' + + '(its own unit test, the isomorphic alias pin and the generated artifacts) ' + + 'in objectstack, and nothing in objectui at the pinned sha. It was ' + + 'unenforceable by construction — the `version` field is `z.bigint()`, ' + + 'which the standard JSON serializer refuses, so the payload as declared ' + + 'could not cross any pubsub transport without a codec no driver ships: a ' + + 'MUST-emit contract no conforming emitter could satisfy. The shipped ' + + 'channels all carry an address-only signal whose receiver re-reads its own ' + + 'store (the 2026-09-01 ruling for the registry lane), the opposite of the ' + + 'declared version-compare receipt, so the one plausible future consumer was ' + + 'decided against; the 2026-08-27 ruling on transitions removes a staged ' + + "window. `MetadataChangeOperationSchema` existed only to type the payload's " + + '`operation` field and leaves with it as its orphan value schema (the ' + + '`DistributedStateConfig` precedent). Route 3: not an authorable surface — ' + + 'no metadata-type binding, stack collection or manifest embed ever carried ' + + 'it, and nothing parsed it outside its own unit test — so no tombstone and ' + + 'no D2 conversion; `RETIRED_DEFS_BY_MAJOR[18]` ' + + '(`kernel/MetadataChangedEventPayload`, `kernel/MetadataChangeOperation`) ' + + 'plus this entry ARE the declaration.', + acceptanceCriteria: + 'No code imports `MetadataChangedEventPayloadSchema`, ' + + '`MetadataChangedEventPayload`, `MetadataChangeOperationSchema` or ' + + '`MetadataChangeOperation` from `@objectstack/spec` or ' + + '`@objectstack/spec/kernel` — every one is TS2305 after upgrade (pinned by ' + + 'runtime namespace probes in kernel/cluster.test.ts, with ' + + '`ClusterCapabilityConfigSchema` as the positive control). No metadata ' + + 'document needs editing: the schema was reachable from no metadata-type ' + + 'binding, stack collection or /meta door. ⚠️ Runtime behaviour is ' + + 'deliberately UNCHANGED: no emitter or subscriber ever existed, and the ' + + 'three shipped cluster lanes publish the same bytes before and after — the ' + + 'retirement removes a false declaration, not behaviour.', + }, { id: 'metadata-customization-protocol-retired', surface: @@ -10411,6 +10469,61 @@ export const RETIRED_DEFS_BY_MAJOR: Readonly> // `metadata-customization-protocol-retired` ARE the declaration (the #8715 // route-3 shape). 'kernel/MergeStrategyConfig', + // #14180 — kernel/cluster.zod.ts `MetadataChangeOperationSchema` / + // `MetadataChangeOperation` (the `create` / `update` / `delete` / `publish` + // enum), the orphan value schema of the retired + // `kernel/MetadataChangedEventPayload` def registered beside it: it existed + // only to type that payload's `operation` field and had no other consumer + // anywhere — measured at the retirement's base commit 2cc461030, every hit + // was the payload itself, its own isomorphic alias pin and the generated + // artifacts; nothing in objectui at the pinned sha. An exported value schema + // with no consumer reads as a capability to whoever finds it (#3950), so it + // leaves with the payload (the playbook's orphan-value-schema rule, the + // `kernel/DistributedStateConfig` precedent). Unlike the payload this enum + // serializes, so it WAS in `json-schema.manifest/kernel.json` and the + // manifest deletion gate adjudicates its removal against this entry. Route 3, + // same declaration: this table plus the D3 semantic entry + // `metadata-changed-event-payload-retired`. + // + // Registered under 18, not 17: v17.0.0 was cut before this landed, so the + // removal ships on the 17.x line (launch-window convention: accept-set + // narrowings ride minor releases) and the prescription lives at the major + // boundary where `migrate meta` users look. + 'kernel/MetadataChangeOperation', + // #14180 — kernel/cluster.zod.ts `MetadataChangedEventPayloadSchema` / + // `MetadataChangedEventPayload`, retired whole (ADR-0049 enforce-or-remove; + // triage ruling 2026-09-02: remove via the ADR-0087 route, ⛔ not "make a + // consumer" — that is contract growth with no pull). The docblock declared a + // MUST-emit / MUST-subscribe contract for a `metadata:changed` event — `type` + // / `name` / `tenantId` / `version: z.bigint()` / `operation` / + // `correlationId`, readers comparing `version` before invalidating — that + // nothing in the tree ever produced or consumed: zero runtime emitters, zero + // subscribers, zero imports outside `packages/spec` (its own unit test, the + // isomorphic alias pin and the generated artifacts), measured at the + // retirement's base commit 2cc461030 with positive controls in objectstack + // and objectui (pinned sha). It was unenforceable by construction: the + // `bigint` version field cannot cross a JSON transport (the standard + // serializer throws on it) without a codec no pubsub driver ships, so no + // conforming emitter could ever have existed. The three cluster channels that + // DO run — `metadata.changed` (`ClusterMetadataChangedPayload`, + // `@objectstack/metadata`), `metadata.mutated` + // (`ClusterMetadataMutationPayload`, `@objectstack/metadata-protocol`) and + // `datasource.mutated` — all carry an address-only signal whose receiver + // re-reads its own store (ruled 2026-09-01 for the registry lane), the + // opposite of the declared version-compare receipt, so the one plausible + // future consumer was decided against. Never in `json-schema.manifest/` (the + // JSON Schema build skips `bigint`), so the manifest deletion gate has nothing + // to adjudicate for this def; the entry is the declaration the retirement + // route requires. Route 3: not an authorable surface — no metadata-type + // binding, stack collection or manifest embed ever carried it — so no + // tombstone and no D2 conversion; this table plus the D3 semantic entry + // `metadata-changed-event-payload-retired` ARE the declaration. + // + // Registered under 18, not 17: v17.0.0 was cut before this landed, so the + // removal ships on the 17.x line (launch-window convention: accept-set + // narrowings ride minor releases) and the prescription lives at the major + // boundary where `migrate meta` users look. + 'kernel/MetadataChangedEventPayload', // #13135 — ADR-0049 enforce-or-remove (maintainer ruling 2026-08-29 on // #12057: retirement adopted, re-scope rejected; re-charter #13135 executes // the widened surface). Part of the whole-module removal of diff --git a/packages/spec/src/type-alias-convention.pin.test.ts b/packages/spec/src/type-alias-convention.pin.test.ts index a49264887e..d542c58e93 100644 --- a/packages/spec/src/type-alias-convention.pin.test.ts +++ b/packages/spec/src/type-alias-convention.pin.test.ts @@ -269,7 +269,7 @@ import type * as M170 from './ui/component.zod.js'; import type * as M183 from './api/sortability.zod.js'; // --------------------------------------------------------------------------- -// 829 isomorphic aliases: `z.input` === `z.infer`, so no `XParsed` is declared. +// 827 isomorphic aliases: `z.input` === `z.infer`, so no `XParsed` is declared. // // That number is machine-checked, not hand-kept. The runtime companion at the // bottom of this file recomputes the pin count from the source and asserts that @@ -859,8 +859,6 @@ export type Iso389 = Assert, export type Iso390 = Assert, z.infer< typeof M80.ServiceLeaderStrategySchema > >>; export type Iso391 = Assert, z.infer< typeof M80.ClusterDriverSchema > >>; export type Iso392 = Assert, z.infer< typeof M80.ClusterTenantIsolationSchema > >>; -export type Iso393 = Assert, z.infer< typeof M80.MetadataChangeOperationSchema > >>; -export type Iso394 = Assert, z.infer< typeof M80.MetadataChangedEventPayloadSchema > >>; // kernel/context.zod.ts export type Iso395 = Assert, z.infer< typeof M81.RuntimeMode > >>; @@ -1680,7 +1678,7 @@ describe('ADR-0122 type-alias convention', () => { // this title and the section header above the pin list — are now asserted // against the recomputed count below, so neither can go stale without a red // test naming it. - it('still declares all 829 isomorphic pins', () => { + it('still declares all 827 isomorphic pins', () => { // The truth of each pin is proved by tsc, not here — an `Assert>` // that stops holding is a compile error with the alias named. What tsc // cannot notice is a pin that was DELETED: removing the assertion removes @@ -2103,9 +2101,22 @@ describe('ADR-0122 type-alias convention', () => { // `KnowledgeSourceParsed`) in the same commit — the ADR-0122 D6 order: // declare the parsed name, THEN delete the pin. -2 removed; the Iso // numbers stay vacant. + // + // 829 -> 827 is #14180's ADR-0049 retirement of the `metadata:changed` + // event payload (kernel/cluster.zod.ts): `MetadataChangedEventPayloadSchema` + // — a MUST-emit contract nothing ever produced or consumed, whose + // `z.bigint()` version could not cross a JSON transport — and the + // `MetadataChangeOperationSchema` enum that existed only to type its + // `operation` field left the module whole (RETIRED_DEFS_BY_MAJOR[18] + // `kernel/MetadataChangedEventPayload` + `kernel/MetadataChangeOperation`), + // so their pins `Iso393` / `Iso394` left with them — the aliases no longer + // exist, so there is nothing to be isomorphic. `kernel/cluster.test.ts` + // asserts the absence of both names on the module and the `./kernel` + // entry. -2 removed; the Iso numbers stay vacant (ids are claims about + // pins, not positions). const self = readFileSync(fileURLToPath(import.meta.url), 'utf8'); const pins = self.match(/^export type Iso\d+ = Assert Date: Fri, 4 Sep 2026 02:50:00 +0000 Subject: [PATCH 2/4] chore(spec): regenerate artifacts for the MetadataChangedEventPayload retirement json-schema.manifest loses kernel/MetadataChangeOperation deliberately (route 3 whole-def removal; the manifest deletion gate adjudicated it against RETIRED_DEFS_BY_MAJOR[18] - the payload def itself was never in the manifest, the JSON Schema build skips bigint); api-surface / export-origins / declaration-map lose the four retired names; the kernel reference page, the references index and the strictness-ledger counts regenerate. Claude-Session: https://claude.ai/code/session_0174WZTU6XcFcS7g2kykC53i Co-authored-by: Claude --- content/docs/references/index.mdx | 10 +++++----- content/docs/references/kernel/cluster.mdx | 18 ++---------------- ...-07-unknown-key-strictness-ledger.counts.md | 2 +- packages/spec/api-surface/kernel.json | 4 ---- packages/spec/declaration-map/kernel.json | 2 -- packages/spec/export-origins/kernel.json | 4 ---- packages/spec/json-schema.manifest/kernel.json | 1 - 7 files changed, 8 insertions(+), 33 deletions(-) diff --git a/content/docs/references/index.mdx b/content/docs/references/index.mdx index 47b1e23769..261b9403f2 100644 --- a/content/docs/references/index.mdx +++ b/content/docs/references/index.mdx @@ -1,6 +1,6 @@ --- title: Protocol Reference -description: Every schema published by @objectstack/spec — 1589 schemas across 14 protocol modules +description: Every schema published by @objectstack/spec — 1588 schemas across 14 protocol modules --- {/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */} @@ -26,14 +26,14 @@ counts are sums of the rows they head. Regenerate with | [Data Protocol](/docs/references/data) | 29 | 166 | Objects, fields, queries, filters, datasources and drivers — the ObjectQL layer. | | [Identity Protocol](/docs/references/identity) | 5 | 27 | Users and accounts, organizations, positions, SCIM provisioning. | | [Integration Protocol](/docs/references/integration) | 1 | 27 | The single connector protocol (ADR-0097) — catalog descriptors and provider-bound instances. | -| [Kernel Protocol](/docs/references/kernel) | 30 | 163 | Plugin lifecycle and manifests, capabilities and security, metadata loading, service registry. | +| [Kernel Protocol](/docs/references/kernel) | 30 | 162 | Plugin lifecycle and manifests, capabilities and security, metadata loading, service registry. | | [QA Protocol](/docs/references/qa) | 1 | 8 | Declarative test suites — scenarios, steps, actions and assertions. | | [Security Protocol](/docs/references/security) | 5 | 29 | Permission sets, row-level security, sharing rules, tenancy posture. | | [Shared Protocol](/docs/references/shared) | 7 | 25 | Primitives used across every protocol — identifiers, HTTP, expressions, error maps, enums. | | [Studio Protocol](/docs/references/studio) | 3 | 35 | Studio designer metadata — the authoring surfaces for the protocols above. | | [System Protocol](/docs/references/system) | 36 | 291 | The runtime environment — logging, jobs, cache, metrics, notifications, i18n and compliance. | | [UI Protocol](/docs/references/ui) | 16 | 153 | Apps, pages, views, dashboards, reports, actions and themes — the ObjectUI layer. | -| **Total** | **199** | **1589** | 14 protocol modules | +| **Total** | **199** | **1588** | 14 protocol modules | --- @@ -217,14 +217,14 @@ The single connector protocol (ADR-0097) — catalog descriptors and provider-bo ## Kernel Protocol -**Source:** `packages/spec/src/kernel/` · **Import:** `@objectstack/spec/kernel` · **30 pages, 163 schemas** +**Source:** `packages/spec/src/kernel/` · **Import:** `@objectstack/spec/kernel` · **30 pages, 162 schemas** Plugin lifecycle and manifests, capabilities and security, metadata loading, service registry. | File | Schemas | | :--- | :--- | | [`cli-extension.zod.ts`](/docs/references/kernel/cli-extension) | `OclifPluginConfig` | -| [`cluster.zod.ts`](/docs/references/kernel/cluster) | `ClusterCapabilityConfig`, `ClusterDriver`, `ClusterTenantIsolation`, `EventClusterOptions`, `EventDeliverySemantics`, `EventScope`, `MetadataChangeOperation`, `ServiceClusterAnnotations`, `ServiceClusterScope`, `ServiceLeaderStrategy` | +| [`cluster.zod.ts`](/docs/references/kernel/cluster) | `ClusterCapabilityConfig`, `ClusterDriver`, `ClusterTenantIsolation`, `EventClusterOptions`, `EventDeliverySemantics`, `EventScope`, `ServiceClusterAnnotations`, `ServiceClusterScope`, `ServiceLeaderStrategy` | | [`context.zod.ts`](/docs/references/kernel/context) | `KernelContext`, `RuntimeMode`, `TenantRuntimeContext` | | [`dependency-resolution.zod.ts`](/docs/references/kernel/dependency-resolution) | `DependencyResolutionResult`, `DependencyStatusEnum`, `RequiredAction`, `ResolvedDependency` | | [`events/bus.zod.ts`](/docs/references/kernel/events-bus) | `EventBusConfig` | diff --git a/content/docs/references/kernel/cluster.mdx b/content/docs/references/kernel/cluster.mdx index 3a2c13cdb2..e51a8179fa 100644 --- a/content/docs/references/kernel/cluster.mdx +++ b/content/docs/references/kernel/cluster.mdx @@ -25,8 +25,8 @@ subsystems depend on. ## TypeScript Usage ```typescript -import { ClusterCapabilityConfigSchema, ClusterDriverSchema, ClusterTenantIsolationSchema, EventClusterOptionsSchema, EventDeliverySemanticsSchema, EventScopeSchema, MetadataChangeOperationSchema, ServiceClusterAnnotationsSchema, ServiceClusterScopeSchema, ServiceLeaderStrategySchema } from '@objectstack/spec/kernel'; -import type { ClusterCapabilityConfig, ClusterDriver, ClusterTenantIsolation, EventClusterOptions, EventDeliverySemantics, EventScope, MetadataChangeOperation, ServiceClusterAnnotations, ServiceClusterScope, ServiceLeaderStrategy } from '@objectstack/spec/kernel'; +import { ClusterCapabilityConfigSchema, ClusterDriverSchema, ClusterTenantIsolationSchema, EventClusterOptionsSchema, EventDeliverySemanticsSchema, EventScopeSchema, ServiceClusterAnnotationsSchema, ServiceClusterScopeSchema, ServiceLeaderStrategySchema } from '@objectstack/spec/kernel'; +import type { ClusterCapabilityConfig, ClusterDriver, ClusterTenantIsolation, EventClusterOptions, EventDeliverySemantics, EventScope, ServiceClusterAnnotations, ServiceClusterScope, ServiceLeaderStrategy } from '@objectstack/spec/kernel'; // Validate data const result = ClusterCapabilityConfigSchema.parse(data); @@ -118,20 +118,6 @@ Where the event must be delivered: local process, whole cluster, or tenant-scope * `tenant` ---- - -## MetadataChangeOperation - -Persistence operation that triggered the change. - -### Allowed Values - -* `create` -* `update` -* `delete` -* `publish` - - --- ## ServiceClusterAnnotations diff --git a/docs/audits/2026-07-unknown-key-strictness-ledger.counts.md b/docs/audits/2026-07-unknown-key-strictness-ledger.counts.md index 1bcbe3a94b..9b442767b7 100644 --- a/docs/audits/2026-07-unknown-key-strictness-ledger.counts.md +++ b/docs/audits/2026-07-unknown-key-strictness-ledger.counts.md @@ -261,7 +261,7 @@ directory rather than per file. | `cloud/` | 83 | | `identity/` | 32 | | `integration/` | 10 | -| `kernel/` | 261 | +| `kernel/` | 260 | | `qa/` | 6 | | `shared/` | 20 | | `system/` | 370 | diff --git a/packages/spec/api-surface/kernel.json b/packages/spec/api-surface/kernel.json index 2f80c331e8..f44ed487cc 100644 --- a/packages/spec/api-surface/kernel.json +++ b/packages/spec/api-surface/kernel.json @@ -163,12 +163,8 @@ "MetadataBulkResultSchema (const)", "MetadataCategory (type)", "MetadataCategoryEnum (const)", - "MetadataChangeOperation (type)", - "MetadataChangeOperationSchema (const)", "MetadataChangeType (type)", "MetadataChangeTypeSchema (const)", - "MetadataChangedEventPayload (type)", - "MetadataChangedEventPayloadSchema (const)", "MetadataDependency (type)", "MetadataDependencySchema (const)", "MetadataDiffItem (type)", diff --git a/packages/spec/declaration-map/kernel.json b/packages/spec/declaration-map/kernel.json index 3c3b2e4c63..82d5a2b368 100644 --- a/packages/spec/declaration-map/kernel.json +++ b/packages/spec/declaration-map/kernel.json @@ -111,8 +111,6 @@ "MetadataBulkResult": "kernel/MetadataBulkResult", "MetadataBulkResultSchema": "kernel/MetadataBulkResult", "MetadataCategoryEnum": "kernel/MetadataCategoryEnum", - "MetadataChangeOperation": "kernel/MetadataChangeOperation", - "MetadataChangeOperationSchema": "kernel/MetadataChangeOperation", "MetadataChangeType": "kernel/MetadataChangeType", "MetadataChangeTypeSchema": "kernel/MetadataChangeType", "MetadataDependency": "kernel/MetadataDependency", diff --git a/packages/spec/export-origins/kernel.json b/packages/spec/export-origins/kernel.json index d392750d4f..efd1dae954 100644 --- a/packages/spec/export-origins/kernel.json +++ b/packages/spec/export-origins/kernel.json @@ -163,12 +163,8 @@ "MetadataBulkResultSchema": "src/kernel/metadata-plugin.zod.ts#MetadataBulkResultSchema (const)", "MetadataCategory": "src/kernel/package-artifact.zod.ts#MetadataCategory (type)", "MetadataCategoryEnum": "src/kernel/package-artifact.zod.ts#MetadataCategoryEnum (const)", - "MetadataChangeOperation": "src/kernel/cluster.zod.ts#MetadataChangeOperation (type)", - "MetadataChangeOperationSchema": "src/kernel/cluster.zod.ts#MetadataChangeOperationSchema (const)", "MetadataChangeType": "src/kernel/package-upgrade.zod.ts#MetadataChangeType (type)", "MetadataChangeTypeSchema": "src/kernel/package-upgrade.zod.ts#MetadataChangeTypeSchema (const)", - "MetadataChangedEventPayload": "src/kernel/cluster.zod.ts#MetadataChangedEventPayload (type)", - "MetadataChangedEventPayloadSchema": "src/kernel/cluster.zod.ts#MetadataChangedEventPayloadSchema (const)", "MetadataDependency": "src/kernel/metadata-plugin.zod.ts#MetadataDependency (type)", "MetadataDependencySchema": "src/kernel/metadata-plugin.zod.ts#MetadataDependencySchema (const)", "MetadataDiffItem": "src/kernel/package-upgrade.zod.ts#MetadataDiffItem (type)", diff --git a/packages/spec/json-schema.manifest/kernel.json b/packages/spec/json-schema.manifest/kernel.json index fa20090d66..b5b365ad59 100644 --- a/packages/spec/json-schema.manifest/kernel.json +++ b/packages/spec/json-schema.manifest/kernel.json @@ -59,7 +59,6 @@ "kernel/ManifestPermissions", "kernel/MetadataBulkResult", "kernel/MetadataCategoryEnum", - "kernel/MetadataChangeOperation", "kernel/MetadataChangeType", "kernel/MetadataDependency", "kernel/MetadataDiffItem", From ceb9887c7d973810ba98d588f1ba8af566fe65a0 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com> Date: Fri, 4 Sep 2026 03:19:03 +0000 Subject: [PATCH 3/4] chore(spec): regenerate the two os-regen artifacts the merge of origin/main deferred Merge commit 9003435dc brought main's automation builtin-node-config work in; the references index and the strictness-ledger counts moved on both sides, so the os-regen driver deferred them. Regenerated from the merged tree with gen:schema, gen:docs and gen:strictness-ledger. Claude-Session: https://claude.ai/code/session_0174WZTU6XcFcS7g2kykC53i Co-authored-by: Claude --- content/docs/references/index.mdx | 10 +++++----- ...2026-07-unknown-key-strictness-ledger.counts.md | 14 +++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/content/docs/references/index.mdx b/content/docs/references/index.mdx index 261b9403f2..f94d321abe 100644 --- a/content/docs/references/index.mdx +++ b/content/docs/references/index.mdx @@ -1,6 +1,6 @@ --- title: Protocol Reference -description: Every schema published by @objectstack/spec — 1588 schemas across 14 protocol modules +description: Every schema published by @objectstack/spec — 1591 schemas across 14 protocol modules --- {/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */} @@ -21,7 +21,7 @@ counts are sums of the rows they head. Regenerate with | :--- | ---: | ---: | :--- | | [AI Protocol](/docs/references/ai) | 11 | 66 | Agents, tools, skills, RAG and knowledge sources, model registry, conversations. | | [API Protocol](/docs/references/api) | 31 | 436 | REST contracts, endpoints, routing, realtime, batch, discovery. | -| [Automation Protocol](/docs/references/automation) | 13 | 69 | Flows and their nodes, approvals, ETL pipelines, webhooks, state machines, execution records. | +| [Automation Protocol](/docs/references/automation) | 13 | 72 | Flows and their nodes, approvals, ETL pipelines, webhooks, state machines, execution records. | | [Cloud Protocol](/docs/references/cloud) | 11 | 94 | Environments, packages and versions, marketplace, developer portal, tenancy. | | [Data Protocol](/docs/references/data) | 29 | 166 | Objects, fields, queries, filters, datasources and drivers — the ObjectQL layer. | | [Identity Protocol](/docs/references/identity) | 5 | 27 | Users and accounts, organizations, positions, SCIM provisioning. | @@ -33,7 +33,7 @@ counts are sums of the rows they head. Regenerate with | [Studio Protocol](/docs/references/studio) | 3 | 35 | Studio designer metadata — the authoring surfaces for the protocols above. | | [System Protocol](/docs/references/system) | 36 | 291 | The runtime environment — logging, jobs, cache, metrics, notifications, i18n and compliance. | | [UI Protocol](/docs/references/ui) | 16 | 153 | Apps, pages, views, dashboards, reports, actions and themes — the ObjectUI layer. | -| **Total** | **199** | **1588** | 14 protocol modules | +| **Total** | **199** | **1591** | 14 protocol modules | --- @@ -103,7 +103,7 @@ REST contracts, endpoints, routing, realtime, batch, discovery. ## Automation Protocol -**Source:** `packages/spec/src/automation/` · **Import:** `@objectstack/spec/automation` · **13 pages, 69 schemas** +**Source:** `packages/spec/src/automation/` · **Import:** `@objectstack/spec/automation` · **13 pages, 72 schemas** Flows and their nodes, approvals, ETL pipelines, webhooks, state machines, execution records. @@ -111,7 +111,7 @@ Flows and their nodes, approvals, ETL pipelines, webhooks, state machines, execu | :--- | :--- | | [`approval.zod.ts`](/docs/references/automation/approval) | `ApprovalDecision`, `ApprovalEscalation`, `ApprovalNodeApprover`, `ApprovalNodeConfig`, `ApproverType`, `DecisionOutputDef` | | [`bpmn-interop.zod.ts`](/docs/references/automation/bpmn-interop) | `BpmnDiagnostic`, `BpmnElementMapping`, `BpmnExportOptions`, `BpmnImportOptions`, `BpmnInteropResult`, `BpmnUnmappedStrategy`, `BpmnVersion` | -| [`builtin-node-config.zod.ts`](/docs/references/automation/builtin-node-config) | `CreateRecordConfig`, `DeleteRecordConfig`, `GetRecordConfig`, `MapConfig`, `ScreenConfig`, `ScreenFieldConfig`, `UpdateRecordConfig` | +| [`builtin-node-config.zod.ts`](/docs/references/automation/builtin-node-config) | `AssignmentConfig`, `AssignmentExpressionValue`, `AssignmentValue`, `CreateRecordConfig`, `DeleteRecordConfig`, `GetRecordConfig`, `MapConfig`, `ScreenConfig`, `ScreenFieldConfig`, `UpdateRecordConfig` | | [`control-flow.zod.ts`](/docs/references/automation/control-flow) | `FlowRegion`, `LoopConfig`, `ParallelBranch`, `ParallelConfig`, `RetryPolicy`, `TryCatchConfig`, `TryCatchErrorValue` | | [`execution.zod.ts`](/docs/references/automation/execution) | `Checkpoint`, `ConcurrencyPolicy`, `ExecutionError`, `ExecutionErrorSeverity`, `ExecutionLog`, `ExecutionStatus`, `ExecutionStepLog`, `ExecutionStepMetrics`, `ExecutionStepSkipReason`, `FlowRunGateSummary`, `FlowRunNodeSummary`, `FlowRunSummary`, `ScheduleState` | | [`flow.zod.ts`](/docs/references/automation/flow) | `Flow`, `FlowEdge`, `FlowNode`, `FlowNodeAction`, `FlowVariable`, `FlowVersionHistory` | diff --git a/docs/audits/2026-07-unknown-key-strictness-ledger.counts.md b/docs/audits/2026-07-unknown-key-strictness-ledger.counts.md index 9b442767b7..85bd73fe7b 100644 --- a/docs/audits/2026-07-unknown-key-strictness-ledger.counts.md +++ b/docs/audits/2026-07-unknown-key-strictness-ledger.counts.md @@ -21,7 +21,7 @@ regenerate. | Measure | Value | |---|---| | Triaged directories | 5 | -| Object sites in them | 439 | +| Object sites in them | 440 | | Still-open (strip) sites | 124 | | Files carrying at least one | 22 | @@ -46,10 +46,10 @@ The `strict` column is the one the campaign schedules against; it counts both th |---|---|---|---|---|---| | `ui/` | 169 | 157 | 5 | 0 | 7 | | `data/` | 157 | 76 | 1 | 0 | 80 | -| `automation/` | 66 | 42 | 0 | 0 | 24 | +| `automation/` | 67 | 42 | 0 | 1 | 24 | | `security/` | 20 | 7 | 0 | 0 | 13 | | `studio/` | 27 | 27 | 0 | 0 | 0 | -| **total** | **439** | **309** | **6** | **0** | **124** | +| **total** | **440** | **309** | **6** | **1** | **124** | ## File-level triage — site counts @@ -115,7 +115,7 @@ classify and is not listed (it becomes reportable the day it grows its first sit |---|---| | `approval.zod.ts` | 4 | | `bpmn-interop.zod.ts` | 5 | -| `builtin-node-config.zod.ts` | 8 | +| `builtin-node-config.zod.ts` | 9 | | `control-flow.zod.ts` | 6 | | `execution.zod.ts` | 13 | | `flow-function.zod.ts` | 1 | @@ -126,7 +126,7 @@ classify and is not listed (it becomes reportable the day it grows its first sit | `state-machine.zod.ts` | 6 | | `time-relative-trigger.zod.ts` | 1 | | `webhook.zod.ts` | 1 | -| **total** | **66** | +| **total** | **67** | ### `security/` — sites @@ -204,7 +204,7 @@ over it is here. ### `automation/` — open -**24 strip of 66**, in 5 file(s). +**24 strip of 67**, in 5 file(s). | File | Strip | Sites | |---|---|---| @@ -213,7 +213,7 @@ over it is here. | `execution.zod.ts` | 13 | 13 | | `flow.zod.ts` | 1 | 11 | | `node-executor.zod.ts` | 4 | 4 | -| **total** | **24** | **66** | +| **total** | **24** | **67** | | Bucket | Sites | |---|---| From fc66ae83351737c52e3976ca3c24d620c33e7a7e Mon Sep 17 00:00:00 2001 From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com> Date: Fri, 4 Sep 2026 04:41:52 +0000 Subject: [PATCH 4/4] chore(spec): regenerate the os-regen artifact the round-3 merge of origin/main deferred Merge commit 63c21fc4b (origin/main 25a59bd10) deferred content/docs/references/index.mdx; regenerated from the merged tree with gen:schema (via the spec build) and gen:docs, then check:generated --fix for whatever else the merged tree left stale. registry.ts was re-run through gen:migration-registry and came out byte-identical to the text merge. Claude-Session: https://claude.ai/code/session_0174WZTU6XcFcS7g2kykC53i Co-authored-by: Claude --- content/docs/references/index.mdx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/content/docs/references/index.mdx b/content/docs/references/index.mdx index f94d321abe..b1604c3ecb 100644 --- a/content/docs/references/index.mdx +++ b/content/docs/references/index.mdx @@ -1,6 +1,6 @@ --- title: Protocol Reference -description: Every schema published by @objectstack/spec — 1591 schemas across 14 protocol modules +description: Every schema published by @objectstack/spec — 1592 schemas across 14 protocol modules --- {/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */} @@ -29,11 +29,11 @@ counts are sums of the rows they head. Regenerate with | [Kernel Protocol](/docs/references/kernel) | 30 | 162 | Plugin lifecycle and manifests, capabilities and security, metadata loading, service registry. | | [QA Protocol](/docs/references/qa) | 1 | 8 | Declarative test suites — scenarios, steps, actions and assertions. | | [Security Protocol](/docs/references/security) | 5 | 29 | Permission sets, row-level security, sharing rules, tenancy posture. | -| [Shared Protocol](/docs/references/shared) | 7 | 25 | Primitives used across every protocol — identifiers, HTTP, expressions, error maps, enums. | +| [Shared Protocol](/docs/references/shared) | 8 | 26 | Primitives used across every protocol — identifiers, HTTP, expressions, error maps, enums. | | [Studio Protocol](/docs/references/studio) | 3 | 35 | Studio designer metadata — the authoring surfaces for the protocols above. | | [System Protocol](/docs/references/system) | 36 | 291 | The runtime environment — logging, jobs, cache, metrics, notifications, i18n and compliance. | | [UI Protocol](/docs/references/ui) | 16 | 153 | Apps, pages, views, dashboards, reports, actions and themes — the ObjectUI layer. | -| **Total** | **199** | **1591** | 14 protocol modules | +| **Total** | **200** | **1592** | 14 protocol modules | --- @@ -286,7 +286,7 @@ Permission sets, row-level security, sharing rules, tenancy posture. ## Shared Protocol -**Source:** `packages/spec/src/shared/` · **Import:** `@objectstack/spec/shared` · **7 pages, 25 schemas** +**Source:** `packages/spec/src/shared/` · **Import:** `@objectstack/spec/shared` · **8 pages, 26 schemas** Primitives used across every protocol — identifiers, HTTP, expressions, error maps, enums. @@ -299,6 +299,7 @@ Primitives used across every protocol — identifiers, HTTP, expressions, error | [`mapping.zod.ts`](/docs/references/shared/mapping) | `FieldMapping` | | [`metadata-types.zod.ts`](/docs/references/shared/metadata-types) | `BaseMetadataRecord`, `MetadataFormat` | | [`protection.zod.ts`](/docs/references/shared/protection) | `Protection` | +| [`value-domain.zod.ts`](/docs/references/shared/value-domain) | `ValueDomain` | ---