Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions .changeset/kernel-metadata-loader-envelope-removed.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
---
"@objectstack/spec": major
---

refactor(spec)!: remove the `kernel` metadata-loader envelope family — eleven names that each existed twice, with different shapes, on two subpath entries (#4411)

`MetadataFormat`, `MetadataStats`, `MetadataLoadOptions`, `MetadataSaveOptions`,
`MetadataExportOptions`, `MetadataImportOptions`, `MetadataLoadResult`,
`MetadataSaveResult`, `MetadataWatchEvent`, `MetadataCollectionInfo` and
`MetadataLoaderContract` (plus each one's `…Schema`) are removed from
`@objectstack/spec/kernel` (`kernel/metadata-loader.zod`). Every one of those
names *also* existed, with a **different shape**, in
`@objectstack/spec/system` (`system/metadata-persistence.zod`).

Which type you got depended on nothing but your import path:

```ts
import type { MetadataWatchEvent } from '@objectstack/spec/kernel'; // one shape
import type { MetadataWatchEvent } from '@objectstack/spec/system'; // another
```

- **The `kernel` copies had zero consumers.** Import-statement scans across this
repo, `cloud` and `objectui` found every consumer importing from
`./system` (or, for the export/import options, `./contracts`' own interface).
Nothing but `kernel/metadata-loader.test.ts` ever parsed the `kernel` copies.
- **The naming intuition pointed the wrong way**, which is what made this worse
than an ordinary duplicate. The `kernel` copies were the ones that *looked*
canonical — normalized enums, required fields, a `.describe()` on every
property — and they were the dead ones. The live copy is the loose superset,
and `metadata-manager.ts` calls it "legacy" in its own comments. An
auto-import or a model completion picking by name, or by which one reads as
more rigorous, picked the dead one; because the shapes overlap heavily, that
choice compiled and only failed later, at an edge value (`add` vs `added`) or
on a field one copy made required.
- **No load path parsed them.** These are runtime envelope types, not authorable
metadata — no authored source can carry them. So there is deliberately **no**
`retiredKey()` tombstone and **no** ADR-0087 conversion: a prescription nobody
can receive is noise, and there is nothing for `os migrate meta` to rewrite
(the `plugin-runtime.zod.ts` / dev-plugin precedents, #3950, #4149).

**FROM → TO — change the import path, keep the name:**

```diff
-import type { MetadataWatchEvent, MetadataStats } from '@objectstack/spec/kernel';
+import type { MetadataWatchEvent, MetadataStats } from '@objectstack/spec/system';
```

The surviving `system` copy is the **looser** of the two, so a *reader* of these
types may need narrowing it did not need before; a *producer* needs nothing. The
differences that actually bite:

| Type | `kernel` (removed) | `system` (keep) |
| --- | --- | --- |
| `MetadataWatchEvent.type` | `'added' \| 'changed' \| 'deleted'` | also `'add' \| 'change' \| 'unlink'` — the raw watcher values the runtime really emits |
| `MetadataWatchEvent` | `metadataType` / `name` / `timestamp` required | all three optional; adds `stats` |
| `MetadataStats` | `size` / `modifiedAt` / `etag` / `format` required | all optional; adds `mtime`, `hash` |
| `MetadataFormat` | `json \| yaml \| typescript \| javascript` | also the `yml` / `ts` / `js` aliases |
| `MetadataSaveResult.path` | required | optional; adds `stats` |
| `MetadataImportOptions` | `conflictResolution` / `dryRun` / `continueOnError` / `transform` | `source` / `strategy` / `validate` |
| `MetadataCollectionInfo` | `formats: MetadataFormat[]` | `namespaces: string[]` |

No runtime behaviour changes: nothing read the removed copies. The `system`
shapes are **not** tightened here — they describe what `MetadataManager`
actually emits, and narrowing them would be a separate behaviour change.

`MetadataManagerConfig` and `MetadataFallbackStrategy` are **unaffected**. They
were never duplicated — `kernel` owns them and `system` re-exports them — and
that is the split that survives: manager *wiring* is kernel's, the loader/watch
*envelope* is system's, and nothing is declared twice.

The retirement kit: baselines dropped deliberately
(`json-schema.manifest.json` minus the 11 `kernel/Metadata*` entries;
`authorable-surface.json` minus the 65 matching lines — nothing can author
these, so no `[RETIRED]` markers); `api-surface.json` regenerated (22 exports
leave `./kernel`); `references/kernel/metadata-persistence.mdx` removed by
`gen:docs`; v17 release notes' dead-clusters table and upgrade checklist
extended. No liveness-ledger entries existed (the ledger tracks authorable
metadata types; these were never one).
1 change: 0 additions & 1 deletion content/docs/references/kernel/meta.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -27,7 +27,6 @@
"execution-context",
"metadata-customization",
"metadata-loader",
"metadata-persistence",
"metadata-plugin",
"metadata-protection",
"service-registry",
Expand Down
10 changes: 4 additions & 6 deletions content/docs/references/kernel/metadata-loader.mdx
Original file line numberDiff line numberDiff line change
Expand Up@@ -5,13 +5,11 @@ description: Metadata Loader protocol schemas

{/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */}

# Metadata Loader Protocol
# Metadata Manager Configuration

Defines the standard interface for loading and saving metadata in ObjectStack.
How the runtime `MetadataManager` is wired: which datasource backs `sys_metadata`, what to fall back to when that datasource is unreachable, cache / watch / validation settings, and the persistence write gates.

This protocol enables consistent metadata operations across different storage backends

(filesystem, HTTP, S3, databases) and serialization formats (JSON, YAML, TypeScript).
The loader and watch *envelope* types (`MetadataFormat`, `MetadataStats`, `MetadataLoadOptions`, `MetadataWatchEvent`, `MetadataLoaderContract`, …) are NOT here — they live in `@objectstack/spec/system` (`system/metadata-persistence.zod`), which is their single source.

<Callout type="info">
**Source:** `packages/spec/src/kernel/metadata-loader.zod.ts`
Expand DownExpand Up@@ -50,7 +48,7 @@ const result = MetadataFallbackStrategy.parse(data);
| **tableName** | `string` | ✅ | Database table name for metadata storage |
| **fallback** | `Enum<'filesystem' \| 'memory' \| 'none'>` | ✅ | Fallback strategy when datasource is unavailable |
| **rootDir** | `string` | optional | Root directory path |
| **formats** | `Enum<'json' \| 'yaml' \| 'typescript' \| 'javascript'>[]` | ✅ | Enabled formats |
| **formats** | `Enum<'yaml' \| 'json' \| 'typescript' \| 'javascript'>[]` | ✅ | Enabled formats |
| **cache** | `{ enabled: boolean; ttl: integer; maxSize?: integer; databaseLoader?: object }` | optional | Cache settings |
| **watch** | `boolean` | ✅ | Enable file watching |
| **watchOptions** | `{ ignored?: string[]; persistent: boolean; ignoreInitial: boolean }` | optional | File watcher options |
Expand Down
196 changes: 0 additions & 196 deletions content/docs/references/kernel/metadata-persistence.mdx

This file was deleted.

4 changes: 2 additions & 2 deletions content/docs/references/kernel/metadata-plugin.mdx
Original file line numberDiff line numberDiff line change
Expand Up@@ -57,11 +57,11 @@ cohesive plugin that "takes over" the entire platform's metadata management:

## References

- [kernel/metadata-loader.zod.ts](/docs/references/kernel/metadata-loader) — Storage backend protocol
- [kernel/metadata-loader.zod.ts](/docs/references/kernel/metadata-loader) — MetadataManager wiring (datasource, cache, write gates)

- [kernel/metadata-customization.zod.ts](/docs/references/kernel/metadata-customization) — Overlay/merge protocol

- [system/metadata-persistence.zod.ts](/docs/references/system/metadata-persistence) — Database record format
- [system/metadata-persistence.zod.ts](/docs/references/system/metadata-persistence) — Database record format + loader/watch envelope types

- contracts/metadata-service.ts — Service interface

Expand Down
2 changes: 1 addition & 1 deletion content/docs/references/system/metadata-loader.mdx
Original file line numberDiff line numberDiff line change
Expand Up@@ -38,7 +38,7 @@ const result = MetadataFallbackStrategy.parse(data);
| **tableName** | `string` | ✅ | Database table name for metadata storage |
| **fallback** | `Enum<'filesystem' \| 'memory' \| 'none'>` | ✅ | Fallback strategy when datasource is unavailable |
| **rootDir** | `string` | optional | Root directory path |
| **formats** | `Enum<'json' \| 'yaml' \| 'typescript' \| 'javascript'>[]` | ✅ | Enabled formats |
| **formats** | `Enum<'yaml' \| 'json' \| 'typescript' \| 'javascript'>[]` | ✅ | Enabled formats |
| **cache** | `{ enabled: boolean; ttl: integer; maxSize?: integer; databaseLoader?: object }` | optional | Cache settings |
| **watch** | `boolean` | ✅ | Enable file watching |
| **watchOptions** | `{ ignored?: string[]; persistent: boolean; ignoreInitial: boolean }` | optional | File watcher options |
Expand Down
12 changes: 11 additions & 1 deletion content/docs/releases/v17.mdx
Original file line numberDiff line numberDiff line change
Expand Up@@ -1016,6 +1016,7 @@ import or the authored key.
| Aspirational config on Theme / Translation / Webhook | still-dead after #3494 |
| `ChartInteraction.zoom` / `.clickAction` | never implemented (#3752) |
| `datasource.readReplicas` | replica connections nothing ever opened — no driver reads the key and no query path splits reads from writes, so every statement went to the primary. #4410 had just taught the schema to validate each entry against the declared driver's contract, which made a dead slot look rigorously alive (#4468) |
| The `kernel` metadata-loader envelope family — `MetadataFormat`, `MetadataStats`, `MetadataLoadOptions`, `MetadataSaveOptions`, `MetadataExportOptions`, `MetadataImportOptions`, `MetadataLoadResult`, `MetadataSaveResult`, `MetadataWatchEvent`, `MetadataCollectionInfo`, `MetadataLoaderContract` (`@objectstack/spec/kernel`) | eleven names that each existed **twice**, with a different shape, on `./kernel` and `./system` — so which type you got depended on your import path. Every consumer imported the `./system` copy; the `./kernel` copies had zero consumers. Import them from `@objectstack/spec/system` (#4411, ADR-0049). `MetadataManagerConfig` / `MetadataFallbackStrategy` are unaffected and still ship from both entries |

The Console side follows: `@object-ui/types` drops its
`ObjectStack`/`ObjectOS`/`ObjectQL`/`ObjectUI` Capabilities re-exports, which
Expand DownExpand Up@@ -2095,7 +2096,16 @@ covers are folded into the list below rather than left to the changelog.)
`maplibre-gl` 5→6 / `chalk` 5→6 major bumps.
- **Type importers:** replace `ObjectStackProtocol` / `ObjectStackProtocolSchema`
with the narrowest per-domain slices; drop GraphQL types and any of the removed
dead spec clusters.
dead spec clusters. If you imported `MetadataFormat`, `MetadataStats`,
`MetadataLoadOptions`, `MetadataSaveOptions`, `MetadataExportOptions`,
`MetadataImportOptions`, `MetadataLoadResult`, `MetadataSaveResult`,
`MetadataWatchEvent`, `MetadataCollectionInfo` or `MetadataLoaderContract`
from `@objectstack/spec/kernel`, change the path to `@objectstack/spec/system`
— same names, and that copy is the one the runtime has always emitted. It is
the *looser* of the two, so a reader may need new narrowing: notably
`MetadataWatchEvent.type` also carries the raw watcher values
`add`/`change`/`unlink`, and `metadataType`/`name`/`timestamp` are optional
there. Nothing to migrate at runtime — the values were always these.
- **Multi-org:** the `group` posture requires the enterprise runtime — deployments
relying on it self-activating must install `@objectstack/organizations` or move
to `isolated`.
Expand Down
7 changes: 6 additions & 1 deletion packages/qa/dogfood/test/expression-conformance.ledger.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -155,7 +155,12 @@ export const EXPRESSION_SURFACE: ExprSurface[] = [
covers: [
'automation/flow.zod.ts:condition',
'automation/sync.zod.ts:condition',
'kernel/metadata-loader.zod.ts:filter',
// `kernel/metadata-loader.zod.ts:filter` (on MetadataLoadOptions and
// MetadataExportOptions) was removed with the rest of that file's
// zero-consumer duplicate envelope family in #4411. The surviving
// `system/metadata-persistence.zod` copies of those options never
// declared a `filter` — so no loader predicate was ever evaluated
// through this surface, and there is nothing to re-point at.
],
},
{
Expand Down
Loading
Loading