feat(ui): identity settings and own-identity chip#111371
Conversation
9f97c21 to
82cfcbc
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9f97c2143b
ℹ️ 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".
| const selfUser = resolveSelfPresenceUser(entries, client?.instanceId); | ||
| if (!sameSelfUser(snapshot.selfUser, selfUser)) { | ||
| setSnapshot({ ...snapshot, selfUser }); |
There was a problem hiding this comment.
Preserve local profile edits across presence snapshots
After a display-name or avatar save, any later presence broadcast replaces the locally updated selfUser with the connection-time metadata here. The server explicitly snapshots profile metadata only at connect (src/gateway/server/ws-connection/connect-session.ts:143-151), so ordinary presence churn on a shared gateway reverts the footer chip until reconnect; the added test at ui/src/app/gateway-store.test.ts:194-223 even codifies this overwrite. Keep the locally refreshed fields while the presence entry still identifies the same profile.
Useful? React with 👍 / 👎.
| if (avatarUrl) { | ||
| this.context.gateway.updateSelfUser?.({ avatarUrl }); |
There was a problem hiding this comment.
Feed the saved profile avatar into chat rendering
When an identified user uploads an avatar, this updates only the gateway selfUser projection used by the new footer/profile UI. Chat still initializes userAvatar exclusively from the browser-local identity (ui/src/pages/chat/chat-state.ts:1218-1233), while this commit removes the last profile-page call to saveLocalUserIdentity; consequently the uploaded durable avatar never appears on the user's chat messages, and the previous chat-avatar editor is no longer available. Either bind chat rendering to the durable profile or retain the local editor until that migration is complete.
Useful? React with 👍 / 👎.
| url.pathname = `/api/users/${encodeURIComponent(profileId)}/avatar`; | ||
| url.search = `?v=${updatedAt}`; | ||
| url.hash = ""; | ||
| return url.href; |
There was a problem hiding this comment.
Fetch protected profile avatars with gateway authentication
For tokenless Tailscale-authenticated identity connections, this URL is assigned directly to an <img>, which cannot attach the Control UI's Bearer credential. The avatar handler requires scoped HTTP authentication (src/gateway/user-profiles-http.ts:34-45), and HTTP authentication intentionally disables Tailscale forwarded-header auth (src/gateway/auth.ts:605-610), so the new profile preview and own-identity chip receive an unauthorized response instead of the saved image. Load the bytes through an authenticated fetch/blob path or provide an equivalent authenticated image-delivery contract.
Useful? React with 👍 / 👎.
|
Codex review: needs real behavior proof before merge. Reviewed July 19, 2026, 6:45 AM ET / 10:45 UTC. Summary PR surface: Source +325, Tests +293. Total +618 across 22 files. Reproducibility: yes. from source inspection: save an avatar or display name, receive a later same-user presence event, and the gateway store restores the connect-time data; tokenless Tailscale authentication also provides a clear protected-avatar rendering path to verify live. Review metrics: 1 noteworthy metric.
Stored data model Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Proof guidance:
Risk before merge
Maintainer options:
Next step before merge
Maintainer decision needed
Security Review findings
Review detailsBest possible solution: Keep durable gateway profiles as the shared identity source, add an authenticated avatar-delivery path, retain refreshed self-profile state through same-profile presence updates, and either migrate chat rendering to that source or preserve the browser-local chat editor until an explicit migration is approved. Do we have a high-confidence way to reproduce the issue? Yes from source inspection: save an avatar or display name, receive a later same-user presence event, and the gateway store restores the connect-time data; tokenless Tailscale authentication also provides a clear protected-avatar rendering path to verify live. Is this the best way to solve the issue? No. The durable-profile direction is coherent, but the implementation must preserve or explicitly migrate the existing chat identity surface and use authenticated avatar delivery rather than raw image URLs. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against ef91ce57124b. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source +325, Tests +293. Total +618 across 22 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
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
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e439871276
ℹ️ 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".
| if (nextSelfUser && (clientChanged || selfProfileChanged)) { | ||
| void this.loadIdentity(); |
There was a problem hiding this comment.
Gate profile bootstrap on operator.write
When an identified Control UI connection is restricted to operator.read—for example, a trusted-proxy connection capped by x-openclaw-scopes—presence still supplies nextSelfUser, so this unconditionally calls users.self. That RPC requires operator.write (src/gateway/methods/core-descriptors.ts:129-133), while read-only identified connections are explicitly supported (src/gateway/server.auth.trusted-proxy-device-autoapprove.test.ts:256-277), leaving the advertised Identity section permanently at “profile could not be loaded” and its controls unusable. Gate the section/bootstrap on write access or provide a read-only profile contract.
Useful? React with 👍 / 👎.
|
Merged via squash.
|
* feat(ui): identity settings and own-identity chip * feat(ui): resolve own identity via users.self * fix(ui): rebase identity settings onto landed identity stack * fix(ui): footer identity chip prefers locally updated self profile * fix(ui): settings CI conformance — split profile page, lean exports
What Problem This Solves
The identity stack is live on shared gateways (#111179, #111207, #111224, #111225, #111311), but a person has no way to see or shape their own identity: no profile view, no display-name editing, no avatar upload, and no "this is me" anchor in the UI.
Part of the multiplayer-identity program: #111133 (settings/UI PR — the final piece).
Why This Change Was Made
users.selfbootstrap RPC; edits display name (users.setDisplayName) and avatar (client-side downscale to 256×256, 512 KB cap,users.setAvatar) — self-service authorized by the write-scope + own-profile contract from feat(gateway): durable user profiles with email aliases and avatars #111224.Hard product rule enforced and tested: no identity → no Identity section, no chip, no
users.selfcall, byte-identical UI.User Impact
Teammates on shared gateways can set their name and avatar, and see themselves anchored bottom-left. Identity-less gateways see zero change.
Evidence
user.idandusers.self).