Skip to content

release: v4.8.4 - #300

Merged
kevintseng merged 5 commits into
mainfrom
release/v4.8.4
Sep 4, 2026
Merged

release: v4.8.4#300
kevintseng merged 5 commits into
mainfrom
release/v4.8.4

Conversation

@kevintseng

Copy link
Copy Markdown
Contributor

What it does

Bumps to v4.8.4 and closes three gaps a v4.8.3 dogfood pass found: a plugin-cache
sweep that only ever removed the ONE version it had just replaced, a release gate
that never actually started any of the 17 shipped entry points, and two
real-credential checks (qa:pre-release, qa:live-journey) that existed but
were not required by the one command that actually cuts a release.

Why it is needed

  • Plugin cache never cleaned up an old version, only the one it just
    replaced.
    Measured on the maintainer's machine: 9 stale version
    directories, 1.2 GB, with nothing ever sweeping them.
  • No gate had ever started a shipped entry point. Every existing check
    only asked "does the file exist / does it parse / is it in the tarball" —
    none of them ran the code. Found the host-runtime fail-closed bug (already
    fixed) this way.
  • npm run release:finish ran zero real-credential checks. qa:pre-release
    and qa:live-journey both existed since the previous release but neither was
    wired into the command that actually publishes — a check nobody has to run is
    a check that gets skipped exactly when a release is rushed, which is the
    shape of three past incidents (v4.7.0's ghost publish, v4.8.2's stale plugin
    cache, a 4.8.2 CLI beside a 4.8.3 plugin).

How to test

npm run verify:release   # includes the new check:entry-points-start step
node scripts/run-tests-isolated.mjs

Both were run against this exact branch; see CHANGELOG.md [4.8.4] for the
full per-change detail.

Linked issues

Closes the plugin-cache-sweep, entry-point-gate, and release-credential-check
gaps identified in the 2026-09-02 v4.8.3 dogfood pass.

kevintseng and others added 5 commits September 4, 2026 20:37
All 9 version anchors updated (package.json, package-lock.json x2,
.claude-plugin/plugin.json, .codex-plugin/plugin.json,
.claude-plugin/marketplace.json, CHANGELOG.md, CODEMAP.md,
docs/ARCHITECTURE.md, docs/api/API_REFERENCE.md, herdr-plugin.toml),
confirmed agreeing via scripts/check-version-coherence.mjs. CHANGELOG's
[Unreleased] section moved to a dated [4.8.4] section, with a fresh
empty [Unreleased] above it. dist/skills-manifest.json rebuilt to
match.
Two PRs merged into main between 4.8.3 and this release cut each
carried their own ### Added block under [Unreleased]; the version
bump moved both into [4.8.4] as-is instead of merging them. Combined
into one Added section, content unchanged.
…st replaced

upgrade-plugin.sh's atomic swap always removed the ONE version directory
it had just replaced (PREVIOUS_PATH), but anything left behind by an
interrupted upgrade, or one predating this swap mechanism, had no path
back to zero. Measured on a real machine: 9 stale version directories
under plugins/cache/pcircle-memesh/memesh/, 1.2 GB, accumulated with no
bound.

sweep_stale_cache_versions() removes every directory under the cache
root whose name is exactly <major>.<minor>.<patch>, except the version
just installed and the registry's own recorded install path (protected
even when it is a stray non-canonical directory the existing "noncanonical
... repairing it" branch deliberately leaves for a human -- a regression
caught by the existing same-version-repair test suite and fixed by
threading that path through as a second protected name, not by narrowing
the sweep).

Defined near the top of the script behind a
MEMESH_UPGRADE_PLUGIN_SOURCE_ONLY=1 guard so
tests/upgrade-plugin-cache-sweep.test.ts can source the real function and
test it in isolation, without running the rest of the script against a
real Claude Code marketplace checkout. Mutation-verified: breaking the
keep-version exclusion turns 4 of 6 tests red.
…nto the release path

verify:release now ends with check:entry-points-start, which spawns all 17
shipped bins and hooks for real instead of only checking that their files
exist — a CLI must accept --version, an MCP server must exit 0 on stdin
EOF, a long-lived daemon must reach its "running" signal, and a host
runtime with no config must fail closed with a named message, never a raw
stack trace. It also fails on any unresolved ${...} left in .mcp.json or
hooks/hooks.json, evaluated against each manifest's own real substitution
environment.

finish-release.mjs now runs qa:pre-release itself and blocks on its real
exit code, and requires a qa:live-journey receipt (.qa/codex-report.json
or .qa/claude-report.json, either host) that is PASS, clean-tree, and
names the exact commit being released before it will cut a tag. Both
qa:pre-release and qa:live-journey were available since the previous
release but neither was in the one command that actually ships one — a
check nobody has to run is a check that gets skipped exactly when a
release is rushed.
…e it

check-entry-points-start.mjs put the router's probe socket at
`${gateRoot}-r.sock` — a sibling of the mkdtemp'd gate directory, so its
parent was os.tmpdir() itself. On ubuntu-latest CI that is the shared,
world-writable /tmp (mode 1777), and agent-router.ts's own startup check
correctly refuses to bind there: insecure_socket_directory, "Router
socket directory must be private." Invisible locally because macOS's
os.tmpdir() already resolves to a per-user 0700 directory.

Nest the socket and token file inside gateRoot instead (already 0700 via
mkdtemp, now also chmod'd explicitly rather than assumed) and measured
the resulting path at 66 bytes on macOS's unusually long tmpdir — well
under the 103-byte AF_UNIX limit, shorter still on Linux.

Never shipped: caught by this PR's own CI before merge, so no CHANGELOG
entry for a bug no release ever had.
@kevintseng
kevintseng merged commit 580fb5b into main Sep 4, 2026
13 checks passed
@kevintseng
kevintseng deleted the release/v4.8.4 branch September 5, 2026 11:50
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