acpmux: send --supersede KEY replaces your prompt still queued under KEY

Merged
TE
15d ago
+667-24

What

acpmux send --supersede KEY: a prompt replaces the same sender's prompts still waiting in the queue under the same KEY.

  • session/prompt takes _meta.acpmux.supersede (a non-empty string of at most 256 bytes; anything else is refused with supersede.invalid).
  • A replaced prompt leaves the queue the way an unsent agent message does (remove_queued):
    • its session/prompt answers withdrawn;
    • its queue_removed record says reason: "superseded" and supersededBy;
    • a restart never runs it. The key is kept on the queued record, so a prompt restored after a restart can still be replaced.
  • Only a prompt that still waits is replaced. One whose turn started, or one being sent into the running turn, stays.
  • "Same sender" is the queue's own notion of it (digest.rs agent_sender): an agent's name (--from, or the session the connection runs in), or the person.
  • The new prompt's acceptance carries replaced (a count) and replacedPromptIds.
    • acpmux send prints replaced N queued under queued/steered.
    • --json adds replaced and replacedPromptIds.
    • Without --supersede the output is unchanged.
  • An edit of a waiting prompt drops its key, as it drops its provenance: the person rewrote it.

Why

acpmux prompts queue behind running turns, often 3 to 6 deep, so a lane reads a correction after the order it corrects. That is how one of today's tasks bounced between ci-speed and machine-mesh three times.

Tests

Written first:

  • d8985588 adds the tests.
  • 93581938 makes the tests count a prompt that went in with an agent-message turn as run, which also makes the "never ran" checks stricter.
  • a661042d is the implementation.

tests/hub_integration/prompt_supersede.rs (end to end through the protocol handler with the fake agent):

  • a same-key prompt is replaced and never runs, and its wait answers withdrawn;
  • another sender's prompt, another key's prompt and an unkeyed prompt stay queued;
  • a running turn under the key is never replaced;
  • a prompt queued before a restart is still replaced;
  • a bad key is refused.

Unit tests in cli/output.rs:

  • through a real unix socket, queue_prompt with a key replaces the earlier prompt, and sent_lines prints replaced N queued;
  • the key goes in _meta.

Results on cmux16:

  • Before the implementation, all 5 integration tests failed (the acceptance had no replaced, and a bad key ran).
  • At the implementation:
    • cargo test -p acpmux: every binary is ok, including 518 unit and 362 hub_integration tests.
    • cargo clippy -p acpmux --all-targets -- -D warnings is clean.
    • cargo fmt --check passes after 4a3e141d.

No overlap with acpmux-unify's open PRs: #23027 and #23598 don't touch the queue or the prompt path.

Agent session: cosmic-gray

๐Ÿค– Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

Adds acpmux send --supersede KEY so a correction replaces the same sender's prompts still queued under KEY instead of being read after the order it corrects.

Behavior

  • Replaced prompts leave the queue like withdrawn ones: their session/prompt answers withdrawn, the queue_removed record says reason: "superseded" and supersededBy, and a restart never runs them; a key survives a restart, so a restored prompt can still be replaced.
  • Only prompts still waiting are replaced; one whose turn started stays. Replacement happens only where the new prompt is committed โ€” under the queue lock that puts it in, when its turn starts at once, or when it is steered in โ€” so a prompt refused while the chat moves replaces nothing and two sends under one key can't both stay.
  • "Same sender" follows the queue's own notion (agent name via --from, or the session the connection runs in); a forwarded keyed prompt names that session to the peer. Editing a waiting prompt drops its key.
  • _meta.acpmux.supersede must be a non-empty string of at most 256 bytes; anything else is refused with supersede.invalid.
  • acpmux send prints replaced N queued (replaced ? queued from a daemon that predates the key); --json adds replaced and replacedPromptIds. Without --supersede the output is unchanged.