Skip to content

fix(social): Past rooms Open works on every home; one face-room title for all members (#171, #172) - #175

Merged
Birfy merged 2 commits into
ThinkFlowLab:mainfrom
Birfy:cursor/past-rooms-open-title-7a34
Oct 17, 2026
Merged

Birfy merged 2 commits into
ThinkFlowLab:mainfrom
Birfy:cursor/past-rooms-open-title-7a34

Conversation

@Birfy

@Birfy Birfy commented Oct 17, 2026

Copy link
Copy Markdown
Collaborator

Fixes #171
Fixes #172

Summary

Fork PR: Birfy#21

Test plan

  • ARCH_DOCS_BASE=upstream/main npm run verify (agent run, Node 24)
  • new tests: poll keeps hosted room openable; client Open via face-open; title sort/rebuild
  • Two homes: close a face room on one side; on the other, Past rooms → Open shows the transcript
  • Same title on both homes

Past rooms on a peer home could not be opened after the room left Bot
Social because the local hosted room was dropped and Open only passed a
dead session id. Keep the hosted transcript when a room falls off the
server list, add social/face-open to resolve or recreate the session,
and route Past Open through it.

Face-to-face titles now list every participant owner in stable handle
order and refresh auto titles when the roster grows, on the server and
in the Friends panel.

Co-authored-by: Danyang Chen <birfychen@gmail.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-17T10:05:01.596296Z 4087048 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4087048cb0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

rememberPastFace(viewHostedFace(hosted, { faceRoomId: serverId, localRoomId: meta?.localRoomId, status: 'closed' })
|| { faceRoomId: serverId, roomId: meta?.localRoomId, name: faceRoomTitle({}, { code: meta?.joinCode, room: hosted }), status: 'closed', members: [] })
if (meta?.localRoomId) await flybot.rooms.dropFace?.(meta.localRoomId).catch(() => {})
delete settings.faceRooms[serverId]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Close the hosted room before deleting active metadata

When faceApi.list() stops returning a room that was already open, this branch now keeps the hosted room but only marks the copied past snapshot as closed; the persisted room.face.status remains open. core/src/client/sidebar.js:isPastFaceRoom therefore continues to show the room as live while social/face-rooms also emits it under Past rooms, and the stale live state remains after this metadata is deleted. Update the hosted room to closed here while retaining its history.

Useful? React with 👍 / 👎.

|| Object.entries(settings.faceRooms).find(([, meta]) => meta.localRoomId === roomId)?.[0]
if (!serverId) throw new Error('which room?')
const seed = past || { faceRoomId: serverId, roomId, status: 'closed', members: [] }
const room = await flybot.rooms.upsertFace?.({

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve history when recreating a past room

When this fallback is actually needed because an explicit Leave or older cleanup removed the hosted room, rememberPastFace has retained only summary fields, and this upsertFace call passes neither the original local session id nor any history. Core consequently creates a new session whose room log is empty, so Open lands on a blank conversation rather than the past transcript. Keep the original hosted room on those transitions or retain and reopen its history instead of creating a metadata-only replacement.

Useful? React with 👍 / 👎.

return { roomId: room.id, faceRoomId: serverId }
}
disposers.push(flybot.api.handle('social/face-join', async ({ code, botId } = {}) => joinFaceRoom({ code, botId })))
disposers.push(flybot.api.handle('social/face-open', async (payload) => openFaceRoom(payload), { read: true }))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Register the recreating endpoint as a write

When the hosted room is absent, openFaceRoom invokes rooms.upsertFace, which creates a DSH session and saves core state. Declaring this handler { read: true } makes channel.js serve it while another DSH owns the state lock and makes authz.js bypass the deployment-wide plugin-write block for every signed member; the fallback then either errors inside createSession on a read-only host or lets a non-owner mutate shared room state. Split pure resolution from recreation or register recreation as a write.

AGENTS.md reference: AGENTS.md:L60-L60

Useful? React with 👍 / 👎.

return `${MONTHS[date.getMonth()]} ${date.getDate()} ${hh}:${mm}`
}

export function isAutoFaceTitle(name) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Add subsystem docs or the required trailer

This commit changes files owned by both core-host and social, but changes neither docs/subsystems/core-host.md nor docs/subsystems/social.md, and its commit message has no Docs-not-needed: trailer. The repository's architecture-doc gate therefore rejects this tip before the required verification can pass; update the subsystem docs or add a justified trailer.

AGENTS.md reference: AGENTS.md:L94-L94

Useful? React with 👍 / 👎.

for (const member of members ?? []) {
const owner = String(member?.ownerName ?? member?.owner_name ?? '').trim()
const key = owner.toLowerCase()
if (!owner || seen.has(key)) continue

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Sort members before deduplicating owners

When one home brings multiple Bots, the same owner appears under multiple handles. Because deduplication happens before handle sorting, the retained handle for that owner depends on input order: members A@z, B@m, A@a produce B, A, while reordering them to A@a, B@m, A@z produces A, B. Homes receiving different member-array orders can therefore still show different titles; sort all member rows by handle first and then deduplicate owners.

Useful? React with 👍 / 👎.

@Birfy
Birfy added this pull request to the merge queue Oct 17, 2026
Merged via the queue into ThinkFlowLab:main with commit 7285208 Oct 17, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants