Repository navigation
AUTH-MAIL-002C1 — Make password-reset requests honest and repeat-safe #155
Description
Officer impact: Members get one safe password-reset result that does not reveal whether an account exists and does not promise that email was sent or delivered. A visible wait prevents accidental repeat requests. Officers never ask for an address, password, code, link, screenshot, or mailbox access in a public issue or AI tool.
Officer documentation: Update docs/officers/EMERGENCY_AND_RECOVERY.md and the minimum exact membership/account guide. Keep the revised behavior NOT AVAILABLE YET until the exact website revision is published and verified.
Deployment evidence: None at issue creation. Closure must separate source/tests, merge, website publication, runmprc.com verification, Firebase/provider configuration, and production behavior. Tests are synthetic and make no network or email request.
Parent and dependencies
Focused AUTH-MAIL-002C1 child of #120. #145 completed registration truth. #153 completed verification resend truth. #99, #103, and #111 provide isolated tests, callback safety, and redacted diagnostics. #119 owns sender/provider configuration. #105/#133/#136 own protected publication. This child does not implement incoming Firebase action-code handling; that remains a separate C2 slice.
Problem
The current Forgot password path always says a link is on its way after the provider call finishes, even when that call failed and was intentionally swallowed. That protects against account enumeration but makes an unproven delivery promise. It also has no immediate in-flight guard, no visible cooldown, and no tested retry or cleanup state.
Atomic outcome
Replace the reset flag with one small state machine:
- Idle: Forgot password? is available after a locally entered address.
- Requesting: one disabled large action; rapid repeat activation makes one provider call.
- Finished: the same fixed public result after provider success or failure. It says email delivery cannot be confirmed and gives safe Inbox/Spam/wait guidance without claiming an account or message exists.
- Cooldown: both provider outcomes show the same 60-second countdown, then allow one retry.
The cooldown is a browser usability guard, not durable abuse protection. Refresh/remount may reset it; Firebase throttling can still apply.
Invariants
- Success, missing-account, throttled, offline, malformed-provider, and provider-failure outcomes use the same public result after a request is attempted.
- Never say sent, delivered, on its way, account exists, account missing, provider accepted, or provider failed.
- Missing local input may ask the member to enter an address; it does not call Firebase.
- A synchronous in-flight guard prevents rapid duplicate calls before React state updates.
- Success and failure use the same visible cooldown and retry transition.
- No caught provider object, address, UID, code, token, link, or query/fragment enters UI, logs, analytics, screenshots, or test output.
- Reset does not sign in, create an account, change membership/roles/dues, navigate, or edit Firestore.
- Tests use synthetic mocks only and make no network or production-mail request.
Exact source boundary
- src/pages/login/LoginForm.jsx
- src/pages/login/LoginForm.test.jsx
- src/pages/login/LoginForm.css only for scoped large/focus-visible reset controls
- docs/officers/EMERGENCY_AND_RECOVERY.md
- docs/officers/EVENTS_SHOP_MEMBERS.md only if needed for one cross-reference
- minimum exact status hunks in SECURITY.md, OPERATIONS_RUNBOOK.md, GITHUB_ISSUES.md, and GITHUB_ISSUE_SLICES.md
Post a scope amendment before editing Identity runtime, Firebase configuration, workflows, packages, Functions, Rules, provider settings, action-code routes, or any other file.
Acceptance criteria
- Provider success and failure render byte-for-byte-equivalent public result content and accessibility state.
- Result copy is enumeration-resistant and makes no send/delivery/account-existence promise.
- Missing local input makes no provider call and gives one clear next action.
- A synchronous guard proves rapid repeat activation makes exactly one provider call.
- Both outcomes start the same visible 60-second cooldown and recover to one retry action.
- Timer cleanup/remount tests prove no stuck state or post-unmount update.
- Sign-in/registration state, intended return route, and input remain intact; reset makes no unrelated service call.
- Screen-reader announcement, keyboard activation, focus visibility, disabled state, and at least a 44px action target are tested.
- Focused and full frontend, SPA, lint/build, diff/link/sensitive-pattern checks pass.
- Officer guidance states purpose, approver, prerequisites, steps, expected result, stop conditions, proof, undo, and escalation.
Excluded
- DNS, Firebase templates, custom sender, SMTP/mail provider, production delivery tests (AUTH-MAIL-001 — Brand and authenticate Firebase Authentication email #119).
- Firebase action-code landing states such as expired/used/already-complete/wrong account (future AUTH-MAIL-002C2).
- Google sign-in/linking, membership/payment state, Firebase Rules/Functions, workflows, or production data.
Claim
CLAIMED by /root at creation on branch codex/issue-155-password-reset-truth from exact main 23bca8c. One atomic source/test outcome; external release remains separate.
Activity
daliu commentedon Jul 13, 2026
CLAIMED by /root at 2026-07-13T13:12:19Z; branch codex/issue-155-password-reset-truth; exact base 23bca8c. Active ownership is limited to the nine paths listed in the issue. No Identity runtime, Firebase, Functions, Rules, workflows, packages, or provider settings are included.
daliu commentedon Jul 13, 2026
EXTRACTION FINISHED by /root at 2026-07-13T13:30:43Z. Exact staged SHA-256: 2a1acc2e9ee0e6c476558697d74853829047c1653ccb238e35d6620cfdb15972 on unchanged base 23bca8c. Exactly nine owned paths; no unstaged delta. Node 20 proof: focused LoginForm 28/28, full frontend 9 suites/130 tests, SPA 10/10, strict changed-file lint, optimized build, diff/link/sensitive-pattern checks all pass. Three independent exact-hash reviews APPROVED after fixes for the scoped hidden announcement and expired/clock-shift timer recovery. No network, Firebase, mailbox, member data, provider setting, or deployment mutation occurred.
daliu commentedon Jul 13, 2026
COMPLETED / CLAIM RELEASED — 2026-07-13T13:39:26Z
mainas594306fb06d9a6a2a44b5675b305f462f11b877d.2a1acc2e9ee0e6c476558697d74853829047c1653ccb238e35d6620cfdb15972.runmprc.com, Firebase/provider configuration, real mail delivery, and live reset behavior remain unverified. Officer docs therefore remainNOT AVAILABLE YET.All issue acceptance boxes are checked for the atomic source outcome. The
status:in-progresslabel and file claim are released. #120 remains open for C2 action-code states and provider/live evidence.