---
id: server-architecture/017
title: Password reset by hand — a support address, not self-service
epic: server-architecture
state: backlog
priority: 3
blocked_by: []
estimate: S
created: 2026-08-13
updated: 2026-08-13
claimed_by: null
claimed_at: null
delivers: []
review_artifact: null
---

## What this is

**Kris's call, 2026-08-13: there is no self-service password reset.** Email
login stays (it's how the web build signs in), but a player who forgets their
password emails a support address, Kris confirms it's really them, and Kris
resets it by hand.

This replaces both earlier attempts at the problem: the emailed reset link
(blocked on DNS at a panel with no API — task 012) and an automated recovery
code (built 2026-08-13, then reverted the same day; a code written down at
signup is a second secret handed to someone who just demonstrated they lose
secrets, so for this game's players the realistic recovery rate is near zero).

Doing it by hand is the honest answer at this scale. There are no players yet;
when there are, a human reply is better service than a broken robot, and it can
be automated later if the volume ever justifies it.

## Step 2 is done — the server no longer lies (2026-08-13)

`request_password_reset` used to ack and silently do nothing, so a client could
say "check your email" for a mail that would never arrive. It now returns
`RESET_UNAVAILABLE` with a message read from the new **`SUPPORT_EMAIL`** env
var: with an address set it says "email X and we'll sort it out"; with none set
(the current state) it says plainly that passwords cannot currently be reset
and names no channel at all — inventing a contact route the player can't use
is the exact failure being fixed. Deployed and verified live.

Turning this on is one env-file line plus `game/update_game_env.sh` — no code
change, no rebuild.

Worth knowing: nothing in the Godot client ever called
`request_password_reset` (there's a helper in `account_session.gd` and no UI),
so no player was ever actually shown the false promise.

## What to do

1. **Pick the address** (Kris) — the open item. It needs a mailbox that
   actually RECEIVES mail; this is unrelated to task 012's Resend *sending*
   setup and does not require it. What was ruled out on 2026-08-13:
   `@cocreations.com.au` addresses don't work, and the reason is worth
   recording — the domain's MX points at `sv1.byethost1.org` (the Byethost
   free-hosting web server), whose Exim accepts mail for *every* address at the
   domain (`kris@` and a deliberately fake address both answered `250
   Accepted`) and then has no mailbox to deliver into. Mail arrives somewhere
   that can't store it. Fixing that needs real hosting, which is the same wall
   task 012's DNS work hit.

   **`ai-task-runner.com` is explicitly ruled out** (Kris, 2026-08-13) — it was
   floated only because its DNS sits somewhere with a working API, but it is
   the task-runner platform's domain and has no business carrying game mail.

   **The intended answer is `spellgrove.com`** (Kris, 2026-08-13): register the
   working title's domain and use it for both the public site and email, set up
   deliberately and simply, with DNS under an API key an agent can actually
   use. That's [018](018-spellgrove-domain.md). Until it exists, a plain new
   Gmail forwarded to Kris's inbox is the stopgap — and since `SUPPORT_EMAIL`
   is just an env var, swapping the stopgap for the real address later costs
   one line.
2. ~~**Make the server honest**~~ — done, see above.
3. **Give Kris a reset command** — resetting by hand currently means hand-rolled
   SQL against `auth_identities`, which is exactly how a wrong row gets updated
   at 11pm. `identities.ts` already exports `updateIdentityPassword`; a small
   one-shot admin script (email in, new password out, refuses on no-match)
   wrapping it is the whole job. It should also revoke that account's sessions,
   per 014's reasoning that a forgotten password may be a stolen one.
4. **Client copy** — the "forgot password" surface says to email the address.

## Definition of done

- ~~No UI anywhere claims a reset email is coming.~~ ✓ (2026-08-13)
- Kris can reset a named account's password with one command, with sessions
  revoked, without writing SQL.
- The support address is documented wherever the client copy points at it.

## Assumptions

That email+password login itself stays exactly as it is — Kris confirmed the
web build still needs it. Nothing here changes signup, login, link codes, or
the provider paths.