Skip to content

feat(spec): retire the inert additionalTypes key from MetadataPluginConfig (#8586, ADR-0049) - #8702

Merged
os-zhuang merged 5 commits into
mainfrom
claude/issue-8586-retire-additionaltypes
Aug 14, 2026
Merged

feat(spec): retire the inert additionalTypes key from MetadataPluginConfig (#8586, ADR-0049)#8702
os-zhuang merged 5 commits into
mainfrom
claude/issue-8586-retire-additionaltypes

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes#8586

Implements the maintainer ruling of 2026-08-14 (verbatim 「同意」, joint with #8421): ADR-0049 disposition remove. MetadataPluginConfig.additionalTypes was declared, authorable, documented on four docs pages as THE way a plugin registers a custom metadata type — and read by nothing. Measured basis re-verified on this tree before implementing: every occurrence is a declaration or a mention, the only production writer of the manager's type registry is setTypeRegistry(DEFAULT_METADATA_TYPE_REGISTRY), declared count == live count (27 == 27). Premise still valid.

Note: #8421 is not addressed here — this card lands first; the refuse-by-static-registry work on #8421 remains open and follows it.

Route: retiredKey() tombstone, not strict deletion

The dispatch prompt presumed a strict object ("authoring it becomes a loud unknown-key refusal"). The tree disagrees: MetadataPluginConfigSchema is a plain z.object, not .strict(), so a plain deletion would be a silent strip — the exact trap the playbook forbids (#3726/#3733, ADR-0104). Per the playbook's route table the removal is a retiredKey() tombstone (the kernel/Manifest:loading precedent, #4914): authoring the key is a tsc error (typed never) and a parse refusal — invalid_type at path additionalTypes, message carrying the full prescription (not unrecognized_keys; tombstones raise invalid_type from z.never(), as alias-integrity.test.ts records). The pin tests assert the strongest envelope this surface has: refusal + issue code + path + prescription text. A status field does not exist on a ZodError issue, so it is deliberately not asserted.

What this PR comprises

  • Tombstone at packages/spec/src/kernel/metadata-plugin.zod.ts, guidance following the five house conventions (no os migrate meta sentence — no conversion covers this surface, see below).
  • ADR-0087 registration, protocol-18 step (post-cut: the refusal ships on 17.x, prescription registers at the 18 boundary — the [finding][spec] memory-driver persistence.path / persistence.key still accept unresolved ${…} placeholders — the #8336 shape one surface over, deliberately outside its connection-material class #8495 / PR feat(spec): refuse ${…} placeholder syntax in memory persistence.path / persistence.key at publish (#8495) #8666 precedent):
    • retired-key entry file 18.kernel__MetadataPluginConfig__additionalTypes.ts (kernel/MetadataPluginConfig:additionalTypes); a new retired-key:18 region was added to RETIRED_KEYS_BY_MAJOR (hand-written markers, generator-filled content);
    • D3 semantic entry 18.metadata-plugin-additional-types-retired.ts;
    • no D2 conversion, deliberately: the conversion chain walks a normalized stack and applyConversionsToStoredItem maps types onto stack collections; a metadata-plugin config is neither (PLURAL_TO_SINGULAR has no plugins entry) — a conversion would be a transform with no seam that ever runs. Same rationale as kernel/Manifest:loading.
    • registry.ts regenerated via gen:migration-registry (85 semantic, 30 retired-key, 53 retired-def); step18 rationale extended (hand-written half).
    • spec-changes.json / docs/protocol-upgrade-guide.md are unchanged, correctly: the projections exclude the uncut major 18 (the on-main [finding][spec] memory-driver persistence.path / persistence.key still accept unresolved ${…} placeholders — the #8336 shape one surface over, deliberately outside its connection-material class #8495 semantic entry is absent from them too); check:spec-changes / check:upgrade-guide green.
  • Generated baselines: authorable-surface/kernel.json row becomes kernel/MetadataPluginConfig:additionalTypes [RETIRED] via gen:schema (tombstone route keeps the row — the dispatch card said the baselines "lose the row", which is the strict-removal shape; [RETIRED] is this route's correct reading). authorable-surface.base.json anchor lags legitimately (informational line, per playbook).
  • Reference pagecontent/docs/references/kernel/metadata-plugin.mdx is pipeline-generated — regenerated via gen:docs, never hand-edited. Its diff includes sibling optionality flips (default-bearing fields now render required): explained and verified by ablation — the old additionalTypes embedded MetadataTypeRegistryEntryBaseSchema (pulling ActionSchema), which made output-shape JSON-Schema emission throw and forced the whole def into the input-shape fallback (x-io: input). With the key tombstoned the def emits output shape like the other ~1460 defs. Ablation proof: restoring the old key and regenerating reverts the page byte-identical to origin/main.
  • Docs: content/docs/plugins/adding-a-metadata-type.mdx — all 4 occurrence sites (TL;DR, built-in-vs-plugin section, schema-wiring note, release checklist) rewritten to how a kind actually enters the live set: as a side effect of registering an item of that kind (SchemaRegistry.registerItem / MetadataManager.register), with registerMetadataTypeSchema for the schema half.
  • Source-comment corrections (comments only, cross-package sanctioned by the ruling): packages/metadata/src/metadata-manager.ts (~2470, false "covers plugin-contributed additionalTypes" claim), packages/metadata-protocol/src/protocol.ts (~4376, kept the real artifact-load half, dropped the phantom), packages/spec/src/kernel/metadata-type-schemas.ts ("register the type as well" note now states the real channel). Additionally two comments in metadata-plugin.zod.ts itself (the MetadataType enum docblock and DEFAULT_METADATA_TYPE_REGISTRY) claimed plugins extend the registry via contributes.kinds — verified false for that registry (registerKind stores kind descriptors as items of the kind type; it does not extend the type registry); corrected in place since they advertise the same phantom growth path on the exact surface being retired.
  • Pin testsadditional-types-retirement.test.ts: refusal with code/path/prescription (direct and through the manifest config embed) + control that the same config without the key parses and grows no property. The old spec test that authored the key re-judged: it merely exercised the alias-free full-config parse, so it was re-spelled (key removed) rather than replaced.
  • Changeset: minor + BREAKING annotation + FROM/TO + adr-0087: registered marker (launch-window convention, PR feat(spec): refuse ${…} placeholder syntax in memory persistence.path / persistence.key at publish (#8495) #8666 precedent; check-changeset-no-major green).
  • Liveness ledger: no edit, correctly — check:liveness walks metadata type schemas (listMetadataTypeSchemaTypes); kernel/MetadataPluginConfig is not in that walk and has no ledger row to keep or delete. check:liveness green.
  • Forms / i18n: no *.form.ts input ever spelled this key; no i18n change.

Verification (all at HEAD 54ae32c17, post-merge of origin/main, after the final commit)

  • check:generated13/13 green (migration-registry, spec-changes, upgrade-guide, skill-docs, skill-refs, react-blocks, authorable-surface, api-surface, export-origins, docs, strictness-ledger, liveness, test-typecheck). api-surface/ unchanged — the tombstone is key-level narrowing, invisible to that snapshot by design; no exported value schema was orphaned (MetadataTypeRegistryEntryBaseSchema keeps its consumer and is module-private).
  • The 7 source audits check:generated names as not-run, run as one group: check:empty-state, check:skill-examples, check:template-manifests, check:variant-docs, check:exported-any, check:dual-source-exports, check:scripts-typecheck — all PASS. check:nul-bytes PASS.
  • Derived via node scripts/pm/dispatch-gates.mjs over the actual changed paths — families beyond the prompt's list, all PASS: check:changeset-gate-self-tests, check:cross-package-test-inputs, check:doc-formula-expressions, check:docs-audit-scope, check:durability-log-level, check:filter-alias-parity, check:merge-driver, check:objectui-changeset, check:quick-reference-counts, check:role-word, check:spec-parsed-alias, check:type-source-resolution, check:query-options-erasure, check:type-check-coverage, check:type-check-debt (after full turbo run build of the packages closure, as lint.yml does), check-adr-0087-registration, check-changeset-no-major, check-empty-changeset, check-dev-prereqs.
  • Tests: @objectstack/spec10572/10572 (399 files); @objectstack/metadata603/603 (31 files); @objectstack/metadata-protocol1317/1317 (89 files). Neither metadata package has a typecheck script — their build (tsup + dts) is the type gate, both green. Pin test 3/3.
  • Reverse verification (fix committed first; predicted red, observed red): restoring the pre-removal key with the registration in place turns gen:schema red at gate (b2) with the exact message — 1 RETIRED_KEYS_BY_MAJOR entr(ies) name a key that is still LIVE: kernel/MetadataPluginConfig:additionalTypes (registered at major 18). Restored from the commit; regeneration reproduces the committed artifacts byte-identically (clean git status).
  • Producer sweep of siblings (read-only): zero additionalTypes authors/writers in /home/user/objectui and /home/user/cloud (control probe confirmed the sweep saw both trees).
  • packages/qa/dogfood: no covers entry references this key (no expression surface on it); the dogfood consumption-radius check was a grep plus the cross-package-test-inputs gate, both clean.

Generated by Claude Code


Generated by Claude Code

@vercel

vercelBot commented Aug 14, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectstackIgnoredIgnoredAug 14, 2026 3:21pm

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 3 package(s): @objectstack/metadata-protocol, @objectstack/metadata, @objectstack/spec.

107 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 @objectstack/spec)
  • content/docs/automation/connectors.mdx(via @objectstack/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 @objectstack/metadata-protocol, @objectstack/metadata, packages/spec)
  • content/docs/concepts/north-star.mdx(via @objectstack/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/tenancy-modes.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 packages/metadata, @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 @objectstack/spec)
  • content/docs/kernel/index.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/data-service.mdx(via @objectstack/spec)
  • content/docs/kernel/runtime-services/email-service.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/examples.mdx(via @objectstack/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 @objectstack/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx(via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx(via @objectstack/spec)
  • content/docs/kernel/services-checklist.mdx(via @objectstack/metadata-protocol, @objectstack/metadata, @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/permissions/system-context.mdx(via packages/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/metadata, @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/http-protocol.mdx(via @objectstack/metadata-protocol, @objectstack/metadata, @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/metadata-service.mdx(via @objectstack/metadata)
  • content/docs/protocol/kernel/plugin-spec.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/ui/actions.mdx(via @objectstack/spec)
  • content/docs/ui/apps.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/field-grouping-and-order.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)

7 release-owned page(s) also reference the affected code. These are read-only:

  • content/docs/releases/implementation-status.mdx(via @objectstack/spec)
  • content/docs/releases/index.mdx(via @objectstack/spec)
  • content/docs/releases/v12.mdx(via @objectstack/metadata, @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/metadata-protocol, @objectstack/metadata, @objectstack/spec)

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

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.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

2 participants

@os-zhuang@claude