memory: retract the stale-lock claim; the plugin gap ate the SessionStart hook

forseti measured my stale-lock claim and it is false. I said a lock file
holding a dead pid would make the next althing-listen exit 3 and turn a
reap into a permanent monitoring outage that reports healthy. The gate is
flock -n on an open fd, which the kernel releases when the holder dies, so
a lock left by a reaped listener is inert and exit 3 only fires against a
live holder. The pid in the file is read by --stop alone.

I reasoned from the artifact's contents when the behaviour is set by the
locking mechanism, and put the consequence in durable memory without
testing it. forseti tested before writing code. That is the third time
tonight I reported a proxy as the thing itself, after sudo -n -v for
NOPASSWD and command -v nvcc for the toolkit.

Deployed 3.2.3, which makes althing-listen refuse on a pane seat with its
own exit code rather than silently demoting it.

And found the real shape of the plugin gap, which is worse than the stale
document forseti and I were both discussing. Nothing syncs the repo's
plugin directory into the marketplace directory, so it was frozen at Aug
28 with only the UserPromptSubmit hook -- no SessionStart, no SessionEnd,
no pane-route.sh at all. That means "CC seats re-declare automatically at
their next SessionStart" has never been true on this box, which is why
every seat including our own needed a hand-fed declare. Source is fixed
and bumped to 0.1.1; refreshing the plugin cache needs a /plugin update
from the operator, and I deliberately did not hand-edit Claude Code's own
plugin bookkeeping to force it.
This commit is contained in:
2026-09-02 00:43:56 -07:00
parent 5563b77867
commit 83217553bb
@@ -377,14 +377,72 @@ recommending the sharpest: **have `althing-listen` REFUSE to arm when a `channel
exists for the handle**, so the stale doc becomes harmless because the binary enforces the
documented precedence. The doc-only fixes rely on a reader noticing.
## ⚠ A STALE WAITER LOCK IS A SILENT PERMANENT OUTAGE THAT REPORTS HEALTHY
## ❌ RETRACTED — "a stale waiter lock is a silent permanent outage" IS FALSE
`~/.althing/wake-listener-<handle>.lock` survived the waiter's reap (held dead pid 2854412 from
22:16). A future `althing-listen` seeing it returns **exit 3 = "a waiter is already running"**,
whose documented response is *"do NOT drain, do NOT re-arm"*. So a stale lock converts a reap
into a **permanent monitoring outage that looks like correct behaviour.** Removed here (pid
verified dead, own handle, literal path). Suggested to forseti that the waiter clear a lock
whose pid is dead rather than trusting the file.
infra-ops claimed a `wake-listener-<handle>.lock` holding a dead pid would make the next
`althing-listen` return exit 3 ("already running" -> do not drain, do not re-arm), converting a
reap into a permanent monitoring outage that reports healthy. **forseti measured it; it does
not happen:**
lock file holds pid 999999 (dead) -> althing-listen ARMED FINE
lock held by a live process -> rc=3, correctly refused
**The gate is `flock -n 9`, not the file's contents.** `flock` is advisory and held by an
**open fd**; the kernel releases it when the holder dies, so a lock left by a reaped listener is
**inert**. Exit 3 only ever fires against a genuinely live holder. The pid stamped in the file
is read by `--stop` alone — which is why the file is opened non-truncating.
⚠ **The lesson: I reasoned from the artifact's CONTENTS when the behaviour is set by the
LOCKING MECHANISM** — and shipped the consequence to durable memory without testing a claim
that would have justified real guard code for a condition that cannot occur. forseti tested it
before writing any. If a reaped seat ever genuinely cannot re-arm, that is a **different** bug:
check `flock -n` on the fd before suspecting the pid.
[[feedback_assert_effective_value_not_substring]]
## ✅ 3.2.3 DEPLOYED — `althing-listen` now REFUSES on a pane seat (exit 4)
$ althing-listen # on a channel=pane seat
'infra-ops' already has a PANE route, and arming a waiter would silently take
precedence over it ... To switch back on purpose: althing-route release
rc=4
Distinct code by design: **not 0** (that is the poke — a refusal exiting 0 announces mail that
never arrived), and **not 3** ("already running" says leave the incumbent alone, a different
instruction from "you do not need this at all"). Scoped to the handle's own route, checked
before the lock, and `--stop` deliberately ungated.
## ⚠⚠ THE REAL PLUGIN GAP — NO SessionStart HOOK WAS EVER DEPLOYED ON THIS BOX
Not a stale doc. The deploy chain is:
repo plugin/ -> ~/.local/share/althing-plugin/ -> ~/.claude/plugins/cache/
^^^ NOTHING SYNCS THIS HOP
The marketplace directory was a frozen copy from **Aug 28**. Comparing what was deployed
against the repo:
deployed 0.0.1 hooks: ['UserPromptSubmit']
repo 0.1.1 hooks: ['UserPromptSubmit', 'SessionStart', 'SessionEnd']
+ scripts/pane-route.sh (absent from the deployment entirely)
⚠ **So forseti's migration note — "CC seats re-declare automatically at their next
SessionStart" — has NEVER been true on this box.** The hook exists and works upstream; it was
simply never deployed. That explains what we both treated as normal: all four smithy seats
needed a hand-fed `althing-route declare`, **and so did infra-ops' own seat** — a Claude Code
seat that should have self-declared. The same applies to 3.2.1's `idle_cursor` pin.
**Fixed at the source** (repo `plugin/` rsynced to the marketplace dir, backed up first,
`marketplace.json` bumped to 0.1.1 — all three hooks + `pane-route.sh` + pane-aware
`monitor.md` now present).
🔵 **ONE STEP LEFT, OPERATOR'S:** refreshing `~/.claude/plugins/cache/` needs a `/plugin`
update. **Deliberately did NOT hand-edit `installed_plugins.json` or fabricate a cache
directory** — that is Claude Code's own bookkeeping, and getting it subtly wrong breaks the
plugin in a way that looks like an upstream bug.
**There is still no deploy script for the first hop**, which is why it drifted five days
unnoticed. Offered to write one; it installs to a per-machine path so ownership (althing repo
vs eshpfi) is forseti's call.
## Rollback (unused)