fix(deploy-althing): diff plugin CONTENT, and document the cc channel

The 3.3.0 deploy exposed a false green. `claude plugin update` matches on
the version in plugin.json and declines when it has not moved, so a release
that edits hook or script content without a version bump leaves the Claude
Code cache stale while every version check in this script reports success.
Marketplace and live cache both read 0.1.1, update said "already at the
latest version", and pane-route.sh + README differed.

That particular delta was documentation-only, so nothing was actually
broken — but the script had no way to say so, which is the defect. It now
diffs the marketplace tree against the live cache dir on every run and on
--check, ignoring orphaned version dirs, and says what to do about drift
(bump upstream; never hand-edit Claude Code's bookkeeping).

The 2026-09-01 lesson was "compare the hook list, not the version string".
This is that lesson one turn deeper: the hook list was identical too.

Also documents the cc channel as a deliberately-taken undocumented
interface — expected to break on some future Claude Code release, failing
to pull-only with a logged reason rather than losing mail — and the
herald-before-declare ordering constraint that the script already honours.
This commit is contained in:
vh
2026-09-02 09:07:21 -07:00
parent 91e2b67074
commit 1147e14b79
2 changed files with 92 additions and 0 deletions
+49
View File
@@ -132,6 +132,55 @@ reaped listener is inert and exit 3 only fires against a genuinely live holder.
The pid in the file is read by `--stop` alone. (Recorded because infra-ops
claimed the opposite, untested, on 2026-09-01; forseti measured it.)
## ⚠ The plugin cache does not take a content-only change
`claude plugin update althing` matches on the version in `plugin.json` and
declines when it is unchanged. A release that edits hook or script CONTENT
without bumping the plugin version therefore leaves the Claude Code cache
stale while **every version check reports success** — the marketplace dir gets
the new bytes, the cache does not, and `update` says "already at the latest
version".
Measured on the 3.3.0 deploy (2026-09-02): marketplace and live cache both read
`0.1.1`, and `pane-route.sh` + `README.md` differed. That delta was
documentation-only and harmless. The next one need not be.
`scripts/deploy-althing.sh` now diffs the marketplace tree against the live
cache dir on every run and on `--check`, so the drift is reported rather than
inferred. **The fix is a plugin version bump upstream, not a hand-edit** —
`~/.claude/plugins/installed_plugins.json` and the cache directory are Claude
Code's own bookkeeping.
The 2026-09-01 lesson was *compare the hook list, not the version string*. This
is the same lesson one turn deeper: here the hook list was identical too, and
only the file contents moved.
## ⚠ The `cc` channel is an undocumented interface, taken deliberately
From 3.3.0 a Claude Code seat is poked over its own message socket
(`$XDG_RUNTIME_DIR/cc-socks/<pid>.sock`) rather than by typing into its pane.
No process to reap, nothing near the input line, and delivery lands at the
receiver's next turn boundary.
It is not a published interface and **is expected to break on some future
Claude Code release**. Accepted on the operator's reasoning: the FIFO poker it
replaces was also an unsanctioned hack of the background-watcher system, so
this is a better instance of a dependency class we already had, not a new one.
When it breaks the failure mode is a seat going **pull-only with a logged
reason** — not lost mail; the post office holds it either way. Recovery is one
command:
althing-route declare --pid <pid> # prefers cc, falls back to pane
⚠ **Ordering constraint at any upgrade that changes the channel set:** a
pre-3.3.0 herald refuses `channel=cc` at parse, so a seat that declares the new
channel before the herald restarts goes silently pull-only. `uv tool install
--force` then the herald restart, and only then let anything re-declare.
`deploy-althing.sh` already runs them in that order and updates the plugin
(whose SessionStart hook declares the route) last, which is what keeps the
window to a couple of seconds.
## Rollback
uv tool install althing-core==3.1.2
+43
View File
@@ -50,6 +50,39 @@ market_plugin_version() {
cache_versions() {
ls -1 "$HOME/.claude/plugins/cache/althing/althing/" 2>/dev/null | tr '\n' ' ' || echo "absent"
}
# ⚠ COMPARE CONTENT, NOT THE VERSION STRING.
#
# `claude plugin update` matches on the version in plugin.json and declines
# when it is unchanged — so a release that edits hook or script CONTENT without
# bumping the plugin version leaves the Claude Code cache stale while every
# version check in this script reports success. Measured on the 3.3.0 deploy
# (2026-09-02): marketplace and cache both read 0.1.1, update said "already at
# the latest version", and pane-route.sh + README differed. That delta was
# documentation-only and harmless — the next one need not be.
#
# The 2026-09-01 lesson was "compare the hook list, not the version string".
# This is the same lesson one turn deeper: the hook list was identical too.
plugin_content_drift() {
# Only the cache dir matching the marketplace version is live. Older dirs
# carry a .orphaned_at marker and Claude Code no longer loads them; they
# differ by construction and saying so every run is noise.
local live="$HOME/.claude/plugins/cache/althing/althing/$(market_plugin_version)"
local c
for c in "$HOME"/.claude/plugins/cache/althing/althing/*/; do
[[ -d "$c" && -f "$c/.orphaned_at" ]] && say " · cache $(basename "$c") orphaned, ignored"
done
if [[ ! -d "$live" ]]; then
say " ⚠ no cache dir for the marketplace version $(market_plugin_version)"
return 1
fi
if diff -rq --exclude marketplace.json "$MARKET" "$live" >/dev/null 2>&1; then
say " ✓ live cache $(basename "$live") matches the marketplace tree"
return 0
fi
say " ⚠ live cache $(basename "$live") DIFFERS from the marketplace tree:"
diff -rq --exclude marketplace.json "$MARKET" "$live" 2>&1 | sed 's/^/ /'
return 1
}
step "state"
say " repo $(git -C "$REPO" describe --tags --always) $(git -C "$REPO" diff --quiet && echo clean || echo DIRTY)"
@@ -57,6 +90,7 @@ say " installed tool $(uv tool list 2>/dev/null | awk '/^althing-core/{print $
say " repo plugin $(repo_plugin_version)"
say " marketplace $(market_plugin_version)"
say " CC cache $(cache_versions)"
plugin_content_drift || true
if (( CHECK )); then
say ""
@@ -111,6 +145,15 @@ step "verify"
say " installed tool $(uv tool list 2>/dev/null | awk '/^althing-core/{print $2}')"
say " marketplace $(market_plugin_version)"
say " CC cache $(cache_versions)"
if ! plugin_content_drift; then
say ""
say " ⚠ The cache did NOT take the new plugin content. This happens when the"
say " release changed hook/script content without bumping the plugin version"
say " — `claude plugin update` matches on version and declines. Ask the"
say " althing maintainer for a version bump; do NOT hand-edit the cache or"
say " ~/.claude/plugins/installed_plugins.json, which is Claude Code's own"
say " bookkeeping. Check the diff above for whether it is load-bearing."
fi
say " herald $(systemctl --user is-active althing-po-herald)"
say ""
say "⚠ RESTART Claude Code to load the new plugin hooks. A running session keeps the old ones."