Files
esh-pfi-infrastructure/persistent-memory.d/2026-09-01-althing-320-deploy.md
T
vh 71d97f36b6 memory: snapshot — althing 3.2.0 deployed; uv tool install is a silent no-op
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.
2026-09-01 22:15:51 -07:00

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.