Repository navigation
Description
Priority: P0. Owner request (translated from Chinese, 2026-10-23): "A complete stranger, holding my QR code or link, must be able to join my group with their Bot. I need this urgently."
What this is
The connector half of FlyBot #853: the op:"ask" envelope a redeemed link produces must be allowed to leave the home of a stranger, and only that envelope.
Today it cannot leave at all. Measured on main 690093bc, plugins/social/src/social.js:
:1436— the send middleware denies whensendTarget(msg)resolves nothing: "… is not a Bot a friend shared with you". A cold handle is exactly that, so a stranger'saskdies here before any room logic runs.:1453— even with a roster entry, the deny returns once the friendship is gone.:1450—msg.via === 'room' || 'room-share'skips the approval decision, but that is downstream of:1436: it does not help a stranger.- Transport
:1545(… is no longer reachable) and:1558(the same friendship sentence) are the second gate on the same path.
(The line numbers quoted in #853 — 1339-1357 — are from an older main and have drifted.)
The exception, exactly
One send passes, and only when all four hold:
- the envelope is a
FLYBOT-ROOM-SHAREwithop: "ask"(core/src/shared/room-share.js:94already refuses anaskwhose ticket is not^[A-Za-z0-9_-]{16,64}$); - the ticket has been claimed — read from Bot Social's preview/claim answer, not from anything in the message;
- the sending home is the claiming home, and the Bot it sends as is the claimed
bot_handle; - the ticket is live (not expired, not revoked) and the
roomIdinside the envelope is the room the ticket is bound to.
Anything else keeps today's deny. Every failed condition gets its own sentence — a single generic refusal is not acceptable, because "the link expired" and "that link is someone else's" are different things to the person holding it.
Acceptance
- A home with no friendship and no shared Bot, holding a live claimed ticket, sends
op:"ask"and it leaves; the inviter's host receives it. - Each of the four conditions forced on its own produces a denial with its own sentence: not claimed, expired/revoked, claimed by another home, and a different
roomIdthan the ticket names. - A lookup failure is a deny, never a pass (fail-closed): if the preview/claim answer cannot be read, the envelope stays home.
- The same home sending any other text, or any other op (
invite,join,line,leave), is still denied with today's sentence. - The same home reaching any Bot outside that room is still denied — the exception is per envelope, not per home.
- Negative control: removing the exception returns the
askto today's:1436deny, and every other test stays green. - A test pins that a stranger's ordinary line (no envelope) is still denied at
:1436.
Depends on
The server-side ticket record (the separate bot-social issue: mint / preview / claim). Until it exists there is nothing to verify against, so this cannot pass its acceptance end to end — write the "blocked on that issue" line in the PR body, and pin the positive case with the fake server meanwhile.
Related
FlyBot #853 — the cross-repo gate; this issue is its connector half. FlyBot #884 — the host-side admission door, without which the invitee is still seated nowhere. FlyBot #876 — the UI that hands out the link.
Activity
Birfy commentedon Oct 23, 2026
Written-by: Dev
Taking this one. Branch
feat/883-stranger-ask, after #884's PR (it consumes the same seam). Bot Social side is Birfy/bot-social#60 (I am building that too).How the four conditions are read, all from Bot Social's answers, never from the message: the guest home's own
POST /v1/local-room-invites/:ticket/claimanswer (claimed, by this home, these Bots, this room, not expired) is kept in the plugin's settings; an outboundFLYBOT-ROOM-SHAREto a handle the roster does not know passes only when that record names the target as the ticket's inviter, the sender as one of the claimed Bots, and the envelope's room as the ticket's room — and it goes out withroom_id, so the server checks the same claim a second time. On the inviter side the host's answer to a seated stranger (join,line) passes on the seat record #884 writes. Plain text, any other target, or an envelope for another room keeps today's deny and sentence; a failed read is a deny.feat(rooms): a room link's pairs are the only reach it opens (#883, #884
feat(social): a room link's shares reach exactly its seat, under that…
feat(social): a room link's shares reach exactly its seat, under that…
fix(social): a 204 from Bot Social is an answer, not a crash; a guest…
docs(core-host): a guest reads the owner, not the host's own "You" (#883
test(social): a plain line under the room's scope still cannot reach …
fix(rooms): what the live two-home run found: the seat stays, the gue…
feat(rooms): seat a stranger's Bots through a link Bot Social records (…
feat(social): a room link's shares reach exactly its seat, under that…
feat(rooms): Invite by link in the Members card, with its QR, and Joi…
fix(rooms): name the pair a room link seated
fix(rooms): list the host's Bots in a guest's copy of the room (Think…
fix(rooms): name the pair a room link seated (ThinkFlowLab#927)
Deliver shared-room mentions without a Sharing grant (ThinkFlowLab#1130)