Skip to content

Harden registry-drift vocab: projected MCP schema, not Zod internals (v0.5.1, closes #27) - #33

Merged
bdelanghe merged 1 commit into
mainfrom
claude/harden-drift-vocab
Jun 23, 2026
Merged

Harden registry-drift vocab: projected MCP schema, not Zod internals (v0.5.1, closes #27)#33
bdelanghe merged 1 commit into
mainfrom
claude/harden-drift-vocab

Conversation

@bdelanghe

Copy link
Copy Markdown
Contributor

Closes #27. Removes a latent false-positive risk in the registry-drift gate.

The bug

vocabFromRegistry built the drift vocab by reaching into Zod internalsverb.input._def.shape(), field._def.entries — inside a swallowing try/catch. A zod/verbspec bump that changes those private surfaces silently degrades the vocab to {help, version}. And because an unknown --flag is an error, a degraded vocab turns valid copy (--catalog, --store) into false-positive errors that break the consumer gate — with the catch hiding the failure.

The fix

  • prose.mjs — replace it with vocabFromToolset(toolset): pure, builds from verbspec's public projection ({ name, inputSchema }name → verb id, inputSchema.properties keys → flags, properties[x].enum → enum values). No _def access. Plus a fail-safe: registryDrift no-ops when the vocab is degraded (flags.size <= 2), so a projection failure yields no findings rather than false errors. prose.mjs stays verbspec-free (the consumer's prose-only gate keeps no JSR deps).
  • verbs.mjs — projects via Object.values(registry).map(toMcpTool) (its inputSchema is the contract test.mjs already pins) and passes the built vocab in.
  • test.mjs — test vocab now comes from a projected-toolset stub; adds a regression guard that builds from the REAL registry (toMcpTool over registry) — so a future bump that breaks projection fails CI here instead of silently disabling the gate — plus a degraded-vocab no-op assertion.

Verify

Pure functions smoke-tested locally (vocab build, drift detection, degraded no-op, non-doc-type skip all pass). The real-registry projection test runs in CI under installed verbspec.

Release

Includes package.json 0.5.0 → 0.5.1 (and refreshes the stale README Status, which still read v0.4.0). On merge, the release workflow auto-tags + publishes v0.5.1; the consumer can pin to it for the hardened gate.

🤖 Generated with Claude Code


Generated by Claude Code

… internals (#27)

vocabFromRegistry reached into Zod internals (verb.input._def.shape(),
field._def.entries) inside a swallowing try/catch — a private surface a
zod/verbspec bump could change, silently degrading the vocab to {help,version}.
Since an unknown --flag is an error, a degraded vocab false-positives valid copy
(--catalog, --store) and breaks the consumer gate.

- prose.mjs: replace vocabFromRegistry(reg) with vocabFromToolset(toolset) —
  pure, builds from verbspec's PUBLIC projection ({ name, inputSchema }: name →
  verb id, inputSchema.properties → flags, properties[x].enum → enum values). No
  _def access. Add a fail-safe: registryDrift no-ops on a degraded vocab
  (flags.size <= 2) so projection failure → no findings, never false errors.
- verbs.mjs: project via Object.values(registry).map(toMcpTool) (its inputSchema
  is the contract test.mjs already pins) and pass the built vocab in.
- test.mjs: build the test vocab from a projected-toolset stub; add a regression
  guard that builds from the REAL registry — a bump that breaks projection fails
  CI here instead of silently disabling the gate — plus a degraded-vocab no-op.
- README: refresh Status to v0.5.1 (was stale at v0.4.0); note registry-drift.
- package.json: 0.5.0 → 0.5.1 (release workflow auto-cuts on merge).

Closes #27.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011GNDVjvsbTPsbWV9fEyjLt
@bdelanghe
bdelanghe marked this pull request as ready for review June 23, 2026 16:19
@bdelanghe
bdelanghe merged commit 7ac60d4 into main Jun 23, 2026
1 check passed
@bdelanghe
bdelanghe deleted the claude/harden-drift-vocab branch June 23, 2026 20:37
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.

Harden registry-drift vocab: build from the projected MCP schema, not Zod internals

2 participants