Read the Codex composer through its idle animation - #588
Conversation
Codex draws an idle animation of braille particles across the composer box, and in the observed layout the particle row above the prompt became the first line of the trailing input block, so no live prompt was recognised and sends were refused with an unrecognisable-prompt error. Drop rows that hold nothing but particles, so they cannot hide the prompt row, and ignore particles when comparing the placeholder that marks an empty composer. Retained composer text keeps every character, braille included, so ownership checks, cleanup and delivery verification are unaffected.
Dropping particle-only rows let the prompt be recognised, but a send still failed once text was in the composer: the animation keeps drawing single particles over typed characters for seconds at a time, so the typed chunk never matched, no two screen reads stayed identical long enough to count as settled, cleanup could not locate the owned text, and a queue notice with no blank row under it hid the prompt after submit. For the Codex pane only, compare screen rows with a particle standing for the one cell it covers, or for an empty cell when it trails the text; treat the cell after the prompt marker and the two-cell indent of wrapped rows as decoration; judge a typed chunk settled once the expected text has matched for the settle delay; judge cleanup by the owned spans and cursor column; read the empty placeholder through particles; and treat particle-only rows as blank when the trailing input block is delimited. Claude's composer is still compared verbatim. A particle can hide a wrong character until it moves, so the pre-submit check now verifies the visible body against the intended text again, asking only for the visible suffix the final chunk needed so a long body whose beginning scrolled away still submits; a wrong or foreign character that is visible still fails verification and cleanup. A particle that covers the only character of a wrapped row hides that row, and such a send fails closed until the particle moves.
923170b to
ec99ee0
Compare
umputun
left a comment
There was a problem hiding this comment.
lgtm, it does what it claims: all three breakages from #590 are closed on the code, the Claude path is byte-identical, and shell mode, dialogs, a particle over the chevron and a glued notice still fail closed.
one note, not blocking. cookbook/two-agent-chat/peer-chat.py:760 - a trailing particle can stand for a covered character or for an empty cell, so k missing trailing characters plus k particles in the freed cells read as the intact text at the chunk check, the marker-removal check and the pre-submit recheck alike: …pin⠁ passes for "ping". test_particle_cannot_hide_a_missing_character checks a two-cell length mismatch, not this case, so its name promises what the code does not do. Fix: count an expected cell as verified only once a settle poll has seen it unmasked and withhold at timeout otherwise, plus the k-for-k negative case. Reachable only when a keystroke drops or someone backspaces mid-send with a particle parked on the freed cell, hence a note.
btw the animation has an off switch, whimsy = false under [tui] in the Codex config. Worth a line in the README's Limits for a reader who would rather turn it off than read through it.
Previously, a send to the Codex pane was refused with "target composer prompt is not recognisable" while Codex drew its idle animation. The animation sprays braille particles (U+2800-U+28FF) across the composer box, and in the observed layout the particle row above the prompt became the first line of the trailing input block, so no prompt row was matched. Once that was fixed, a send still failed with text in the composer: the animation keeps drawing single particles over typed characters for seconds at a time, so a typed chunk never matched the screen, no two reads stayed identical long enough to count as settled, cleanup could not locate the owned text, and after submit a queue notice with no blank row under it hid the prompt.
After this change, for the Codex pane only, particle-only rows count as blank when the trailing input block is delimited, so they neither hide the prompt row nor glue a queue notice to it. When screen rows are compared with source text, a particle stands for the one cell it covers, or for an empty cell when it trails the text; the cell after the prompt marker and the two-cell indent of wrapped rows are decoration. A typed chunk counts as settled once the expected text has matched for the settle delay, cleanup is judged by the owned spans and cursor column instead of the raw text, and the empty placeholder is read through particles. A particle can hide a wrong character until it moves, so the pre-submit check verifies the visible body against the intended text once more, asking only for the visible suffix the final chunk needed so a long body whose beginning scrolled away still submits. Claude's composer shows no animation and is still compared verbatim: a wrong or foreign character that is visible fails verification and cleanup as before, and a message that itself contains braille still verifies. One case stays fail-closed: a particle that covers the only character of a wrapped row makes that row look like an animation row, and the send is withheld until the particle moves.
Verified with twenty-two new cases in
test_peer_chat.py, covering the prompt through the animation, particle-tolerant row matching, settling on the expected text, cleanup through moving particles, the placeholder and the queue notice, the full chunk path for both agents, and the clipped composer before submit in Latin and Cyrillic; the cases that encode the new behaviour fail on master and pass here. The full suite is green at 162 tests, and a live send to an animating Codex pane typed, verified, submitted and was accepted.