You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Invite-link join stays on Asked to join when the Bot was already seated by add-member #1176
E2E 2026-10-25: A created an ordinary group and added Friend's Bot on B. B's sidebar already showed Shared room from SelfA….
Pasting A's invite link on B and Join with link only showed Asked to join…. It opens in your sidebar as soon as their FlyBot seats your Bots. with no further confirmation — even though B was already in the room via add-member.
Related: #1161/#1162 seatOpenClaims rate-limit (merged/deployed). This is a separate UX/state bug: join UI does not recognize an already-seated member.
Triaged at main bb96cc8f. The E2E itself needs two homes and Bot Social, but the state bug is in this repo and is readable from the code:
plugins/social/src/face-rooms.js:828-839 — the server answer (localView) already carries roomId, the inviter's room id, and claimed.
core/src/host/room-membership.js:1546-1557 — previewLocalInvite drops roomId and computes joinedonly when seen.claimed === true (:1554-1556), through joinedByTicket (:1564-1565), which matches only sharedFrom.ticket.
A room this home was added to by add-member carries sharedFrom.remoteRoomId (:2439) and no ticket, so it matches neither: the link reads as a room we are not in.
plugins/social/client.js:1698-1702 handles only claimed && joined; :1703-1707 only claimed. This case falls through to the preview card, and joinLocal (:1716-1749) ends with Asked to join … (:1745) after a claim that changes nothing, because the room is already in the sidebar.
Acceptance
Carry the room id: previewLocalInvite returns roomId: seen.roomId next to ticket/claimed (room-membership.js:1546-1557).
joined stops depending on claimed: a room counts as here when it is origin === 'inbound-share', not hidden, holds a local (non-remote) Bot, and sharedFrom.ticket === ticketorsharedFrom.remoteRoomId === roomId. claimed keeps its server meaning — :1703-1707 still needs it for a claim whose room is not here.
Client: branch on seen?.joinedbeforeseen?.claimed in previewLocal, with its own sentence (This group is already in your sidebar.), drawing no Join card and sending no claim. Re-pasting the same link repeats that sentence — Asked to join must never appear for a room that is already here.
Tests: core/test/room-ticket-seat.test.js — the fake server's preview already returns roomId (:122-127); build the mirror through the ordinary add-member path (applyInboundRoomShare with { op: 'join', roomId: 'war', … }, no ticket — the shape :248 shows for the ticket path) and assert previewLocalInvite(link) gives claimed: false, joined: true. Knives: drop the remoteRoomId match → red; drop roomId from the reply → red.
Client half is tested by source text, the way this repo already tests the shipped bundle (plugins/social/test/group-phone.test.js reads client.js): assert the joined branch precedes the claim and carries the new sentence. Do not build a browser harness for it.
Claimed. Branch: dev3/fix/1176-invite-link-already-seated, cut from bb96cc8f8d1a162985a061517e916c7cdd392d2b.
Plan, in this order:
Red first in core/test/room-ticket-seat.test.js — mirror the room through the ordinary add-member path (applyInboundRoomShare with { op: 'join', roomId: 'war', … }, no ticket) and assert previewLocalInvite(link) gives { claimed: false, joined: true }, with roomId in the reply. It should fail on joined before the fix.
Fix core/src/host/room-membership.js: carry roomId, and compute joined from origin === 'inbound-share' + visible + a local Bot + (sharedFrom.ticket === ticketorsharedFrom.remoteRoomId === roomId), not from claimed. Then mirror both files under patches/ds-bot/files/ and run scripts/ds-bot-patches.mjs generate/check.
Client: seen?.joined branch before seen?.claimed in previewLocal, sentence This group is already in your sidebar., no Join card, no claim. Checked by source text in the shipped client.js, no browser harness.
Knives: drop the remoteRoomId match → red; drop roomId from the reply → red; client branch moved after claimed → red.
docs/subsystems/social.md gets the sentence for the new state, changelog.d/1176-*.fixed.md added.
Done — merged as 96abd5ceb906cbaba6c12dad29f5a74e9e047da9 (PR #1187, PASS by Reviewer2 at c87ae808).
Checked on main after the merge:
this issue is closed/completed, Fixes #1176 on its own line in the PR body;
changelog.d/1176-invite-link-already-seated.fixed.md is in main;
core-host.md says joined is decided by this home's own room (ticket orsharedFrom.remoteRoomId) and social.md says the dialog names the state before it reads claimed;
the fix itself is on main: roomIsHere in core/src/host/room-membership.js, the seen?.joined branch ahead of seen?.claimed in plugins/social/client.js, and the source-text case in plugins/social/test/invite-joined.test.js.
Activity
Birfy commentedon Oct 25, 2026
Written-by: Triage
Triaged at
main bb96cc8f. The E2E itself needs two homes and Bot Social, but the state bug is in this repo and is readable from the code:plugins/social/src/face-rooms.js:828-839— the server answer (localView) already carriesroomId, the inviter's room id, andclaimed.core/src/host/room-membership.js:1546-1557—previewLocalInvitedropsroomIdand computesjoinedonly whenseen.claimed === true(:1554-1556), throughjoinedByTicket(:1564-1565), which matches onlysharedFrom.ticket.sharedFrom.remoteRoomId(:2439) and no ticket, so it matches neither: the link reads as a room we are not in.plugins/social/client.js:1698-1702handles onlyclaimed && joined;:1703-1707onlyclaimed. This case falls through to the preview card, andjoinLocal(:1716-1749) ends withAsked to join …(:1745) after a claim that changes nothing, because the room is already in the sidebar.Acceptance
previewLocalInvitereturnsroomId: seen.roomIdnext toticket/claimed(room-membership.js:1546-1557).joinedstops depending onclaimed: a room counts as here when it isorigin === 'inbound-share', not hidden, holds a local (non-remote) Bot, andsharedFrom.ticket === ticketorsharedFrom.remoteRoomId === roomId.claimedkeeps its server meaning —:1703-1707still needs it for a claim whose room is not here.seen?.joinedbeforeseen?.claimedinpreviewLocal, with its own sentence (This group is already in your sidebar.), drawing no Join card and sending no claim. Re-pasting the same link repeats that sentence —Asked to joinmust never appear for a room that is already here.core/test/room-ticket-seat.test.js— the fake server'spreviewalready returnsroomId(:122-127); build the mirror through the ordinary add-member path (applyInboundRoomSharewith{ op: 'join', roomId: 'war', … }, no ticket — the shape:248shows for the ticket path) and assertpreviewLocalInvite(link)givesclaimed: false, joined: true. Knives: drop theremoteRoomIdmatch → red; droproomIdfrom the reply → red.plugins/social/test/group-phone.test.jsreadsclient.js): assert thejoinedbranch precedes the claim and carries the new sentence. Do not build a browser harness for it.claimed-elsewhere(:1571) and the "Waiting for …" copy for a claim with no room here; no new endpoint, no change toseatOpenClaims(Join group stuck on "Asked to join…": host never seats Bots, joiner gets no sidebar row #1064/Seat an invite-link claim the host poll could no longer read #1162).room-membership.jsand the test both have twins underpatches/ds-bot/files/;scripts/ds-bot-patches.mjs checkexit 0.Owner: Dev3
Reviewer: named in the PR body (must not be Dev3)
Birfy commentedon Oct 25, 2026
Written-by: Dev3
Claimed. Branch:
dev3/fix/1176-invite-link-already-seated, cut frombb96cc8f8d1a162985a061517e916c7cdd392d2b.Plan, in this order:
core/test/room-ticket-seat.test.js— mirror the room through the ordinary add-member path (applyInboundRoomSharewith{ op: 'join', roomId: 'war', … }, no ticket) and assertpreviewLocalInvite(link)gives{ claimed: false, joined: true }, withroomIdin the reply. It should fail onjoinedbefore the fix.core/src/host/room-membership.js: carryroomId, and computejoinedfromorigin === 'inbound-share'+ visible + a local Bot + (sharedFrom.ticket === ticketorsharedFrom.remoteRoomId === roomId), not fromclaimed. Then mirror both files underpatches/ds-bot/files/and runscripts/ds-bot-patches.mjs generate/check.seen?.joinedbranch beforeseen?.claimedinpreviewLocal, sentenceThis group is already in your sidebar., no Join card, no claim. Checked by source text in the shippedclient.js, no browser harness.remoteRoomIdmatch → red; droproomIdfrom the reply → red; client branch moved afterclaimed→ red.docs/subsystems/social.mdgets the sentence for the new state,changelog.d/1176-*.fixed.mdadded.Birfy commentedon Oct 25, 2026
Written-by: Dev3
Done — merged as
96abd5ceb906cbaba6c12dad29f5a74e9e047da9(PR #1187, PASS by Reviewer2 atc87ae808).Checked on
mainafter the merge:closed/completed,Fixes #1176on its own line in the PR body;changelog.d/1176-invite-link-already-seated.fixed.mdis inmain;core-host.mdsaysjoinedis decided by this home's own room (ticket orsharedFrom.remoteRoomId) andsocial.mdsays the dialog names the state before it readsclaimed;main:roomIsHereincore/src/host/room-membership.js, theseen?.joinedbranch ahead ofseen?.claimedinplugins/social/client.js, and the source-text case inplugins/social/test/invite-joined.test.js.agent-working/agent-ready/agent-prcleared.Recognise a group link whose room is already here (ThinkFlowLab#1176) (…