Skip to content

harness: queue-row ✎ closes immediately; edit latch survives longer-session hydrate #676

Description

@btipling

Summary

PR #666 merged (5db96bb) with two Major L1 findings from the last adversarial review still open. In-canvas queue edit is effectively unusable, and a stale edit latch can ghost the band and block promote after a session hydrate.

Source review: PR #666 comment @ 5a910c7 (CONCERNS). 5a910c7 claimed to fix both; it did not.

Major 1 — blur-save closes ✎ on the first editor frame

queue_band.paint (native/harness/src/ui/queue_band.zig ~93–105) treats “TE not focused this frame” as blur and calls saveEditcloseEdit.

  • beginEdit does not focusWidget.
  • Frame 1 of ✎: editing was false at paintRow, so no textEntry is created; queue_edit_textentry_id stays stale or null.
  • Frame 2: TE is created, id stored, then focused == null or focused != te_id is almost always true (focus is still the ✎ button). Editor closes.
  • ui.zig n < prev_msg clears queue_editing_index / buf but not queue_edit_textentry_id. After New/Clear the next ✎ compares against a dead widget id and save-closes in the same frame as beginEdit.
  • focused == null is treated as blur (unknown ≠ blur).

Break: Busy → enqueue ≥1 → click ✎ → field flashes at most one frame → preview row returns. Cannot edit. After New/Clear, even the flash is gone.

Major 2 — latch drop is still n < prev_msg, not queue SoT

inv_clear_messages already submit_queue.clears. The UI latch is only dropped on ring shrink (ui.zig ~379).

Rail / restore hydrate is hydrateMessagesclearMessages + push in one batch (lib/harnessBridge.ts). Next frame n is the new session length. If that length ≥ last_msg_count, the branch never runs.

FIFO is empty; queue_editing_index stays Some. desiredHeight still treats n==0 && editing as an 80 px ghost band (“0 queued”). Trigger A (ui.zig ~135) still refuses tryPromoteQueued.

New/Clear happens to work (one system line → n < prev). Session switch to a longer transcript does not.

Break: Session A (3 rows) → Busy, enqueue, ✎ (or leftover latch) → switch to session B (20 rows) → ghost band; next Busy follow-ups never promote until an unmarked Escape.

Suggested fix (not locked — for a later plan)

  1. Blur-save: focusWidget on the open frame; ignore blur until the TE id has been seen focused at least once; treat focused == null as unknown, not blur; clear queue_edit_textentry_id on every latch drop.
  2. Latch vs SoT: if queuedCount()==0, drop queue_editing_index / te id / draft. Do not proxy through ring n < prev_msg.

Non-goals

Refs

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingharnessHarness / agent UIui

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions