Skip to content

fix(engine): version-gate vendored plugin assets in check-bumps - #123

Merged
aryeh-stark merged 1 commit into
mainfrom
fix/plugin-asset-bump-gate
Jul 27, 2026
Merged

fix(engine): version-gate vendored plugin assets in check-bumps#123
aryeh-stark merged 1 commit into
mainfrom
fix/plugin-asset-bump-gate

Conversation

@aryeh-stark

Copy link
Copy Markdown
Contributor

The hole

check-bumps compared only artifact digests (skills/commands) recorded in index.json. A bundle's vendored plugin assetsvendor/plugins/<bundle>/**, a stark-skills plugin's own tools/ + config — are not artifacts. They carried no digest and participated in no gate.

So a change confined to a plugin's tools/** left every artifact digest untouched. The gate printed "OK: no un-bumped source changes", publish.sh left the bundle version alone, and the bundle shipped modified content under a version consumers already had — and would never re-fetch. The change was invisible on every installed machine.

Hit live on 2026-07-27: the stark-gh lib/git.ts fix shipped un-bumped at 0.1.10 and only reached anyone because I caught it by hand in #122.

Correction: this affects five bundles, not one

CLAUDE.md claimed vendor/plugins/ existed "currently for stark-gh" alone. It does not — stark-analyze, stark-gh, stark-implement, stark-ops, stark-plan all carry vendored plugin assets. I repeated that claim in #122; it understated the blast radius 5×. Corrected in this PR.

The fix

digest.Files / digest.Dir deterministic hash over a file set — LF-normalized to match what build writes to dist/, length-prefixed fields so no (path, content) concatenation can collide, path-sensitive so a pure rename counts
index.Index.PluginAssets {bundle, version, digest} per plugin-backed bundle. New optional field; the index package's contract is that consumers ignore unknown fields, so existing readers are unaffected
check-bumps recomputes the digest from vendor/plugins/<bundle> and applies the same immutability rule, keyed <bundle>/plugin-assets/<bundle> so it can never collide with an artifact key <bundle>/<type>/<name>

publish.sh needs no change — its auto-bump loop parses violation lines as - <bundle>/..., so a plugin-asset violation now patch-bumps that bundle automatically. The manual step I had to perform in #122 is exactly what this makes unnecessary.

Rollout is graceful: an index.json predating the field contributes no previous rows, so the first publish after this merges records them rather than failing the repo.

Verification

The regression test is TestCheckBumpsFailsWhenPluginToolChangedWithoutABump — a repo whose committed index records a stale plugin-asset digest at an unchanged version. Mutation-checked: with the new gate line disabled it fails with

want exit 1 when a vendored plugin tool changed un-bumped, got 0

got 0 is precisely the old silent-pass. Restored, it passes.

Plus controls that keep the gate satisfiable and honest: a bumped change passes, an unchanged tree passes, a missing vendor/plugins/<bundle> digests to the stable empty set rather than erroring, CRLF checkouts don't force spurious bumps, a rename does count, the key can't collide with any artifact type, and a legacy index parses cleanly.

  • go test ./...26 packages, all pass
  • stark build --checkOK: no drift
  • stark check-bumpsOK: no un-bumped source changes
  • Root VERSION → 0.8.2

🤖 Generated with Claude Code

check-bumps compared only ARTIFACT digests (skills/commands) recorded in
index.json. A bundle's vendored plugin assets — vendor/plugins/<bundle>/**, a
stark-skills plugin's own tools/ + config — are not artifacts, so they carried no
digest and participated in no gate. A change confined to a plugin's tools/**
therefore left every artifact digest untouched: the gate printed "OK: no
un-bumped source changes", publish.sh left the bundle version alone, and the
bundle shipped modified content under a version consumers already had and would
never re-fetch. The change was invisible on every installed machine.

Hit live 2026-07-27: a stark-gh lib/git.ts fix shipped un-bumped at 0.1.10 and
needed a hand-applied bump to reach anyone (#122).

- digest.Files / digest.Dir: deterministic content hash over a file set, LF-
  normalized to match what build writes to dist, path-sensitive so a rename counts.
- index.Index.PluginAssets: {bundle, version, digest} per plugin-backed bundle.
  New optional field; consumers ignore unknown fields per the package contract.
- check-bumps recomputes the digest from vendor/plugins/<bundle> and holds it to
  the same immutability rule, keyed <bundle>/plugin-assets/<bundle> so it can
  never collide with an artifact key.

publish.sh needs no change: its auto-bump loop parses violation lines as
`  - <bundle>/...`, so a plugin-asset violation now patch-bumps that bundle
automatically instead of shipping silently.

This affects FIVE bundles, not one — stark-analyze, stark-gh, stark-implement,
stark-ops, stark-plan all carry vendored plugin assets. CLAUDE.md claimed only
stark-gh did; corrected.

Co-Authored-By: Claude Fable 5 <[email protected]>
@aryeh-stark
aryeh-stark merged commit 8f497c1 into main Jul 27, 2026
5 checks passed
@aryeh-stark
aryeh-stark deleted the fix/plugin-asset-bump-gate branch July 27, 2026 16:03
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