Skip to content

A friend's Bot @-mentioned in a group answers in that group, and its lines can call another participant's Bot #825

Closed

Description

@Birfy

Goal (one observable behavior). In a group that has a friend's Bot as a participant, @-mentioning that Bot gets an answer in that group, drawn as that Bot's line — not a muted receipt and not a message in its own 1:1 chat. A Bot's answer may @ another participant's Bot and the discussion continues in the same group for at most N hops.

This reverses the decision recorded for #80 / #81 / #86 (a receipt instead of a reply) and the "not team mode" note in core-host.md:226. Those issues stay closed as designed; this is a new requirement, not a duplicate. Face-to-face rooms are unchanged.

What happens today (main 3d062b9f)

Two paths, both silent for the group:

  1. The friend's Bot is not in the room yet. sendUserMentions (core/src/host/hooks.js:899-907) sends a 1:1 send({ via: 'user-mention' }), and mentionReceipt (:916-940) posts the muted line "<name>: sent — its replies appear in its own chat, not in this group" (:928). The reply lands in that Bot's own chat.
  2. The friend's Bot is already a participant. :900 (remoteHandleInRoom) skips the 1:1 send entirely (Face-to-face: a human's message to a room's friend Bot is blocked with 'Chief has no grant to that Bot' #143) — the human line in the room is the delivery. The line reaches the friend's home through fanoutRoomLine (core/src/host/room-membership.js:874-922, op: 'line', via: 'room', meta.roomId), and applyInboundRoomShare appends it as a bubble in the projected origin: 'inbound-share' room (:1086-1097). Nothing starts a turn, so no answer ever comes back.

The transport for the answer already exists in both directions: fanoutRoomLine sends a line to every current remote participant, and rt.ingestRemoteRoomLine (:973-996) appends a remote line into the local rooms it belongs to. The missing piece is the turn on the receiving side, plus the hop accounting and the mention signal that says which Bot was called.

What to build

  1. Carry the call, do not guess it from text. The appended room line gains the remote handles it mentions (e.g. calls: ['@handle', …]), computed where mentions are already resolved for the team (hooks.js mentionSpans / SESSION_CHIP, :886-896), and fanoutRoomLine puts that list on the op: 'line' envelope. The receiving home starts a turn only for its own Bots named in that list; a handle-looking string inside quoted text or a fenced block never starts one.
  2. A line that names one of my Bots opens exactly one turn in the projected room. In applyInboundRoomShare, after the line is appended, resolve the named local Bot(s) and start one round in the inbound-share room — the same shape a local group uses, so the answer is an ordinary room line. The Bot's prompt must say which line it answers (room name, author label, seq) and that the text is remote. One answer per Bot per line, keyed by (remoteRoomId, seq, botId) in a capped map like room.faceLine's answered (Face room: held Bot replies show as sent bubbles before approval and a rejected one stays; one Bot answers a single line twice #456).
  3. The answer goes back as a room line. The reply is appended in the projected room and fanned out with the same meta.roomId/via: 'room', so ingestRemoteRoomLine on the origin home appends it in the original group. Not a 1:1 send. The "its replies appear in its own chat" receipt (hooks.js:928) must be gone on the success path; keep mentionReceipt only for deny / hold / refused cases, with the real reason.
  4. Bounded, once per line. Each op: 'line' envelope carries hop (0 for a person's line, +1 for each Bot answer). A line at hop >= N starts no turn on the receiving side. N is stored per room (room.maxHops, default 3); the setting UI may land separately, but the stored field and its cap are part of this issue. A repeated delivery of the same line (the Bot-to-bot reports duplicate and pile up because cross-line delivery only goes through the parent chain #641 dedupe path) must not answer twice.
  5. Approval and fencing are not bypassed. The reply still runs the owner's pending_approval / Auto-send rules (docs/subsystems/social.md:187); a held or rejected reply must produce one explicit line in that group (held for approval / rejected by its owner) instead of nothing. Remote text stays fenced: fanoutRoomLine already fences with fenceUntrusted (room-membership.js:901-903) and isFencedUntrusted keeps an already-fenced body — the new turn must pass the fenced body as remote content, and the inbound append path must not unwrap it.

Acceptance criteria

Tests extend core/test/remote-room.test.js (it covers applyInboundRoomShare) and core/test/rounds.test.js.

  • A. Answer in the group. Home A's owner, in a group where A's Bot and B's Bot are participants, writes @B-bot …. B's home starts one turn; B's answer appears as B's line in A's room. A's room shows no "replies appear in its own chat" line.
  • B. A Bot's answer can call another Bot. B's answer @-mentions C's Bot (a third participant). C answers in the same room, one line, in order. Both answers are ordinary bubbles, not notices.
  • C. Bounded and once. With room.maxHops = 2, the third hop starts no turn and adds no line. The same (remoteRoomId, seq, botId) delivered twice produces exactly one answer.
  • D. Approval. With B's Auto-send off and the reply held, A's group shows one line saying it is held; after the owner rejects, one line says it was rejected; after approve, the answer line appears. Never silent.
  • E. Fencing holds. A remote line containing a @-lookalike inside a quoted or fenced block starts no turn; the delivered answer keeps its fence in the room log.
  • F. Negative control. Removing the turn start in applyInboundRoomShare must make A and B fail; removing the hop check must make C fail. Both must be demonstrated, not just asserted.

Scope

  • core/src/host/hooks.js, core/src/host/room-membership.js (and the room share envelope in core/src/shared/room-share.js), plus tests.
  • Docs: docs/subsystems/core-host.md (the :226 receipt paragraph and the inbound shared rooms section) and docs/subsystems/social.md (inbound shared groups), and a changelog.d/ fragment.
  • This touches core/, so the change must also update patches/ds-bot/files/ in the same commit.
  • Not in scope: face-to-face rooms, new Bot Social endpoints, grants, team mode, or a 1:1 friend chat becoming a group.

Activity

  1. added
    enhancementNew feature or request
    agent-readyMaintainer-approved spec: an agent may take it. Only maintainers set this; never in a template
    area:socialFriends, invites, grants, Bot Social
    on Oct 23, 2026
  2. Birfy commented on Oct 23, 2026

    @Birfy
    CollaboratorAuthor

    Written-by: Dev3

    Claimed: branch feat/825-group-mention-answers (fork Birfy/FlyBot), base 3d062b9f — rebased onto the main that includes #38 if it lands first.

    Reading order before the code: sendUserMentions/mentionReceipt (core/src/host/hooks.js:899-940), fanoutRoomLine + applyInboundRoomShare + ingestRemoteRoomLine (core/src/host/room-membership.js:874-1097), the op: 'line' envelope in core/src/shared/room-share.js, and the round shape a local group uses so the answer is an ordinary room line.

    Will report the acceptance walk (A–F) with the two negative controls from criterion F demonstrated by reverting each half.

  3. added
    agent-workingAn agent has claimed this issue (the claim comment names the branch)
    on Oct 23, 2026
  4. self-assigned this
    on Oct 23, 2026
  5. changed the title [-]A friend's Bot @-mentioned in a group answers in that group, with a bounded Bot-to-Bot discussion[/-] [+]A friend's Bot @-mentioned in a group answers in that group, and its lines can call another participant's Bot[/+] on Oct 23, 2026
  6. removed
    agent-readyMaintainer-approved spec: an agent may take it. Only maintainers set this; never in a template
    on Oct 23, 2026
  7. removed
    agent-workingAn agent has claimed this issue (the claim comment names the branch)
    on Oct 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:socialFriends, invites, grants, Bot SocialenhancementNew feature or request

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions