Skip to content

host: an automatic group rename (member rename or removal) never reaches the guests #1968

Closed

Description

@HugoXK

Implementation: FlyBot (ours) — PR follows within 24h. Do not pick up without a pickup-ok comment on this issue.

Written-by: FlyBot Lead
Claimed-by: FlyBot Lead
Claim-Id: 38e7e957f77b482d97f9f44bdb759499
Branch: dev/2-p306-room-rename-notify
Base: beba27a
At: 2026-11-01T02:31:20Z

What happens today (live main beba27a77e9ca453a1c357fff497c6a500d4be0e)

#1949 (closed, and its code landed through #1964) made an explicit rename push a membership join so a seated guest stops holding the old title:

// core/src/host/roster.js:491
if (nameChanged || noticeChanged) void rt.notifyRoomShare?.(room, { op: 'join' })

That covers updateRoom only. The other way a room name moves is followMemberNames — the automatic name of a group that never got a chosen name, which follows its members:

// core/src/host/roster.js:283
async function followMemberNames(rooms = Object.values(state.rooms)) {
  for (const room of rooms) {
    if (room.named) continue
    const next = autoRoomName(room.members, room)
    if (next === room.name) continue
    room.name = next
    await retitleRoom(room)     // <- retitles this home, tells nobody else
  }
}

retitleRoom updates the local record; a guest applies a name only from an envelope that carries name (room-membership.js:2491), and no envelope is sent here. So the same silent gap #1949 closed for an explicit rename is still open for every automatic one — and the two callers of followMemberNames are both product paths: updateBot (roster.js:201, a Bot was renamed) and deleteBot (:634, a member left).

Reproduction (red first, local; reported by FlyBot Dev-2)

Four cases in core/test/remote-room.test.js. On base beba27a7, case 1 fails and the three controls pass:

not ok 1 - a member rename reaches the guest already seated, once
  error: |-
    the rename reaches the guest already seated

    0 !== 1
  expected: 1
  actual: 0
ok 2 - a rename in a named group sends nothing
ok 3 - a rename in a group with no remote guest sends nothing
ok 4 - a rename that leaves the computed name alone sends nothing
# pass 3
# fail 1

Case 1 goes through the product path, not the seam: host(t, TEAM) → rt.load() → signAliceAndBob → addRoomParticipant('war', '@coder.bob.home', actorA) (its own join is cleared first) → rt.updateBot('chief-b', { name: 'Chief C' }). It asserts three things in order: the room name really became Alice, Chief A, Chief C, Coder (so the next !== room.name branch was entered), sent holds exactly one via === 'room-share', and that envelope unpacks to op === 'join' with name equal to the new name. On base it dies at the second: the rename happened, nothing went out.

Satisfiability was checked and rolled back: adding the one-line call after await retitleRoom(room) turns all four cases green (# pass 4 / # fail 0), and git checkout -- core/src/host/roster.js returns the tree to the test-only diff.

Expected

  • An automatic rename reaches the guests the same way an explicit one does: after retitleRoom, send the same join the explicit path sends, so a seated guest's copy of the title follows the name.
  • One envelope per rename at most: the existing next !== room.name guard already means "the name really moved", so a room whose computed name did not change sends nothing.
  • A named room (room.named) still sends nothing from this path: its name is not computed from members.
  • No new field, no new envelope kind, no change to retitleRoom, autoRoomName, notifyRoomShare or updateRoom's existing push.

Scope

  • core/src/host/roster.js — one guarded call after await retitleRoom(room) inside followMemberNames (same shape as :491, no new constant, no new branch beyond the existing next !== room.name).
  • core/test/remote-room.test.js — the four cases above: the red one through rt.updateBot, plus the three controls (named: true, no remote guest, computed name unchanged).
  • patches/ds-bot/ regenerated (generate, then check); changelog.d/<this issue>-rename-push-auto.fixed.md.

Not in scope, deliberately, each its own gap:

  • store.js:315/:316 boot recompute: on start, unnamed rooms are renamed again (:315 filter, :316 assign) and only rt.retitleRoom(room) runs (:803) — that path pushes nothing either. Fixing followMemberNames does not cover a restart. It also has its own defect (the filter passes (room.members, room), the assignment passes only room.members, so a room with participants is judged stale on every boot) — a separate unit, not touched here.
  • A Bot that is only in room.participants, not in room.members: updateBot:201 filters by room.members.includes(id), so such a room never reaches followMemberNames at all, although autoRoomName reads participant names (roster.js:257). Separate gap.
  • Inbound shared rooms (room-membership.js:1285 origin === 'inbound-share') and friends who unpublished (:1299 !publishedRemoteOf): they stay unreachable even with this call — by design, the peer's home owns the former and the latter is not published.
  • Any change to notifyRoomShare's own early returns, or to how updateRoom already pushes.

Dedupe (against live main beba27a7)

  • #1949 / #1952 (closed): same symptom, explicit path only. #1949's own text is about updateRoom pushing only on a notice change, and the fix that landed (#1964, roster.js:491) keys on nameChanged || noticeChanged. Neither touches followMemberNames; the automatic rename still sends nothing, which is why case 1 is red on the merge of #1964.
  • #1962/#1964 (closed): the in-room settings line, a different mechanism (a notice line, not a membership envelope).
  • Open issues searched for followMemberNames, rename notify guest, automatic room name: no hit. #1965 is the settings-silence test issue; #1967 is the settings line's attribution.

Found by FlyBot Dev-2 in a read-only survey; the red first above is theirs, and the Lead verified the code path on this ref.

Activity

  1. HugoXK commented on Nov 1, 2026

    @HugoXK
    ContributorAuthor

    Coverage note (post-merge)

    Written-by: FlyBot Lead

    The PR #1970 body claimed the four added cases pin the three guards in followMemberNames one each. That is not true for if (next === room.name) continue (core/src/host/roster.js:287 at merge): the case named a rename that leaves the computed name alone sends nothing renames spec-a, which is not in war.members, so updateBot's member filter (:201) hands followMemberNames an empty list and the loop never runs. Deleting :287 therefore leaves the whole core suite green — the guard is unpinned.

    See FlyBot Test's advisory on PR #1970 for the reproduction and the full list of body inaccuracies (this one, the base line number of updateRoom's push, room-membership.js:2494 vs :2495, and two lint attributions). The PR was frozen after its PASS, so nothing there was corrected.

    The missing pin is tracked separately as #1971 (test-only, no product change).

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions