Skip to content

fix(muse): blank rows in the draft no longer lose the composer - #275

Merged
AltanS merged 1 commit into
AltanS:mainfrom
jpcarranza94:fix/muse-blank-row-draft
Sep 24, 2026
Merged

AltanS merged 1 commit into
AltanS:mainfrom
jpcarranza94:fix/muse-blank-row-draft

Conversation

@jpcarranza94

Copy link
Copy Markdown
Contributor

Fixes #274 (which supersedes the #261 bargain).

What broke, live on 1.12.1: any message containing a blank row (a paragraph break) wedged its Muse pane. The first send typed but never submitted (verify reads null forever → stuck spinner); from the next poll the unread-dialog card covered the live box and locked the composer; and every two-tap retry appended a full duplicate, because the force path types without the pre-clear sweep. Observed: one message typed six times, no way to clear the box from the phone (Esc no-ops on a live box; Ctrl+C from the terminal cleared it).

Root cause: locateTail walked up from the bottom rule over continuation rows only, so a blank draft row stopped the walk and prompt resolved null — a healthy box reading as "no composer". Reproduced against the real adapter over the captured screen: before, composerReady=false tail.prompt=null draft=null → card FIRES; after the fix, composerReady=true tail.prompt=36 draft=<1134 chars folded> → no card.

The fix (markers.ts): the walk steps over blank rows as part of the draft run, under the same MAX_DRAFT_ROWS bound. The ❯ row itself still stops the walk before transcript, and approval still resolves null at its non-continuation subject rows — verified by the unchanged approval/trust/dialog suites. extractInputDraft already folds blanks out, matching FOLD_SEAM, so verify passes once the prompt binds. Also lists the rotated /loop 10m <prompt> schedules a recurring prompt placeholder tip (seen live the same night) so it stops reading as a ghost draft.

The flipped test is maintainer-sanctioned: unread-dialog.test.ts pinned the card-on-blank-draft behavior with the note "When locateTail tolerates a bounded blank run inside the draft, this test must be INVERTED (card null, composerReady true), not deleted." Inverted exactly that way, keeping the construction. The two new fixtures auto-enroll in the pinned corpus, the ready/raw/conformance sweeps, and the per-adapter card set.

Verification: web suite 8746 passed / 41 todo / 0 failed, oxlint 0/0, both typechecks clean, vite build green, plus the before/after adapter run over the live capture above.

locateTail's walk stopped at the first non-continuation row, so a paragraph break inside the box resolved prompt null: verify read null forever (stuck send), the unread-dialog card drew over the live box, and each two-tap retry appended a full duplicate. The walk now steps over blank rows under the same bound; approval still resolves null at its subject rows. Also lists the rotated /loop placeholder tip as non-draft.
@github-actions github-actions Bot added area: web Phone PWA — UI, mirror, composer, service worker area: harness Per-agent adapters and send guards (claude/codex/pi/omp) bug Something isn't working labels Sep 23, 2026
@AltanS
AltanS merged commit 9b3a59f into AltanS:main Sep 24, 2026
3 of 4 checks passed
AltanS added a commit that referenced this pull request Sep 24, 2026
PR #275 lets locateTail step over blank rows, so the rows that still stop
the walk carry the safety: the pointer and the column-0 question. The new
case takes an approval frame, renames its question to one no detector
knows and tears off the pointer, the screen where the walk crosses blanks
furthest. It must still find no box, refuse the composer and read no
draft, so the unread-dialog card keeps the way out.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
AltanS added a commit that referenced this pull request Sep 24, 2026
…-built

The Muse corpus section promises byte-faithful captures, and the four
PRs each added fixtures made by editing one of those captures: the frame
is real, the box or dialog rows carry text seen live. Say so, the way
the Codex and Pi reconstructions already do, so nobody reads their
colours as measured. Doc-only, so no CHANGELOG line
(SKIP_VERSION_CHECK=1: the hook counts any file under web/src).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
AltanS added a commit that referenced this pull request Sep 24, 2026
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@AltanS

AltanS commented Sep 24, 2026

Copy link
Copy Markdown
Owner

Thanks @jpcarranza94, this goes in as it stands, with one test of ours on top. You inverted the pinned unread-dialog test the way its note asked instead of deleting it, and you ran the adapter before and after on the live capture, which saved me the question. Our commit pins where the blank-row walk now stops, the pointer and the column-0 question, so a box-less dialog still gets its card. Your authorship is kept, the changelog credits you, and the PR closes when the branch merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: harness Per-agent adapters and send guards (claude/codex/pi/omp) area: web Phone PWA — UI, mirror, composer, service worker bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Blank row in Muse draft loses the composer: verify never passes, retries append duplicates, card locks sends

2 participants