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
57 changes: 57 additions & 0 deletions .changeset/docs-gen-module-description-selection.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
---
"@objectstack/spec": patch
---

fix(spec): a reference page's opening paragraph is the module's own doc block, never a symbol's (#5059)

`getFileDescription()` took the **first** doc block anywhere in a `*.zod.ts`
file, verbatim, and published it as the page's opening paragraph. That is not a
rule about descriptions — it is a rule about *ordering*: whichever declaration
happened to sit at the top of the file donated its comment to a public
document. Adding a helper above the first schema silently rewrote a published
page, and no gate could see it. `check:docs` compares the generated page against
the source and the page reproduced the wrong block faithfully, so there was no
drift to report; the trap was written down when the generator was built and
still landed on `main` twice.

The measured victim surface was **six pages**. The Translation protocol
reference opened with `Shared history sentence for every shape in this file
(#4001).` — this repo's internal tightening-campaign narrative — and the Mapping
page with its sibling. Four more had no history constant anywhere near them:
`api/contract` published the doc of `ApiErrorSchema.code` (a comment *nested
inside* an object literal), `api/realtime` published `Transport Protocol Enum`
on a page documenting fourteen schemas, and `api/protocol` / `kernel/plugin` the
same shape. Any future "move a helper to the top of the file" makes another.

The selection now follows **TSDoc's own rule, read back**: a doc block belongs
to the declaration it immediately precedes — which is exactly the text an editor
shows when you hover that symbol. So a module description must be a block that

- starts at column 0 (a block indented inside a declaration body documents a
property, never a module),
- appears before the first declaration (imports and re-exports introduce no
symbol of their own and do not close the header zone), and
- is not immediately followed by a declaration.

When no block qualifies the page prints no description at all — 宁可缺,不要错.
A confidently rendered internal note is a page that lies about its subject,
which is worse for a reader (and for an AI author working from these pages) than
a page that opens with its `Source:` pointer.

**Twenty reference pages lost an opening paragraph**, each of which was a
symbol's JSDoc rather than the module's: the six above plus `ai/solution-blueprint`,
`ai/tool`, `api/error-code-ledger`, `api/router`, `automation/approval`,
`cloud/template-manifest`, `data/driver-mysql`, `data/driver-postgres`,
`data/driver-sqlite`, `kernel/manifest`, `shared/enums`, `system/doc`,
`system/notification`, `ui/responsive`. **No page lost a real module header** —
the other 178 pages with a `Source:` line keep their description byte for byte.
A module that wants its opening paragraph back writes one block that documents
no symbol; 178 sources already do.

The rule is also the gate. The issue proposed failing on first sentences
matching `#\d{3,}` / `Shared history`, but that recognises only the
history-constant subclass, and only after publication — it would have caught two
of the six. A selection rule that cannot pick a symbol's comment makes the whole
class impossible instead. `scripts/lib/file-description.ts` (extracted from
`build-docs.ts`, following `format-type.ts` #4912 and `escape-mdx.ts` #5452) and
its pin suite `scripts/file-description.test.ts` carry it, corpus check included.
22 changes: 0 additions & 22 deletions content/docs/references/ai/solution-blueprint.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,6 @@ description: Solution Blueprint protocol schemas

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

Solution Blueprint Schema (ADR-0033 §4 — plan-first authoring)

The structured-output target an AI agent emits for a *high-level* goal

("build me a project-management system") instead of transcribing a field

list. It is a **simplified proposal shape** — deliberately lighter than the

full `ObjectSchema` / `ViewSchema` / `DashboardSchema`.

The `apply_blueprint` tool expands each entry into a proper metadata body

and stages it as a draft (so the per-type Zod schema still validates the

real artifact at write time).

The blueprint is **never persisted on its own**: the agent presents it for

conversational confirmation/edit (cheap), and only on human approval does it

batch-draft. This is the safety valve for low-specificity input.

<Callout type="info">
**Source:** `packages/spec/src/ai/solution-blueprint.zod.ts`
</Callout>
Expand Down
8 changes: 0 additions & 8 deletions content/docs/references/ai/tool.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,6 @@ description: Tool protocol schemas

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

Retired `ToolSchema` keys — the rejection carries the upgrade prescription,

because the parse error is the one channel every consumer bumping

`@objectstack/spec` is guaranteed to hit (pattern of `object.zod.ts`'s

`UNKNOWN_KEY_GUIDANCE`, ADR-0049 enforce-or-remove).

<Callout type="info">
**Source:** `packages/spec/src/ai/tool.zod.ts`
</Callout>
Expand Down
8 changes: 0 additions & 8 deletions content/docs/references/api/contract.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,6 @@ description: Contract protocol schemas

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

Machine-readable semantic code (ADR-0112): a `StandardErrorCode` member or

a code registered in `ERROR_CODE_LEDGER`. A closed set on purpose — an

unregistered code fails parse, so the envelope conformance suites catch

invented codes instead of letting a new dialect grow (#3841).

<Callout type="info">
**Source:** `packages/spec/src/api/contract.zod.ts`
</Callout>
Expand Down
46 changes: 0 additions & 46 deletions content/docs/references/api/error-code-ledger.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,52 +5,6 @@ description: Error Code Ledger protocol schemas

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

Error-Code Ledger (ADR-0112 D3).

The top-level `error.code` vocabulary is two-tier:

1. **Standard catalog** — `StandardErrorCode` (`errors.zod.ts`): a small,

closed set with platform-wide HTTP semantics. It does NOT grow when a

service invents a code.

2. **Registered extension codes** — THIS ledger: every service-specific code

a route may put in `error.code`, registered under its owning package.

`ErrorCode` (exported below) is the union, and is what `ApiErrorSchema.code`

validates against. An unregistered code fails schema parse — which fails the

envelope conformance suites — which fails CI. That friction is the point

(ADR-0112: "no silent fourth state" for error codes, per ADR-0049/0078).

## Registering a new code

Add it to your package's entry (create the entry if your package has none),

SCREAMING_SNAKE (`^[A-Z][A-Z0-9_]*$` — lint-enforced by

`error-code-ledger.test.ts`), with a trailing `//` comment when the name

alone doesn't carry the meaning. Prefer a domain prefix for anything not

self-evidently global (`ATTACHMENT_*`, `REPORT_*`, `SETTINGS_*`). If the

condition is generic (not found / permission / validation / rate limit),

use the standard catalog instead of registering a synonym.

A code emitted by several packages is listed once per emitting package —

the union dedupes; the per-package rows are provenance, not identity.

Field-level codes (`FieldErrorSchema.code`, the `fields[]` array) are a

SEPARATE vocabulary and do not belong here — see #3977 (ADR-0112 D6).

<Callout type="info">
**Source:** `packages/spec/src/api/error-code-ledger.zod.ts`
</Callout>
Expand Down
8 changes: 0 additions & 8 deletions content/docs/references/api/protocol.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,6 @@ description: Protocol protocol schemas

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

Response for `GET /api/v1/automation/actions` (ADR-0018).

Returns the live action/node registry — the platform's built-in actions plus

any plugin-contributed ones — backing the designer palette and flow

validation. Each entry is a canonical `ActionDescriptorSchema`.

<Callout type="info">
**Source:** `packages/spec/src/api/protocol.zod.ts`
</Callout>
Expand Down
4 changes: 0 additions & 4 deletions content/docs/references/api/realtime.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@ description: Realtime protocol schemas

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

Transport Protocol Enum

Defines the communication protocol for realtime data synchronization

<Callout type="info">
**Source:** `packages/spec/src/api/realtime.zod.ts`
</Callout>
Expand Down
4 changes: 0 additions & 4 deletions content/docs/references/api/router.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@ description: Router protocol schemas

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

Route Category Enum

Classifies routes for middleware application and security policies.

<Callout type="info">
**Source:** `packages/spec/src/api/router.zod.ts`
</Callout>
Expand Down
8 changes: 0 additions & 8 deletions content/docs/references/automation/approval.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,6 @@ description: Approval protocol schemas

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

Approval Step Approver Type

Declaration order is author-facing: designers derive their picker from this

enum, and it leads with the portable indirect bindings (`manager`,

`position`, `department`, `team`) — a literal `user` id comes last.

<Callout type="info">
**Source:** `packages/spec/src/automation/approval.zod.ts`
</Callout>
Expand Down
8 changes: 0 additions & 8 deletions content/docs/references/cloud/template-manifest.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,6 @@ description: Template Manifest protocol schemas

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

`objectstack.manifest.json` — on-disk descriptor for a template / package

source tree. Strict projection of `CreatePackageRequestSchema` (server-

managed fields excluded) plus scaffold-time extras (name slug,

specVersion, skills, preview, scaffold, readmePath).

<Callout type="info">
**Source:** `packages/spec/src/cloud/template-manifest.zod.ts`
</Callout>
Expand Down
20 changes: 0 additions & 20 deletions content/docs/references/data/driver-mysql.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,6 @@ description: Driver Mysql protocol schemas

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

MySQL / MariaDB driver configuration — the `config` slot of a `datasource`

whose `driver` resolves to `mysql` (`mysql2`).

The driver id was offered by the connection form and buildable by the shared

factory long before #4410, but had no config shape at all in `packages/spec`

— postgres, mongo and memory each had one and mysql did not, so its `config`

was the one slot with neither a gate nor a documented shape.

Every key here is read by `createDefaultDatasourceDriverFactory`

(→ `SqlDriver`, knex `mysql2`). Postgres-only knobs are deliberately absent:

`mysql2` has no `application_name` and no `statement_timeout`, so declaring

them would advertise settings the client drops.

<Callout type="info">
**Source:** `packages/spec/src/data/driver/mysql.zod.ts`
</Callout>
Expand Down
16 changes: 0 additions & 16 deletions content/docs/references/data/driver-postgres.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,6 @@ description: Driver Postgres protocol schemas

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

PostgreSQL driver configuration — the `config` slot of a `datasource` whose

`driver` resolves to `postgres` (`pg` / `postgresql`).

ENFORCED as of #4410: `DatasourceSchema` parses `config` against this schema,

so a misspelled connection key fails at authoring time instead of leaving the

datasource on the client's localhost defaults. Every key here is read by

`createDefaultDatasourceDriverFactory` (→ `SqlDriver`, knex `pg`).

Pool sizing is NOT here: it lives in the driver-agnostic `datasource.pool`

block, which the factory now honours for every SQL driver.

<Callout type="info">
**Source:** `packages/spec/src/data/driver/postgres.zod.ts`
</Callout>
Expand Down
24 changes: 0 additions & 24 deletions content/docs/references/data/driver-sqlite.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,6 @@ description: Driver Sqlite protocol schemas

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

SQLite driver configuration — the `config` slot of a `datasource` whose

`driver` resolves to `sqlite` (native `better-sqlite3`, with the dev-only

step-down to wasm then in-memory, #2229) or to `sqlite-wasm` (pure-JS).

The one key that matters is `filename`, and it is exactly the key the silent

strip used to hide: an author who wrote `path:` got no error, the connection

fell back to `:memory:`, and their data vanished on restart with every signal

saying the datasource was configured.

`file` and `database` once also worked, purely because the factory read them

as undeclared `??` fallbacks. That tolerance has graduated into the declared

ADR-0087 conversion `datasource-config-driver-key-aliases` (#4456): stored

rows are rewritten to `filename` at load, the factory reads one spelling,

and authoring rejects both with the rename hint below.

<Callout type="info">
**Source:** `packages/spec/src/data/driver/sqlite.zod.ts`
</Callout>
Expand Down
12 changes: 0 additions & 12 deletions content/docs/references/data/mapping.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,6 @@ 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/. */}

Shared history for this file (#4001).

An import mapping is instructions for moving somebody's data. A dropped key

does not fail the import — it runs, to completion, with a "success" the

author reads as "the data arrived the way I described it". The rows land

untransformed, or unmatched, or duplicated, and the diagnosis starts from a

green run.

<Callout type="info">
**Source:** `packages/spec/src/data/mapping.zod.ts`
</Callout>
Expand Down
20 changes: 0 additions & 20 deletions content/docs/references/kernel/manifest.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,6 @@ description: Manifest protocol schemas

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

Structured permission grants requested by a plugin (ADR-0025 §3.2).

Each list scopes one capability surface the plugin may touch. The

install-time consent flow (ADR §3.5 step 2) turns this declaration into

the persisted `granted_permissions` set enforced at load by the

PluginPermissionEnforcer.

@example

```jsonc

\{ "services": ["object", "http"], "hooks": ["record.beforeInsert"],

"network": ["api.acme.com"], "fs": [] \}

```

<Callout type="info">
**Source:** `packages/spec/src/kernel/manifest.zod.ts`
</Callout>
Expand Down
4 changes: 0 additions & 4 deletions content/docs/references/kernel/plugin.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@ description: Plugin protocol schemas

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

Shared Plugin Types

These are the specialized plugin types common between Manifest (Package) and Plugin (Runtime).

<Callout type="info">
**Source:** `packages/spec/src/kernel/plugin.zod.ts`
</Callout>
Expand Down
2 changes: 0 additions & 2 deletions content/docs/references/shared/enums.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ description: Enums protocol schemas

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

Sort direction used across query, data-engine, analytics

<Callout type="info">
**Source:** `packages/spec/src/shared/enums.zod.ts`
</Callout>
Expand Down
Loading
Loading