refactor(chat): retire members' handles: nothing reads or writes them
Merged
DA
5d ago+15616+15616+01234567890123456789012345678901234567890123456789-153-153-012345678901234567890123456789
Summary
This is step 3a of replacing chat handles with mention links, from Audit Chat page and use common app components/styles. Since #4004 and #4009, nothing shows or uses a member's handle, but the code still minted and read one. This PR stops both, so the column can be dropped in a contract migration. That drop is step 3b, at least 25 hours after this reaches production, following the repo's expand–migrate–contract rule: a column may only be dropped once the code that stopped writing it has drained.
Store
- No handle is minted or read. These are removed:
mintHandle,findHandles,findAccountName,personStem,SPOKEN_FOR,FALLBACK_HANDLEandMAX_HANDLE_STEM_CHARS, plushandleonChatMemberRowandinsertMember. - Migration
20261021033224_chat_member_handle_retire:chat_member.handledefaults togen_random_uuid(). A deployment from before this PR still reads a non-null string, and the column's unique index still holds for rows minted without a handle.
Wire and service
- Removed:
chatMemberSchema.handle,chatHandleSchema,LUKE_HANDLEandCHAT_BOUNDS.MAX_HANDLE_CHARS. - The window's held read no longer sends a handle, and the desktop's live-row decoder no longer reads one.
- Live members statement: it hands each row the member's id in place of a handle, instead of reading the column.
Evidence
- Typecheck is clean in features, database, service, ui, panel, host and desktop.
- Lint and migrations: oxlint, biome and
check:migrationspass. Knip's findings are all onmainalready; none are from this PR. - Tests: 248 pass across the features, panel, host, ui and inbox suites.
coding-agents-app.test.tspasses 46 chat tests,workspace-chat.test.tsandlive-statements.test.tspass 11, and the chat-store and inbox-store suites pass 54. - New and rewritten tests:
- Minting: members are minted once per subject and numbered among their kind. The test inserts five people and two agents with no handle, which proves the new default stays unique under the index.
- Live stand-in: each live member row's
handleis the member's id. - Wire assertions: the window's read names its reader and teammates by name rather than by handle.
Invariants
-
./scripts/check.shgreen. (CI) - No column dropped. The
-- contract:drop is step 3b, at least 25 hours after this reaches production. - Every behavior change has, in this PR, the test that fails without it; no change-detector test added.
- No new
astype assertion outside the allowlisted files. (CI via anti-slop) - No
Effect.runPromise/runSync/runForkoutside the runtime edges. (CI) - No new raw async primitives. (CI)
- Test count: the handle grammar test removed; the minting test rewritten; the live stand-in test added.
-
PRIVACY.mdunchanged. - Package deps unchanged. (CI)
After this
Step 3b: a migration that drops chat_member.handle and chat_member_organization_handle, marked -- contract:, with the schema property removed. It can start 25 hours after this reaches production.
Made with Luke