Repository navigation
Description
Summary
When two friends have each accepted the other's invite, People with access on both homes says Nobody has this Bot yet. Invite a friend to grant it., but the shares are still live on Bot Social. The owner cannot see who has the Bot and cannot Revoke it. Per-Bot grants are the core promise of sharing, so the owner must always see and control every live share.
The root cause is in FlyBot. I confirmed it by reading the code and checking the API (see Verification). It is a side effect of the #383 fix (#387).
Environment
- FlyBot main
a7adfe0882d3e37c81616871e24b442bd4a5047f, core + plugins/social + plugins/tree on@deepseek-ai/dsh@0.2.0-rc.2, Node 24.21.0. - Two fresh installs on one Linux box: A
:3090(owner SelfA1233,@selfa1233.home, one Bot: Chief =@chief.selfa1233.home) and B:3091(owner SelfB1233,@selfb1233.home, one Bot: Chief =@chief.selfb1233.home). Bot Social prodhttps://47-80-69-220.sslip.io. Both Chiefs onark/deepseek-v4-flash. - Product self-test 2026-10-20, focus C (Invites and grants), browser run 12:37–12:42 Asia/Shanghai, API checks about 12:45 Asia/Shanghai. Screenshots stayed on the test machine; what they show is written out below.
Reproduction
- On A: + New… > Add friend > Copy invite link for Chief. On B: + New… > Add friend, paste the link, Accept invite. Bot Social creates relationship
rel_01M5BSN98FSFWGS9V9MMRRF3AE(12:38:35 Asia/Shanghai).- On A, Chief settings > Sharing > People with access correctly shows
SelfB1233 (@selfb1233.home) Auto-send Revoke.
- On A, Chief settings > Sharing > People with access correctly shows
- On B: Chief settings > Sharing > Invite to this Bot > Copy link (
https://47-80-69-220.sslip.io/i/…). On A: Add friend, paste, Accept invite. A showsSelfB1233 shared Chief with you., andChief SelfB1233 / Friend's Botappears in A's list. - On B, open Chief settings > Sharing again. It shows
Nobody has this Bot yet. Invite a friend to grant it., even after 2 reloads and 15 s. - On A, Chief settings > Sharing now also shows
Nobody has this Bot yet., although B still has A's Chief in its list and can message it.
Screenshot (B, Chief settings > Sharing): The Sharing card shows the hint Invite grants Chief only. Revoke anytime in People with access. and the full invite link with Copy link, Copy with instructions and New link. Under People with access it reads Nobody has this Bot yet. Invite a friend to grant it. Behind the dialog, B's sidebar still lists Chief SelfA1233 with the preview hi from B.
Verification (local API + Bot Social, about 12:45 Asia/Shanghai)
social/accessfor each home's own Chief returnsgranted: false, grants: []on both A and B.- B
social/remote-bots {fresh:true}still lists A's Chief withgrantId grt_01M5BSN98G852C68465C8807C1inrel_01M5BSN98FSFWGS9V9MMRRF3AE. So A's share to B is live on Bot Social, but A's UI hides it and A cannot revoke it. .dsh/bot/flybot-social-settings.jsonon both homes hasjoinedRelationships: { "rel_01M5BSN98FSFWGS9V9MMRRF3AE": true }. A hasinboundBots: { "@chief.selfb1233.home": true }and B hasinboundBots: { "@chief.selfa1233.home": true }.- Both invites resolved to one relationship id. In Bot Social
src/platform.tsjoinInvite, a join between existing friends whose inviter has only a reply-only grant goes throughregrantViaInvite. That function adds the inviter's full grants to the existing relationship and returns the samerelationship_idwithregranted: true.
Root cause (confirmed by code reading)
plugins/social/src/social.jsisTalkThroughGrant()treats a grant as talk-through when its relationship is insettings.joinedRelationshipsand its grantee is insettings.inboundBots.syncOutgoingGrants()then drops it from the stored grants, sosocial/accessand People with access never show it.- After step 2, both homes recorded the same relationship as one they "joined" (B in step 1, A in step 2). So on both homes the real share is classified as talk-through and hidden.
- Bot Social already tells FlyBot which grants are only for replying.
list_bot_grantsreturnsreply_onlyon every grant (platform.tslistBotGrants, from CI: cache npm, manual runs, Windows/flaky test fixes; auto-approve sync #23).normalizeGrant()inplugins/social/src/mcp-client.jsdrops that field, so FlyBot has to guess.
Actual vs expected
| Actual | Expected | |
|---|---|---|
| B after A accepts B's invite | Nobody has this Bot yet |
SelfA1233 (@selfa1233.home) Auto-send Revoke |
| A after both invites | Nobody has this Bot yet while B still has A's Chief |
SelfB1233 (@selfb1233.home) Auto-send Revoke |
| Revoke | impossible (no row) | Revoke removes the share, and B loses A's Chief |
Suggested scope
plugins/social/src/mcp-client.jsnormalizeGrant: keepreply_only(asreplyOnly), andsideif present.plugins/social/src/social.jsisTalkThroughGrant: when the server sendsreplyOnly, use it as the only rule: talk-through meansreplyOnly === true, and a grant withreplyOnly === falseis always a share. Fall back to thejoinedRelationships/ roster heuristic only when the field is missing (older server).accessRows: the People with access lists the same friend twice when my already-shared Bot joins that friend's invite (talk-through grant shown as a share) #383 merging (one row per person) stays the same.- Tests (plugins/social): (a) A shares Chief to B, then B shares Chief to A in the same relationship (
regranted): both homes'social/accesslist the other person once. (b) A reply-only grant alone is still hidden. (c) The People with access lists the same friend twice when my already-shared Bot joins that friend's invite (talk-through grant shown as a share) #383 case (my already-shared Bot joins the friend's invite) still shows one row.
Acceptance criteria
- After steps 1–2, People with access lists the friend on both A and B within one refresh, and Revoke works from both sides.
- A reply-only talk-through grant is never shown as a share (Granted friend Bot never shows for the grantee: the talk-through grant hides it (regression from the #161 fix) #178 / Accepting an invite never shows the inviter's Bot to the joiner, and the joiner's Chief lists the inviter in People with access (regression of #178 from #334) #342 / People with access lists the same friend twice when my already-shared Bot joins that friend's invite (talk-through grant shown as a share) #383 still pass).
- No People with access row can disappear while Bot Social still has a non-reply-only grant for that person.
Related: #496 (re-invite wording / Remove), #383 (fix that introduced joinedRelationships), #178, #342, #23 (Bot Social reply-only), #51.
Activity
Birfy commentedon Oct 20, 2026
Triage (2026-10-20 12:57 Asia/Shanghai, Birfy maintenance): confirmed bug, consistent with the per-Bot grant rule (the owner must always see and be able to revoke every live share). Planned fix as written in the issue: keep Bot Social's
reply_onlyinnormalizeGrant, makeisTalkThroughGrantuse it as the only rule when present (heuristic fallback only for older servers), keep #383 one-row-per-person merging, plus the three tests. No server change needed.Waiting for the owner's confirmation before
agent-ready(needs-human).Birfy commentedon Oct 20, 2026
Owner decision (2026-10-20): option (a) — fix using the server's reply_only field (no Bot Social change needed) and add tests.
Birfy commentedon Oct 20, 2026
Claimed by maintenance run (2026-10-20 13:54 Asia/Shanghai). Working on branch
fix/495-share-reply-only(fork Birfy/FlyBot), developed in parallel with #495-#499; scope per the Owner decision only.Birfy commentedon Oct 20, 2026
Minor decisions (PR #501, 2026-10-20 13:59 Asia/Shanghai), within the owner's option (a):
isTalkThroughGrantreturnsreplyOnlywhenever the server sends it as a boolean, for any grant (also one without a relationship id); the old guess runs only when the field is missing.normalizeGrantkeepssideonly when it isjoinerorinviter; it is stored for later use, nothing reads it yet.accessRows: a grant Bot Social confirmed as a full share (reply_only: false) at the last sync is never kept on a separate "possible talk-through" row, so People with access lists the same friend twice when my already-shared Bot joins that friend's invite (talk-through grant shown as a share) #383's one row per person also holds when a Bot shared with us joins our invite. Grants from servers without the field keep today's separate-row safety.Keep live shares in People with access using Bot Social's reply_only (T…
Birfy commentedon Oct 20, 2026
Cleanup 2026-10-20 14:54 Asia/Shanghai: PR merged; removed
agent-working/ assignee.Merge origin/main into fix/496-already-friends-copy (resolve after Th…
Split People with access into one row per Bot (ThinkFlowLab#1009)