feat(spec): retire the inert additionalTypes key from MetadataPluginConfig (#8586, ADR-0049) - #8702
Conversation
… ADR-0049) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E5tUwGM3LQoqErTfkvRW7W
…ire-additionaltypes
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
📓 Docs Drift CheckThis PR changes 3 package(s): 107 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
⛔ 7 release-owned page(s) also reference the affected code. These are read-only:
|
…ire-additionaltypes
…g main (Batch D analytics entry absorbed; 86 semantic)
Fixes #8586
Implements the maintainer ruling of 2026-08-14 (verbatim 「同意」, joint with #8421): ADR-0049 disposition remove.
MetadataPluginConfig.additionalTypeswas 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 issetTypeRegistry(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 deletionThe dispatch prompt presumed a strict object ("authoring it becomes a loud unknown-key refusal"). The tree disagrees:
MetadataPluginConfigSchemais a plainz.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 aretiredKey()tombstone (thekernel/Manifest:loadingprecedent, #4914): authoring the key is atscerror (typednever) and a parse refusal —invalid_typeat pathadditionalTypes, message carrying the full prescription (notunrecognized_keys; tombstones raiseinvalid_typefromz.never(), asalias-integrity.test.tsrecords). The pin tests assert the strongest envelope this surface has: refusal + issuecode+path+ prescription text. Astatusfield does not exist on a ZodError issue, so it is deliberately not asserted.What this PR comprises
packages/spec/src/kernel/metadata-plugin.zod.ts, guidance following the five house conventions (noos migrate metasentence — no conversion covers this surface, see below).${…}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):18.kernel__MetadataPluginConfig__additionalTypes.ts(kernel/MetadataPluginConfig:additionalTypes); a newretired-key:18region was added toRETIRED_KEYS_BY_MAJOR(hand-written markers, generator-filled content);18.metadata-plugin-additional-types-retired.ts;applyConversionsToStoredItemmaps types onto stack collections; a metadata-plugin config is neither (PLURAL_TO_SINGULARhas nopluginsentry) — a conversion would be a transform with no seam that ever runs. Same rationale askernel/Manifest:loading.registry.tsregenerated viagen:migration-registry(85 semantic, 30 retired-key, 53 retired-def); step18 rationale extended (hand-written half).spec-changes.json/docs/protocol-upgrade-guide.mdare 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-guidegreen.authorable-surface/kernel.jsonrow becomeskernel/MetadataPluginConfig:additionalTypes [RETIRED]viagen: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.jsonanchor lags legitimately (informational line, per playbook).content/docs/references/kernel/metadata-plugin.mdxis pipeline-generated — regenerated viagen:docs, never hand-edited. Its diff includes sibling optionality flips (default-bearing fields now render required): explained and verified by ablation — the oldadditionalTypesembeddedMetadataTypeRegistryEntryBaseSchema(pullingActionSchema), 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.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), withregisterMetadataTypeSchemafor the schema half.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 inmetadata-plugin.zod.tsitself (theMetadataTypeenum docblock andDEFAULT_METADATA_TYPE_REGISTRY) claimed plugins extend the registry viacontributes.kinds— verified false for that registry (registerKindstores kind descriptors as items of thekindtype; it does not extend the type registry); corrected in place since they advertise the same phantom growth path on the exact surface being retired.additional-types-retirement.test.ts: refusal with code/path/prescription (direct and through the manifestconfigembed) + 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.minor+ BREAKING annotation + FROM/TO +adr-0087: registeredmarker (launch-window convention, PR feat(spec): refuse${…}placeholder syntax in memory persistence.path / persistence.key at publish (#8495) #8666 precedent;check-changeset-no-majorgreen).check:livenesswalks metadata type schemas (listMetadataTypeSchemaTypes);kernel/MetadataPluginConfigis not in that walk and has no ledger row to keep or delete.check:livenessgreen.*.form.tsinput 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 (MetadataTypeRegistryEntryBaseSchemakeeps its consumer and is module-private).check:generatednames 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-bytesPASS.node scripts/pm/dispatch-gates.mjsover 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 fullturbo run buildof the packages closure, as lint.yml does),check-adr-0087-registration,check-changeset-no-major,check-empty-changeset,check-dev-prereqs.@objectstack/spec10572/10572 (399 files);@objectstack/metadata603/603 (31 files);@objectstack/metadata-protocol1317/1317 (89 files). Neither metadata package has atypecheckscript — theirbuild(tsup + dts) is the type gate, both green. Pin test 3/3.gen:schemared 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 (cleangit status).additionalTypesauthors/writers in/home/user/objectuiand/home/user/cloud(control probe confirmed the sweep saw both trees).packages/qa/dogfood: nocoversentry 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