activateKeylessUser(userId: number,password: string,): Promise<boolean>
Complete a keyless invite (the editor role): set the password and clear
the invite, leaving wrapped_data_key NULL. An editor holds no DATA_KEY, so
unlike acceptInvite there is no handoff to unwrap or re-wrap — the
password only authenticates; it protects no key. The user's role is fixed at
invite time and is not changed here.
Single-use: the UPDATE is guarded on password_hash = '' (the unactivated
marker — buildUserInsert stores a literal empty string until a password is
set, and database pruning uses the same marker). So a replay or a race only
affects the row on the first submit; later submits no-op and return false
rather than overwriting the password the first submit set.