feat(gateway): durable user profiles with email aliases and avatars#111224
Conversation
|
Codex review: needs real behavior proof before merge. Reviewed July 19, 2026, 3:11 AM ET / 07:11 UTC. Summary PR surface: Source +940, Tests +599, Other +4. Total +1543 across 21 files. Reproducibility: not applicable. This PR proposes a new durable identity capability rather than reporting a current failing behavior; the linked identity program supplies the design rationale. Review metrics: 2 noteworthy metrics.
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 lazy activation, but declare the additive tables in the canonical shared-state schema, preserve the one-time lazy ensure, demonstrate a redacted authenticated end-to-end users/avatar flow, and land only with explicit approval of the durable identity API. Do we have a high-confidence way to reproduce the issue? Not applicable: this PR proposes a new durable identity capability rather than reporting a current failing behavior; the linked identity program supplies the design rationale. Is this the best way to solve the issue? No, not yet: durable profiles are a plausible solution, but persistent tables must be declared through the canonical shared-state schema and the resulting operator flow needs real authenticated proof. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against aae5b0f041db. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source +940, Tests +599, Other +4. Total +1543 across 21 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
Review history (1 earlier review cycle)
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1807de5d26
ℹ️ 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".
| // Canonical additive schema for durable user profiles. Kept feature-local so | ||
| // ordinary shared-state opens do not create identity tables until they are used. | ||
| export const USER_PROFILES_SCHEMA_SQL = ` |
There was a problem hiding this comment.
Register the profile tables in the canonical state schema
These tables exist only in this feature-local DDL, so scripts/generate-kysely-types.mjs omits them from generated shared-state types and src/state/openclaw-state-db-maintenance.ts cannot validate or repair their shape. This also directly violates AGENTS.md:80, which requires additive SQLite tables to be declared in src/state/openclaw-state-schema.sql as well as lazily ensured. Keep the idempotent feature-use ensure, but make the canonical schema the authoritative declaration so future schema generation, verification, and migrations include this persistent user data.
Useful? React with 👍 / 👎.
…sers CLI json output
1807de5 to
bdfa07c
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bdfa07c402
ℹ️ 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".
| export * from "./schema/audit-activity.js"; | ||
| export * from "./schema/audit.js"; | ||
| export * from "./schema/board.js"; | ||
| export * from "./schema/users.js"; |
There was a problem hiding this comment.
Register user schemas in the canonical protocol registry
Exporting users.ts here does not add these definitions to ProtocolSchemas in packages/gateway-protocol/src/schema/protocol-schemas.ts; both scripts/protocol-gen.ts and scripts/protocol-gen-swift.ts iterate only that registry. Consequently, the published protocol.schema.json and generated Swift bindings omit UserProfile and every new Users* request/result type, leaving native and schema-driven clients without the typed contracts for these RPCs. Register all new definitions in ProtocolSchemas and regenerate the protocol outputs.
Useful? React with 👍 / 👎.
|
Merged via squash.
|
…penclaw#111224) * feat(gateway): durable user profiles with email aliases and avatars * fix(gateway): compress merge tombstones, content-hash avatar ETags, users CLI json output * fix(gateway): lean profile listing, scoped avatar routing, typed email validation * fix(gateway): protocol-complete profile payloads and consistent store reads * fix(gateway): mark profile schema ensured only after commit * fix(gateway): avatar endpoint HEAD support and RFC If-None-Match * fix(gateway): profiles CI conformance — bindings, lint, knip, sql boundary * feat(gateway): self-service profile edits for authenticated users * fix(gateway): users.self bootstrap, tombstone-aware ownership, escaped CLI output * fix(gateway): raw-DDL allowlist entry and lean profile exports
What Problem This Solves
The identity program (#111133) keys everything on the email that Cloudflare/trusted-proxy auth verifies — but emails are login claims, not durable keys. People change emails; a raw-email identity layer would orphan presence grouping and prompt attribution history. There is also nowhere to store a display name or avatar for a teammate on a shared gateway.
Part of the multiplayer-identity program: #111133 (profiles PR of the train; #111179 and #111207 already landed).
Why This Change Was Made
Adds the durable identity layer as additive tables in the shared state SQLite DB (no schema-version bump; idempotent lazy ensure on first use):
user_profiles— stable opaque id, display name, avatar blob + sha256,merged_intotombstone.user_profile_emails— lowercased email aliases → profile id.ensureProfileForEmaillazily creates a profile on first login;resolveProfileByEmailfollows at most one tombstone hop. Email change: the new email auto-creates a profile; adminusers.linkEmailre-points the alias to the person's real profile; if the orphan loses its last alias it is tombstoned (merged_into), and merge path-compression repoints older tombstones so chains never exceed depth 1 — durable references (e.g. prompt attribution) written before the merge still resolve.users.list(read scope) /users.linkEmail,users.setDisplayName,users.setAvatar(admin scope), with protocol-complete result payloads.GET /api/users/:profileId/avatar— authenticated avatar serving with content-hash+MIME ETags, HEAD support, RFC 9110 If-None-Match semantics.openclaw users list,openclaw users link-email <email> --to <profileId>.Identity remains purely optional: nothing runs (not even DDL) until a profile API is first used; existing gateways are byte-identical.
User Impact
No visible change on its own. Enables the settings identity UI (display name/avatar) and the presence enrichment that switches
user.idfrom email to stable profile id.Evidence
node scripts/run-vitest.mjs src/state/user-profiles.test.ts src/gateway/user-profiles-http.test.ts src/gateway/server-methods/users.test.ts src/cli/users-cli.test.ts src/gateway/method-scopes.test.ts src/gateway/server-methods.authorization.test.ts— all green (store roundtrip/merge/tombstone compression/cycle prevention, ETag + HEAD + If-None-Match forms, RPC scope enforcement incl. dispatcher-level admin test, CLI JSON output).node scripts/generate-kysely-types.mjs --verify— passed.