From 505d711e1bbc7911b4ccc17bbc8d0ad137c4bc1e Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 31 Aug 2026 11:32:30 +0000 Subject: [PATCH 1/3] Select an import-list doc block as module description only on an explicit @module marker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Route 1 of #13334: inside the import list — imports before the block, an import the first thing after it — no positional signal separates a genuine module header from one schema's detached comment (the card measured every signal; only the prose differs). The selector now asks the author instead: only a block carrying @module on a prose line selects there, in both directions, with the one exception of plumbing that runs to EOF (a pure re-export module has no symbol the block could have been torn from). The two genuine headers in that position, shared/mapping and system/cache, each gain the one-line marker — the repo's existing spelling, fourteen headers above their imports already open with it. No other source is touched. Measured over all 208 corpus sources, old selector vs new: 200 verdicts byte-identical, exactly the 8 misattributed openings flip SELECTED->null, 0 change to a different block. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01PBjwYLS6BciTQW3c9xQiD2 --- .../spec/scripts/file-description.test.ts | 225 +++++++++++++++++- packages/spec/scripts/lib/file-description.ts | 111 ++++++--- packages/spec/src/shared/mapping.zod.ts | 2 + packages/spec/src/system/cache.zod.ts | 4 +- 4 files changed, 300 insertions(+), 42 deletions(-) diff --git a/packages/spec/scripts/file-description.test.ts b/packages/spec/scripts/file-description.test.ts index eb799771df..28358e1d0a 100644 --- a/packages/spec/scripts/file-description.test.ts +++ b/packages/spec/scripts/file-description.test.ts @@ -245,7 +245,8 @@ describe('findModuleDocBlock — a block documents a symbol, or it documents the * The tightening applies only INSIDE the import block and stops at a comment of * any kind, which is what the four `keeps` cases below pin: without the first * limb, three real headers written above their imports go blank; without the - * second, `api/analytics` and `system/cache` do. + * second, `api/analytics` does (and `system/cache` did, until #13334 put its + * selection on the `@module` marker instead — the describe after this one). * * MEASURED over `packages/spec/src` (193 sources, base `3322527f`): 28 pages * lose a misattributed opening, 0 change to a different block, 165 are @@ -330,15 +331,18 @@ describe('findModuleDocBlock — #13263: an import injected between a block and expect(opening(findModuleDocBlock(source))).toBe('Package Documentation Metadata Protocol (ADR-0046)'); }); - it('keeps a header inside the imports when the next schema carries its own JSDoc', () => { - // `system/cache.zod.ts` — its block names itself ("This File") and the - // declaration beyond the injected import is already documented, so that - // import says nothing about what the block documents. + it('keeps a marked header inside the imports when the next schema carries its own JSDoc', () => { + // `system/cache.zod.ts`, as #13334 left it: a block inside the import list + // with a comment on the far side is the position no structural signal can + // decide (see the #13334 describe below), so the real header now carries + // `@module` — and that marker, not the far-side comment, is what selects it. const source = [ "import { z } from 'zod';", "import { CronExpressionInputSchema } from '../shared/expression.zod';", '', '/**', + ' * @module system/cache', + ' *', ' * Application-Level Cache Protocol', ' */', "import { lazySchema } from '../shared/lazy-schema';", @@ -347,12 +351,15 @@ describe('findModuleDocBlock — #13263: an import injected between a block and "export const CacheStrategySchema = z.enum(['lru']);", '', ].join('\n'); - expect(opening(findModuleDocBlock(source))).toBe('Application-Level Cache Protocol'); + expect(opening(findModuleDocBlock(source))).toBe('@module system/cache'); }); it('keeps a block with no declaration on the far side at all', () => { // A module that is nothing but re-exports — the plumbing runs to the end of // the file, so there is no symbol for the block to have been torn from. + // #13334's marker gate deliberately leaves this shape alone: with no symbol + // anywhere beyond, the block cannot be a detached symbol doc, so it selects + // bare. const source = [ "import { z } from 'zod';", '', @@ -367,6 +374,132 @@ describe('findModuleDocBlock — #13263: an import injected between a block and }); }); +/** + * #13334 — inside the import list, only `@module` selects. + * + * The position #13263 could not decide: a block with imports before it, an + * import the FIRST thing after it, and a comment beyond that plumbing. Two + * genuine headers (`system/cache`, `shared/mapping`) and eight detached symbol + * docs (`ai/agent`, `data/datasource`, `data/hook`, `security/permission`, + * `ui/action`, `ui/app`, `ui/component`, `ui/page`) sat there structurally + * identical — #13334 measured every positional signal (line number, imports + * before, block length, whether the next declaration has its own JSDoc) and + * none separates them; only the prose differs, and a prose pattern check is the + * approach `file-description.ts`'s own header rejects with the measurement + * behind the rejection. So the rule asks the author: the explicit `@module` + * marker — already this repo's spelling for a module header, fourteen sources + * above their imports open with it — decides, in both directions. + */ +describe('findModuleDocBlock — #13334: inside the import list, only `@module` selects', () => { + // `ui/page.zod.ts` as #13263 left it, reduced: the block reads like (and is) + // one schema's doc, the injected import sits against it, and the next thing + // beyond the plumbing is another doc block. Under the far-side-comment rule + // this was SELECTED — the eighth published page opening with `Page Region + // Schema`. + const unmarked = [ + "import { z } from 'zod';", + '', + '/**', + ' * Page Region Schema', + ' * A named region in the template where components are dropped.', + ' */', + "import { lazySchema } from '../shared/lazy-schema';", + '', + '/** Shared history for this file. */', + "const PAGE_HISTORY = 'Until this shape was closed…';", + '', + 'export const PageRegionSchema = lazySchema(() => strictObject({}));', + '', + ].join('\n'); + + it('rejects an unmarked block inside the import list, comment on the far side or not', () => { + expect(findModuleDocBlock(unmarked)).toBeNull(); + }); + + it('selects the byte-identical block once it carries `@module` — the minimal pair', () => { + const marked = unmarked.replace(' * Page Region Schema', ' * @module ui/page\n *\n * Page Region Schema'); + expect(opening(findModuleDocBlock(marked))).toBe('@module ui/page'); + }); + + it('lets `@module` decide even with a declaration on the far side of the plumbing', () => { + // The marker is the author's explicit declaration, and explicit beats + // inferred: a marked header whose next schema happens to be undocumented + // must not go blank the day that schema loses its JSDoc. + const source = [ + "import { z } from 'zod';", + '', + '/**', + ' * @module system/example', + ' *', + ' * Example Protocol', + ' */', + "import { lazySchema } from '../shared/lazy-schema';", + '', + 'export const ExampleSchema = lazySchema(() => z.object({}));', + '', + ].join('\n'); + expect(opening(findModuleDocBlock(source))).toBe('@module system/example'); + }); + + it('reads an `@module` inside a fenced example as content, never as the marker', () => { + // The predicate runs through `classifyLines`, the same model of "which + // lines are code" the renderer uses — an author ILLUSTRATING the convention + // must not thereby publish the block they illustrated it in. + const source = [ + "import { z } from 'zod';", + '', + '/**', + ' * Widget Config Schema', + ' *', + ' * ```ts', + ' * @module not/a/marker', + ' * ```', + ' */', + "import { lazySchema } from '../shared/lazy-schema';", + '', + '/** The widget. */', + 'export const WidgetSchema = lazySchema(() => z.object({}));', + '', + ].join('\n'); + expect(findModuleDocBlock(source)).toBeNull(); + }); + + it('reads a mid-sentence mention of the tag as prose about it, never as the marker', () => { + const source = [ + "import { z } from 'zod';", + '', + '/**', + ' * Widget Config Schema — needs no @module marker to look like one.', + ' */', + "import { lazySchema } from '../shared/lazy-schema';", + '', + '/** The widget. */', + 'export const WidgetSchema = lazySchema(() => z.object({}));', + '', + ].join('\n'); + expect(findModuleDocBlock(source)).toBeNull(); + }); + + it('still needs no marker ABOVE the imports — the gate is scoped to the ambiguous position', () => { + // ~180 real headers sit outside the import list and stay untouched; the + // fixture beside `keeps a module header written above the imports` pins the + // same thing, and this one pins it against the gate specifically. + const source = [ + '/**', + ' * Widget Protocol', + ' */', + '', + "import { z } from 'zod';", + "import { lazySchema } from '../shared/lazy-schema';", + '', + '/** The widget. */', + 'export const WidgetSchema = lazySchema(() => z.object({}));', + '', + ].join('\n'); + expect(opening(findModuleDocBlock(source))).toBe('Widget Protocol'); + }); +}); + describe('renderFileDescription', () => { // `fromCategory` is the directory the rendered module lives in (#6484); these // cases reference `automation/` and are written as if from there. @@ -1222,6 +1355,80 @@ describe('corpus — no reference source donates a symbol comment to its page', expect(openingOf('kernel/execution-context.zod.ts')).toBeNull(); expect(openingOf('data/field.zod.ts')).toBeNull(); }); + + /** + * #13334's corpus limb — the half that cannot rot. + * + * Re-derives the marker gate from the real tree: a SELECTED block that sits + * inside the import list — plumbing somewhere before it, plumbing the first + * thing after it — must carry `@module` on a prose line, unless nothing but + * plumbing and blanks follows it to the end of the file. A source that + * drifts back into the ambiguous position (the lazify codemod's insertion + * point is exactly there) cannot quietly re-acquire a wrong page opening: + * unmarked, it renders no description at all. + */ + it('never selects an unmarked block inside the import list (#13334)', () => { + const PLUMBING = /^(?:import\b|export\s*(?:\*|\{|type\s*\{))/; + const offenders: string[] = []; + for (const file of zodFiles) { + const source = fs.readFileSync(file, 'utf-8'); + const block = findModuleDocBlock(source); + if (block === null) continue; + const marker = `/**${block}*/`; + const at = source.indexOf(marker); + if (at < 0) continue; // already reported by the first corpus case + const lines = source.split('\n'); + const startLine = source.slice(0, at).split('\n').length - 1; + const endLine = startLine + marker.split('\n').length - 1; + if (!lines.slice(0, startLine).some(l => PLUMBING.test(l))) continue; // above the imports + const next = lines.slice(endLine + 1).find(l => l.trim() !== '') ?? ''; + if (!PLUMBING.test(next)) continue; // a comment or declaration against the block decides for itself + // The same walk the selector runs: over blanks and plumbing, does + // anything but the end of the file lie beyond? A comment or a + // declaration both count — only a pure re-export tail selects bare. + const runsToEof = lines.slice(endLine + 1).every( + l => l.trim() === '' || (PLUMBING.test(l) || (!l.trimStart().startsWith('/') && !/^[A-Za-z_$@]/.test(l))), + ); + const marked = block.split('\n').some(l => /^@module\b/.test(l.replace(/^\s*\*\s?/, ''))); + if (!marked && !runsToEof) { + offenders.push(path.relative(SRC_DIR, file)); + } + } + expect(offenders).toEqual([]); + }); + + it('opens `system/cache` and `shared/mapping` with their marked headers (#13334)', () => { + // The two genuine headers the ambiguous position held; each now carries + // the one-line `@module` marker, and the gate is what makes that marker + // load-bearing rather than decorative. + const openingOf = (rel: string) => + opening(findModuleDocBlock(fs.readFileSync(path.join(SRC_DIR, rel), 'utf-8'))); + expect(openingOf('system/cache.zod.ts')).toBe('@module system/cache'); + expect(openingOf('shared/mapping.zod.ts')).toBe('@module shared/mapping'); + }); + + it('publishes no description for the eight modules whose opening was one schema\'s doc (#13334)', () => { + // The corpus half of route ② — each of the eight had a symbol's comment + // wedged into its import list by the lazify codemod, published as the + // page's opening and as the module's skill-index pointer row. The comments + // moved back to the declarations they document (or to the family they + // head), so no block sits in the header zone documenting nothing: the page + // honestly prints no description. 宁可缺,不要错. + const openingOf = (rel: string) => + opening(findModuleDocBlock(fs.readFileSync(path.join(SRC_DIR, rel), 'utf-8'))); + for (const rel of [ + 'ai/agent.zod.ts', + 'data/datasource.zod.ts', + 'data/hook.zod.ts', + 'security/permission.zod.ts', + 'ui/action.zod.ts', + 'ui/app.zod.ts', + 'ui/component.zod.ts', + 'ui/page.zod.ts', + ]) { + expect(openingOf(rel), rel).toBeNull(); + } + }); }); /** @@ -1422,7 +1629,11 @@ describe('corpus — every rendered description is well-formed markdown', () => }; it('finds descriptions to check', () => { - expect(described.length).toBeGreaterThan(150); + // 146 at #13334 (154 before it — the marker gate blanked the eight modules + // whose "description" was one schema's detached comment; the diff of every + // per-file verdict, old selector vs new over all 208 sources, is in that + // card's PR: 200 identical, 8 SELECTED→null, 0 to a different block). + expect(described.length).toBeGreaterThan(140); }); it('never cuts an inline code span in half (#5553)', () => { diff --git a/packages/spec/scripts/lib/file-description.ts b/packages/spec/scripts/lib/file-description.ts index b16f90ef14..44172b4dd8 100644 --- a/packages/spec/scripts/lib/file-description.ts +++ b/packages/spec/scripts/lib/file-description.ts @@ -33,8 +33,10 @@ * and this repo writes module headers on either side of them); the first * `const`/`export const`/… does. * 3. **Documenting nothing** — the block is not immediately followed by a - * declaration, and — when the block sits INSIDE the import block — no - * declaration sits on the far side of that plumbing either. + * declaration, and — when the block sits INSIDE the import list, an import + * the first thing on its far side — it carries the explicit `@module` + * marker (see the #13334 section below; a far side that is nothing but + * plumbing to the end of the file needs no marker). * * (3) is the load-bearing one, and it is simply TSDoc's own rule read back: a * doc block belongs to the declaration it immediately precedes, which is why @@ -76,18 +78,31 @@ * `cloud/template-manifest` and `system/doc` — three real headers whose * imports happen to be followed directly by a declaration — lose their * opening paragraph. - * - **A comment of any kind on the far side still ends the preamble.** A `// ═══` - * banner or a second doc block means the block did NOT sit against the - * declaration before the codemod ran, so the injection tells us nothing. - * `api/analytics` (banner) and `system/cache` (the next schema's own JSDoc) - * keep their headers through exactly this clause. - * - * What it deliberately does NOT decide is the block that sits inside the import - * list with a comment on the far side: `system/cache` and `shared/mapping` are - * genuine headers there and seven others are detached symbol docs, and no - * positional or structural signal separates them — only the prose does. That - * residue needs an explicit `@module` marker or a corpus pass, not a cleverer - * detector; #13263 records the reading, module by module. + * - **A comment directly against the block's far side still ends the preamble.** + * A `// ═══` banner or a second doc block as the FIRST thing after the block + * means the block did NOT sit against an injected import at all, so the + * codemod's ambiguity never arises. `api/analytics` (banner) keeps its header + * through exactly this clause. + * + * ## Inside the import list, only `@module` selects (#13334) + * + * What position cannot decide is the block whose far side opens with an IMPORT + * and whose walk beyond that plumbing then meets a comment: `system/cache` and + * `shared/mapping` were genuine headers there and eight others were detached + * symbol docs, and every positional signal was measured and separates nothing — + * line number, imports-before count, block length, whether the next declaration + * has its own JSDoc; only the prose differs (#13334 carries the table). A + * first-sentence pattern check is the approach this header already rejects, so + * the rule asks the author instead: a block sitting inside the import list — + * imports before it, an import the first thing after it — is selected only when + * it carries an explicit `@module` marker on a prose line of its own. The + * marker is this repo's existing spelling for "this block is the module's" + * (fourteen headers above their imports already open with it), and it decides + * in BOTH directions: with it the block is the header whatever lies beyond the + * plumbing, without it the block is not selected even though a comment on the + * far side would once have kept it. One exception needs no marker: plumbing + * that runs to the end of the file leaves no symbol the block could have been + * torn from (a pure re-export module), so the block still selects bare. * * When no block qualifies, the module has no description and the page prints * none. 宁可缺,不要错 — a missing paragraph is a gap the reader can see, while @@ -300,37 +315,51 @@ function nextNonBlankLine(lines: readonly string[], from: number): number | null } /** - * Is there a declaration on the far side of the plumbing that starts at `from` - * — i.e. does everything between hold nothing but blank lines and imports? + * What the walk from `from`, over blank lines and plumbing, reaches first. * - * Only ever asked of a block that sits INSIDE the import block, where the one - * thing known to put an import between a doc block and its symbol is the lazify - * codemod (see the module comment). Answering `true` there restores the verdict - * the block had before that import was injected. + * Only ever asked of a block that sits INSIDE the import list (see the module + * comment's #13334 section), where the answer routes an UNMARKED block: + * `'eof'` selects it — the plumbing runs to the end of the file, so there is + * no symbol the block could have been torn from (a pure re-export module) — + * while `'declaration'` (the #13263 codemod shape) and `'comment'` (the + * position #13334 measured as undecidable) both refuse it, leaving `@module` + * as the only thing that selects there. * * A comment of any kind — a `// ═══` banner, a second doc block, an import's - * own explanatory note — answers `false` instead of being walked over. That is - * the same boundary `nextNonBlankLine` draws and for the same reason: it means - * the block was NOT sitting against the declaration beforehand either, so the - * injected import carries no information about what the block documents. It is - * what keeps `api/analytics` (banner) and `system/cache` (the next schema's own - * JSDoc) opening with their real module headers. + * own explanatory note — stops the walk instead of being walked over. That is + * the same boundary `nextNonBlankLine` draws and for the same reason. * * Continuation and closing lines of a multi-line import (` Foo,`, * `} from './x';`) are plumbing too — they open with neither an identifier * character nor a comment delimiter, exactly as `findModuleDocBlock`'s own walk * reads them. */ -function declarationBeyondPlumbing(lines: readonly string[], from: number): boolean { +function beyondPlumbing(lines: readonly string[], from: number): 'declaration' | 'comment' | 'eof' { for (let i = from; i < lines.length; i++) { const line = lines[i]; if (line.trim() === '') continue; - if (line.trimStart().startsWith('/')) return false; // a comment ends the preamble + if (line.trimStart().startsWith('/')) return 'comment'; if (MODULE_PLUMBING.test(line)) continue; if (!startsDeclaration(line)) continue; // continuation / closing punctuation - return true; + return 'declaration'; } - return false; + return 'eof'; +} + +/** + * Does the block carry the `@module` marker — this repo's existing spelling + * for "this block documents the module" — on a prose line of its own? + * + * Judged on gutter-stripped lines through the same `classifyLines` model the + * renderer uses, so an `@module` shown inside a fenced example (an author + * illustrating the convention) is content, never a marker. The line must OPEN + * with the tag: fourteen real headers write it exactly that way (`@module + * ui/sharing`), and a mid-sentence mention of the tag is prose about it. + */ +function hasModuleMarker(inner: string): boolean { + const lines = stripDocGutter(inner); + const kind = classifyLines(lines); + return lines.some((line, i) => kind[i] === 'prose' && /^@module\b/.test(line)); } /** @@ -364,11 +393,25 @@ export function findModuleDocBlock(source: string): string | null { if (end >= lines.length) return null; // unterminated — nothing to trust const next = nextNonBlankLine(lines, end + 1); if (next !== null && startsDeclaration(lines[next])) return null; // documents a symbol - // …and the same verdict when only injected plumbing stands between the - // two: the import moved, the attachment did not. - if (insideImportBlock && declarationBeyondPlumbing(lines, end + 1)) return null; const raw = lines.slice(i, end + 1).join('\n'); - return raw.slice(raw.indexOf('/**') + 3, raw.lastIndexOf('*/')); + const inner = raw.slice(raw.indexOf('/**') + 3, raw.lastIndexOf('*/')); + // INSIDE the import list — imports before the block, an import the first + // thing after it — position cannot say what the block documents (#13334; + // the measurement is in the module comment). Only the author's explicit + // `@module` marker selects it there, except when the plumbing runs to the + // end of the file and no symbol exists for the block to have been torn + // from. This subsumes #13263's far-side rule: an unmarked block with a + // declaration beyond the plumbing is still refused. + if ( + insideImportBlock && + next !== null && + MODULE_PLUMBING.test(lines[next]) && + !hasModuleMarker(inner) && + beyondPlumbing(lines, next) !== 'eof' + ) { + return null; + } + return inner; } if (line.startsWith('/*')) { i = endOfBlockComment(lines, i) + 1; continue; } diff --git a/packages/spec/src/shared/mapping.zod.ts b/packages/spec/src/shared/mapping.zod.ts index 3fc3a765e9..506db6ca70 100644 --- a/packages/spec/src/shared/mapping.zod.ts +++ b/packages/spec/src/shared/mapping.zod.ts @@ -4,6 +4,8 @@ import { z } from 'zod'; import { retiredKey } from './retired-key'; /** + * @module shared/mapping + * * Base Field Mapping Protocol * * Shared by: Connector diff --git a/packages/spec/src/system/cache.zod.ts b/packages/spec/src/system/cache.zod.ts index e1585142a2..5f353d1277 100644 --- a/packages/spec/src/system/cache.zod.ts +++ b/packages/spec/src/system/cache.zod.ts @@ -4,8 +4,10 @@ import { z } from 'zod'; import { CronExpressionInputSchema } from '../shared/expression.zod'; /** + * @module system/cache + * * Application-Level Cache Protocol - * + * * Multi-tier caching strategy for application data. * Supports Memory, Redis, Memcached, and CDN. * From a78e38710fc1bb43527034383737d63914593509 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 31 Aug 2026 11:52:16 +0000 Subject: [PATCH 2/3] Move the eight wedged doc blocks back to the declarations they document MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Route 2 of #13334. The lazify codemod's injected import had wedged itself between each block and its symbol; the injected imports move up into the import block and each comment moves back against its subject — verbatim, a position fix, not a rewrite. Editor hover is restored for the four symbols that had no attached doc at all: AIModelConfigSchema, DriverType, ActionParamSchema, PageRegionSchema. In the other four modules (data/hook, security/permission, ui/app, ui/component) the documented symbol or family head already carries its own richer JSDoc, so the moved block sits directly above it as a section lead and hover was already correct — a refinement of the card's reading, recorded in the PR. Regenerated: 10 reference pages (8 lose the misattributed opening, 2 gain their @module line) and 4 published skill indexes (8 pointer rows fall back to the honest export list). Changeset included; no schema behavior changes. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01PBjwYLS6BciTQW3c9xQiD2 --- .changeset/module-doc-block-selection.md | 15 ++++ content/docs/references/ai/agent.mdx | 2 - content/docs/references/data/datasource.mdx | 3 - content/docs/references/data/hook.mdx | 3 - .../docs/references/security/permission.mdx | 8 --- content/docs/references/shared/mapping.mdx | 2 + content/docs/references/system/cache.mdx | 2 + content/docs/references/ui/action.mdx | 33 --------- content/docs/references/ui/app.mdx | 15 ---- content/docs/references/ui/component.mdx | 2 - content/docs/references/ui/page.mdx | 3 - packages/spec/src/ai/agent.zod.ts | 7 +- packages/spec/src/data/datasource.zod.ts | 9 ++- packages/spec/src/data/hook.zod.ts | 10 +-- packages/spec/src/security/permission.zod.ts | 21 +++--- packages/spec/src/ui/action.zod.ts | 69 +++++++++---------- packages/spec/src/ui/app.zod.ts | 34 ++++----- packages/spec/src/ui/component.zod.ts | 26 +++---- packages/spec/src/ui/page.zod.ts | 8 +-- skills/objectstack-ai/references/_index.md | 2 +- skills/objectstack-data/references/_index.md | 8 +-- .../objectstack-platform/references/_index.md | 6 +- skills/objectstack-ui/references/_index.md | 8 +-- 23 files changed, 122 insertions(+), 174 deletions(-) create mode 100644 .changeset/module-doc-block-selection.md diff --git a/.changeset/module-doc-block-selection.md b/.changeset/module-doc-block-selection.md new file mode 100644 index 0000000000..8c659118fd --- /dev/null +++ b/.changeset/module-doc-block-selection.md @@ -0,0 +1,15 @@ +--- +'@objectstack/spec': patch +--- + +Reference pages and skill indexes no longer open with one schema's comment: a +doc block sitting inside a module's import list is selected as the module +description only when it carries an explicit `@module` marker. The two genuine +headers in that position (`shared/mapping`, `system/cache`) now carry the +marker; the eight modules whose "description" was a detached symbol comment +(`ai/agent`, `data/datasource`, `data/hook`, `security/permission`, +`ui/action`, `ui/app`, `ui/component`, `ui/page`) had the comment moved back to +the declaration it documents — restoring editor hover for +`AIModelConfigSchema`, `DriverType`, `ActionParamSchema` and +`PageRegionSchema` — and their pages honestly print no module description +instead of a wrong one. No schema behavior changes. diff --git a/content/docs/references/ai/agent.mdx b/content/docs/references/ai/agent.mdx index 5664bd01bb..880bc15536 100644 --- a/content/docs/references/ai/agent.mdx +++ b/content/docs/references/ai/agent.mdx @@ -5,8 +5,6 @@ description: Agent protocol schemas {/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */} -AI Model Configuration - **Source:** `packages/spec/src/ai/agent.zod.ts` diff --git a/content/docs/references/data/datasource.mdx b/content/docs/references/data/datasource.mdx index a346d23ce3..8f2c8e67ba 100644 --- a/content/docs/references/data/datasource.mdx +++ b/content/docs/references/data/datasource.mdx @@ -5,9 +5,6 @@ description: Datasource protocol schemas {/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */} -Driver Identifier -Can be a built-in driver or a plugin-contributed driver (e.g., "com.vendor.snowflake"). - **Source:** `packages/spec/src/data/datasource.zod.ts` diff --git a/content/docs/references/data/hook.mdx b/content/docs/references/data/hook.mdx index 68b61c4fc1..9aa788bd38 100644 --- a/content/docs/references/data/hook.mdx +++ b/content/docs/references/data/hook.mdx @@ -5,9 +5,6 @@ description: Hook protocol schemas {/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */} -Hook Lifecycle Events -Defines the interception points in the ObjectQL execution pipeline. - **Source:** `packages/spec/src/data/hook.zod.ts` diff --git a/content/docs/references/security/permission.mdx b/content/docs/references/security/permission.mdx index e2e81725db..d98e3febd5 100644 --- a/content/docs/references/security/permission.mdx +++ b/content/docs/references/security/permission.mdx @@ -5,14 +5,6 @@ description: Permission protocol schemas {/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */} -Entity (Object) Level Permissions -Defines CRUD + VAMA (View All / Modify All) + Lifecycle access. - -Refined with enterprise data lifecycle controls: -- Transfer (Ownership change) -- Restore (Soft delete recovery) -- Purge (Hard delete / Compliance) - **Source:** `packages/spec/src/security/permission.zod.ts` diff --git a/content/docs/references/shared/mapping.mdx b/content/docs/references/shared/mapping.mdx index cba9e4ef28..81cf20989c 100644 --- a/content/docs/references/shared/mapping.mdx +++ b/content/docs/references/shared/mapping.mdx @@ -5,6 +5,8 @@ description: Mapping protocol schemas {/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */} +@module shared/mapping + Base Field Mapping Protocol Shared by: Connector diff --git a/content/docs/references/system/cache.mdx b/content/docs/references/system/cache.mdx index f2ae75b68b..1541c5d040 100644 --- a/content/docs/references/system/cache.mdx +++ b/content/docs/references/system/cache.mdx @@ -5,6 +5,8 @@ description: Cache protocol schemas {/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */} +@module system/cache + Application-Level Cache Protocol Multi-tier caching strategy for application data. diff --git a/content/docs/references/ui/action.mdx b/content/docs/references/ui/action.mdx index af20ace4c8..baa6002cf1 100644 --- a/content/docs/references/ui/action.mdx +++ b/content/docs/references/ui/action.mdx @@ -5,39 +5,6 @@ description: Action protocol schemas {/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */} -Action Parameter Schema - -Defines inputs required before executing an action. - -Two declaration modes: - -1. **Field-backed** (preferred) — reference an existing object field; the - runtime resolves the field's label (i18n), type, validation rules, - options, placeholder, help text, and widget mapping from object - metadata. Cross-object references use `objectOverride`. - - ```ts - params: [ - { field: 'email' }, // same object - { field: 'role', objectOverride: 'sys_member' }, // different object - ] - ``` - -2. **Inline** (legacy / bespoke) — declare `name`, `label`, `type` etc. - inline when no matching object field exists. Inline values may also be - used alongside `field` to override individual properties. A `lookup` / - `master_detail` param declared this way MUST name its target object via - `reference` — there is no field to inherit it from: - - ```ts - params: [ - { name: 'inspector', label: 'Inspector', type: 'lookup', reference: 'sys_user' }, - ] - ``` - -`name` is required unless `field` is provided (in which case it defaults -to the field name and is used as the request-body key). - **Source:** `packages/spec/src/ui/action.zod.ts` diff --git a/content/docs/references/ui/app.mdx b/content/docs/references/ui/app.mdx index 40a3236a4a..16ac1a9440 100644 --- a/content/docs/references/ui/app.mdx +++ b/content/docs/references/ui/app.mdx @@ -5,21 +5,6 @@ description: App protocol schemas {/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */} -Base Navigation Item Schema -Shared properties for all navigation types. - -**NAMING CONVENTION:** -Navigation item IDs are used in URLs and configuration and must be lowercase snake_case. - -@example Good IDs -- 'menu_accounts' -- 'page_dashboard' -- 'nav_settings' - -@example Bad IDs (will be rejected) -- 'MenuAccounts' (PascalCase) -- 'Page Dashboard' (spaces) - **Source:** `packages/spec/src/ui/app.zod.ts` diff --git a/content/docs/references/ui/component.mdx b/content/docs/references/ui/component.mdx index 9149aa32b7..33c8c9bdd4 100644 --- a/content/docs/references/ui/component.mdx +++ b/content/docs/references/ui/component.mdx @@ -5,8 +5,6 @@ description: Component protocol schemas {/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */} -Empty Properties Schema - **Source:** `packages/spec/src/ui/component.zod.ts` diff --git a/content/docs/references/ui/page.mdx b/content/docs/references/ui/page.mdx index d03ef7ec13..8b2ac56291 100644 --- a/content/docs/references/ui/page.mdx +++ b/content/docs/references/ui/page.mdx @@ -5,9 +5,6 @@ description: Page protocol schemas {/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */} -Page Region Schema -A named region in the template where components are dropped. - **Source:** `packages/spec/src/ui/page.zod.ts` diff --git a/packages/spec/src/ai/agent.zod.ts b/packages/spec/src/ai/agent.zod.ts index ee4a886094..690dc4e58e 100644 --- a/packages/spec/src/ai/agent.zod.ts +++ b/packages/spec/src/ai/agent.zod.ts @@ -5,10 +5,6 @@ import { retiredKey } from '../shared/retired-key'; import { ProtectionSchema } from '../shared/protection.zod'; import { MetadataProtectionFields } from '../kernel/metadata-protection.zod'; import { StateMachineSchema } from '../automation/state-machine.zod'; - -/** - * AI Model Configuration - */ import { lazySchema } from '../shared/lazy-schema'; import { strictObject } from '../shared/strict-object'; @@ -24,6 +20,9 @@ const AGENT_HISTORY = 'Until this shape was closed these were dropped silently — the agent still registered ' + 'and still answered, minus whatever the key was meant to configure or constrain.'; +/** + * AI Model Configuration + */ export const AIModelConfigSchema = lazySchema(() => strictObject({ surface: 'this model configuration', history: AGENT_HISTORY, diff --git a/packages/spec/src/data/datasource.zod.ts b/packages/spec/src/data/datasource.zod.ts index c004d5ab8c..0581ad4065 100644 --- a/packages/spec/src/data/datasource.zod.ts +++ b/packages/spec/src/data/datasource.zod.ts @@ -1,11 +1,6 @@ // Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license. import { z } from 'zod'; - -/** - * Driver Identifier - * Can be a built-in driver or a plugin-contributed driver (e.g., "com.vendor.snowflake"). - */ import { lazySchema } from '../shared/lazy-schema'; import { strictObject } from '../shared/strict-object'; import { MetadataProtectionFields } from '../kernel/metadata-protection.zod'; @@ -173,6 +168,10 @@ const RETIRED_READ_REPLICAS = + '`config` at that endpoint, which is the only read-scaling path that works today. ' + 'Run `os migrate meta --from 16` to list the mechanical edits for existing sources; apply them by hand.'; +/** + * Driver Identifier + * Can be a built-in driver or a plugin-contributed driver (e.g., "com.vendor.snowflake"). + */ export const DriverType = z.string().describe('Underlying driver identifier'); export type DriverType = z.input; diff --git a/packages/spec/src/data/hook.zod.ts b/packages/spec/src/data/hook.zod.ts index d14db06138..079adc8dde 100644 --- a/packages/spec/src/data/hook.zod.ts +++ b/packages/spec/src/data/hook.zod.ts @@ -2,11 +2,6 @@ import { z } from 'zod'; import { ExpressionInputSchema } from '../shared/expression.zod'; - -/** - * Hook Lifecycle Events - * Defines the interception points in the ObjectQL execution pipeline. - */ import { lazySchema } from '../shared/lazy-schema'; import { retiredKey } from '../shared/retired-key'; import { strictObject } from '../shared/strict-object'; @@ -68,6 +63,11 @@ const hookTargetError = + "`object: 'account'` or `object: ['account', 'contact']` — or, if firing on " + "every object really is the intent, write the wildcard explicitly: `object: '*'`."; +/** + * Hook Lifecycle Events + * Defines the interception points in the ObjectQL execution pipeline. + */ + /** * The lifecycle events a hook can subscribe to. * diff --git a/packages/spec/src/security/permission.zod.ts b/packages/spec/src/security/permission.zod.ts index 1c726da8af..fd6a64e59f 100644 --- a/packages/spec/src/security/permission.zod.ts +++ b/packages/spec/src/security/permission.zod.ts @@ -6,19 +6,10 @@ import { RowLevelSecurityPolicySchema } from './rls.zod'; import { ApiOperationSchema } from '../data/object.zod'; import { ProtectionSchema } from '../shared/protection.zod'; import { MetadataProtectionFields } from '../kernel/metadata-protection.zod'; - -/** - * Entity (Object) Level Permissions - * Defines CRUD + VAMA (View All / Modify All) + Lifecycle access. - * - * Refined with enterprise data lifecycle controls: - * - Transfer (Ownership change) - * - Restore (Soft delete recovery) - * - Purge (Hard delete / Compliance) - */ import { lazySchema } from '../shared/lazy-schema'; import { acceptRetiredDefaultResidue, retiredKey } from '../shared/retired-key'; import { strictObject } from '../shared/strict-object'; + /** * [ADR-0057 D1] Object access DEPTH — the Dataverse "access level" axis, * layered on top of OWD. Widens the owner-match for owner-scoped objects. @@ -43,6 +34,16 @@ export type ObjectAccessScope = z.input; * a recognisable spelling of it. */ +/** + * Entity (Object) Level Permissions + * Defines CRUD + VAMA (View All / Modify All) + Lifecycle access. + * + * Refined with enterprise data lifecycle controls: + * - Transfer (Ownership change) + * - Restore (Soft delete recovery) + * - Purge (Hard delete / Compliance) + */ + /** * Semantic near-misses for object-permission bits — mostly the bare CRUD verbs * (Salesforce object-permission vocabulary) an author reaches for before diff --git a/packages/spec/src/ui/action.zod.ts b/packages/spec/src/ui/action.zod.ts index 2fc47a80f3..d4bdb99391 100644 --- a/packages/spec/src/ui/action.zod.ts +++ b/packages/spec/src/ui/action.zod.ts @@ -23,41 +23,6 @@ import { PUBLIC_AUTH_FEATURE_NAMES, lowerRequiresFeature } from '../kernel/publi import { strictUnknownKeyError } from '../shared/suggestions.zod'; import { strictObject } from '../shared/strict-object'; import { MetadataProtectionFields } from '../kernel/metadata-protection.zod'; - -/** - * Action Parameter Schema - * - * Defines inputs required before executing an action. - * - * Two declaration modes: - * - * 1. **Field-backed** (preferred) — reference an existing object field; the - * runtime resolves the field's label (i18n), type, validation rules, - * options, placeholder, help text, and widget mapping from object - * metadata. Cross-object references use `objectOverride`. - * - * ```ts - * params: [ - * { field: 'email' }, // same object - * { field: 'role', objectOverride: 'sys_member' }, // different object - * ] - * ``` - * - * 2. **Inline** (legacy / bespoke) — declare `name`, `label`, `type` etc. - * inline when no matching object field exists. Inline values may also be - * used alongside `field` to override individual properties. A `lookup` / - * `master_detail` param declared this way MUST name its target object via - * `reference` — there is no field to inherit it from: - * - * ```ts - * params: [ - * { name: 'inspector', label: 'Inspector', type: 'lookup', reference: 'sys_user' }, - * ] - * ``` - * - * `name` is required unless `field` is provided (in which case it defaults - * to the field name and is used as the request-body key). - */ import { lazySchema } from '../shared/lazy-schema'; /** @@ -167,6 +132,40 @@ const actionParamOptionUndeclaredAnywhere = (key: 'icon' | 'disabled'): string = + `\`SelectOptionMetadata\` type, which no metadata path populates and no widget reads. An ` + `action param's options are \`{ label, value, visibleWhen }\`; drop the key.`; +/** + * Action Parameter Schema + * + * Defines inputs required before executing an action. + * + * Two declaration modes: + * + * 1. **Field-backed** (preferred) — reference an existing object field; the + * runtime resolves the field's label (i18n), type, validation rules, + * options, placeholder, help text, and widget mapping from object + * metadata. Cross-object references use `objectOverride`. + * + * ```ts + * params: [ + * { field: 'email' }, // same object + * { field: 'role', objectOverride: 'sys_member' }, // different object + * ] + * ``` + * + * 2. **Inline** (legacy / bespoke) — declare `name`, `label`, `type` etc. + * inline when no matching object field exists. Inline values may also be + * used alongside `field` to override individual properties. A `lookup` / + * `master_detail` param declared this way MUST name its target object via + * `reference` — there is no field to inherit it from: + * + * ```ts + * params: [ + * { name: 'inspector', label: 'Inspector', type: 'lookup', reference: 'sys_user' }, + * ] + * ``` + * + * `name` is required unless `field` is provided (in which case it defaults + * to the field name and is used as the request-body key). + */ export const ActionParamSchema = lazySchema(() => strictObject( { surface: 'this action param', diff --git a/packages/spec/src/ui/app.zod.ts b/packages/spec/src/ui/app.zod.ts index fe8562b7da..7804ae2c07 100644 --- a/packages/spec/src/ui/app.zod.ts +++ b/packages/spec/src/ui/app.zod.ts @@ -6,23 +6,6 @@ import { ExpressionInputSchema } from '../shared/expression.zod'; import { I18nLabelSchema } from './i18n.zod'; import { retiredKey } from '../shared/retired-key'; import { strictObject, type StrictObjectOptions } from '../shared/strict-object'; - -/** - * Base Navigation Item Schema - * Shared properties for all navigation types. - * - * **NAMING CONVENTION:** - * Navigation item IDs are used in URLs and configuration and must be lowercase snake_case. - * - * @example Good IDs - * - 'menu_accounts' - * - 'page_dashboard' - * - 'nav_settings' - * - * @example Bad IDs (will be rejected) - * - 'MenuAccounts' (PascalCase) - * - 'Page Dashboard' (spaces) - */ import { lazySchema } from '../shared/lazy-schema'; import { MetadataProtectionFields } from '../kernel/metadata-protection.zod'; import { ProtectionSchema } from '../shared/protection.zod'; @@ -256,6 +239,23 @@ const navItemSurface = (variant: NavItemVariant): StrictObjectOptions => ({ 'an entry that should have been gated).', }); +/** + * Base Navigation Item Schema + * Shared properties for all navigation types. + * + * **NAMING CONVENTION:** + * Navigation item IDs are used in URLs and configuration and must be lowercase snake_case. + * + * @example Good IDs + * - 'menu_accounts' + * - 'page_dashboard' + * - 'nav_settings' + * + * @example Bad IDs (will be rejected) + * - 'MenuAccounts' (PascalCase) + * - 'Page Dashboard' (spaces) + */ + /** * Shared shape of every navigation item — spread into the nine branches below. * diff --git a/packages/spec/src/ui/component.zod.ts b/packages/spec/src/ui/component.zod.ts index 97678b04ea..68a1cc03bd 100644 --- a/packages/spec/src/ui/component.zod.ts +++ b/packages/spec/src/ui/component.zod.ts @@ -6,6 +6,15 @@ import { ViewFilterRuleSchema, ViewDataSchema } from './view.zod'; import { InlineActionSchema, ActionLocationSchema } from './action.zod'; import { I18nLabelSchema, AriaPropsSchema } from './i18n.zod'; import { FeedItemType, FeedFilterMode } from '../data/feed.zod'; +import { lazySchema } from '../shared/lazy-schema'; +import { ExpressionInputSchema } from '../shared/expression.zod'; +import { retiredKey } from '../shared/retired-key'; +// `element:record_picker`'s flat `sort` shorthand is the SAME contract as +// `ElementDataSourceSchema.sort` (page.zod.ts) — one shape, imported from the +// shared source rather than re-spelled here (#6276). +import { SortItemSchema } from '../shared/enums.zod'; +import { strictObject } from '../shared/strict-object'; +import type { KeySetGuidance } from '../shared/suggestions.zod'; // --------------------------------------------------------------------------- // CLOSED AGAINST UNKNOWN KEYS as of #4001 batch A -- all 31 object sites. @@ -210,19 +219,6 @@ import { FeedItemType, FeedFilterMode } from '../data/feed.zod'; // --------------------------------------------------------------------------- -/** - * Empty Properties Schema - */ -import { lazySchema } from '../shared/lazy-schema'; -import { ExpressionInputSchema } from '../shared/expression.zod'; -import { retiredKey } from '../shared/retired-key'; -// `element:record_picker`'s flat `sort` shorthand is the SAME contract as -// `ElementDataSourceSchema.sort` (page.zod.ts) — one shape, imported from the -// shared source rather than re-spelled here (#6276). -import { SortItemSchema } from '../shared/enums.zod'; -import { strictObject } from '../shared/strict-object'; -import type { KeySetGuidance } from '../shared/suggestions.zod'; - /** * What silently happened to an undeclared prop before these shapes were closed * — the one sentence every rejection on this file carries. @@ -313,6 +309,10 @@ const COMPONENT_LEVEL_GUIDANCE: readonly KeySetGuidance[] = [ COMPONENT_NODE_KEYS_GUIDANCE, ]; +/** + * Empty Properties Schema + */ + /** * A component that declares no props at all — `app:launcher`, `nav:menu`, * `nav:breadcrumb`, `global:search`, `global:notifications`, `user:profile`, diff --git a/packages/spec/src/ui/page.zod.ts b/packages/spec/src/ui/page.zod.ts index 2183197394..bd5bf6c2b7 100644 --- a/packages/spec/src/ui/page.zod.ts +++ b/packages/spec/src/ui/page.zod.ts @@ -19,10 +19,6 @@ import { ListColumnSchema, } from './view.zod'; -/** - * Page Region Schema - * A named region in the template where components are dropped. - */ import { lazySchema } from '../shared/lazy-schema'; import { strictObject } from '../shared/strict-object'; import { MetadataProtectionFields } from '../kernel/metadata-protection.zod'; @@ -39,6 +35,10 @@ const PAGE_HISTORY = 'Until this shape was closed these were dropped silently — the page still rendered, ' + 'without whatever the key was meant to configure.'; +/** + * Page Region Schema + * A named region in the template where components are dropped. + */ export const PageRegionSchema = lazySchema(() => strictObject({ surface: 'this page region', history: PAGE_HISTORY, diff --git a/skills/objectstack-ai/references/_index.md b/skills/objectstack-ai/references/_index.md index ad27f6e764..aae04aa4f2 100644 --- a/skills/objectstack-ai/references/_index.md +++ b/skills/objectstack-ai/references/_index.md @@ -9,7 +9,7 @@ from `node_modules` — there is no local copy in the skill bundle. ## Core schemas -- `node_modules/@objectstack/spec/src/ai/agent.zod.ts` — AI Model Configuration +- `node_modules/@objectstack/spec/src/ai/agent.zod.ts` — Exports: AIModelConfigSchema, StructuredOutputFormatSchema, TransformPipelineStepSchema, StructuredOutputConfigSchema, AgentSchema - `node_modules/@objectstack/spec/src/ai/conversation.zod.ts` — AI Conversation Memory Protocol - `node_modules/@objectstack/spec/src/ai/embedding.zod.ts` — Embedding & Vector Store Primitives - `node_modules/@objectstack/spec/src/ai/knowledge-document.zod.ts` — Knowledge Document / Chunk / Hit — canonical shapes shared by every diff --git a/skills/objectstack-data/references/_index.md b/skills/objectstack-data/references/_index.md index 107b66d09d..a87f7fb377 100644 --- a/skills/objectstack-data/references/_index.md +++ b/skills/objectstack-data/references/_index.md @@ -9,13 +9,13 @@ from `node_modules` — there is no local copy in the skill bundle. ## Core schemas -- `node_modules/@objectstack/spec/src/data/datasource.zod.ts` — Driver Identifier +- `node_modules/@objectstack/spec/src/data/datasource.zod.ts` — Exports: DriverType, DriverDefinitionSchema, SchemaModeSchema, ExternalDatasourceSettingsSchema, DatasourceSchema - `node_modules/@objectstack/spec/src/data/field.zod.ts` — Exports: FieldType, SelectOptionSchema, LocationCoordinatesSchema, CurrencyConfigSchema, CurrencyValueSchema -- `node_modules/@objectstack/spec/src/data/hook.zod.ts` — Hook Lifecycle Events +- `node_modules/@objectstack/spec/src/data/hook.zod.ts` — Exports: HookEvent, HookSchema, HookContextSchema - `node_modules/@objectstack/spec/src/data/object.zod.ts` — Exports: ApiMethod, ApiOperationSchema, ObjectCapabilities, IndexSchema, TenancyConfigSchema - `node_modules/@objectstack/spec/src/data/seed.zod.ts` — Exports: SeedMode, SeedSchema, leadSeed - `node_modules/@objectstack/spec/src/data/validation.zod.ts` — ObjectStack Validation Protocol -- `node_modules/@objectstack/spec/src/security/permission.zod.ts` — Entity (Object) Level Permissions +- `node_modules/@objectstack/spec/src/security/permission.zod.ts` — Exports: ObjectAccessScopeSchema, ObjectPermissionSchema, EffectiveObjectPermissionSchema, AdminScopeSchema, FieldPermissionSchema ## Transitive dependencies @@ -45,7 +45,7 @@ from `node_modules` — there is no local copy in the skill bundle. - `node_modules/@objectstack/spec/src/shared/suggestions.zod.ts` — "Did you mean?" Suggestion Utilities - `node_modules/@objectstack/spec/src/system/deploy-bundle.zod.ts` — Deploy Bundle Protocol - `node_modules/@objectstack/spec/src/ui/action-params.zod.ts` — The action DISPATCH contract: what the platform validates on the way in, and -- `node_modules/@objectstack/spec/src/ui/action.zod.ts` — Action Parameter Schema +- `node_modules/@objectstack/spec/src/ui/action.zod.ts` — Exports: ActionParamSchema, ActionType, ActionLocationSchema, ActionAiSchema, ActionSchema - `node_modules/@objectstack/spec/src/ui/bulk-action.zod.ts` — Bulk Action Schemas - `node_modules/@objectstack/spec/src/ui/chart.zod.ts` — Unified Chart Type Taxonomy - `node_modules/@objectstack/spec/src/ui/i18n.zod.ts` — Display-label and ARIA-label primitives shared by every `ui/` shape. diff --git a/skills/objectstack-platform/references/_index.md b/skills/objectstack-platform/references/_index.md index 14638841fb..f67bd317f5 100644 --- a/skills/objectstack-platform/references/_index.md +++ b/skills/objectstack-platform/references/_index.md @@ -9,7 +9,7 @@ from `node_modules` — there is no local copy in the skill bundle. ## Core schemas -- `node_modules/@objectstack/spec/src/data/datasource.zod.ts` — Driver Identifier +- `node_modules/@objectstack/spec/src/data/datasource.zod.ts` — Exports: DriverType, DriverDefinitionSchema, SchemaModeSchema, ExternalDatasourceSettingsSchema, DatasourceSchema - `node_modules/@objectstack/spec/src/data/seed.zod.ts` — Exports: SeedMode, SeedSchema, leadSeed - `node_modules/@objectstack/spec/src/kernel/context.zod.ts` — Exports: RuntimeMode, KernelContextSchema, TenantRuntimeContextSchema - `node_modules/@objectstack/spec/src/kernel/manifest.zod.ts` — Exports: PluginPermissionsSchema, ManifestPermissionsSchema, PluginEnginesSchema, PluginRuntimeSchema, PluginPackagingSchema @@ -44,8 +44,8 @@ from `node_modules` — there is no local copy in the skill bundle. - `node_modules/@objectstack/spec/src/shared/suggestions.zod.ts` — "Did you mean?" Suggestion Utilities - `node_modules/@objectstack/spec/src/system/tenant.zod.ts` — Tenant Schema (Multi-Tenant Architecture) - `node_modules/@objectstack/spec/src/ui/action-params.zod.ts` — The action DISPATCH contract: what the platform validates on the way in, and -- `node_modules/@objectstack/spec/src/ui/action.zod.ts` — Action Parameter Schema -- `node_modules/@objectstack/spec/src/ui/app.zod.ts` — Base Navigation Item Schema +- `node_modules/@objectstack/spec/src/ui/action.zod.ts` — Exports: ActionParamSchema, ActionType, ActionLocationSchema, ActionAiSchema, ActionSchema +- `node_modules/@objectstack/spec/src/ui/app.zod.ts` — Exports: ObjectNavItemSchema, DashboardNavItemSchema, PageNavItemSchema, UrlNavItemSchema, ReportNavItemSchema - `node_modules/@objectstack/spec/src/ui/i18n.zod.ts` — Display-label and ARIA-label primitives shared by every `ui/` shape. ## How to read these diff --git a/skills/objectstack-ui/references/_index.md b/skills/objectstack-ui/references/_index.md index 8fed011033..8efc51b9d7 100644 --- a/skills/objectstack-ui/references/_index.md +++ b/skills/objectstack-ui/references/_index.md @@ -9,13 +9,13 @@ from `node_modules` — there is no local copy in the skill bundle. ## Core schemas -- `node_modules/@objectstack/spec/src/ui/action.zod.ts` — Action Parameter Schema -- `node_modules/@objectstack/spec/src/ui/app.zod.ts` — Base Navigation Item Schema +- `node_modules/@objectstack/spec/src/ui/action.zod.ts` — Exports: ActionParamSchema, ActionType, ActionLocationSchema, ActionAiSchema, ActionSchema +- `node_modules/@objectstack/spec/src/ui/app.zod.ts` — Exports: ObjectNavItemSchema, DashboardNavItemSchema, PageNavItemSchema, UrlNavItemSchema, ReportNavItemSchema - `node_modules/@objectstack/spec/src/ui/chart.zod.ts` — Unified Chart Type Taxonomy -- `node_modules/@objectstack/spec/src/ui/component.zod.ts` — Empty Properties Schema +- `node_modules/@objectstack/spec/src/ui/component.zod.ts` — Exports: PageContainerProps, PageHeaderProps, PageTabsProps, PageCardProps, RecordDetailsProps - `node_modules/@objectstack/spec/src/ui/dashboard.zod.ts` — Exports: WidgetColorVariantSchema, WidgetActionTypeSchema, DashboardHeaderActionSchema, DashboardHeaderSchema, DashboardWidgetOptionsSchema - `node_modules/@objectstack/spec/src/ui/dataset.zod.ts` — Analytics Dataset — the one semantic layer (ADR-0021). -- `node_modules/@objectstack/spec/src/ui/page.zod.ts` — Page Region Schema +- `node_modules/@objectstack/spec/src/ui/page.zod.ts` — Exports: PageRegionSchema, PageComponentType, ElementDataSourceSchema, PageComponentSchema, PageVariableSchema - `node_modules/@objectstack/spec/src/ui/report.zod.ts` — Exports: ReportType, ReportChartSchema, ReportSortSchema, JoinedReportBlockSchema, ReportSchema - `node_modules/@objectstack/spec/src/ui/view.zod.ts` — View protocol schemas — the `view` metadata type and its three persisted body spellings. - `node_modules/@objectstack/spec/src/ui/widget.zod.ts` — Exports: FieldWidgetPropsSchema From b25f061c68df855f5098b44b0580a76cb034e3cf Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 31 Aug 2026 23:51:57 +0000 Subject: [PATCH 3/3] regenerate ui/component reference page on the merged tree Discharges the os-regen deferral recorded by the merge commit. The page now carries main's section-group-reference body and no longer opens with the misattributed 'Empty Properties Schema' block, which is this branch's route-1 gate acting on the merged tree. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01PBjwYLS6BciTQW3c9xQiD2 --- content/docs/references/ui/component.mdx | 2 -- 1 file changed, 2 deletions(-) diff --git a/content/docs/references/ui/component.mdx b/content/docs/references/ui/component.mdx index 3bdc82eedc..50cfcd3867 100644 --- a/content/docs/references/ui/component.mdx +++ b/content/docs/references/ui/component.mdx @@ -5,8 +5,6 @@ description: Component protocol schemas {/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */} -Empty Properties Schema - **Source:** `packages/spec/src/ui/component.zod.ts`