Repository navigation
Friend DM: a shared Bot's reply to the grantee is silently denied (grantee's Bot not shared back), never held or delivered #272
Description
Summary
A person writes to a friend's Bot that was shared with them. The Bot answers, but the answer never reaches the person. Nothing is held, and neither side sees an error. Because B's Chief was not shared back to A, A cannot address it, so the reply is denied without any notice.
Environment
- FlyBot main
ab723ac(after fix(ui): + menu is a popover next to +; one Copy invite entry; 6 digits room hint (#173) #265), core + plugins/social + plugins/tree on@deepseek-ai/dsh@0.2.0-rc.2, Node 24. - Two fresh installs on one Linux box: A
:3090(owner SelfA1220,@selfa1220.home) and B:3091(owner SelfB1220,@selfb1220.home). Bot Socialhttps://47-80-69-220.sslip.io. - Both Chiefs on
ark/deepseek-v4-flash(real model). - A's Chief is shared with B through a per-Bot invite (grant
grt_01M56M32HBPKTGVE0G51AM23C4, grantee@chief.selfb1220.home). B joined with its Chief as the talk-through Bot. B's Chief is not shared back (by design, Per-Bot grants leak: accepting a Helper invite exposes the joiner's Chief; face-room Chief shows in Friends' Bots; Manage access wrong/raw #138/Regression of #138: joining a friend's invite still puts the joiner's Chief on the inviter's main list #161). - Scheduled product self-test, focus A (friend DM), browser run 2026-10-18 12:27–12:31 Asia/Shanghai. Screenshots stayed on the test machine; what they show is written out below.
Repro
- On B, open SelfA1220's Chief in the sidebar (it has the Friend's Bot marker).
- Type
Hi from B, what's 2+2?and send it. - Wait at least 1 minute, then reload B.
Actual
- B: the line shows as B's own right-aligned bubble and is not held (correct, Direct chat with a friend's Bot: my own typed line is sent as Chief and held for my approval (regression of #179 in DMs) #227). A "Weighing the options…" row with the Bot's avatar appears, then disappears after about 20 s with no reply. After a reload, B's chat still has only B's line. Screenshot: B's DM with SelfA1220's Chief after the waiting row went away, showing only B's line.
- A: the line goes into A's own Chief main chat, mixed in with A's own conversation, shown as the person (
typedBySelfB1220). A's Chief answered4.there (turn completed,deepseek-v4-flash). That answer was not held: A has no approval card, andflybot/approvalsandsocial/approvalsare both empty on A and B. It never reached B. Screenshot: A's Chief chat showing B's line and then4.. - The
web.logfiles have no warning. A'sstate.exchangeshas only the inbound request and no reply.
Expected (design)
docs/subsystems/social.mdinvariant 8 (A friend Bot's reply to a typed DM is held on its owner and no approval card ever shows (overlay hook crash, no in-chat card for the replying Bot) #254): "A friend's Bot's reply to a line you typed (or to any request) goes back throughbot.sendas anauto-replyand, unless Auto-send is on for that pair, is held for the replying Bot's owner." So A should see the held reply in A's Chief chat, with the in-chat card (Approve / Always approve / Reject). After approval, or with Auto-send on for that pair, the reply should land in B's DM with SelfA1220's Chief.- If a reply really cannot be sent, someone should be told: at least A's owner in that chat, and B should not see a waiting row that just disappears.
- Answering the question from the run: yes, the reply should be held for A's approval (the replying Bot's owner) unless Auto-send is on for B. The person's typed line is unheld only on the sender side (Direct chat with a friend's Bot: my own typed line is sent as Chief and held for my approval (regression of #179 in DMs) #227).
Hunch (code read on ab723ac, not verified)
- The inbound line arrives with
source.remote.handle = @chief.selfb1220.home(B's talk-through Chief).turns.jsL443answer()→rt.flybotReplyRemote→hooks.jsL984send({ to: { kind: 'remote', handle: '@chief.selfb1220.home' }, role: 'reply', via: 'auto-reply' }). reach()allows it: A's Chief has a grant whose grantee is@chief.selfb1220.home.- The
socialsend middleware (plugins/social/src/social.js~L1025) then callsremoteBot(msg.target.handle). That only knows Bots granted to A (list_remote_bots). B's Chief was never shared back, so the lookup isundefined, and the middleware returns{ action: 'deny', reason: '@chief.selfb1220.home is not a Bot of a friend on Bot Social' }. This happens before the hold branch. replyRemoteonly.catch()es thrown errors. A deny verdict resolves normally, so nothing is logged or shown. That would explain no hold, no card, no warning, and no reply.- A friend Bot's reply to a typed DM is held on its owner and no approval card ever shows (overlay hook crash, no in-chat card for the replying Bot) #254 and A friend Bot's reply the owner approved never leaves: Bot Social holds it a second time, on a card nobody sees #258 were tested with a setup where the replier could see the requester's Bot. With the default one-way per-Bot grant (no reverse grant), this path is never reachable. A reply addressed to the Bot that carried a request to a granted Bot probably needs to be allowed (and held), even when that Bot is not in Friends' Bots. The Auto-send toggle for that pair also needs a home, because A has no friend-Bot row for B.
Note (by design, not part of this bug)
The request landing in A's Chief's own chat follows turns.js L165 ("the turn stays in the Bot's own chat, where the user sees it"). Still, it reads poorly: B's question and A's Chief's answer are mixed into A's own conversation, and A's sidebar has no entry for SelfB1220. The model's reasoning even assumed "the user does not see it." Worth a design look once the reply works.
Related: #254, #258 (closed; different root cause), #227, #138/#161 (no reverse grant), #273 (Bot sends to a friend's Bot refused), #275 (header of the inbound line).
Activity
Held reply to a friend: held in place, decision on the bubble, Sent /…