forseti requested the deploy, operator-approved and tagged at c4ede0f. All three steps landed on nh3-dev and verified: force reinstall to 3.2.0 with seven binaries, herald restart, skill sync. The durable lesson is the trap in step 1. `uv tool install .` matches on the source spec rather than its contents, so on a box that already had the tool installed from that path it prints "already installed" and exits 0 having done nothing. Following the runbook literally would have left the new binary absent with every command reporting success. Always use --force when reinstalling from a local path. Also recorded: the pane-route migration revoked exactly four routes, verified by splitting on channel= before the restart rather than by auditing fields (all twelve route files lack the new fields, so a field audit over-counts). The four affected agents were deliberately not notified, per the standing rule against unsolicited fleet broadcast, and that is surfaced to the operator instead. And this closes an open question from earlier today: the waiter that died with status "killed" was CC 2.1.257 reaping detached tasks, which is the premise 3.2.0 exists to address.
4.5 KiB
[2026-09-01] althing 3.2.0 deployed on nh3-dev — pane routes, and uv tool install . lies
Operator-approved, tagged v3.2.0 at c4ede0f on master. forseti authored; infra-ops
deployed. Host work, nh3-dev only.
What 3.2.0 changes
A Claude Code session in a zellij pane is now poked in its own pane instead of through a
detached althing-listen waiter, because CC 2.1.257 reaps detached tasks whenever the seat
sits in shell — the seat is targeted, not the task, so no amount of hardening the waiter
helps. A pane route is a file; there is no process to reap.
⚠ Independently corroborated here. ~30 min before forseti's request landed, infra-ops'
own althing-listen ended with status killed — not exit 0/2/3, no mail, inbox empty, seat
silently back to mode: pull. Written up at the time as "cause unknown, probably a harness
reaper" rather than guessed at. 2.1.257 is the mechanism.
The deploy — three steps, order matters
22:13:xx uv tool install --force . 3.1.2 -> 3.2.0, 7 executables
22:13:44 systemctl --user restart althing-po-herald pid 180370 -> 2850064
22:14:07 scripts/sync_skill.sh 3.1.0 text -> 3.2.0, --check clean
althing-route is the seventh console script and the whole point — the plugin's new
SessionStart hook calls it by name, so on 3.1.2's six binaries the hook correctly degrades
to silence and every seat stays pull-only. Nothing breaks by waiting; nothing works until it
lands. Skill sync must come after the install or it documents a binary that is not there.
⚠ NOT --editable (standing rule): an editable install puts the working tree on
sys.path, so a branch switch changes what every running agent's tooling does with no deploy
step in between.
⚠ THE TRAP — uv tool install . IS A SILENT NO-OP ON A REINSTALL
$ uv tool install .
`althing-core @ file:///home/lkraven/development/althing` is already installed
$ echo $?
0
uv matches on the source SPEC, not the source CONTENTS. On a box where the tool was already installed from that same path, it declines and reports success. Nothing says "I did not do the thing you asked."
Always uv tool install --force . when reinstalling from a local path. Generalises the
nh3-extdev lesson (reference_nh3_extdev_althing_mesh) from the system-wheel case to every
local-path uv tool. Same shape as feedback_assert_effective_value_not_substring: the
command exited 0 and the state was unchanged.
Fleet-visible: 4 pane routes revoked, and the count to trust
Pane routes now carry started_at (declaring pid's start time, so a recycled pid cannot
inherit a route) and command (so a pane that has dropped to a shell stops being poked).
Routes without them are observed and excluded with a reason in the herald log, not
silently ignored — this closes a real hazard where the herald would write a line into whatever
shell inherited an exited agent's pane and press Enter, running whatever was half-typed there.
Verified by splitting ~/.althing/routes on channel= before the restart — all twelve
route files lack the new fields (3.1.2 never wrote them), so a field audit over-counts; only
pane routes are affected:
pane: 4 -> bil-smithy-dev, dvalin-smithy-dev, eitri-smithy-dev, regin-smithy-dev
fifo: 8 (+ 9 fifos in ~/.althing/wake/)
forseti's list of four matched exactly. ⚠ Their note said "the twelve fifo seats are untouched" — twelve is the total route count; fifo is 8. Untouched either way.
Re-declare is one command per agent: althing-route declare --pid <long-lived agent pid>.
Not notified. Four targeted messages about a change none of them asked about reads as a broadcast however addressed → feedback_notify_before_tearing_down_a_seat. Surfaced to the operator instead; the herald logs the exclusion every tick so it is discoverable.
⚠ Log-noise papercut raised with forseti (not a bug): the exclusion lines repeat every tick (~26 s), so the four stale routes emit ~140 lines/hour, ~3,300/day until re-declared — enough to bury real signal in the log you reach for when a seat misbehaves. Suggested a back-off after N consecutive exclusions. Their call.
Rollback (unused)
uv tool install althing-core==3.1.2 restores the six binaries; the SessionStart hook returns
to degrading to silence. Routes written by 3.2.0 stay parseable to 3.1.2 (the old reader
ignores unknown keys), so nothing is stranded.
Thread: 01M1G8EJ2K1DD6NEDRNN1PR9N0.