Skip to content

openclaw-tps-mail: dispatcher replies go to a dead-drop outbox (4,159 unsigned files since May) — deliver one explicit, signed, idempotent reply per inbound #338

Description

@tps-flint

openclaw-tps-mail: the dispatcher reply path writes every assistant text block to a dead-drop outbox; make delivery one explicit, signed, idempotent reply

Observed (rockit, 2026-09-02)

  • For every inbound mail, the plugin's outbound ("reply … via dispatcher, route=outbox" in gateway.log) writes each assistant text block of the agent's turn as a separate reply file. Intermediate narration ("Now let me check…", "All five SHAs match…") included.
  • The recipient (flint) has no tps-mail binding in openclaw.json, so the plugin treats it as remote and writes to ~/.tps/outbox/new/. Nothing consumes that directory (the relay watches ~/.tps/mail). Result: 4,159 files since 2026-05-23, all unsigned, no messageId, 4,143 addressed to flint (kern 3,428, sherlock 726). Archived to ~/.tps/outbox/archive-20260902/.
  • Real delivery has therefore always been the agent's explicit tps mail send tool call. An agent whose verdict exists only as a final assistant message has delivered nothing while the plugin acks the inbound as complete (milton#30 review, 2026-09-02 14:23Z).

Required behavior

  1. One reply per inbound, at most. The dispatcher sends only the agent's final assistant message, never intermediate blocks.
  2. Idempotent with explicit sends. If the agent already ran tps mail send <sender> during the turn, the dispatcher sends nothing (the explicit send is the delivery). No double-write.
  3. Local recipients are local. A recipient with a maildir under ~/.tps/mail/<id>/ on this host is delivered to <id>/new/ in the standard signed envelope — never to ~/.tps/outbox. ~/.tps/outbox is only for recipients that are genuinely remote (no local maildir and no binding).
  4. Signed, with a messageId. Dispatcher replies carry the agent's Ed25519 signature and a messageId exactly like tps mail send; an unsigned bare envelope is never written anywhere.
  5. Loud, not silent. If a reply cannot be delivered (no local maildir, no remote route), log a warning naming recipient + reason; do not write to a directory nothing reads.

Must-fail tests (each must be RED before the fix)

  • inbound from a local, unbound sender → agent turn with two text blocks and no explicit send → exactly ONE file in ~/.tps/mail/<sender>/new/, signed, with messageId; zero files in ~/.tps/outbox/new/.
  • same, but the agent runs tps mail send <sender> mid-turn → zero dispatcher files (the explicit send is the only delivery).
  • recipient with neither maildir nor binding → one warning line, zero files.

Refs ops-8mhg (private tracker). Flint gates; K&S review after reviewer assignment.

Activity

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

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