Skip to content

refactor(spec)!: retire the plugin lifecycle-hook family the kernel never implemented (#4212) - #4233

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

refactor(spec)!: retire the plugin lifecycle-hook family the kernel never implemented (#4212)#4233
os-zhuang merged 1 commit into
mainfrom
claude/plugin-boot-logs-visibility-12kkwh

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Closes #4212 — the enforce-or-remove half; #4216 already fixed the advice that pointed at the dead hook.

What is being removed, and the evidence standard

PluginLifecycleSchema declared onInstall / onEnable / onDisable / onUninstall / onUpgrade, each with confident TSDoc ("Called when plugin is installed", …). The kernel calls none of them, and never has. Its plugin contract is init / start / destroy (packages/core/src/types.ts:91-163): use() validates and stores (kernel.ts:180-201 — no code runs), bootstrap() runs init (:544) then start (:587), shutdown runs destroy in reverse (:649). There is no install phase and no first-time-only path.

Consumer check, per the retirement playbook ("a grep can only prove presence; close the call graph"):

  • PluginLifecycleSchema / PluginSchema — only importer repo-wide was plugin.test.ts itself.
  • UpgradeContextSchema / UpgradeContext — zero consumers; built to serve onUpgrade exclusively.
  • The @objectstack/spec/system ./types module (ObjectStackPlugin + PluginContext/PluginLogger/ObjectQLClient/IKernel/ObjectOSKernel) — referenced by no file in any repo; it was seeded verbatim by the aspirational spec in issue ✨ Set up Copilot instructions #2 (January) and survived as fiction since.
  • Swept objectui and cloud too: the only hits are objectui's own unrelated blocks.zod key and React props sharing the names.
  • The build then refereed the removal (below) rather than the grep being trusted.

Route: plain deletion, not tombstones

Per the spec-property-retirement playbook §2, third row: nothing parses plugin objects through these schemasstack.zod carries plugins as z.array(z.unknown()) — so a retiredKey() prescription could never be received. Precedent: plugin-runtime.zod.ts (#3950/#4149).

The build enforced the two consequences the playbook predicts, and both are handled deliberately in this PR:

  • gen:schema's vanish-guard flagged kernel/UpgradeContext:* — the four baseline lines in authorable-surface.json are dropped deliberately (the guard's message allows exactly this, done in the same PR).
  • kernel/UpgradeContext leaves json-schema.manifest.json; and with the function members gone, PluginSchema became JSON-representable for the first time — the generator added kernel/Plugin to the published manifest.

No ADR-0087 conversion: function members on runtime objects are not authorable stack metadata; there is no source file for os migrate meta to rewrite. Authors who still write onDisable: on a stack keep hearing about it from the stack-level lint (lintUnknownStackKeys), which reports it as an undeclared key — a test pins that.

FROM → TO

Retired Where the concern actually lives
onInstall No install-time code hook exists. Installation is a registry transition (registry.installPackage()sys_packages). Install-shaped setup (services, schemas, metadata types) → init(ctx)
onEnable (kernel plugin) init(ctx) / start(ctx). The app-bundle onEnable module export is a different, real contract and is untouched — AppPlugin invokes it at boot (STACK_RUNTIME_MEMBERS)
onDisable / onUninstall destroy() for runtime teardown; package uninstall is a registry transition
onUpgrade + UpgradeContext Package upgrades apply metadata migrations (ADR-0087); no plugin code runs
onBoot (docs-only) init / start

The docs taught the fiction; they now teach the contract

  • protocol/kernel/lifecycle.mdx — the five-hook plain-object example → an init/start/destroy class with real phase semantics, the app-bundle onEnable distinction, and a callout naming the retirement.
  • protocol/kernel/index.mdx — "The kernel resolves plugin dependencies, calls each plugin's onInstall / onEnable" (false) and a fictional Kernel.installPlugin({ onInstall }) API → the real use → init → start order and the real package-install flow (validate → register → materialize; no package code executes at install).
  • protocol/kernel/plugin-spec.mdx — a manifest lifecycle: file-map ManifestSchema never declared, six per-file hooks (incl. onBoot) against an invented context.db/context.scheduler API, and a fictional execution order → the runtime contract (verified against PluginContext: registerService is real), the real boot/shutdown order, and a callout.
  • AGENTS.md — its own plugin example taught the dead hooks; now shows the real class shape.
  • releases/v17.mdx — row added to Dead spec clusters removed.

Each callout says what was fiction, so an author who wrote against the old docs finds the correction at the place the fiction lived.

Verification

  • spec build green (including the two vanish-guards above, first failing then satisfied deliberately); gen:api-surface / gen:spec-changes / gen:upgrade-guide / gen:docs / gen:skill-refs regenerated.
  • Playbook gate loop: check:liveness / empty-state / authorable-surface / docs / api-surface / spec-changes / upgrade-guide / skill-refs / skill-docs / skill-examplesall PASS (skill-refs after regen).
  • check:i18n PASS; spec suite 276 files / 7154 tests; CLI build + suite 89 files / 916 tests; root pnpm lint clean; doc guards (doc-authoring, role-word, org-identifier, release-notes, nul-bytes) PASS.
  • 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.
  • Changeset: major (pre-mode is active, so it lands as an rc pre-release bump), carrying the FROM → TO table per house convention.

Deliberately untouched


Generated by Claude Code

…ever implemented (#4212)

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.

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:51pm

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/cli, @objectstack/spec.

112 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 packages/cli, @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/api/data-flow.mdx (via @objectstack/cli)
  • content/docs/api/environment-routing.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/cli, @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/cli, 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/backup-restore.mdx (via @objectstack/cli)
  • content/docs/deployment/cli.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/deployment/self-hosting.mdx (via @objectstack/cli)
  • 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/cli, @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/data-service.mdx (via packages/cli)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/cli, 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/authentication.mdx (via @objectstack/cli)
  • 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/cli, @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/cli, @objectstack/spec)
  • content/docs/protocol/kernel/realtime-protocol.mdx (via @objectstack/cli)
  • 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/cli, @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/cli, @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 17:03
@os-zhuang
os-zhuang merged commit 40e420f into main Jul 30, 2026
18 checks passed
@os-zhuang
os-zhuang deleted the claude/plugin-boot-logs-visibility-12kkwh branch July 30, 2026 17:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Four of the five declared plugin lifecycle hooks are never invoked — and the metadata-type registry docs tell plugins to use one of them

2 participants