diff --git a/persistent-memory.d/2026-09-01-althing-320-deploy.md b/persistent-memory.d/2026-09-01-althing-320-deploy.md index 21df35d..9ff46e4 100644 --- a/persistent-memory.d/2026-09-01-althing-320-deploy.md +++ b/persistent-memory.d/2026-09-01-althing-320-deploy.md @@ -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-.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-.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)