tickmarkr 1.92.1 → 1.96.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,140 @@
1
+ #!/bin/bash
2
+ # Deliver ONE directive to a seat with VERIFIED submission — the send path that failed five distinct
3
+ # ways in one leg (2026-08-17, P98): front-truncation at the PTY (~1024B), text sitting unsubmitted,
4
+ # two silent losses, and probes that mistook presence for delivery. A prose protocol loses one step
5
+ # under load; this encodes the steps.
6
+ #
7
+ # seat-send.sh <agent-name-or-pane> <message>
8
+ #
9
+ # TKR_INTERRUPT=1 end a `working` seat's turn first (Esc, at most twice, verified between) so the
10
+ # directive is READ now instead of queued behind the turn. A message to a working
11
+ # claude seat lands in its queue and drains only at the turn boundary — with
12
+ # in-process teammates that is 20–40 minutes, so A QUEUED HOLD IS NOT A HOLD.
13
+ # Measured 2026-08-18: two freeze-class directives sat queued behind a planner's
14
+ # teammate fan-out and THE OPERATOR pressed Esc by hand because no seat owned the
15
+ # interrupt. The interrupt loses the seat's in-flight step; for a correctness-class
16
+ # directive that is the price, and it is cheaper than a voided verdict.
17
+ #
18
+ # ⚠ WHY THE READ-BACK IS THE PROMPT LINE AND NOTHING ELSE (measured 2026-08-18, three methods failing
19
+ # identically): `herdr pane read` INCLUDES THE INPUT BOX, so an unsubmitted message renders exactly
20
+ # like a submitted one and every content-based probe — token grep, tail token, full-text match —
21
+ # returns the same answer in both states. A freeze hold was "verified delivered" three ways and had
22
+ # never been submitted; the receiving seat stopped 19 minutes later without ever reading it. Only the
23
+ # PROMPT LINE discriminates: text sitting on `❯` is exactly what will not run. Prompt-line state
24
+ # alone, or nothing — a decorative check beside a real one reads as corroboration.
25
+ #
26
+ # First output line is the machine-greppable verdict:
27
+ # DELIVERED_SUBMITTED | QUEUED_BEHIND_TURN | SEND_UNSUBMITTED | INTERRUPT_FAILED | TARGET_GONE
28
+ # | REFUSED_SIZE | REFUSED_BOX_OCCUPIED
29
+ #
30
+ # This verifies SUBMISSION — the text left the input box — never that the seat understood or acted.
31
+ # Read the seat's ARTIFACT for that; a send receipt is not a response.
32
+ set -u
33
+
34
+ TARGET="${1:?usage: seat-send.sh <agent-name-or-pane> <message>}"
35
+ MSG="${2:?message required}"
36
+
37
+ # PTY input front-truncates around 1KB and a truncated brief silently drops policy — the drop is at
38
+ # the FRONT, so what survives still reads as a complete message. Long content goes in a FILE; the
39
+ # pane gets one line pointing at it.
40
+ if [ "${#MSG}" -gt 900 ]; then
41
+ echo "REFUSED_SIZE ${#MSG} bytes — write a brief file and send a one-line pointer instead"; exit 2
42
+ fi
43
+
44
+ status_of() {
45
+ herdr agent get "$TARGET" 2>/dev/null \
46
+ | sed -n 's/.*"agent_status":"\([a-z_]*\)".*/\1/p' | head -1
47
+ }
48
+
49
+ # The rendered `❯` line — the only state that discriminates submitted from sitting. head -1 returns
50
+ # the first rendered line, i.e. a PREFIX of a wrapped draft, so callers compare prefixes, never
51
+ # whole sentences (OBS-396: a full-sentence match returns false on a message that arrived intact).
52
+ prompt_line() {
53
+ herdr agent read "$TARGET" --source visible --lines 14 2>/dev/null \
54
+ | sed -n 's/^[[:space:]]*❯[[:space:]]*//p' | head -1 | sed 's/[[:space:]]*$//'
55
+ }
56
+
57
+ # Is $1 a rendered prefix of our message? (first line of a wrapped draft = prefix of MSG)
58
+ is_ours() {
59
+ case "$MSG" in "$1"*) return 0 ;; *) return 1 ;; esac
60
+ }
61
+
62
+ # GHOST DISCRIMINATOR (OBS-482): claude-code AUTOSUGGEST renders its suggestion on the prompt line
63
+ # wrapped in SGR dim; typed text renders default. A dim-wrapped line is rendering, not state.
64
+ is_ghost() {
65
+ herdr agent read "$TARGET" --source visible --lines 14 --format ansi 2>/dev/null \
66
+ | grep -F -- "❯" | grep -F -- "$1" | head -1 | grep -q "$(printf '\033')\[2m"
67
+ }
68
+
69
+ S=$(status_of)
70
+ if [ -z "$S" ]; then
71
+ echo "TARGET_GONE $TARGET — agent get returned nothing (pane closed, or the name resolves nowhere)"
72
+ exit 1
73
+ fi
74
+
75
+ # A pre-existing draft in the box is a decision, not an obstacle: `agent prompt` would APPEND to it
76
+ # and submit both. Superseding someone else's text needs an author and the arrow form — refuse and
77
+ # surface it rather than silently stomping it (D-206: an unattributed line in a box, origin never
78
+ # resolved because it was cleared).
79
+ PRE=$(prompt_line)
80
+ if [ -n "$PRE" ] && ! is_ghost "$PRE"; then
81
+ echo "REFUSED_BOX_OCCUPIED $TARGET — input box already holds: $PRE"
82
+ echo " ANSI-verify first (dim SGR = autosuggest ghost, ignorable). A real draft is superseded by a"
83
+ echo " DECISION, not by this script: send the arrow form naming what you are overriding."
84
+ exit 2
85
+ fi
86
+
87
+ QUEUED=""
88
+ if [ "$S" = "working" ]; then
89
+ if [ "${TKR_INTERRUPT:-0}" = "1" ]; then
90
+ # Esc at most twice, VERIFIED between: the first Esc can merely dismiss a UI surface or stop one
91
+ # step (the operator needed two on 2026-08-18). Unbounded Esc into an idle seat starts clearing
92
+ # state that is not yours to clear.
93
+ for _ in 1 2; do
94
+ herdr agent send-keys "$TARGET" esc >/dev/null 2>&1
95
+ sleep 3
96
+ S=$(status_of)
97
+ [ "$S" != "working" ] && break
98
+ done
99
+ if [ "$S" = "working" ]; then
100
+ echo "INTERRUPT_FAILED $TARGET still working after 2x esc — NOT sending; a directive queued now lands after the turn, which is the failure you set TKR_INTERRUPT to avoid"
101
+ exit 1
102
+ fi
103
+ else
104
+ QUEUED=1
105
+ fi
106
+ fi
107
+
108
+ # Atomic text+Enter honouring the pane's live bracketed-paste mode — never send-text + separate
109
+ # Enter, which is the "sitting unsubmitted" failure by construction.
110
+ herdr agent prompt "$TARGET" "$MSG" >/dev/null 2>&1
111
+
112
+ sleep 2
113
+ PL=$(prompt_line)
114
+ if [ -n "$PL" ] && is_ours "$PL"; then
115
+ # The text is SITTING, not sent — the swallowed-Enter shape. Submitting the existing draft is not a
116
+ # re-send (nothing is duplicated); one bounded Enter, then re-read.
117
+ herdr agent send-keys "$TARGET" enter >/dev/null 2>&1
118
+ sleep 2
119
+ PL=$(prompt_line)
120
+ fi
121
+
122
+ if [ -n "$PL" ] && is_ours "$PL"; then
123
+ echo "SEND_UNSUBMITTED $TARGET — the message is SITTING on the prompt line after send + one Enter."
124
+ echo " Do NOT re-send (it appends and submits both). Read the pane; supersede with the arrow form."
125
+ exit 1
126
+ fi
127
+
128
+ if [ -n "$PL" ]; then
129
+ # Not ours: either autosuggest ghost (dim SGR — benign) or a draft that appeared under us.
130
+ echo "DELIVERED_SUBMITTED $TARGET — prompt line clear of our text; NOTE it now holds: $PL"
131
+ echo " ANSI-verify (dim = ghost). If typed, treat per D-206: discriminate before anyone clears it."
132
+ exit 0
133
+ fi
134
+
135
+ if [ -n "$QUEUED" ]; then
136
+ echo "QUEUED_BEHIND_TURN $TARGET — submitted into a working seat's queue; it is READ at turn end. A freeze-class or superseding directive belongs behind TKR_INTERRUPT=1."
137
+ else
138
+ echo "DELIVERED_SUBMITTED $TARGET"
139
+ fi
140
+ exit 0
@@ -115,7 +115,7 @@ while :; do
115
115
  echo "WAKE: ${#ready[@]} of $# artifact(s) complete with marker '$MARKER' — ${#pending[@]} still outstanding"
