Skip to content

Bot-to-bot reports duplicate and pile up because cross-line delivery only goes through the parent chain #641

Closed

Description

@hsliuustc0106

Summary

On a real two-level team (Chief → coordinators → specialists) the same conclusion reaches the Chief several times and piles up in the input queue: a specialist reports to its coordinator, the coordinator forwards the same text up, and the group chat already shows the same message. The harness also re-delivers items that arrived while a turn was running ("you read it during your last task"), so stale or duplicate items sit in the queue until a human deletes them.

This is a workflow issue rather than a single bug: it comes from how Bot-to-Bot delivery is routed, what gets re-sent, and the queue having no de-duplication or backpressure.

What happens today

  1. Cross-line work must relay through the parent chain. The tree middleware lets a Bot message only its parent and direct children (plugins/tree/src/middleware.js, treeSendMiddleware). A reviewer and a repo maintainer in different subtrees cannot talk directly, so every cross-line request goes specialist → coordinator → Chief → coordinator → specialist, re-sending the full text at each hop.
  2. The same result exists twice. When the work happens in a group chat every member already sees it, but the Bot also sends the result upward as a message. The recipient then gets both the group message and the direct copy.
  3. No de-duplication. Re-sending an identical conclusion (e.g. a review verdict for a head SHA that has since changed) creates a new queue item; nothing collapses or drops it. Observed on 2026-10-21: a FAIL verdict for PR head 06bc70a was delivered twice after the branch had already been force-updated to a different SHA.
  4. No backpressure. Any number of Bot messages can be addressed to one recipient; each becomes a turn. A busy coordinator relaying every subordinate reply fills the root's queue.

Impact

  • The human sees a queue of pending items in the composer and has to discard duplicates by hand.
  • The root spends turns answering reports it already has, instead of deciding or coordinating.
  • Stale information is reported as if current (the review SHA problem above), which is a correctness risk, not only noise.

Options

A. De-duplicate at delivery. Drop or merge an identical (from, to, text) message within a window; a repeated verdict with the same SHA is dropped and the sender is told so.

B. Make room-visible messages not re-sent. Prompt rule plus a delivery mode: when a Bot reports in a shared room, the upward copy carries only a delta ("no change since the room message") instead of the full text.

C. Allow cheap cross-line edges inside a shared room. A member of the same group may message another member of that group even when the tree edge does not exist. This removes the relay hop without loosening messaging outside the room. Related: #635 (move a Bot), #638 (delete/retire a Bot).

D. Queue ergonomics. Collapse identical pending items, show a count, and allow discarding all duplicates in one action.

E. Rate/volume control. Per-sender limit on unsolicited messages to the same recipient per hour, with the coordinator's scheduled summary as the normal path.

My preference is A + C: de-duplication fixes the visible symptom and the stale-verdict risk, and same-room delivery removes the structural relay without changing the tree policy outside rooms.

Where

  • plugins/tree/src/middleware.js — the parent/child send policy (the room exception would go here)
  • core/src/host/hooks.js — delivery gates and the re-delivery of unanswered items
  • core/src/client/ — how pending Bot messages are queued and shown in the composer
  • docs/subsystems/team.md (planned team mode) — the delivery rules

Acceptance (for whichever option is chosen)

  • In a 3-level tree, a specialist's result reaches the root once, even when it was also posted in a group the root is in.
  • An identical resend within a short window does not create a second queue item, and the sender learns it was dropped.
  • A verdict naming a git SHA that no longer matches the target head is visibly marked stale rather than queued as current.
  • No change to messaging outside tree edges and outside shared rooms.

