Skip to content

feat(gateway): watched sessions in presence with viewer facepiles#111225

Merged
steipete merged 5 commits into
mainfrom
claude/identity-session-viewing
Jul 19, 2026
Merged

feat(gateway): watched sessions in presence with viewer facepiles#111225
steipete merged 5 commits into
mainfrom
claude/identity-session-viewing

Conversation

@steipete

Copy link
Copy Markdown
Contributor

What Problem This Solves

On a shared gateway you cannot see who else is online or which session they are looking at — collaboration is blind. The gateway already knows both facts: presence entries carry identity (#111179), and per-session event subscriptions tell it what each connection watches; neither was exposed.

Part of the multiplayer-identity program: #111133 (who's-viewing PR of the train).

Why This Change Was Made

  • Presence entries gain an optional watchedSessions array (sorted for deterministic snapshots), maintained from the existing session-scoped event subscription lifecycle — no new client→gateway messages. Recency-capped at 32 sessions per connection to keep snapshots small.
  • Concurrent subscribe/rollback settlement uses an explicit per-connection/key in-flight state machine (committed base + outstanding count + last success), so overlapping failed replays can never leave a ghost subscription advertising a session nobody watches.
  • Control UI: a shared viewer-facepile component renders (a) up to 3 overlapping viewer avatars + +N on each sidebar session row for other identified viewers, and (b) a global online facepile in the sidebar footer bar (Zone 5) showing everyone identified online — one circle per person regardless of connection count (grouped by user.id), self included, initials + deterministic color fallback, avatarUrl wins when set.
  • Identity optional throughout: anonymous connections still report watched sessions but render nowhere; gateways without identity show zero new UI.

User Impact

Shared-gateway teams see who is online (footer facepile) and who is viewing which session (row avatars), Google-Docs style. Single-user gateways look exactly as before.

Evidence

  • Blacksmith Testbox tbx_01kxwace801n9pche7p953svgp: 25 gateway, 3 protocol, 134 sidebar tests green; core/UI production + test type gates green.
  • node scripts/run-vitest.mjs src/gateway/server-chat-state.test.ts src/gateway/session-message-events.test.ts src/gateway/server-methods/sessions.messages-subscribe-approvals.test.ts — green locally, including both concurrent-rollback failure orders, mixed failure/success orders, cap-at-32 recency, unsubscribe/disconnect cleanup, anonymous reporting.
  • Structured autoreview (codex/gpt-5.6-sol, xhigh): one real concurrency finding (ghost subscription on double-failed overlapping subscribes) — fixed via the in-flight state machine; final run clean, "patch is correct".

@steipete
steipete marked this pull request as ready for review July 19, 2026 05:20
@openclaw-barnacle openclaw-barnacle Bot added app: web-ui App: web-ui gateway Gateway runtime size: L maintainer Maintainer-authored PR labels Jul 19, 2026

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

Copy link
Copy Markdown
Contributor

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: 7b821e587a

ℹ️ 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".

Comment on lines +1254 to +1256
upsertPresence(client.presenceKey, {
watchedSessions: watchedSessions.length > 0 ? watchedSessions : undefined,
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Badge Redact watched session keys from unscoped presence

Presence broadcasts are intentionally delivered to operator.pairing and node-role connections (src/gateway/server-broadcast.ts:52), while session discovery and subscription require operator.read (src/gateway/methods/core-descriptors.ts:194-198). Adding the raw keys here bypasses that boundary: a pairing-only client or node can observe watched keys such as agent:main:whatsapp:direct:+1555..., exposing agent, channel, group, and peer identifiers it cannot otherwise list. Emit watchedSessions only in a read-scoped/redacted presence projection rather than the globally visible snapshot.

Useful? React with 👍 / 👎.

Comment on lines +100 to +104
protected presenceViewersForSession(sessionKey: string): readonly PresenceViewer[] {
return this.onlinePresenceViewers.filter(
(viewer) =>
viewer.id !== this.selfPresenceUserId && viewer.watchedSessions.includes(sessionKey),
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Badge Match scoped global subscription keys to sidebar rows

When the selected session is global, the gateway records the subscription as agent:<agentId>:global (src/gateway/server-methods/sessions-subscriptions.ts:28-31) but returns and lists the canonical row key as global. This exact includes(sessionKey) comparison therefore never matches for global-session sidebar rows, so other viewers of a global session are absent from its facepile even though their presence advertises the scoped key. Normalize or compare these keys with the selected agent scope before filtering.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P1 High-priority user-facing bug, regression, or broken workflow. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. labels Jul 19, 2026
@clawsweeper

clawsweeper Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed July 19, 2026, 5:46 AM ET / 09:46 UTC.

Summary
The PR adds optional watchedSessions to gateway presence and renders identified online users and session viewers as Control UI facepiles.

PR surface: Source +549, Tests +156, Other +4. Total +709 across 21 files.

Reproducibility: yes. from source inspection: connect a pairing-only or node-role recipient, have another client subscribe to a sensitive session key, and observe the presence snapshot; the current changed path inserts and broadcasts that key without a shown recipient read-scope projection.

Review metrics: 1 noteworthy metric.

  • Presence protocol surface: 1 additive watchedSessions field. This externally visible snapshot field is populated from subscription state, so its recipient authorization and viewer-state semantics need an explicit contract.

Stored data model
Persistent data-model change detected: serialized state: src/gateway/server-methods/sessions-subscriptions.ts, serialized state: src/gateway/server-methods/sessions.messages-subscribe-approvals.test.ts, serialized state: src/gateway/session-message-events.test.ts, unknown-data-model-change: src/gateway/session-message-events.test.ts. Confirm migration or upgrade compatibility proof before merge.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🧂 unranked krab
Patch quality: 🧂 unranked krab
Result: blocked until real behavior proof from a real setup is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P1] Implement per-recipient watched-session redaction and the remaining viewer-state fixes.
  • [P1] Add focused regression coverage for authorized and unauthorized recipients, multi-connection device state, connect-time presence, active viewing, and the Home row.
  • Attach redacted two-client real behavior proof; after updating the PR body, request a fresh review if it does not occur automatically.

Proof guidance:

  • [P1] Needs real behavior proof before merge: The PR body reports Testbox, unit, protocol, and UI test results, but it provides no reviewed after-fix shared-gateway recording, terminal/live output, or redacted logs that demonstrate authorized viewer visibility and unauthorized-recipient redaction. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Risk before merge

  • [P1] Pairing-only or node-role presence recipients can learn raw session keys, which may encode agent, channel, group, or peer identifiers outside their authorized session-discovery scope.
  • [P1] Per-connection presence can make an older retained disconnect row override a live connection in device-oriented consumers; accumulated subscriptions also misrepresent previously visited sessions as actively viewed.
  • [P1] The new shared-gateway collaboration UI has no reviewed after-fix real behavior artifact showing authorized visibility, unauthorized redaction, and expected sidebar updates.

Maintainer options:

  1. Add scoped presence projection before merge (recommended)
    Keep the collaboration feature but redact watched keys for unauthorized recipients and repair the identified connection/viewer-state gaps with focused regression coverage.
  2. Pause for an explicit disclosure contract
    Do not merge until a maintainer decides whether presence is permitted to reveal raw session identifiers outside the existing read scope.

Next step before merge

  • [P1] A protected maintainer-labeled feature needs an explicit security-boundary decision before any repair lane can safely choose the presence disclosure contract.

Maintainer decision needed

  • Question: Should watched session keys be visible in presence to pairing-only and node-role clients, or only to recipients already authorized with operator.read for each referenced session?
  • Rationale: The current feature turns subscription keys into broadly broadcast presence data, and those keys may disclose channel or peer identifiers beyond the existing session-discovery boundary.
  • Likely owner: steipete — The merged identity prerequisite and the shared-gateway identity design context connect this person most directly to the intended disclosure contract.
  • Options:
    • Redact per recipient (recommended): Expose watched-session data only through a recipient-specific projection that omits sessions the recipient cannot read.
    • Approve broad presence disclosure: Treat watched-session keys as intentionally visible to all presence recipients and document that expanded disclosure contract.

Security
Needs attention: The PR introduces a concrete authorization-boundary concern by placing raw watched-session identifiers in presence snapshots without shown recipient-specific redaction.

Review findings

  • [P1] Restrict watched keys to read-authorized presence recipients — src/gateway/server.impl.ts:1259-1261
  • [P2] Preserve device connectivity across per-connection presence rows — src/gateway/server/ws-connection/connect-session.ts:125-130
  • [P2] Broadcast presence when an identified connection comes online — src/gateway/server/ws-connection/connect-session.ts:349-355
Review details

Best possible solution:

Project watchedSessions only to recipients authorized to read the relevant session, model active viewing separately from retained subscriptions, preserve device connectivity semantics, broadcast identified connects, render the Home row, and attach redacted two-client live proof covering both authorized display and unauthorized redaction.

Do we have a high-confidence way to reproduce the issue?

Yes from source inspection: connect a pairing-only or node-role recipient, have another client subscribe to a sensitive session key, and observe the presence snapshot; the current changed path inserts and broadcasts that key without a shown recipient read-scope projection.

Is this the best way to solve the issue?

No. Subscription membership is not a reliable active-view signal, and a globally broadcast raw key is not the narrowest safe representation; scoped presence projection plus explicit active-view semantics is safer.

Full review comments:

  • [P1] Restrict watched keys to read-authorized presence recipients — src/gateway/server.impl.ts:1259-1261
    watchedSessions is copied from subscriptions into the presence record and then broadcast. Pairing-only and node-role clients can receive presence while lacking operator.read; this reveals raw session keys that may include channel or peer identifiers. Project this field per recipient and omit keys the recipient cannot read.
    Confidence: 0.98
  • [P2] Preserve device connectivity across per-connection presence rows — src/gateway/server/ws-connection/connect-session.ts:125-130
    Changing non-node presence to connId creates multiple retained rows for a device. Existing device-oriented consumers can collapse those rows so an older disconnect wins over a live connection, leaving connectivity and session-catalog state stale. Preserve a device aggregate or make consumers reduce live rows before disconnect rows.
    Confidence: 0.9
  • [P2] Broadcast presence when an identified connection comes online — src/gateway/server/ws-connection/connect-session.ts:349-355
    The new facepile depends on presence events, but the connect-time presence insertion only advances state unless another event occurs. Existing users therefore do not learn that a newly identified direct Control UI connection is online until it subscribes or another presence change happens. Broadcast the snapshot after the connect insertion.
    Confidence: 0.88
  • [P2] Track active viewing instead of accumulated subscriptions — src/gateway/server.impl.ts:1234-1239
    This projects every retained message subscription as currently watched. Native clients subscribe when switching sessions without unsubscribing the prior session, so one person can remain in facepiles for every session visited during the connection. Add an explicit active-view lifecycle or change the client subscription lifecycle before using it as viewer state.
    Confidence: 0.94
  • [P2] Render the viewer facepile on the Home row — ui/src/components/app-sidebar-session-list.ts:161-167
    The new facepile is added to recent-session rows, but the main session is rendered by the separate Home row rather than that list. Other users viewing the default main session therefore remain invisible even though presence contains their watched key. Render the same component for the Home row using mainKey.
    Confidence: 0.93

Overall correctness: patch is incorrect
Overall confidence: 0.94

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against d4ed08994d31.

Label changes

Label changes:

  • add rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🧂 unranked krab.
  • remove rating: 🦪 silver shellfish: Current PR rating is rating: 🧂 unranked krab, so this older rating label is no longer current.

Label justifications:

  • P1: The PR introduces a shared-gateway disclosure path that can expose session identifiers to recipients outside the established read boundary.
  • merge-risk: 🚨 session-state: Viewer facepiles derive active-looking state from retained subscriptions and per-connection presence, which can leave UI state stale or misleading.
  • merge-risk: 🚨 security-boundary: Raw watched-session identifiers are added to broadly delivered presence snapshots without demonstrated per-recipient authorization filtering.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🧂 unranked krab.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR body reports Testbox, unit, protocol, and UI test results, but it provides no reviewed after-fix shared-gateway recording, terminal/live output, or redacted logs that demonstrate authorized viewer visibility and unauthorized-recipient redaction. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed

PR surface:

Source +549, Tests +156, Other +4. Total +709 across 21 files.

View PR surface stats
Area Files Added Removed Net
Source 16 616 67 +549
Tests 4 176 20 +156
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 1 5 1 +4
Total 21 797 88 +709

Security concerns:

  • [high] Presence can disclose unauthorized session identifiers — src/gateway/server.impl.ts:1259
    The changed presence update stores subscription-derived session keys and broadcasts the snapshot. Presence can reach recipients that do not have session read access, so those identifiers can disclose channel, group, or peer metadata.
    Confidence: 0.98

What I checked:

  • Current-head disclosure path: The PR head derives watched-session keys from each connection’s message subscriptions, writes them into presence, and broadcasts the presence snapshot; the changed path has no recipient-specific read-scope projection. (src/gateway/server.impl.ts:1259, 5fecb08fa18c)
  • Prior blocker remains applicable: The supplied prior review identified raw watched-session disclosure to pairing-only and node recipients; the current PR file list contains no changed recipient-projection or broadcast-authorization implementation that would resolve that boundary. (src/gateway/server.impl.ts:1261, 5fecb08fa18c)
  • Connection-row change affects existing consumers: The PR changes non-node presence identity from device/instance ownership to per-connection ownership, while the prior review identified existing consumers that collapse presence into device connectivity state. (src/gateway/server/ws-connection/connect-session.ts:125, 5fecb08fa18c)
  • Feature provenance: The related merged identity-in-presence work establishes the user identity prerequisite; this PR is the candidate implementation for the watched-session portion of the broader shared-gateway identity design. (packages/gateway-protocol/src/schema/snapshot.ts:37, c684b1321333)
  • Current-main status: The supplied GitHub state reports this PR open and unmerged at head 5fecb08, with current main at d4ed089; no merged replacement is identified that would make this PR obsolete. (d4ed08994d31)

Likely related people:

  • steipete: Authored the merged presence-identity prerequisite and the current watched-session implementation, and the related umbrella design identifies this work as part of the shared-gateway identity program. (role: feature owner and recent area contributor; confidence: high; commits: c684b1321333, 5fecb08fa18c; files: src/gateway/server/ws-connection/connect-session.ts, src/gateway/server.impl.ts, packages/gateway-protocol/src/schema/snapshot.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (3 earlier review cycles)
  • reviewed 2026-07-19T06:06:10.762Z sha 7b821e5 :: needs real behavior proof before merge. :: [P1] Restrict watched session keys to read-authorized clients | [P2] Normalize global session keys before viewer lookup
  • reviewed 2026-07-19T07:30:31.334Z sha a6d0efb :: needs real behavior proof before merge. :: [P1] Restrict watched session keys to read-authorized recipients | [P2] Preserve device connectivity when presence becomes per-connection | [P2] Broadcast identified presence when a client connects | [P2] Track an active session instead of accumulated subscriptions
  • reviewed 2026-07-19T08:12:43.277Z sha a6d0efb :: needs real behavior proof before merge. :: [P1] Restrict watched keys to read-authorized presence recipients | [P2] Preserve device connectivity across per-connection presence rows | [P2] Broadcast presence when an identified connection comes online | [P2] Do not equate retained subscriptions with active viewing

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

Copy link
Copy Markdown
Contributor

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: 85ba6a0c2c

ℹ️ 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".

Comment on lines +126 to +129
const presenceKey = shouldTrackPresence
? role === "node"
? (device?.id ?? instanceId ?? connId)
: connId

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Badge Preserve device connectivity across reconnect presence rows

When a paired non-node client reconnects or has multiple tabs, keying presence by connId leaves several rows with the same deviceId, including disconnect rows retained for five minutes. listSystemPresence() returns newest-first, but both ui/src/pages/nodes/nodes-page.ts:59-70 and ui/src/components/app-sidebar-session-catalog-live.ts:286-300 overwrite device state while iterating, so an older disconnect row can win over the live row. The reconnect then appears to have no connectivity transition, preventing the immediate device/node and session-catalog refresh and leaving the UI stale until polling. Preserve a device-level aggregate or make every consumer explicitly reduce multiple connection rows so any live connection wins.

Useful? React with 👍 / 👎.

@steipete steipete closed this Jul 19, 2026
@steipete steipete reopened this Jul 19, 2026

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

Copy link
Copy Markdown
Contributor

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: 887e7024ea

ℹ️ 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".

Comment on lines +1237 to +1240
const presenceWatchedSessions = (connId: string): string[] => {
// Presence snapshots stay small even if a long-lived client accumulates
// subscriptions. Keep only the 32 most recently subscribed session keys.
return [...sessionMessageSubscribers.getForConnection(connId)].slice(-32).toSorted();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Badge Track the active native session instead of every subscription

On trusted-proxy or Tailscale gateways where native iOS/macOS clients receive a user identity, this projects every accumulated message subscription as actively watched. Both native setActiveSessionKey implementations only call subscribe and never unsubscribe the previous key (apps/ios/Sources/Chat/IOSGatewayChatTransport.swift:300-305, apps/macos/Sources/OpenClaw/WebChatSwiftUI.swift:625-633), so after switching sessions the user remains in facepiles for every session visited during that connection, up to this 32-key cap. Track an explicit active key or update the native subscription lifecycle before treating these keys as viewer presence.

Useful? React with 👍 / 👎.

Comment on lines +332 to 335
instanceId: role === "node" ? (device?.id ?? instanceId) : instanceId,
...(authenticatedUserId
? { user: { id: authenticatedUserId, email: authenticatedUserId } }
: {}),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Badge Broadcast presence when an identified connection comes online

When an identified Control UI client connects directly to a non-chat route, existing clients never learn that it is online: this connect block updates the presence map but only increments the version, while the sidebar consumes hello and presence events and message subscription broadcasts occur only after the chat page calls sessions.messages.subscribe. Consequently the new footer facepile stays stale until that user visits chat or an unrelated presence change happens; broadcast the connect-time snapshot after inserting the per-connection row.

Useful? React with 👍 / 👎.

@steipete
steipete force-pushed the claude/identity-session-viewing branch from 887e702 to a6d0efb Compare July 19, 2026 07:27
@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. labels Jul 19, 2026
@steipete
steipete force-pushed the claude/identity-session-viewing branch from a6d0efb to 5fecb08 Compare July 19, 2026 08:59

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

Copy link
Copy Markdown
Contributor

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: 5fecb08fa1

ℹ️ 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".

Comment on lines +164 to +170
<openclaw-viewer-facepile
.presencePayload=${this.presencePayload}
.selfInstanceId=${this.presenceInstanceId}
.sessionKey=${session.key}
.maxVisible=${3}
variant="session"
></openclaw-viewer-facepile>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Badge Show viewers on the main-session Home row

This adds the session facepile only to renderRecentSession, but selectedAgentSessionRows deliberately removes the main session from that list (ui/src/components/app-sidebar-session-navigation.ts:560-571) and renderHomeRow has no equivalent facepile. Consequently, when another identified user watches the agent's main session—the default and most prominent conversation—the sidebar shows no viewers on Home even though presence advertises them. Render the same facepile on the Home row using mainKey.

Useful? React with 👍 / 👎.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels Jul 19, 2026
@steipete
steipete merged commit 5c99169 into main Jul 19, 2026
129 of 131 checks passed
@steipete
steipete deleted the claude/identity-session-viewing branch July 19, 2026 09:53
@steipete

Copy link
Copy Markdown
Contributor Author

Merged via squash.

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 20, 2026
…enclaw#111225)

* feat(gateway): expose watched sessions in presence

* fix(gateway): resolve concurrent watched-session rollbacks via in-flight state

* fix(ui): viewing CI conformance — lazy facepile, bindings, dead exports

* fix(ui): move viewer presence projection out of the startup chunk

* fix(ui): capture sessionKey before facepile filter closure
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app: web-ui App: web-ui gateway Gateway runtime maintainer Maintainer-authored PR merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. P1 High-priority user-facing bug, regression, or broken workflow. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: L status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant