Repository navigation
Description
Environment
Seen on box instances A :3080 / B :3081 (UiA1415 / UiB1415), FlyBot 932ee57 (#233), Bot Social prod https://47-80-69-220.sslip.io. Face room code 995447 (frm_01M5632VXX5DZA2RAB9W76JRND), earlier API typed_by_owner probe (2026-10-18 ~07:27 Asia/Shanghai).
Actual (B's hosted room log)
0 joined UiB1415's Chief joined; available to this room only (system, eventId)
1 joined UiA1415's Chief joined; available to this room only (system, no eventId — member-snapshot path)
2 left who=Chief authorKind=bot authorId=<B's Chief session> text="" seq=3
3 started The room is now open…
4 human UiA1415 typed-by-owner probe…
B's local Chief stayed in participants[] (no leftSeq; joinedSeq was reset to 3). A's log for the same room has no spurious leave.
Transcript / model view of an empty left line is [${who} ${kind}] → [Chief left] (core/src/host/groups.js lineText). Chat UI uses reply.text alone for face notices, so the bubble can look blank while the transcript says Chief left.
This is not a Bot Social face_room.left / platformLeaveText notice (authorKind: 'system', text like UiB1415 left the room).
Root cause (code)
- Face locals are built by
faceLocalRecordwithoutviaCode: true(core/src/host/room-membership.js).isCodeJoined/mayShareRoomtherefore do not treat them as code-joined. setRoomGrantwrites a room-scoped grant withgrantee: room:frm_….hasAnyGrantignores room-scoped grants; that grantee also does not match peer handles inmayShareRoom.evictUnshareddoes not skiporigin: 'face-to-face'. Once a remote peer is in the room and grants change (setGrants→evictUnshared), a local face Bot that failsmayShareRoomgets:
{ kind: 'left', who: displayName, authorId, authorKind: 'bot', text: '' }- The next
syncFaceParticipantssees the Bot still in servermembers[], clearsleftSeq, setsjoinedSeq = seq— resurrecting membership but leaving the leave line in the log.
A avoided it here because A's Chief already had a person-grant to @chief.uib1415.home from earlier rooms (hasAnyGrant true). B's peer grant for this room arrived around join time — race with setRoomGrant / first remote sync.
Expected
- Bringing your own Bot by number must not emit a local "left" for that Bot while it is still a face-room member.
- Leave notices in face rooms should be platform system lines from
face_room.leftonly (person-named per Face-to-face: peer-leave notice is invisible and names the Bot; top bar shows the previous room's title after joining #191), not emptyauthorKind: botlines.
Suggested fix (pick one primary; tests for both)
- Preferred:
faceLocalRecord(and rejoin insyncFaceParticipants) setviaCode: truesomayShareRoom/isCodeJoinedhold for face members; and/orevictUnsharedskips face-to-face rooms (membership is server-driven viasyncFaceParticipants). - Optionally make room-scoped face grants count for
mayShareRoomin that room (todayroom:frm_…grantees are useless for peer checks). - Do not append a bot
leftline when only silently markingleftSeqfrom face sync (already the case); ensure resurrection never follows a spurious local leave.
Related
#191 (leave names the person), #182 (leave / past-room), #83 / #89 (code-join / room-only), face room 995447 typed_by_owner probe notes.
Activity