Account Linking
/login without arguments mints a 2-minute account-wide code for the current platform identity. The user sends /login <code> from another supported platform to link both platform identities to one account_people record.
A sender has at most one live code: minting a new one supersedes any previous unredeemed code. A code is one-time — once redeemed it is bound to the redeeming sender, so a redelivery of the same /login <code> from that sender is idempotent, and no one else can claim it.
Memory
Linking only asks a question when it has to. Let *target* be the identity that minted the code and *source* the identity that redeemed it.
- Only the target has relationship memory — the source inherits it. No prompt.
- Only the source has relationship memory — the source keeps it, and emotional state is left alone because nothing was discarded. No prompt.
- Both have relationship memory — the chat asks which side should win.
Accepted replies to the prompt are 1 (source), 2 (target), either platform label, or cancel. 1/2 are the only forms that work for a same-provider link (both labels start with the same platform name) and the only forms typeable on every keyboard; 取消 also cancels. After a few unrecognized replies the prompt cancels itself rather than intercepting the sender's messages forever, and a pending prompt stops intercepting once it expires.
Memory resolution does not merge relationship memory. After the user chooses a side, the selected relationship memory remains active and emo_emotions rows for the selected relationships are cleared so emotion reads fall back to the character baseline. cancel leaves the account link in place and keeps the current memory mapping.
Known follow-up: while a memory prompt is pending, command-shaped replies like /logout, /reset, or /help are currently treated as unrecognized memory-choice text and may reprompt instead of executing the command. This is acceptable for the initial rollout because prompts expire and self-cancel, but the router should eventually define an explicit command escape policy, especially for /logout.
Logout
/logout detaches the sender's messaging identity from the apps reachable on that line. Once no live user_surfaces row remains for that subject anywhere in the account, the account-wide account_person_surfaces row is retired too — otherwise the account-wide identity would resolve the detached user (and their memory) back on the sender's next message.