Skip to content

Commit 78b1a63

Browse files
docs(metadata-core): name the real write-path labels on MetadataEvent.source (#24675)
Fixes #24336 Clause-②: no ## What changed `MetadataEventSchema.source` in `@objectstack/metadata-core` described itself as `Origin label: "fs", "studio", "rest", "ai", "git-import", …`. No producer on this tree writes `studio`, `rest`, `ai` or `git-import`, so a reader of the published schema was pointed at values it will never see. The describe now says what the field is: the write path that produced the event, an open label its writer stamps, not an enum of authoring surfaces to pick from or match against. Its examples are labels real producers stamp: `protocol.saveMetaItem`, `protocol.publishMetaItem`, `migrate-stored`, `sys-metadata-repo` (`SysMetadataRepository`'s default) and `fs` (`FileSystemRepository`). The field stays `z.string()`. The two `sys-metadata-history.object.ts` comments (the module header and the comment above `source`) now agree with the describe. They list the labels that actually reach the `sys_metadata_history.source` column, and they no longer list `fs`: `FileSystemRepository` writes its events to its own JSONL change log, never to this table. No key, type, export, accepted value or emitted value changes. One `patch` changeset on `@objectstack/metadata-core` (`.changeset/24336-metadata-event-source-describe.md`, carrying `Clause-②: no`). ## Producers measured on `origin/main` `bfc1539fe0` (non-test code) | producer | label(s) written | reaches | |:--|:--|:--| | `SysMetadataRepository` (`packages/metadata-protocol/src/sys-metadata-repository.ts`) | the caller's `opts.source`, else `sys-metadata-repo` (put / delete), `sys-metadata-repo.publish` (promoteDraft and the promoted draft-row drop), `sys-metadata-repo.revert` (restoreVersion); `history()` passes the stored value through and answers `sys-metadata-repo` for a row that stored none | `sys_metadata_history`, `MetadataEvent` | | the protocol (`packages/metadata-protocol/src/protocol.ts`) | `protocol.saveMetaItem`, `protocol.publishMetaItem`, `protocol.deleteMetaItem`, `protocol.rollbackMetaItem`, `protocol.revertCommit` | via `SysMetadataRepository` | | stored-row rewrites | `migrate-stored` (the protocol's `migrateStoredMetadata`, and `service-automation`'s `flow-credential-migration.ts`) | via `saveMetaItem` | | CLI `os migrate security-catalog-overlays` | `os migrate security-catalog-overlays` | via `SysMetadataRepository.delete` | | `@objectstack/metadata` `DatabaseLoader` (`database-loader.ts`) | `database-loader` | `sys_metadata_history` directly | | `@objectstack/metadata-fs` `FileSystemRepository` | `fs` | its own JSONL change log and events, not the table | | `InMemoryRepository` (metadata-core) | `in-memory` | events; no non-test instantiation | | `LayeredRepository` (metadata-core) | the layer label prefixed to the inner label (`LAYER:SOURCE`) | events; no non-test instantiation | The card's list missed `DatabaseLoader`, the three further protocol labels, the CLI migration and the two metadata-core repositories; none of them writes `studio`, `rest`, `ai` or `git-import` either. No consumer compares `source` against a fixed value. Generated artifacts: nothing reads this describe. A repo-wide search for `Origin label` and `git-import` finds only the source line, the governed ADR sketch below and two changelog/changeset entries of the earlier spec-half fix. `metadata-core` is not `packages/spec`, so `check:generated` does not cover it and nothing was regenerated. ## File surface - `packages/metadata-core/src/types.ts`: `MetadataEventSchema.source`'s `.describe()` only. - `packages/metadata-core/src/objects/sys-metadata-history.object.ts`: the module header bullet and the comment above `source`. - `.changeset/24336-metadata-event-source-describe.md`. ## Verification (head `197216c57f`) - `pnpm --filter '@objectstack/metadata-core...' build` (metadata-core and its dependency closure): exit 0. The built `dist/index.js` and `dist/index.cjs` each carry the new describe once and `git-import` zero times. - `pnpm --filter @objectstack/metadata-core test`: 18 files, 774 tests passed. `pnpm --filter @objectstack/metadata-core typecheck` (`tsc --noEmit && tsc --noEmit -p tsconfig.test.json`): exit 0. - Derived gate list (`node scripts/pm/dispatch-gates.mjs --commands`, from the real diff): 57 commands, every one run with its exit code captured before any pipe. 56 exited 0. `pnpm check:lean-entry-closure` first answered PREREQUISITE NOT MET (exit 3) and exited 0 after building `@objectstack/objectql`'s closure. - NOT MEASURED: `pnpm check:dual-build-cjs-loads`. It refuses with exit 3 until all of the roughly 90 workspace packages are built, and only a whole-workspace build satisfies it. CI's `Lint & Repo Gates` runs it. Declared narrowing. - `node scripts/pm/dispatch-gates.mjs --ran`: 57 derived families accounted for, 56 run, 1 NOT MEASURED, 0 UNRUN. - No ablation: the diff changes describe and comment prose only, and no test pins that text. ## Acceptance notes - Rider for `domain:spec`, not taken here (it is that lane's file): `packages/spec/src/api/protocol.test.ts` (around lines 2141 to 2162) calls its fixture "a verbatim-shaped capture of a real `historyMetaItem` return", but the update event carries `source: 'studio'`. A real save through that door stamps `protocol.saveMetaItem`. - For a person, governed (Tier H) and not touched: `docs/adr/0008-metadata-repository-and-change-log.md` line 226, the section 2.4 sketch, still reads `source: string; // 'fs', 'studio', 'rest', 'ai', 'git-import', …`. It is illustration only, and correcting it is a maintainer's edit. - Cloud's writers were not read. The new describe calls the label open, so a cloud write path that stamps its own label still fits the contract. --- _Generated by [Claude Code](https://claude.ai/code/session_01AHeUBbe6S3JRawcpbLejXD)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent 073b1b2 commit 78b1a63

3 files changed

Lines changed: 35 additions & 6 deletions

File tree

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
'@objectstack/metadata-core': patch
3+
---
4+
5+
Clause-②: no
6+
7+
The `source` describe on `MetadataEventSchema` no longer lists `"fs"`, `"studio"`, `"rest"`, `"ai"` and
8+
`"git-import"` as origin labels: of those, only `fs` is written by any producer (`FileSystemRepository`),
9+
and no write path stamps an authoring surface there. It now says what the field is: the write path that
10+
produced the event, an open label its writer stamps rather than an enum to pick from or match against, for
11+
example `protocol.saveMetaItem`, `protocol.publishMetaItem`, `migrate-stored`, `sys-metadata-repo`
12+
(`SysMetadataRepository`'s default) or `fs`. The field stays `z.string()`, so no key, type, export or
13+
accepted value changes, and every repository emits exactly what it emitted before.

‎packages/metadata-core/src/objects/sys-metadata-history.object.ts‎

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,10 @@ import { ObjectSchema, Field } from '@objectstack/spec/data';
3232
* • `metadata` / `checksum` are nullable — DELETE rows have no body or
3333
* hash. Readers must tolerate null on both columns.
3434
*
35-
* • `source` records the producer ('sys-metadata-repo', 'fs',
36-
* 'studio', …) and feeds MetadataEvent.source on history() reads.
35+
* • `source` records the write path that produced the row — an open
36+
* label its writer stamps, not an enum of authoring surfaces
37+
* ('protocol.saveMetaItem', 'migrate-stored', 'sys-metadata-repo', …)
38+
* — and feeds MetadataEvent.source on history() reads.
3739
*
3840
* Indexes are purpose-built for the two dominant read patterns:
3941
* 1. per-item history view → `(type, name, version)`
@@ -133,9 +135,18 @@ export const SysMetadataHistoryObject = ObjectSchema.create({
133135
}),
134136

135137
/**
136-
* Producer of the event ('sys-metadata-repo', 'fs', 'studio',
137-
* 'api', …). Defaults to 'sys-metadata-repo' on the canonical
138-
* write path; preserved on history() reads as MetadataEvent.source.
138+
* The write path that produced the event (= MetadataEvent.source): an
139+
* open label its writer stamps, not an enum of authoring surfaces.
140+
* `SysMetadataRepository` stamps the caller's label or its own default
141+
* — 'sys-metadata-repo' (put / delete), 'sys-metadata-repo.publish'
142+
* (promoteDraft), 'sys-metadata-repo.revert' (restoreVersion). The
143+
* protocol names its method ('protocol.saveMetaItem',
144+
* 'protocol.publishMetaItem', 'protocol.deleteMetaItem',
145+
* 'protocol.rollbackMetaItem', 'protocol.revertCommit'); a stored-row
146+
* rewrite passes 'migrate-stored'; `@objectstack/metadata`'s
147+
* DatabaseLoader writes 'database-loader'. history() reads pass the
148+
* stored value through and answer 'sys-metadata-repo' for a row that
149+
* stored none.
139150
*/
140151
source: Field.text({
141152
label: 'Source',

‎packages/metadata-core/src/types.ts‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,12 @@ export const MetadataEventSchema = z.object({
145145
actor: z.string().nullable(),
146146
message: z.string().optional(),
147147
ts: z.string(),
148-
source: z.string().describe('Origin label: "fs", "studio", "rest", "ai", "git-import", …'),
148+
source: z.string().describe(
149+
'Which write path produced the event: an open label its writer stamps, not an enum of '
150+
+ 'authoring surfaces to pick from or match against (e.g. `protocol.saveMetaItem`, '
151+
+ '`protocol.publishMetaItem`, `migrate-stored`, `sys-metadata-repo` as '
152+
+ '`SysMetadataRepository`\'s default, or `fs` from `FileSystemRepository`).',
153+
),
149154
});
150155

151156
export type MetadataEvent = z.infer<typeof MetadataEventSchema>;

0 commit comments

Comments
 (0)