Activity

  1. Birfy commented on Oct 22, 2026

    @Birfy
    Collaborator

    Triaged: this is a real workflow problem but not yet actionable — three answers turn it into a scoped PR. Please answer; short is fine.

    1. Routing: may a Bot message anyone in the tree, or does it stay parent + direct children? (Allowing direct sends removes the relay hops; keeping the chain and de-duplicating keeps the tree policy.)
    2. Duplicates: should the fix de-duplicate identical text within a window, or drop a relayed line when the same text is already visible in the recipient's group chat?
    3. Backpressure: when the queue piles up, is the wanted behaviour "refuse the send like Dev has not read the last N messages" or "merge the items"?

    Acceptance I would write once answered: a two-level bench (Chief → coordinator → specialist) where the specialist reports one conclusion and the Chief receives exactly one turn carrying it, asserted on turn count, not on text.

    Written-by: Triage

  2. added
    needs-infoWaiting for the reporter or a maintainer decision
    on Oct 22, 2026
  3. Birfy commented on Oct 22, 2026

    @Birfy
    Collaborator

    Design decision (owner, 2026-10-22: decide the design in the issue instead of asking). The questions in the previous comment are answered here; this is the spec to build, agent-ready.

    1. Routing stays as it is. A Bot may message its parent and its direct children only. Opening direct cross-line sends would delete the reason the tree exists (a coordinator that can see who is doing what); the fix is to stop the same text being delivered twice, not to shorten the path.
    2. De-duplicate at delivery, per sender and per recipient Session. When a Bot-to-Bot message arrives, normalise its text (collapse whitespace, trim) and drop it if the same sender already delivered text equal after normalisation to that Session within the last 60 s. Journal the drop (delivery: dedupe <sender> -> <session>) — dropping without a record is the thing we punished elsewhere.
    3. No cross-chat magic. Do not suppress a line because it also appears in a group chat: the group copy is often the only one a person sees, and matching across chats is how a real report gets lost. The double delivery through the parent chain is what (2) catches.
    4. Backpressure is already there, use it. The existing refusal ("has not read the last N messages …") is the correct answer to a full queue; the fix must not add a second queue or a TTL cache of its own.

    Acceptance (test in the host's own suite, two levels):

    • specialist reports the same conclusion twice within 60 s to its coordinator → the coordinator's Session receives one turn, and the second delivery is journalled as dedupe;
    • the same text sent 61 s later makes its own turn;
    • two different senders with identical text are both delivered (the key is sender + text, not text alone);
    • a message already visible in a group is still delivered to a Bot that was not in that group.

    Red without the change: the first case produces two turns (2 != 1).

    Scope: core/src/host/delivery.js (the Bot-to-Bot enqueue path) + one test file. No change to plugins/tree/src/middleware.js, no new setting.

    Written-by: Triage

  4. added
    agent-readyMaintainer-approved spec: an agent may take it. Only maintainers set this; never in a template
    and removed
    needs-infoWaiting for the reporter or a maintainer decision
    questionFurther information is requested
    on Oct 22, 2026
  5. Birfy commented on Oct 22, 2026

    @Birfy
    Collaborator

    Claimed (2026-10-22, branch feat/641-delivery-dedupe).

    Building the design in the issue's decision comment (6332554010): de-duplicate at delivery, per sender and per recipient Session — normalise the text (collapse whitespace, trim), drop a Bot-to-Bot line whose sender already delivered the same normalised text to that Session within 60 s, and journal the drop as delivery: dedupe <sender> -> <session>. No cross-chat suppression (a group copy stays), no new queue or setting, routing and the existing backpressure refusal unchanged. Scope core/src/host/delivery.js + one host test; patches/ds-bot/ regenerated and checked.

    Written-by: Dev4

  6. added
    agent-workingAn agent has claimed this issue (the claim comment names the branch)
    and removed
    agent-readyMaintainer-approved spec: an agent may take it. Only maintainers set this; never in a template
    on Oct 22, 2026
  7. self-assigned this
    on Oct 22, 2026
  8. removed
    agent-workingAn agent has claimed this issue (the claim comment names the branch)
    agent-prPull request opened by an agent
    on Oct 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:automationScheduled tasks and automationarea:uiWeb/desktop UI and copyenhancementNew feature or request

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions