Repository navigation
Description
Reported by the owner, 2026-10-24, with a screenshot of the approval card: "this is still broken, and I still cannot receive the messages other people send."
The card reads Group update for Chief in a group chat, Chief → Chief, with an Auto-send switch, and the error under it is Bot Social decide_approval: no active relationship between these bots. So the send was held, the owner approved it, and the approval itself was refused. Pressing Approve can never work on this card — the two Bots have no relationship by construction, because a link admits a seat, not a friendship.
Where each half is produced (read at the refs named; not executed here)
FlyBot side — why a room envelope became an approval card instead of being exempted. #883 added the connector exception: ticketPair in plugins/social/src/social.js:1556-1566 passes a send only when msg.via is room/room-share, meta.scope is the room, the text is that room's whole envelope, and the pair is in flybot.rooms.ticketPeers(). That list is ticketPeers in core/src/host/reach.js:212-241, and for a seat in one of this home's rooms it requires all four of:
:226 if (p.kind !== 'bot' || p.remote !== true || p.admittedBy !== 'ticket' || !p.hostBotId) continue
:227 if (!(room.members ?? []).includes(p.hostBotId)) continue
:228 peers.push({ from: p.hostBotId, to: handleOf(p), scope: String(room.id), ticket: p.ticket })
Hypothesis to check first: a guest admitted by a ticket that does not record which local Bot invited them gets a seat with no hostBotId (core/src/host/room-membership.js writes ...(invite.botId ? { hostBotId: invite.botId } : {})), so :226 skips it, the pair is absent, ticketPair returns undefined, and the envelope falls into the ordinary approval path — the card in the screenshot. The same list feeds reach at :259-261, which decides whether the send is allowed at all.
Bot Social side — why approving it cannot succeed. The held item is an outbound_message approval (src/platform.ts:2093-2096, status pending_approval). On approve, decideApprovalOnce (:1910) calls deliverMessage (:2156), which accepts the conversation only when the pair's relationship is a room one:
:2163 if (cRel && cRel.status === 'room') { …room grant checks… }
:2167 } else this.activeRelationship(sender.id, recipient.id)
and activeRelationship (:872-876) throws exactly 403 no_relationship — "no active relationship between these bots". So a card whose conversation is not status: 'room' is unreleasable. Auto-delivery never ran either: it needs roomRel from the send's own room context (:2101-2111, byRoom = !!roomRel && refs.length === 0).
The three things to pin — each with a test, not a paragraph
- Which condition at
reach.js:226-228fails for this guest, and why. PrintticketPeers()for the reported room and name the failing one. If it ishostBotId, find where the claim losesinvite.botId(the#884server-minted claim path) and fix that, rather than widening the exception. - Why a seat the roster and the Members card already show can still miss the room gate.
#904/#907fixed the guest's display of the host's Bots; this is the send direction, and it must not be decided by display facts. Say which fact the gate reads and why it can be absent. - What
#883covered and what it did not. It covered "a room envelope from an enumerated ticket pair skips the card". It did not cover (a) a seat whose pair cannot be enumerated, or (b) the settle path at all: once a room envelope is carded,deliverMessage:2167can only refuse. So the second half of this issue is: a room envelope that is held must be releasable, or must never be carded.
Acceptance
- Host side: a guest admitted by a link into one of my rooms, with no friendship in either direction, sends a group update and an ordinary line; both are received, and no approval card is produced for either.
- Guest side: the same two sends in the other direction are received. The screenshot only proves the host→guest card; if this direction has a different cause, split it into a second issue with its own lines rather than folding it in silently.
- Negative control: a Bot that is neither seated in the room nor a friend still gets the approval card, and the refusal still names the step the owner can take. The exception must not widen to strangers.
- If a room envelope is ever carded (a DLP flag, an attachment, suspected injection — the cases
#45/#57keep), approving that card delivers; it must not end inno_relationship. State in the PR what makes the conversation a room one at that moment, or why the card is refused with a sentence that names the real step. - Every refusal keeps its own sentence: no raw
no_relationship, nodecide_approvalon screen. - A red test on the current
mainfor at least the host-side case. If the honest proof needs two Bot Social instances, say exactly what the harness drives and what it fakes — the#912lesson: a check that silently does nothing looks green.
If the cause is on the Bot Social side
Then this issue keeps the FlyBot half (the pair must be enumerable, and a carded room envelope must be releasable with a sentence), and a separate issue on Birfy/bot-social carries the deliverMessage:2167 half: roomRel for a conversation that began under a room, so an approved room message does not fall back to friendship. Open it there with these lines rather than quietly widening this one.
Open question — the other screen, not blocking this issue
The screenshot proves the outbound card (host → guest). It cannot prove the inbound symptom, so the two directions are recorded separately:
- If the guest's FlyBot shows "Not sent: … you are not friends with this Bot", it is the same
no_relationshiprefusal on its sending side, and one server fix covers both directions. Tracked onBirfy/bot-social#67. - If the guest's FlyBot shows the message as sent while nothing arrives here, the message left and never landed: a delivery problem, to be traced separately with its own issue.
Waiting on the user's answer from the guest's screen. It does not block the two FlyBot tasks (the pair must be enumerable; a carded room envelope must be releasable). When the answer arrives, add it here; do not change this issue's acceptance because of it.
Writer side
Birfy/bot-social#67 carries the settle half: deliverMessage (:2156-2167) and activeRelationship (:876). It states the check is sender-side, so this issue's FlyBot half, on its own, cannot make the message arrive.
Related
#883 / #884 — the connector exception and the seat; #904 / #907 — the guest's view of the host's Bots, which is done and is not this; #881 / #866 — room_id on a claimed-room send, the sibling of this on another path; #59 / #60 / #61 on Birfy/bot-social — the server-side ticket work.
Activity
fix(rooms): name the pair a room link seated
Birfy commentedon Oct 24, 2026
Written-by: Dev3
Claiming this one. Branch
fix/923-room-link-seat-pair, PR #927 (Fixes #923), headf27d23493c55d35371bc19582622a79319492c8f, base0b22aa53(current main).Root cause, one layer below the line numbers in the issue:
reach.js:226is the symptom. The local-link accept (answerLocalInvite) seats the guest throughaddRoomParticipant, and that record carries none of the three fieldsticketPeersrequires (admittedBy: 'ticket',ticket,hostBotId) — only the server-ticketseatByTicketwrites them. So a room opened from a locally minted link never enumerates the pair, its room envelopes name no room, Bot Social holds them aspending_approval, and approving ends inno active relationship.Fix: the accept records the link's ticket and the Bot it was minted for, and
ticketPeersalso reads the link's ownhomesrecord, so a room opened before this is the same pair without rewriting anything on load. A seat no link names (a friend's Bot added by hand) stays out, and that is asserted.The card in the report is outbound (host -> that guest):
shownRoomShareTextrenders every op other than join/leave/line asGroup update for <to>, andApprove/Auto-send from now onis the outbound pair hold. The reverse direction is not decided here; it needs the other machine's screen and, if the cause is the server-side fallback,Birfy/bot-social#67.fix(rooms): name the pair a room link seated
Birfy commentedon Oct 24, 2026
Residual from the #923 review, recorded here and not opened as a ticket yet — the condition that would make it one is written at the end.
Reviewer2's second note: writing
admittedBy: 'ticket'on a link seat also moves that seat into #884's ticket-seat branch (seatSenderas the sender, roster sync no longer removes it, removal goes throughsettleTicket, room deletion adds a leave). Meanwhilereach.js:253falls back toroom.adminwhen the recordedhostBotIdis no longer inroom.members, andseatSenderhas no such fallback — so a room whose recorded host left the members can produce a pair and still send no envelope.Not opened now because no reachable shape is demonstrated: it needs the recorded host to leave
room.memberswhile the room survives. When such a room is observed (or when anyone touchesseatSender), it becomes abug | area:socialissue with two tests: pair-but-no-envelope must send, and the friend-Bot negative control must still be refused.The first note is opened as #929, because that one does have a reachable shape: a link accepted before
homeswas written enumerates no pair, which is the same symptom on rooms that already exist.fix(rooms): name the pair a room link seated (ThinkFlowLab#927)
Read a link's seats through homesOf, so a room older than the field e…