[object Object]

← back to Terminal Status

fix: raise process-table timeout so dot painting survives a busy box

63f3fae001f9b8ec2758058855bddf78cc2e6208 · 2026-09-10 07:58:58 -0700 · Steve Abrams

`ps -ax` costs ~4-5s idle and ~30s under load on this workstation (~2k
processes from the MCP fleet), so the 8s ceiling in processes() was
marginal at rest and failed outright whenever anything ran in parallel --
every color-dot script died with "timed out after 8 seconds" and no tab
could be painted at all. Raise to 60s and convert the bare TimeoutExpired
into an actionable StatusError. The full table is genuinely required
(owners() proves a tty has exactly ONE live runtime before agreeing to
paint it), so this is headroom, not a narrower query.

Verified: 26/26 tests pass; current.sh now resolves ttys022 in 9.2s.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MHKdiEfwLNDHqKgMRbBNS2

Files touched

Diff

commit 63f3fae001f9b8ec2758058855bddf78cc2e6208
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Thu Sep 10 07:58:58 2026 -0700

    fix: raise process-table timeout so dot painting survives a busy box
    
    `ps -ax` costs ~4-5s idle and ~30s under load on this workstation (~2k
    processes from the MCP fleet), so the 8s ceiling in processes() was
    marginal at rest and failed outright whenever anything ran in parallel --
    every color-dot script died with "timed out after 8 seconds" and no tab
    could be painted at all. Raise to 60s and convert the bare TimeoutExpired
    into an actionable StatusError. The full table is genuinely required
    (owners() proves a tty has exactly ONE live runtime before agreeing to
    paint it), so this is headroom, not a narrower query.
    
    Verified: 26/26 tests pass; current.sh now resolves ttys022 in 9.2s.
    
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01MHKdiEfwLNDHqKgMRbBNS2
---
 terminal_status.py | 22 ++++++++++++++++++----
 1 file changed, 18 insertions(+), 4 deletions(-)

diff --git a/terminal_status.py b/terminal_status.py
index 8cc6e20..4cab0a8 100644
--- a/terminal_status.py
+++ b/terminal_status.py
@@ -97,10 +97,24 @@ class Process:
 
 
 def processes():
-    result = subprocess.run(
-        ["ps", "-axo", "pid=,ppid=,tty=,lstart=,comm="],
-        capture_output=True, text=True, timeout=8,
-        env={**os.environ, "LC_ALL": "C"})
+    # `ps -ax` walks the whole process table, so its cost scales with how many
+    # processes the box is running -- on a workstation with a large MCP fleet
+    # (~2k procs) it measures ~4-5s idle and ~30s under concurrent load. The old
+    # 8s ceiling was marginal even at rest, so any parallel work turned it into
+    # a hard failure: every dot script died with "timed out after 8 seconds"
+    # and no tab could be painted at all.
+    # Ownership resolution genuinely needs the full table (owners() proves a
+    # tty has exactly ONE live runtime before we agree to paint it), so the fix
+    # is headroom plus an actionable message, not a narrower query.
+    try:
+        result = subprocess.run(
+            ["ps", "-axo", "pid=,ppid=,tty=,lstart=,comm="],
+            capture_output=True, text=True, timeout=60,
+            env={**os.environ, "LC_ALL": "C"})
+    except subprocess.TimeoutExpired:
+        raise StatusError(
+            "Timed out reading the process table (ps -ax took >60s); the box is "
+            "overloaded -- check the process count with `ps -A | wc -l`.")
     if result.returncode:
         raise StatusError("Cannot inspect live terminal owners: " + result.stderr.strip())
     rows = {}

← 914a88d fix: paint guard resolves ancestry before refusing on CLAUDE  ·  back to Terminal Status  ·  set: automatic paints yield to sticky semantic dots (orange/ e6a426b →