116
116
  for f in ${ready[@]+"${ready[@]}"}; do echo " READY $(wc -c <"$f" | tr -d ' ') bytes sha1 $(shasum -a 1 "$f" | cut -c1-12) $f"; done
117
117
  for f in ${pending[@]+"${pending[@]}"}; do
118
- if [ -s "$f" ]; then echo " PARTIAL $(wc -c <"$f" | tr -d ' ') bytes, no marker yet $f"
118
+ if [ -s "$f" ]; then echo " PARTIAL $(wc -c <"$f" | tr -d ' ') bytes, no marker yet $f last-line: $(tail -n 1 "$f" | tr -d '\0' | cut -c1-72)"
119
119
  else echo " NOT STARTED $f <- check whether that seat is BLOCKED; a stalled seat writes nothing"; fi
120
120
  done
121
121
  exit 0
@@ -147,7 +147,10 @@ while :; do
147
147
  echo "WAKE: cap ${CAP}s reached — ${#ready[@]} of $# complete, re-arm"
148
148
  for f in ${ready[@]+"${ready[@]}"}; do echo " READY $(wc -c <"$f" | tr -d ' ') bytes $f"; done
149
149
  for f in ${pending[@]+"${pending[@]}"}; do
150
- if [ -s "$f" ]; then echo " PARTIAL $(wc -c <"$f" | tr -d ' ') bytes, no '$MARKER' yet $f"
150
+ # PARTIAL prints the file's ACTUAL last line: a seat that reports the wrong marker for its own
151
+ # artifact leaves the file complete while this watcher waits forever, and the mismatch is visible
152
+ # only here (measured 2026-08-17: demanded/reported `SWEEP-END`, written `ORDER4-END`).
153
+ if [ -s "$f" ]; then echo " PARTIAL $(wc -c <"$f" | tr -d ' ') bytes, no '$MARKER' yet $f last-line: $(tail -n 1 "$f" | tr -d '\0' | cut -c1-72)"
151
154
  else echo " ABSENT $f"; fi
