Skip to content

stash-edge pins @cipherstash/stack@1.0.0-rc.4 and nothing updates it on release #791

Description

@coderdan

skills/stash-edge/SKILL.md hardcodes @cipherstash/stack@1.0.0-rc.4 in four places. Nothing in the build or release pipeline rewrites it, so the moment the package leaves the prerelease line the shipped skill will tell Deno and Supabase Edge Function users to pin a release candidate in production.

The skill ships inside the stash npm tarball and is copied into customer repos by stash init, so this lands in someone else's codebase, not ours.

The four literals

Line Context
59 import … from 'npm:@cipherstash/stack@1.0.0-rc.4/wasm-inline' — the Deno example
65 prose: @^1.0.0 will not match 1.0.0-rc.4
67 prose: use a prerelease-bearing range (@^1.0.0-rc.4)
77 the deno.json import-map example

Nothing updates them

Three plausible mechanisms, none of which reach the file:

  1. Changesets. pnpm run release is pnpm run build && changeset publish. Changesets bumps package.json versions and writes CHANGELOG.md; it does not touch other markdown.
  2. The build. packages/cli/tsup.config.ts:88 copies the skills with cpSync('../../skills', 'dist/skills', { recursive: true }) — a verbatim recursive copy, no transform or substitution.
  3. The existing version embed. src/runtime-versions.ts / pinnedSpec / RELEASE_TRAIN_MANIFESTS do solve exactly this problem, but as a tsup define injected into compiled CLI code (the install commands the CLI prints at runtime). It never reaches markdown.

scripts/lint-no-dead-package-paths.mjs does scan skills/, but for dead package paths, not version strings.

It is not just a find-and-replace

The prose at lines 64–67 exists specifically to explain prerelease semver — that @^1.0.0 does not match 1.0.0-rc.4 because ranges exclude prereleases unless the range itself names one. Swapping the number to 1.0.0 would leave a paragraph explaining a hazard that no longer applies, which is its own kind of wrong guidance. Whatever fixes the version needs to flag the prose for a human, not silently rewrite it.

The existing mitigation is weak but real: the skill already says to check npm view @cipherstash/stack dist-tags.

Suggested fix

A test, rather than release-time codegen — following the precedent already set by packages/cli/tests/e2e/runtime-versions-embed.e2e.test.ts, whose docstring notes it reads the workspace manifests directly so it "never needs updating per release":

  • Read packages/stack/package.json's version.
  • Scan skills/**/SKILL.md for @cipherstash/stack@<version> specifiers.
  • Fail if any names a version that disagrees.

That is roughly ten lines, needs no build step, and fires on the version-bump PR — the moment someone is in a position to update the surrounding prose as well.

Worth deciding at the same time whether the examples should pin exactly at all once the package is on a stable line, or switch to @^1.0.0 and delete the prerelease explanation entirely. The "pin exactly, Deno caches by specifier" advice stands on its own merits; the prerelease caveat does not.

Timing

Not a regression — the skill is unreleased, landing with #777. This needs to be resolved before @cipherstash/stack goes to 1.0.0, not before #777 merges.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions