Skip to content

Face room: own Chief spuriously "left" (authorKind bot, empty text) before start — evictUnshared vs missing viaCode #236

Closed

Description

@Birfy

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)

  1. Face locals are built by faceLocalRecord without viaCode: true (core/src/host/room-membership.js). isCodeJoined / mayShareRoom therefore do not treat them as code-joined.
  2. setRoomGrant writes a room-scoped grant with grantee: room:frm_…. hasAnyGrant ignores room-scoped grants; that grantee also does not match peer handles in mayShareRoom.
  3. evictUnshared does not skip origin: 'face-to-face'. Once a remote peer is in the room and grants change (setGrants → evictUnshared), a local face Bot that fails mayShareRoom gets:
    { kind: 'left', who: displayName, authorId, authorKind: 'bot', text: '' }
  4. The next syncFaceParticipants sees the Bot still in server members[], clears leftSeq, sets joinedSeq = 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

Suggested fix (pick one primary; tests for both)

  1. Preferred: faceLocalRecord (and rejoin in syncFaceParticipants) set viaCode: true so mayShareRoom / isCodeJoined hold for face members; and/or evictUnshared skips face-to-face rooms (membership is server-driven via syncFaceParticipants).
  2. Optionally make room-scoped face grants count for mayShareRoom in that room (today room:frm_… grantees are useless for peer checks).
  3. Do not append a bot left line when only silently marking leftSeq from 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions