Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/1605.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
An open face-to-face room a home is a member of no longer disappears from that home's sidebar row list: a stored `hidden` flag is cleared by the room's open snapshot, and the sidebar's past-room and hidden-row filters never drop an open face room.
5 changes: 5 additions & 0 deletions core/src/host/room-membership.js
Original file line number Diff line number Diff line change
Expand Up @@ -2938,6 +2938,11 @@ export function install(rt) {
...(faceJoinCode(spec, room) ? { joinCode: faceJoinCode(spec, room) } : {}),
...(lead ? { lead } : {}),
}
// #1605: a face room this home is a member of is a row in the sidebar, never a hidden room.
// A `hidden` left by an earlier state (a share that ended here, a room made before its snapshot
// named it open) must not outlive an open or waiting snapshot: the API already lists the room,
// so the row has to be there too.
if (room.face.status !== 'closed' && room.face.status !== 'left') delete room.hidden
if (spec.name || isAutoFaceTitle(room.name)) room.name = title
if (Array.isArray(spec.members)) rt.syncFaceParticipants(room, spec.members, spec.localBots)
// When the lead is one of my Bots it is this room's admin here, so the round asks it first (#476).
Expand Down
24 changes: 24 additions & 0 deletions core/test/remote-room.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4021,3 +4021,27 @@ test('#2009: a group with a chosen name sends its seated guests nothing for a hu
assert.equal(joins.get(CODER.handle) ?? 0, 0, 'a human leave sends nothing either')
assert.equal(titles.length, 0, 'and no Session is renamed for a chosen name')
})

test('#1605: an open face room a home is a member of is never left hidden', async (t) => {
const { rt } = host(t, TEAM)
await rt.load()
const spec = {
roomId: 'frm_1605',
localId: 'face-1605',
status: 'open',
startedAt: '2026-11-04T10:00:00.000Z',
localBots: [{ id: 'spec-a', handle: '@writer.alice.home', name: 'Writer A' }],
members: [
{ handle: '@writer.alice.home', displayName: 'Writer', ownerName: 'Alice', published: false },
{ handle: '@coder.bob.home', displayName: 'Coder', ownerName: 'Bob', published: false },
],
}
const room = await rt.upsertFaceRoom(spec)
assert.equal(room.face.status, 'open')
// A row hidden by an earlier state is still this home's room: the open snapshot has to show it,
// because `social/face-rooms` already lists it and the sidebar is the only way into it.
room.hidden = true
await rt.upsertFaceRoom(spec)
assert.equal(room.hidden, undefined)
assert.equal(room.face.status, 'open')
})
5 changes: 5 additions & 0 deletions patches/ds-bot/files/src/host/room-membership.js
Original file line number Diff line number Diff line change
Expand Up @@ -2938,6 +2938,11 @@ export function install(rt) {
...(faceJoinCode(spec, room) ? { joinCode: faceJoinCode(spec, room) } : {}),
...(lead ? { lead } : {}),
}
// #1605: a face room this home is a member of is a row in the sidebar, never a hidden room.
// A `hidden` left by an earlier state (a share that ended here, a room made before its snapshot
// named it open) must not outlive an open or waiting snapshot: the API already lists the room,
// so the row has to be there too.
if (room.face.status !== 'closed' && room.face.status !== 'left') delete room.hidden
if (spec.name || isAutoFaceTitle(room.name)) room.name = title
if (Array.isArray(spec.members)) rt.syncFaceParticipants(room, spec.members, spec.localBots)
// When the lead is one of my Bots it is this room's admin here, so the round asks it first (#476).
Expand Down
24 changes: 24 additions & 0 deletions patches/ds-bot/files/test/remote-room.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4021,3 +4021,27 @@ test('#2009: a group with a chosen name sends its seated guests nothing for a hu
assert.equal(joins.get(CODER.handle) ?? 0, 0, 'a human leave sends nothing either')
assert.equal(titles.length, 0, 'and no Session is renamed for a chosen name')
})

test('#1605: an open face room a home is a member of is never left hidden', async (t) => {
const { rt } = host(t, TEAM)
await rt.load()
const spec = {
roomId: 'frm_1605',
localId: 'face-1605',
status: 'open',
startedAt: '2026-11-04T10:00:00.000Z',
localBots: [{ id: 'spec-a', handle: '@writer.alice.home', name: 'Writer A' }],
members: [
{ handle: '@writer.alice.home', displayName: 'Writer', ownerName: 'Alice', published: false },
{ handle: '@coder.bob.home', displayName: 'Coder', ownerName: 'Bob', published: false },
],
}
const room = await rt.upsertFaceRoom(spec)
assert.equal(room.face.status, 'open')
// A row hidden by an earlier state is still this home's room: the open snapshot has to show it,
// because `social/face-rooms` already lists it and the sidebar is the only way into it.
room.hidden = true
await rt.upsertFaceRoom(spec)
assert.equal(room.hidden, undefined)
assert.equal(room.face.status, 'open')
})
Loading