fix(identity): per-user-agent id convention (u+sha10) + shortest-unambiguous handles - #930
Merged
Merged
Conversation
…biguous mention handles Sam on the first migrated identity: "that guide agent id is that long? will this be our convention????" No. Two fixes, one convention: 1. instanceId = u + sha256(userId).slice(0,10) — short enough for a handle, derivable at signup, and OPAQUE: the raw ObjectId no longer survives into any identity tier (the first cut leaked it through instanceId, username, and the collision-suffixed displayName; fleet review measured all three). Migration normalizes both legacy forms — long-form envelopes are renamed (single-owner by construction), shared 'default' envelopes stay quarantine-only. 2. The hash should also never be SEEN: the typeahead and delivery hint now apply the backend's own shortest-unambiguous rule (bare agentName resolves whenever a pod has exactly one installation of it — mention map line 195). "@guide" is the handle in every workspace; instanceId handles surface only when two instances of one agent actually share a pod — the case they were built for. Without this, the fork regressed the #914 hint into "Try @u6a7d154a0ec237d4b15dd286". Tests pin the convention shape (u+10hex, raw userId absent) and distinctness. Typecheck clean both tiers. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XeUH4HVDsDHYPsHJthXjB8
…ceIds always
CI caught my shortest-unambiguous rule regressing the moltbot case: for
openclaw agents the instanceId ("aria") IS the identity and agentName is the
runtime label we never surface — the rule would have suggested "@openclaw".
The distinction that actually matters is opacity, and the new convention
makes it detectable: isOpaqueInstanceToken (u+sha10 + legacy long form)
falls back to agentName; every human-chosen instanceId stays the handle.
Both directions pinned in the hint suite (@aria stays; @guide never shows
the token).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeUH4HVDsDHYPsHJthXjB8
lilyshen0722
added a commit
that referenced
this pull request
Aug 13, 2026
…ffixes (#934) Every user's Guide is displayName "Guide" by design, so the inline collision resolver suffixed each one after the first with its own opaque instance token — "Guide (U0da521ab41)" in every chat byline (observed live 2026-08-13). That is the exact leak the #930 identity convention exists to prevent, at the third of the four name sources. - resolveCollisionFreeDisplayName: opaque tokens (convention u+10hex or legacy long form) keep the bare name — per-user agents are pod-scoped, so same-named agents of different users never co-render; a future shared-pod surface should disambiguate by OWNER, not token (ADR-020). - offline dedup script: opaque-token agents excluded from grouping entirely (neither receive nor force a suffix); regex kept identical. - strip-opaque-displayname-suffixes.ts: one-shot repair for rows written before the fix — only strips a suffix exactly matching the row's own humanized token, --dry supported. Claude-Session: https://claude.ai/code/session_01XeUH4HVDsDHYPsHJthXjB8 Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Sam's two flags on the migrated Guide identity, answered as one convention:
The id itself:
u<24-hex-ObjectId>was the 2am privacy fix, not a convention. The convention for per-user agents is nowu+ first 10 hex of sha256(userId) — short, signup-derivable, and opaque (the ObjectId no longer survives into any identity tier; the fleet review measured it leaking through instanceId, username, AND the collision-suffixed displayName). Migration (--drysupported) normalizes both legacy forms: long-form memory envelopes are renamed (single-owner by construction), shareddefaultenvelopes remain quarantine-only.Whether anyone sees it: they shouldn't. The backend's mention map already resolves a bare agentName whenever a pod has exactly one installation of it — but the typeahead and the delivery hint preferred instanceId, which post-fork meant "Try @u6a7d154a0ec237d4b15dd286". Both now apply the same shortest-unambiguous rule: @guide everywhere, instanceId handles only when two instances of one agent genuinely share a pod.
Post-merge: run the migration on dev (normalizes the smoke install), then verify @guide typeahead live.
Tests pin the convention shape and distinctness; typecheck clean both tiers; frontend jest in CI.
🤖 Generated with Claude Code
https://claude.ai/code/session_01XeUH4HVDsDHYPsHJthXjB8