152
155
  done
153
156
  exit 0
@@ -162,7 +162,7 @@ while [ "$elapsed" -lt "$CAP" ]; do
162
162
  && printf '%s' "$T" | grep -qEi -- "$AUTO_ALLOW_RE"; then
163
163
  auto=$((auto + 1))
164
164
  herdr agent prompt "$TARGET" \
165
- " <-- disregard everything before this arrow (stale unsubmitted draft, auto-detected). ACTUAL: proceed exactly as that draft said: ${T}" \
165
+ " <-- [watch-pending-input auto-supersede] disregard everything before this arrow (stale unsubmitted draft, auto-detected). ACTUAL: proceed exactly as that draft said: ${T}" \
166
166
  >/dev/null 2>&1
167
167
  echo "$(date '+%H:%M:%S') auto-superseded #${auto}: ${T}" >> "${AUTO_LOG}"
168
168
  streak=0
@@ -198,4 +198,20 @@ while [ "$elapsed" -lt "$CAP" ]; do
198
198
  esac
199
199
  done
200
200
 
201
+ # The negative alone is not evidence: a draft can arrive inside the final poll window, and a draft
202
+ # sitting in the box while the seat is WORKING is invisible to the loop above by design (working
203
+ # resets the streak). Measured 2026-08-17 (D-206): this watcher capped with "no sustained pending
204
+ # input in 1800s" while an unattributed instruction sat in the target's box, and blind-vs-timing
205
+ # could not be distinguished afterwards. So the cap line carries one FINAL unsustained read — the
206
+ # last frame of the window, whatever the seat's status — plus the styled bytes so ghost text is
207
+ # discriminable at the only moment it can be.
201
208
  echo "WATCH_CAP_REACHED $TARGET status=$(status_of) — no sustained pending input in ${CAP}s"
209
+ FINAL=$(pending_text)
210
+ if [ -n "$FINAL" ]; then
211
+ echo " final read (UNSUSTAINED — present at cap, not confirmed across polls): $FINAL"
212
+ echo " styling evidence (dim/grey SGR = autosuggest ghost, NOT a draft):"
213
+ herdr agent read "$TARGET" --source visible --lines 14 --format ansi 2>/dev/null \
214
+ | grep -F -- "$FINAL" | head -2 | cat -v | sed 's/^/ /'
215
+ else
216
+ echo " final read: input box empty"
217
+ fi