Skip to content

[finding] PluginSchema.version refuses the prerelease and build-metadata forms SemVer defines, while the loader that actually runs accepts them #16365

Description

@claude

Filed by the domain:engine execution seat while implementing #16049 (enforce PluginSchema at kernel.use()), using Claude Code. ⛔ Deliberately not repaired there: it is packages/spec work, and the ruling on #16049 was about type. No severity asserted, no lane asserted — both are triage's.

The finding

Two declarations in this repository disagree about what a plugin version is, and the disagreement became load-bearing the moment the boot path started running the schema.

Declaration Grammar Accepts 1.0.0-alpha.1 / 1.0.0+20230101
PluginSchema.versionpackages/spec/src/kernel/plugin.zod.ts, described as "Semantic Version" /^\d+\.\d+\.\d+$/ no
PluginLoader.isValidSemanticVersionpackages/core/src/plugin-loader.ts, the check the boot path has always run /^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$/ yes

SemVer 2.0.0 defines both prerelease and build metadata as part of a semantic version, so the spec's spelling is the narrow one and the loader's is the correct one. The spec key's own describe() says "Semantic Version" without qualification.

Why it is being filed rather than resolved in place

The loader's acceptance is pinned, deliberately, in two named casespackages/core/src/plugin-loader.test.ts:

  • should accept versions with pre-release tags (1.0.0-alpha.1)
  • should accept versions with build metadata (1.0.0+20230101)

and two in-repo class-based plugin fixtures ship version = '0.0.0-fixture' through a real kernel boot (packages/cli/test/serve-organizations-host-resolution.e2e.test.ts, packages/verify/src/harness.host-resolution.test.ts).

So enforcing PluginSchema.version verbatim at kernel.use() would not have enforced the protocol — it would have retired a pinned capability, silently, under a card whose ruling enumerated three refusal classes (unknown type, invalid slug, invalid homepage) and did not name version. PR #16363 therefore excludes the version key from the enforced projection, declares the exclusion in the code, and pins it with tests. That exclusion is a stopgap, and this card is the place the disagreement gets settled.

The shape of the decision

  • widen the spec — give PluginSchema.version the full SemVer 2.0.0 grammar, matching the loader and the key's own describe. The two spellings converge, the exclusion in PluginLoader.validatePluginContract can be dropped, and nothing that loads today stops loading. Costs a packages/spec change with its generated baselines (gen:schema, check:authorable-surface) and a changeset — the published JSON Schema for this key widens.
  • narrow the runtime — keep the spec regex, drop the exclusion, and retire the two loader pins. ⚠️ This refuses plugin objects that load today, including any plugin published on a prerelease version, and would want stating as a published-behaviour change in its own right.

⛔ This seat does not grade which; the first looks strictly better to it, but "the protocol is the baseline" is the standing principle and the two answers are not symmetric in what they cost consumers.

Adjacent


Generated by Claude Code

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions