← back to Terminal Status
set: automatic paints yield to sticky semantic dots (orange/purple/yellow)
e6a426bbfeb783df18d98983311f612ae718852d · 2026-09-10 08:21:00 -0700 · Steve Abrams
A UserPromptSubmit hook fires `set green WORKING` on EVERY prompt, and green
overwrote whatever dot the tab held. So typing into a tab silently erased its
purple (gated memo), orange (paste waiting) or yellow (question waiting) and
replaced it with green = 'nothing needed'. Observed twice in one session.
PRIORITY (orange > purple > yellow > green > pink > none) already existed at
line 31 but was only ever used to sort scan() output, never to arbitrate a
paint. This makes set() consult it: a caller passing --deferential will not
overwrite a state ranked above green; it repaints the existing record and
returns it unchanged (no revision bump, no mirror churn).
Only the automatic per-prompt painter passes --deferential. Every EXPLICIT
paint stays authoritative, so /greendot, /color, /pinkdot and --off can still
clear a sticky dot and a tab can still be reused for new work. The teal
monitoring variant is green-family and yields too.
Verified with an in-process truth table (11/11): sticky states survive an
automatic green; green/pink do not; explicit green/pink/none still win;
revision does not bump when the guard yields.
TK-11378, DTD verdict A (6/7). Steve approved 2026-09-10.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RwTfiTtWZNjLoowhjXdWV1
Files touched
Diff
commit e6a426bbfeb783df18d98983311f612ae718852d
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Thu Sep 10 08:21:00 2026 -0700
set: automatic paints yield to sticky semantic dots (orange/purple/yellow)
A UserPromptSubmit hook fires `set green WORKING` on EVERY prompt, and green
overwrote whatever dot the tab held. So typing into a tab silently erased its
purple (gated memo), orange (paste waiting) or yellow (question waiting) and
replaced it with green = 'nothing needed'. Observed twice in one session.
PRIORITY (orange > purple > yellow > green > pink > none) already existed at
line 31 but was only ever used to sort scan() output, never to arbitrate a
paint. This makes set() consult it: a caller passing --deferential will not
overwrite a state ranked above green; it repaints the existing record and
returns it unchanged (no revision bump, no mirror churn).
Only the automatic per-prompt painter passes --deferential. Every EXPLICIT
paint stays authoritative, so /greendot, /color, /pinkdot and --off can still
clear a sticky dot and a tab can still be reused for new work. The teal
monitoring variant is green-family and yields too.
Verified with an in-process truth table (11/11): sticky states survive an
automatic green; green/pink do not; explicit green/pink/none still win;
revision does not bump when the guard yields.
TK-11378, DTD verdict A (6/7). Steve approved 2026-09-10.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RwTfiTtWZNjLoowhjXdWV1
---
terminal_status.py | 24 ++++++++++++++++++++++--
1 file changed, 22 insertions(+), 2 deletions(-)
diff --git a/terminal_status.py b/terminal_status.py
index 4cab0a8..03068f0 100644
--- a/terminal_status.py
+++ b/terminal_status.py
@@ -329,7 +329,7 @@ class Store:
return r, reason
def set(self, owner, color, label="", *, issued_ns=None, ticket_update=None,
- variant=""):
+ variant="", deferential=False):
issued_ns = issued_ns if issued_ns is not None else issued_clock()
if color not in COLORS or not valid_label(label) or variant not in ("", "monitoring"):
raise StatusError("Invalid status or label")
@@ -345,6 +345,22 @@ class Store:
previous, _ = self.load(owner)
if previous and issued_ns <= previous["issued_ns"]:
raise StatusError("Obsolete status update; a newer event already won")
+ # TK-11378 (DTD verdict A) — an AUTOMATIC paint must never erase a pending
+ # request for Steve's attention. PRIORITY already encodes the ordering
+ # (orange > purple > yellow > green > pink > none) but until now was only
+ # used to sort scan() output, never to arbitrate a paint. "Sticky" = anything
+ # ranked above green, i.e. the three colors that mean a human is blocked.
+ # Only deferential callers (the per-prompt working-state hook) yield; every
+ # EXPLICIT paint (/greendot, /color, /pinkdot, --off) stays authoritative, so
+ # a session can still clear its own dot or reuse the tab for new work.
+ if (deferential and previous and color == "green"
+ and PRIORITY.get(previous.get("state"), PRIORITY["none"]) < PRIORITY["green"]):
+ self.assert_owner(owner)
+ try:
+ self.painter(owner, previous)
+ except (OSError, StatusError):
+ pass # keep the record authoritative even if the repaint fails
+ return previous
ticket = self.ticket_info(owner, previous)
if ticket_update is not None:
ticket = {"id": ticket_update, "at": time.time(), "source": "explicit"}
@@ -490,6 +506,9 @@ def main(argv=None):
cmd.add_argument("label", nargs="?", default="")
cmd.add_argument("--all", choices=["claude", "codex"])
cmd.add_argument("--monitoring", action="store_true")
+ cmd.add_argument("--deferential", action="store_true",
+ help="automatic paint: yield to a sticky semantic dot "
+ "(orange/purple/yellow) instead of overwriting it")
if name == "ticket":
cmd.add_argument("ticket")
cmd.add_argument("--quiet", action="store_true")
@@ -596,7 +615,8 @@ def main(argv=None):
record = store.repaint(owner)
else:
record = store.set(owner, color, label,
- variant="monitoring" if getattr(args, "monitoring", False) else "")
+ variant="monitoring" if getattr(args, "monitoring", False) else "",
+ deferential=getattr(args, "deferential", False))
if not getattr(args, "quiet", False):
print(f'/terminal-status → /dev/{owner.tty} {record["title"] or "CLEARED"}')
return 0
← 63f3fae fix: raise process-table timeout so dot painting survives a
·
back to Terminal Status
·
osascript enumeration: raise timeout to 30s and record blind 29475ed →