Skip to content

[finding] PluginSchema.version and isValidSemanticVersion both call themselves SemVer but accept eight forms SemVer 2.0.0 forbids #17070

Description

@os-bill

Filed by the domain:spec execution seat while implementing #16365 (widen PluginSchema.version onto the loader's grammar), using Claude Code. ⛔ Deliberately not repaired there: #16365's ruling forbids narrowing this key, and every repair here is a narrowing. No severity asserted, no lane asserted — both are triage's.

The finding

Two declarations call themselves a semantic version and accept eight strings SemVer 2.0.0 forbids.

Declaration Spelling
PluginSchema.versionpackages/spec/src/kernel/plugin.zod.ts, described "Semantic Version" /^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$/
PluginLoader.isValidSemanticVersionpackages/core/src/plugin-loader.ts the same regex, character for character

Measured against the official SemVer 2.0.0 regex over the corpus of examples the SemVer spec text itself lists, plus this repo's own pinned strings. The grammar accepts every SemVer-valid string — there is no gap in that direction — and additionally accepts these, which SemVer 2.0.0 forbids:

  • Leading zeroes in the numeric core (SemVer 2.0.0 §2: numeric identifiers "MUST NOT include leading zeroes"): 01.1.1, 1.01.1, 1.1.01
  • Leading zeroes / empty identifiers in the prerelease (§9): 1.0.0-0123, 1.0.0-alpha..1, 1.0.0-alpha.., 1.0.0-.
  • Degenerate build metadata (§10, identifiers must be non-empty): 1.0.0+.

Reproduce, no build needed:

node -e "const g=/^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?\$/; console.log(['01.1.1','1.01.1','1.1.01','1.0.0-0123','1.0.0-alpha..1','1.0.0+.'].map(v=>v+' '+g.test(v)).join('\n'))"

Why it is being filed rather than resolved in place

The leading-zero half is older than #16365 and was never introduced by it. PluginSchema.version's pre-#16365 regex, /^\d+\.\d+\.\d+$/, already accepted 01.1.1, 1.01.1 and 1.1.01\d+ has always admitted them. #16365 widened the key by adding the two optional suffix groups and changed nothing about the numeric core.

That is exactly why it could not be fixed under #16365. That card's ruling was widen the spec, do not narrow, on the ground that "nothing that loads today stops loading". Tightening the numeric core to the official SemVer regex would refuse 01.1.1, which PluginSchema accepts today and accepted before — a narrowing, and a published-behaviour change on both the schema and the loader, wanting its own statement.

The shape of the decision

  • Tighten both spellings to the official SemVer 2.0.0 regex. The two stay converged, and describe('Semantic Version') becomes exactly true. ⚠️ Refuses plugin objects that load today. No in-repo fixture or pin uses any of the eight forms (checked), so the blast radius is external plugins only — but that is precisely the population that cannot be measured from here.
  • Keep the grammar and qualify the prose, the way ManifestSchema.version already does: its TSDoc says (major.minor.patch) explicitly and manifest.test.ts pins 1.0.0-beta invalid, so its narrow regex and its prose agree. The parallel move here is to stop calling this key plain "Semantic Version" and say what it actually accepts.
  • Do nothing, on the ground that a lenient validator upstream of a real refusal costs nobody anything.

⛔ This seat does not grade which. The asymmetry that decided #16365 does not repeat here: there the wide answer was free, and here every answer that makes the declaration true has a cost.

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

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions