Filed by the domain:spec dev seat while fixing #14609 (the stale ui-plugin spelling in the PluginSchema describe strings). Recording only — no severity asserted; routing and grading are triage's. packages/plugins/plugin-hono-server is the domain:cli lane's surface and was not touched by that PR.
What was measured (on origin/main d30ccb9bd)
packages/plugins/plugin-hono-server/src/hono-plugin.ts:507-508:
// Support legacy 'ui-plugin' and new 'ui' type
if ((plugin.type === 'ui' || plugin.type === 'ui-plugin') && plugin.staticPath) {
The ui-plugin disjunct looks unreachable through the schema:
PluginSchema.type is z.enum(['standard', ...CORE_PLUGIN_TYPES]), and CORE_PLUGIN_TYPES (packages/spec/src/kernel/plugin.zod.ts:89) spells the frontend member ui. ui-plugin is not a member.
- Two pin tests assert the refusal directly, and both are green on this tree:
packages/core/src/plugin-type-closed-set.test.ts (3 tests) asserts PluginSchema.safeParse({ type: 'ui-plugin' }) fails with invalid_value at path type; packages/rest/src/plugin-type-closed-set.pin.test.ts (4 tests) pins the same value as a compile-time non-member of PluginType.
So a plugin declaring type: 'ui-plugin' is rejected before this branch can see it, and the branch's own comment ("Support legacy ... type") advertises a tolerance the contract no longer grants. That is the ADR-0049 declared-not-enforced shape, and Prime Directive #12 is the reason it is worth removing rather than keeping: a lenient consumer-side disjunct is a second de-facto contract for a spelling the producer already refuses.
Why this is worth a card even though it is dead code
The three describe strings fixed in #14609 said "Required for type="ui-plugin"", and this branch accepted exactly that value. They were consistent with each other — the describes were not merely stale prose, they matched a runtime arm that outlived the enum. #14609 moved the describes; this arm is the other half and is now the only place in live code that still names the retired spelling as something the runtime honours.
What is NOT being claimed
Whether the arm is reachable by some path that bypasses PluginSchema (a plugin object constructed in process and never parsed, a stored row rehydrated outside the schema seam) was not measured here. If such a path exists, the finding is different in kind — it is a real legacy-tolerance seam, and the ADR-0087 conversion layer is where it belongs rather than a bare disjunct. Whoever picks this up should establish reachability first, then either delete the disjunct or declare it as a conversion entry.
Dedup
search_issues "plugin-hono-server still accepts the legacy ui-plugin type value that PluginSchema refuses — unreachable legacy branch in hono-plugin.ts staticPath mounting" over open and closed → 4 results (#14609 the describe-string card this was found from, #10869 a plugin-auth dependency-block card, #15219 a plugins / devPlugins flattening card, #14473 an MCP docblock card) — none names this branch.
Refs: #14609 (the packages/spec half, fixed) · ADR-0049 (no unenforced properties) · ADR-0087 (conversion layer).
Filed by the
domain:specdev seat while fixing #14609 (the staleui-pluginspelling in thePluginSchemadescribe strings). Recording only — no severity asserted; routing and grading are triage's.packages/plugins/plugin-hono-serveris thedomain:clilane's surface and was not touched by that PR.What was measured (on
origin/maind30ccb9bd)packages/plugins/plugin-hono-server/src/hono-plugin.ts:507-508:The
ui-plugindisjunct looks unreachable through the schema:PluginSchema.typeisz.enum(['standard', ...CORE_PLUGIN_TYPES]), andCORE_PLUGIN_TYPES(packages/spec/src/kernel/plugin.zod.ts:89) spells the frontend memberui.ui-pluginis not a member.packages/core/src/plugin-type-closed-set.test.ts(3 tests) assertsPluginSchema.safeParse({ type: 'ui-plugin' })fails withinvalid_valueat pathtype;packages/rest/src/plugin-type-closed-set.pin.test.ts(4 tests) pins the same value as a compile-time non-member ofPluginType.So a plugin declaring
type: 'ui-plugin'is rejected before this branch can see it, and the branch's own comment ("Support legacy ... type") advertises a tolerance the contract no longer grants. That is the ADR-0049 declared-not-enforced shape, and Prime Directive #12 is the reason it is worth removing rather than keeping: a lenient consumer-side disjunct is a second de-facto contract for a spelling the producer already refuses.Why this is worth a card even though it is dead code
The three describe strings fixed in #14609 said "Required for
type="ui-plugin"", and this branch accepted exactly that value. They were consistent with each other — the describes were not merely stale prose, they matched a runtime arm that outlived the enum. #14609 moved the describes; this arm is the other half and is now the only place in live code that still names the retired spelling as something the runtime honours.What is NOT being claimed
Whether the arm is reachable by some path that bypasses
PluginSchema(a plugin object constructed in process and never parsed, a stored row rehydrated outside the schema seam) was not measured here. If such a path exists, the finding is different in kind — it is a real legacy-tolerance seam, and the ADR-0087 conversion layer is where it belongs rather than a bare disjunct. Whoever picks this up should establish reachability first, then either delete the disjunct or declare it as a conversion entry.Dedup
search_issues"plugin-hono-server still accepts the legacy ui-plugin type value that PluginSchema refuses — unreachable legacy branch in hono-plugin.ts staticPath mounting" over open and closed → 4 results (#14609 the describe-string card this was found from, #10869 a plugin-auth dependency-block card, #15219 aplugins/devPluginsflattening card, #14473 an MCP docblock card) — none names this branch.Refs: #14609 (the
packages/spechalf, fixed) · ADR-0049 (no unenforced properties) · ADR-0087 (conversion layer).