* fix(runtime): hold tui-idle until a cold-starting Claude has painted (STA-2380)
A shell auto-title (oh-my-zsh preexec) names the pane `claude` the moment
the command execs. Claude's `idle_title` rule counts that bare name as weak
idle once output has been quiet for 3s, so a Claude that took >3s to draw
its first frame settled `terminal wait --for tui-idle` on a blank screen.
`dispatch --inject` then pasted into a TUI that had not mounted yet and the
prompt was lost.
Name-only idle lanes (agent rule verdicts that require quiet, and the
sustained-title lane) now also require that the running command has painted
something since the shell's OSC 133;C command-start marker. Shells without
the marker keep today's behavior.
* fix(runtime): corroborate Claude's name-only idle with its own composer marker (STA-2380, C1 F1)
Orca's zsh OSC 133;C hook is first in preexec_functions, so a later user or
framework preexec hook (zsh-you-should-use, a custom echo) prints after the
command-start marker and before Claude runs. The any-visible-byte paint latch
counted that text as Claude's paint, so a silent cold start under such a hook
still settled tui-idle ready-weak on the shell's bare `claude` title.
For agents whose worker start already trusts their composer marker (Claude),
"painted" now means that marker (`❯`+NBSP after DECSET 2031, which no shell
sends) arrived since the command started. Other agents keep any-byte paint;
markerless shells and output gaps keep the permissive default.
Evidence: a real-zsh live-shell test under the production wrapper with
oh-my-zsh title-only, p10k/starship-style silent, and you-should-use-style
printing hooks, replayed through the real wait; runtime tests for the hook
text, a boot banner, the positive bare-title + composer path, and worker-start
readiness plus brief delivery timing.
* fix(ci): route command-paint attribution sources to shell_contracts; attribute live-shell bytes by stream offset (STA-2380, C2 F1/F2)
- pr-shell-contract-prefixes: the live-shell test, terminal-command-paint.ts,
tui-idle-evidence-source.ts and draft-paste-ready-scanner.ts route to the
shell_contracts job; a routing test reads the job's step from pr.yml and
asserts every listed test routes there.
- tui-idle-zsh-preexec-hook-order.live-shell.test: locate the DECSET 2031
anchor by offset in the accumulated stream, split a straddling read, carry
pending escapes across the shell/agent halves, and assert attribution is
invariant under coalescing and 3-byte re-chunking.
- terminal-command-paint: disclose the accepted trade-off (a known Claude with
marker history but no supported composer signal times out; markerless shells
and output gaps still fail open; no version cutoff claimed).
* test(ci): stream-offset launch-order proof, route tui-idle-evidence.ts, parse the whole shell-contracts step (STA-2380, C3-1/2/3)
- live-shell test: assert the launch order on the joined bytes by stream
offset (133;C, then the user hook's output, then the agent's anchor and
composer); no read-boundary or timestamp assertions remain. Re-chunk
cases add a split anchor and a shell-tail/agent-start coalesced read.
- pr-shell-contract-prefixes: route tui-idle-evidence.ts, the readiness
evaluator the live-shell replay exercises.
- routing ratchet: read the step's run script through the YAML parser so
a blank line or later command cannot truncate it; cross-check against
the real-shell tests UNIT_EXCLUDE drops so a dropped entry fails rather
than a smaller count; fixture tests for blank line, exact list, missing
step.
* test(ci): answer compinit's insecure-directory prompt in the zsh preexec live-shell test (STA-2380)
Ubuntu's global zshrc runs a plain compinit, which on CI runners stops at
"Ignore insecure directories and continue [y] or abort compinit [n]?"
before zle exists, so the stand-in never launched and the shell-contracts
job failed with "no composer frame from the stand-in". Answer the prompt
with y as zsh-startup-hook-pty-harness.ts does. The prompt bytes precede
Orca's OSC 133;C marker, so stream-offset attribution is unchanged.