Skip to content

feat(manifest): version pinning, piece 1 — pins only (see Consiliency/pmcp#294) - #319

Merged
ViperJuice merged 1 commit into
mainfrom
feat/294-pin-core
Sep 30, 2026
Merged

ViperJuice merged 1 commit into
mainfrom
feat/294-pin-core

Conversation

@ViperJuice

@ViperJuice ViperJuice commented Sep 30, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

This implements piece 1 of the additive split of #294: version pins only.

The plan merged in #317:
.consiliency/plans/detailed-294-pin-core-20260929-0822.md.
Its embedded patch and test file were extracted with the plan's own rule and applied as-is.
They are cmp-identical to the spike the plan's numbers were measured on.

A manifest entry's version:, or an overlay's server_version: {<server>: <version>}, holds an
npx-launched MCP client at one exact version:

# ~/.pmcp/manifest.yaml
server_version:
  firecrawl: "3.25.5"

What it guarantees

  • Every argv that spawns the server runs the pinned spec: args and every platform's
    install argv, all or nothing, with the package name kept. The provision gate's
    _config_runs_exactly(entry, "firecrawl-mcp@3.25.5") is true.
  • A pin is refused, and the entry left unchanged, when:
    • the value is not one exact version by main's is_valid_package_version (no ranges,
      dist-tags, build metadata or specs);
    • the package slot is not a plain same-name registry spec (the npa class allowlist);
    • the launcher is not bare npx (npx.cmd/npx.exe are allowed on Windows only);
    • the entry's own env could redirect npm. Only shipped-declared keys, locale and terminal
      keys, and npm logging/timing keys are allowed.
  • Refusal warnings are fixed text. They never include the pin value, an argv, a command,
    a package or an exception message, and they name a server only if pmcp's shipped manifest
    defines it.
  • gateway.update_server keeps main's reporting. It adds pinned_version only for a pin
    that pmcp materialised, when the config runs exactly that argv, with no cwd and no env that
    could redirect npm.
  • pmcp update prints [PINNED] <server>: pinned at <version>. Every other line is
    main's.
  • Trust boundary: the host's environment, .npmrc, npm cache and inherited working
    directory are trusted.

What is piece 2 (not here)

#295 remains piece 2's reference. Piece 2 covers:

  • the unpinned-self-hosted warning;
  • pins and exactness for uvx, pip, cargo and docker;
  • hardening main's refusal message, which still echoes the configured argv.

The plan's Non-goals list the 21 board-round finding classes that piece 2 must address.

Docs

  • A README section, "Pinning a client version", as the plan specifies. It adds one sentence
    for the round-3 claude seat's N2: an install argv's launcher is judged by the rules of the
    host pmcp runs on, whatever its platform key.
  • A CHANGELOG entry under [Unreleased] → Added.
  • N1 (npx.bat/npx.ps1 stay refused) needs no change.

Gates (read from the logs of this branch at c470ff7, origin/main 4c5a961)

uv run ruff check src/ tests/            -> All checks passed!
uv run ruff format --check src/ tests/   -> 171 files already formatted
uv run mypy src/                         -> Success: no issues found in 52 source files
uv run pytest tests/test_version_pin.py  -> 159 passed in 29.40s
uv run pytest tests/ -q -m 'not live and not slow'   (npm_config_cache, npm_config_store_dir, pnpm_config_store_dir unset)
                                         -> 4866 passed, 3 skipped, 80 deselected in 611.30s (0:10:11)

Recorded in the plan (measured on the identical tree):

  • 39 of 39 mutants red;
  • npa 12.0.2 and 13.0.2 conformance corpus: 0 slot violations and 0 pin violations over
    1,617,455 slots and 41,472 pin values;
  • 77 of 107 shipped entries pinnable, with none refused by the env rule.

🤖 Generated with Claude Code

https://claude.ai/code/session_01RiabTgWZRfuqiUQ9siEegF


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

Implements the plan merged in #317
(.consiliency/plans/detailed-294-pin-core-20260929-0822.md): the embedded
patch and test file, applied as-is and cmp-identical to the verified
spike.

A manifest entry's `version:` or an overlay's `server_version:` holds an
npx-launched server at one exact version. load_manifest writes it into the
package slot of args and every platform's install argv, keeping the
package name, all or nothing. It refuses, leaving the entry unchanged, a
value that is not one exact version, a slot that is not a plain same-name
registry spec, a launcher that is not bare npx, and an entry env that could
redirect npm. Refusal warnings are fixed text and name a server only if
pmcp ships it. update_server keeps main's reporting and adds
pinned_version for a materialised pin; `pmcp update` prints [PINNED].

Adds the README section and CHANGELOG entry the plan specifies, plus one
README sentence that an install argv's launcher is judged by the host's
rule whatever its platform key.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RiabTgWZRfuqiUQ9siEegF
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant