Skip to content

docs(spec): the metadata-type registry named a hook that does not exist (#4212) - #4216

Merged
os-zhuang merged 1 commit into
mainfrom
claude/plugin-boot-logs-visibility-12kkwh
Jul 30, 2026
Merged

docs(spec): the metadata-type registry named a hook that does not exist (#4212)#4216
os-zhuang merged 1 commit into
mainfrom
claude/plugin-boot-logs-visibility-12kkwh

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Part of #4212 — the half that is a factual correction rather than a design decision.

What was wrong

registerMetadataTypeSchema and registerMetadataTypeActions both told plugins to call them "from their onInstall hook", and named /api/v1/meta/types/:type as the endpoint that would then serve the result. Neither exists.

The hook. The kernel's plugin contract is init / start / destroy (packages/core/src/types.ts:91-163). kernel.use() validates and stores (packages/core/src/kernel.ts:180-201) — it invokes nothing; bootstrap() calls init (:544) then optionally start (:587). The onInstall / onEnable / onDisable / onUninstall / onUpgrade family on PluginLifecycleSchema has no invocation site anywhere in the runtime — its only importer repo-wide is its own test. A plugin that followed the documented advice registered nothing and got no error, and its custom metadata type silently served no JSON Schema.

The endpoint. /api/v1/meta/types/:type is not a registered route. route-ledger.ts:216 carries GET /meta/types (server-only), and the public surface is GET /api/v1/meta.

The one plugin doing this in production already ignores the docs: DatasourceAdminServicePlugin calls registerMetadataTypeActions as the first statement of init(ctx) (packages/services/service-datasource/src/datasource-admin-plugin.ts:189-199), and its own comment names /api/v1/meta correctly. registerMetadataTypeSchema has zero callers repo-wide — not even a test — which is roughly what you'd expect of an API whose only documented entry point cannot fire.

What this changes

Both TSDoc blocks and content/docs/plugins/adding-a-metadata-type.mdx now name init(ctx) and GET /api/v1/meta. The doc example is rewritten as a real Plugin with an init, matching the production caller instead of a shape that does not load.

Two facts the old text obscured, now stated because each changes how an author writes the code:

  • getMetaTypes() reads these registries at request time, not from a boot snapshot (packages/metadata-protocol/src/protocol.ts:1889,1898,1913), so a type registered during init is served from the first call onward. The only cache is a WeakMap keyed on Zod object identity for the JSON-Schema conversion — it does not memoise the lookup.
  • Registering a schema does not by itself put a type in the listing. getMetaTypes() enumerates engine.registry.getRegisteredTypes() unioned with the metadata service's (protocol.ts:1858-1873), then decorates each with its schema. A type present only in the schema registry is never reached, so additionalTypes is not optional.

Documentation only. No behaviour change, no API surface change.

Scope — what I deliberately left alone

content/docs/protocol/kernel/{index,lifecycle,plugin-spec}.mdx document the whole onInstall/onEnable/onDisable lifecycle as real; index.mdx:275 states "The kernel resolves plugin dependencies, calls each plugin's onInstall / onEnable", which is false. I did not touch them: rewriting those pages means answering #4212's enforce-or-remove question (implement the hooks, or retire them from the protocol), and that is a maintainer decision rather than something a doc pass should settle by fiat. Whichever way it goes, those three pages move with it.

I also corrected my own filing on #4212 in a comment: I had counted onEnable as invoked, citing app-plugin.ts. Those call sites are the app-bundle runtime member (STACK_RUNTIME_MEMBERS), a different contract that shares the name. The kernel never calls onEnable on a kernel.use() plugin, so the real count is 0 of 5 dead, not 4 of 5.

Verification

check:doc-authoring clean (214 files); metadata-type-actions suite passes; root pnpm lint clean.


Generated by Claude Code

`registerMetadataTypeSchema` and `registerMetadataTypeActions` both told
plugins to call them "from their `onInstall` hook", and named
`/api/v1/meta/types/:type` as the endpoint that would serve the result.
Neither is real.

The kernel's plugin contract is `init` / `start` / `destroy`
(`packages/core/src/types.ts`): `kernel.use()` validates and stores,
`bootstrap()` calls `init` then `start`. The `onInstall` / `onEnable` /
`onDisable` / `onUninstall` / `onUpgrade` family declared on
`PluginLifecycleSchema` has no invocation site anywhere in the runtime — its
only importer repo-wide is its own test. So a plugin following the documented
advice registered nothing and got no error saying so, and its custom metadata
type silently served no JSON Schema.

`/api/v1/meta/types/:type` is likewise not a registered route; the route
ledger carries `GET /meta/types` and the public surface is `GET /api/v1/meta`.

Both TSDoc blocks and `content/docs/plugins/adding-a-metadata-type.mdx` now
name the hook that runs and the endpoint that exists, with the example written
as a real `Plugin` with an `init(ctx)`. That matches
`DatasourceAdminServicePlugin` — the single production caller of
`registerMetadataTypeActions` — which has always used `init` rather than the
`onInstall` the docs prescribed.

Two facts the old text obscured, now stated because both change how an author
writes the code:

- `getMetaTypes()` reads these registries at REQUEST time, not from a boot
  snapshot, so a type registered during `init` is served from the first call.
- Registering a schema does not by itself put a type in the listing.
  `getMetaTypes()` enumerates `engine.registry.getRegisteredTypes()` unioned
  with the metadata service's, then decorates each with its schema — a type
  present only in the schema registry is never reached.

Documentation only; no behaviour change. Whether the five uninvoked lifecycle
hooks get implemented or retired (ADR-0049) is #4212 — this stops the
registry's own docs from sending authors at the dead one meanwhile.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HrRNgrWaRtggzmrHpbomyh
@vercel

vercel Bot commented Jul 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Jul 30, 2026 4:18pm

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tooling labels Jul 30, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec.

106 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx (via @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/spec)
  • content/docs/api/environment-routing.mdx (via @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/spec)
  • content/docs/automation/approvals.mdx (via packages/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/cli.mdx (via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via packages/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/spec)
  • content/docs/kernel/services.mdx (via @objectstack/spec)
  • content/docs/permissions/authorization.mdx (via @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/rls.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/development.mdx (via @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/runtime-capabilities.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx (via @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v16.mdx (via @objectstack/spec)
  • content/docs/releases/v17.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)
  • content/docs/ui/actions.mdx (via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)
  • content/docs/ui/translations.mdx (via @objectstack/spec)
  • content/docs/ui/views.mdx (via @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@os-zhuang
os-zhuang marked this pull request as ready for review July 30, 2026 16:31
@os-zhuang
os-zhuang merged commit 90c2b15 into main Jul 30, 2026
18 checks passed
@os-zhuang
os-zhuang deleted the claude/plugin-boot-logs-visibility-12kkwh branch July 30, 2026 16:31
os-zhuang added a commit that referenced this pull request Jul 30, 2026
…ever implemented (#4212) (#4233)

PluginLifecycleSchema declared onInstall / onEnable / onDisable / onUninstall
/ onUpgrade, each with confident TSDoc. The kernel calls none of them, and
never has. Its plugin contract is init / start / destroy
(packages/core/src/types.ts): use() validates and stores, bootstrap() runs
init then start, shutdown runs destroy in reverse order. There is no install
phase and no first-time-only path. Repo-wide, the schema's only importer was
its own test — and the docs built on it sent authors at a dead seam (#4216
fixed the metadata-type registry's advice; this removes what the advice
pointed at).

Removed, with zero consumers verified across objectstack, objectui and cloud:

- PluginLifecycleSchema + PluginLifecycleHooks, and the five hook members on
  PluginSchema (now a plain descriptor object — and, with the function
  members gone, JSON-representable: it publishes a kernel/Plugin JSON schema
  for the first time).
- UpgradeContextSchema + UpgradeContext, which existed solely to serve
  onUpgrade.
- The @objectstack/spec/system ./types module: the ObjectStackPlugin
  interface and its PluginContext / PluginLogger / ObjectQLClient / IKernel /
  ObjectOSKernel companions — seeded by the aspirational spec in issue #2,
  referenced by no file in any repo since.

Route: plain deletion, not retiredKey() tombstones — nothing parses plugin
objects through these schemas (stack.zod carries plugins as
z.array(z.unknown())), so a prescription nobody can receive is noise; the
plugin-runtime.zod.ts precedent. Per that precedent the key-vanish guard's
baseline entries (kernel/UpgradeContext:* in authorable-surface.json) are
dropped deliberately, and kernel/UpgradeContext leaves
json-schema.manifest.json in the same PR. No ADR-0087 conversion: function
members on runtime objects are not authorable stack metadata; there is no
source for os migrate meta to rewrite.

The kernel docs that taught the fiction now teach the real contract:
protocol/kernel/lifecycle.mdx (five-hook example → init/start/destroy class,
plus the app-bundle onEnable distinction), protocol/kernel/index.mdx (the
"kernel calls onInstall/onEnable" claim and a fictional Kernel.installPlugin
API → the real package-install flow), protocol/kernel/plugin-spec.mdx (a
manifest `lifecycle:` file-map ManifestSchema never declared + a six-hook
section with an invented context API → the runtime contract and real
execution order), and AGENTS.md's own plugin example. Each page carries a
callout naming what was fiction, so an author who wrote against the old docs
finds the correction where the fiction was.

Pin tests: PluginSchema declares none of the five names; an authored hook is
stripped by the parse; the retired exports are gone from the module. The
stack-level lint keeps reporting onDisable and friends as undeclared keys, so
authors who still write them hear about it at load.


Claude-Session: https://claude.ai/code/session_01HrRNgrWaRtggzmrHpbomyh

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants