Skip to content

v0.17.9 (LTS) — cron token split-brain fail-closed + tmux socket containment

Latest

Choose a tag to compare

@seanssoh seanssoh released this 12 Jul 23:54
f5d230b

[0.17.9] — 2026-07-13 (LTS · headless-cron token split-brain fail-closed + tmux socket split-brain containment)

v0.17.9 is a patch on the v0.17 LTS line closing two fleet-down split-brain classes seen on the v0.17.8 line: a headless-cron reactive-quota rotation that overwrote the central token-updater's lease-selected token across the fleet (2026-07-12 token split-brain outage), and a socket-rollout gap where a restored named-socket daemon could spawn a second fleet alongside still-live legacy default-socket sessions. It becomes the new Latest / --channel stable / --channel lts head; LTS_SERIES stays 0.17 (single converged v0.17.x line, no fork), so no host auto-moves — advance with an explicit --ref v0.17.9 (a strict forward move; the downgrade guard is not engaged).

Fixed

  • Headless-cron reactive-quota rotation is fail-closed under connected updater-authority, closing the fleet-wide token split-brain outage (#2469). maybe_reactive_rotate() in bridge-cron-runner.py routed a headless-cron 429 through the shared lease-swap-or-defer verb but, on a defer_local / subprocess-error / malformed-response decision, fell through to a local claude-token rotate — overwriting the central token-updater's lease-selected token across the fleet in connected-authority mode (the daemon already guarded this exact fall-through via #27006 Inc A; the cron-runner did not). The fix mirrors the daemon's connected-authority predicate in the cron-runner (same BRIDGE_UPDATER_AUTHORITY_ENABLED / break-glass gates and last-token-lease-ok marker hysteresis: fail_count < 2, fresh_window = 2*interval + 60, malformed/missing → disconnected): in authority mode a defer_local / subprocess_error / bad_decision converts to a fail-closed authority_defer HOLD (audited, no local rotate), while disconnected / dark / break-glass / lease-disabled keep the classic local fallback byte-identical. Authority-mode swaps omit --if-auto-enabled to match bridge_daemon_lease_swap_route. This is option A (minimal blast radius — mirrors the predicate rather than refactoring the daemon path; a follow-up option B can unify it into one shared read-only predicate). Regression teeth: scripts/smoke/token-updater-swap-or-defer.sh R3a–j (connected-authority defer/bad-JSON/subprocess-error → HOLD; hysteresis; stale/flag-off/break-glass/lease-disabled → local fallback restored).
  • Socket-rollout split-brain containment prevents a restored named-socket daemon from duplicating a still-live legacy default-socket fleet (#2451, backport of #2450). Closes the v0.17.8 rollout gap where restart_agents=false plus a layout-v2 reconcile could restore the named-socket daemon while legacy default-socket sessions were still alive, spawning a second fleet: legacy exact-roster sessions now count as active, duplicate starts are suppressed and cross-socket split-brain is detected, explicit stop/restart drains only the exact managed sessions on both sockets before relaunching a single named-socket instance, and the upgrade rolling-restart enumerates legacy sessions while preserving attached-client skips across both sockets — with no kill-server, regex-wide selection, or shell command-template interpolation. The full automatic old-socket migration remains deferred to #2441. Regression teeth: scripts/smoke/30737-tmux-socket-isolation.sh (5 cases) plus restart/teardown/resume smokes.