Skip to content

tui: a failed playbook live edit is swallowed — no message, no retry, no re-sync #1089

Description

@edwin-zvs

The TUI's per-keystroke Playbook sync discards the daemon's answer when it is an error:

let Ok(result) = self.client.playbook_edit(params).await else {
    return;
};

(crates/cli/src/app/editor.rs ~line 1526 @ ad47152)

The edit is anchored (old_stringnew_string, playbook_anchored_live_edit), so it fails whenever the daemon's document no longer contains that anchor — after a local undo (#1088), or when an agent rewrites the region you are typing in between two keystrokes. When it fails:

  • no status message,
  • no retry,
  • no re-fetch,
  • and popup.saved_markdown is left stale, so playbook_popup_has_unsaved_edits is now true and on_playbook_state stops adopting remote changes (crates/cli/src/app.rs ~line 10155) — by design, to protect unsaved work.

The net effect is a Playbook that silently stops both publishing and receiving. Every later keystroke fails against the same stale anchor. The only signal is the * modified chip in the pane title, which reads as ordinary "you have unsaved edits", not "your last 40 keystrokes are not in the document".

Repro

  1. Open a Playbook in the TUI, type a few characters (synced).
  2. Force an anchor mismatch — press C-x u (tui: playbook undo (C-x u) never reaches the daemon, then every later keystroke is silently dropped #1088), or have an agent rewrite the line under the caret.
  3. Keep typing.

Observed: the TUI buffer advances, the daemon's document does not, and an agent edit made afterwards does not appear in the TUI.

Expected

A failed live edit is a recoverable conflict, not a terminal state. The merge machinery already exists and works: C-x C-s on the same diverged buffer produced playbook merged with agent edits (version 42) with both sides intact.

Suggested fix

On playbook_edit error, fall back to the save/3-way-merge path (optionally after one retry with a re-fetched base), and surface a short status. That single change also bounds the blast radius of #1088 to one lost character.

Acceptance criteria

  • A failed live edit produces a visible status message.
  • The client re-converges with the daemon automatically (merge or rebase) rather than staying diverged until a manual C-x C-s.
  • Regression test: a live edit whose anchor is missing server-side still ends with client and daemon documents equal.

Found during a hands-on UX audit of the Playbook in the TUI and web UI.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions