Skip to content

Read the Codex composer through its idle animation - #588

Merged
umputun merged 2 commits into
umputun:masterfrom
paskal:fix/codex-composer-particles
Sep 11, 2026
Merged

Read the Codex composer through its idle animation#588
umputun merged 2 commits into
umputun:masterfrom
paskal:fix/codex-composer-particles

Conversation

@paskal

@paskal paskal commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

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.

image

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.

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.
@paskal
paskal requested a review from umputun as a code owner September 11, 2026 08:17
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.
@paskal
paskal force-pushed the fix/codex-composer-particles branch from 923170b to ec99ee0 Compare September 11, 2026 16:33

@umputun umputun left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@umputun
umputun merged commit 43f439c into umputun:master Sep 11, 2026
6 checks passed
@paskal
paskal deleted the fix/codex-composer-particles branch September 11, 2026 17:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants