Repository navigation
Sharing to a home member that was deleted reports success and can never deliver #1125
Description
Written-by: Triage
Status 2026-10-26: the local half is delivered. Route (b) — the honest row — landed as #1128 (15d7e525): a row whose Bot the other home removed is drawn removed: true with the reason, its Share is disabled, and social/share-with-friend refuses with bot/removed-bot before posting any grant. What remains on this issue is route (a) only — revoking the grant when a home member is removed, which is a Bot Social behaviour and cannot be closed in this repository. needs-human stays until that side agrees.
Split out of #970, which closed as fixed (#973 made the panel resolve the friend per Bot). That fix leaves this behind, and it is a product behaviour, not a client bug — hence needs-human.
What happens
- B removes one of its Bots from the home (
remove_home_membersucceeds on B's side). - A's relationship with that Bot stays
activeon Bot Social. - A's "Share with a friend" still lists that Bot, e.g.
Coder (SelfTest B2). - A clicks Share: the panel reports
Shared Chief with selftestb2., the row then disappears because the fresh grant hides it, and nothing can ever arrive — the Bot it was granted to no longer exists on that home.
So the owner gets a success message for a grant that is dead on arrival, and the only way to notice is that no line ever comes back.
Two routes (both are acceptable; the owner picks one)
(a) Retire the relationship when the member goes. Removing a home member revokes the grants that name it, so step 3 cannot offer a Bot that is gone. Cleanest for the owner-facing meaning of "revoke", but it changes what removal means across the network and it is a Bot Social behaviour, not ours — it needs the server side to agree.
(b) Keep the grant, make the row honest. The panel marks a row whose Bot no longer exists as not shareable, with the reason ("this Bot was removed from that home"), and never posts the grant. Fully inside plugins/social, no protocol change.
Acceptance
- the chosen route has a test that starts from "B removed the Bot, A still has the relationship" and asserts the outcome: no grant posted (a) / a disabled row plus no grant (b);
- neither route may print a success line for a grant that cannot deliver;
- the existing One-click Share names the friend but grants to one of their Bots: the panel and the success line never say which Bot #973/The re-accept grant falls back to
friend_home, which Bot Social never receives #1024 behaviour (share names the live Bot, re-accept brings the chat back) stays green.
Why not agent-ready yet
Route (a) is a protocol-level decision the owner has to make with the Bot Social side; route (b) is ours but the choice between them is not. Say "route (b)" and this becomes agent-ready in the same round with owner assigned.
Activity
Birfy commentedon Oct 25, 2026
Owner decision (2026-10-25)
Direction (a): removing a member also drops the grant, so the other home stops listing a Bot that no longer exists there. The protocol side has to agree with Bot Social, so split it:
@triage: turn the local half into an
agent-readyfollow-up if it is cleaner as its own issue; keep this one for the protocol change.Birfy commentedon Oct 25, 2026
Written-by: Triage
Owner's call (2026-10-25): route (a) — removing a home member revokes the grants that name it. That is the behaviour to aim at, and it is not a client-only change: it is a Bot Social behaviour that has to be agreed with the server side, which is why this issue stays
needs-human.Split done, so neither half waits on the other:
remove_home_member, retire the relationship (or the grants that name it) so the panel cannot offer a Bot that is gone. Needs the Bot Social side to agree on what "retire" means for an existing relationship.Acceptance for this half: a test that drives a home-member removal and asserts the grants naming that member are gone (or the relationship is marked retired) and that a subsequent share to it fails visibly rather than reporting success.
Birfy commentedon Oct 26, 2026
Route (b) — decision from the task lead, 2026-10-26. Keep the grant, make the row honest.
Why not (a) today: (a) changes what removing a home member means across the network, and the grants live on the Bot Social side, so it is a protocol decision that needs that side to agree — it cannot be closed inside this repository. (b) is fully inside `plugins/social`, removes the lie the owner actually sees (a success line for a grant that can never deliver), and does one thing: a row whose Bot no longer exists is rendered not-shareable with the reason, and no grant is posted.
If Bot Social later adopts (a), this row-level guard stays correct and harmless: it only stops us from posting a grant we already know is dead.
Acceptance is the card's, unchanged:
friend_home, which Bot Social never receives #1024 behaviour stays green (share names the live Bot, re-accept brings the chat back).This turns the card `agent-ready`; owner assigned in the group board.
Birfy commentedon Oct 26, 2026
Written-by: Dev4
Route (b) is already on
main— it shipped as #1128 (PR #1139, merge15d7e525, an ancestor of1e9f1844), so this card needs no new branch. The acceptance in the decision comment above is met by code and tests already in the tree:plugins/social/src/social.js—removedOnRoster(:3141-3153): a row is judged against the roster the panel already reads (remoteBots()→list_remote_bots, "Bots granted to me").social/share-friends— a row whose Bot the friend's home no longer lists comes backremoved: truewith the reason<name> was removed from that home. Sharing with it cannot reach anyone.(:3214-3217).social/share-with-friend— before anygrantBotToFriend, the same predicate refuses withbot/removed-bot(:3277-3283), so no grant is posted and the panel never prints a success line for it.plugins/social/client.js— the row stays drawn withshare-friend-removed, its Share isdisabled, and a click that still arrives says why instead of calling the host (:3488-3489,:3527-3535).Tests that start from exactly this state — B removed the Bot, A's relationship is still
active:#1128: a Bot the other home no longer lists is not shared, and the row says why— assertsrow.removed === true, the reason text,result.ok === false,error.code === 'bot/removed-bot', andgranted.length === 0(no grant sent).#1128: a row for a Bot the other home removed is shown with the reason and cannot be shared— client: the row is visible, its button is disabled, and a click posts nosocial/share-with-friend.#1128: a share to a Bot the other home still lists goes through as beforeand the three "never guess" cases — the One-click Share names the friend but grants to one of their Bots: the panel and the success line never say which Bot #973/The re-accept grant falls back tofriend_home, which Bot Social never receives #1024 behaviour and the ordinary share stay green.What I ran at
1e9f1844:cd plugins/social && TZ=UTC node --import ./test/resolve.mjs --test test/social.test.js→# tests 449 / # pass 449 / # fail 0. Not run: the rest ofnpm run verify(core, tree, timeline, lint) — the card changes no file, so there is no tip of mine to verify.One residual, and it is the part that needs the server (route (a)).
removedOnRosterrefuses only on positive evidence: the home is in the roster and lists other Bots while the relationship's Bot is absent (or its handle is absent). A home that drops out of the roster entirely, or is listed with an emptybotslist, decides nothing and the share goes through as before — the three knife tests (#1139) lock that in on purpose, because a cold or failed roster read must not disable a legitimate row. So in the case where the removed Bot was the friend's only Bot, the row can still post a grant that reaches nobody until Bot Social retires the relationship onremove_home_member(route (a), this issue's protocol half). Tightening the client half to treat a missing home as a removal is a product call, not a code fix: it would also refuse shares while the roster is merely stale.No branch, no PR from me on this one — the client half is done and
mainis green. The protocol half stays with this issue.Birfy commentedon Oct 26, 2026
Written-by: Triage
不转
agent-ready:路线 (b) 已经在 main 上交付完了。#1128(客户端半边)在 2026-10-25 10:29Z 以15d7e525合入,1e9f1844上就是它:plugins/social/src/social.js:3141-3155removedOnRoster():只有 roster 缓存里有这个 home、且两个名字(Bot id 与 handle)都不在,才判「已移除」;缓存缺失不猜;:3213-3219分享列表每一行先rowGone()、在:3217打removed: true并给 reason(docs/subsystems/social.md:165);plugins/social/client.js:3535把 Share 置灰、:3527-3528画出share-friend-removed那行、:3488点击时给出同一句 reason;:3279-3283就算点击绕过置灰,social/share-with-friend也会在发 grant 之前(:3291的grantBotToFriend之前)以bot/removed-bot拒绝;plugins/social/test/social.test.js:活着仍报成功并发 grant、被移除则不报成功也不发 grant。所以给 Dev4 开卡只会让他重做一遍已合入的东西。这张单剩下的只有 (a) 协议半边:
remove_home_member时收回 grant —— 那是 Bot Social 服务端行为,本仓改不了,needs-human保留(我不会去别人的上游仓库开单)。#1128的正文也写着「Not this issue: revoking grants on member removal (#1125)」。我把这条状态补进正文头,免得下一轮又按「面板报假成功」来分诊。
(2026-10-26 01:36 更正锚点:Dev4 在
1e9f1844上复核,removed: true在:3217、守卫在:3279-3283;先前的:3188是rowGone()的调用处、:3280-3282差一行。)