Skip to content

An invitee whose invite can't be read or used is asked to sign in again, instead of let in with no household (#240) - #247

Merged
smilne3 merged 2 commits into
mainfrom
fix/240-invitee-try-again
Nov 5, 2026
Merged

smilne3 merged 2 commits into
mainfrom
fix/240-invitee-try-again

Conversation

@smilne3

@smilne3 smilne3 commented Nov 4, 2026 •

Copy link
Copy Markdown
Owner

This finishes #240, using the option recommended there. An invited partner whose first sign-in couldn't read or use their invite used to get into the app with no household. Now they're asked to sign in again.

What changes for you

Nothing for you or anyone already in the household. The change is for someone signing in for the first time with an invite, when the database fails at that moment:

What fails Before Now
Reading their invite let in: Home says "Connect your first account", Settings "No household found", and the invite is never used "Sign-in couldn't be completed" and Back to sign in. Signing in again finishes it.
Adding them to the household the same, and nothing was logged the same as above, and it's logged
Using up the invite, after they were added let in, and nothing was logged still let in, since they're in the household, and now it's logged
Reading whether they're a member let in still let in, as #240 recommended keeping

The last row is unchanged on purpose. Asking everyone to sign in again when that read fails would also stop existing members, and row-level security still keeps anyone from data that isn't theirs.

The "Sign-in couldn't be completed" page now says "Something went wrong while signing you in." It used to say "reaching the sign-in service", which isn't true when the database is what failed.

How

  • lib/access.ts: ensureHouseholdAccess answers 'let-in', 'try-again' or 'not-invited' instead of true or false.
    • 'try-again' means not a member, and their invite couldn't be read, or adding them failed.
    • The account and the invite are kept, so signing in again can finish it.
    • Each case logs [access] … so ask them to sign in again with the error.
  • Two first sign-ins at once: the second insert of the same membership hits the database's unique key. That person is a member, so they're let in and the invite is used up.
  • app/auth/confirm/route.ts: on 'try-again', it signs the new session out locally and then redirects to /auth/try-again. That's what it already does when Supabase Auth can't be asked (A Supabase auth outage signs everyone out: proxy.ts treats any getUser() error as "no user" #143). Kept, the new session's cookie would let them into the app with no household.
  • Adding them failing wasn't in An invited partner whose first sign-in hits a failed read gets in with no household, and the invite is never used #240's text. It has the same result for the same person, though, so it gets the same answer. If that insert's reply was lost after it landed, signing in again finds the membership and lets them in.

Checked

  • New tests:
    • A failed invite read, or a failed insert, answers 'try-again', deletes no one, keeps the invite and logs it.
    • An insert that finds the membership already made lets them in and uses up the invite.
    • A failed clean-up of the invite still lets them in, and logs it.
    • A failed membership read still lets the sign-in through.
    • An account with no email is still removed.
    • The route sends 'try-again' to "Sign-in couldn't be completed", and signs out before it answers.
  • With the real Supabase client: a local sign-out clears every cookie that a sign-in earlier in the same request wrote. That includes a session big enough to be split across several cookies, with Supabase Auth unreachable for the sign-out. Both try-again paths rely on this, and before, only a cookie that came in with the request was tested.
  • Mutations: I broke each guard in turn (11 mutants), and tests caught all 11. They included:
    • letting them in on either failure
    • asking a racing sign-in, or someone whose invite clean-up failed, to try again
    • leaving the invite after a race
    • dropping the clean-up's log line
    • asking members to try again when the membership read fails
    • keeping the session, or not waiting for the sign-out
    • a cookie store that forgets its own writes, which fails the real-client test
  • Locally: vitest passes 2490/2490 in both time zones. tsc, lint, check:secrets, check:invariants and next build all pass.
  • No phone check needed. Members' sign-in doesn't change, and the page's new sentence is seen only after a failure.

Review

Sign-in failure paths: nothing Critical.

  • It ran next start against a local stand-in for Supabase. On 'try-again', the redirect cleared the session cookie in every run: after a failed invite read, after a failed insert, and with a session split across two cookies while Supabase Auth was unreachable.
  • It found no realistic way to loop on "try again": invite emails are unique, and an invite goes with its household.
  • One Important finding, fixed: the invite clean-up's error was ignored. It's now logged.
  • Suggestions, all taken:
    • the race on the membership insert
    • the real-client cookie test
    • comments in lib/household.ts and seven tests that still said sign-in lets someone through whenever it can't check, and three in lib/access.ts
    • the page's wording

Found along the way

The review filed two issues it found, both from before this PR:

Closes #240.

🤖 Generated with Claude Code

@vercel

vercel Bot commented Nov 4, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
every-dollar-counts Ready Ready Preview Nov 5, 2026 4:33pm UTC

smilne3 and others added 2 commits November 5, 2026 10:42
…in, instead of let in with no household (#240)

When the membership read found none but the invite read failed, or adding
the invited person to the household did, lib/access.ts let the sign-in
through. The invited partner then reached the app with no household, and
the invite went unused, until they happened to sign out and in again.

ensureHouseholdAccess now answers 'let-in', 'try-again' or 'not-invited'.
On 'try-again', app/auth/confirm/route.ts signs the new session out
locally and sends them to /auth/try-again, as it already does when
Supabase Auth can't be asked, and signing in again runs the check again.
The account and the invite are kept, and both cases are logged.

A failed membership read still lets the sign-in through. An existing
member gets past a passing failure, and RLS still guards the data.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… and the try-again words fit both causes (#240)

From the review of #247:

- Two first sign-ins at once: the second insert of the membership hits
  the unique key. That person is a member, so they're let in and the
  invite is used up, rather than asked to sign in again.
- When using up the invite fails after the membership was made, they're
  still let in, and it's logged. The invite left behind would add them
  back if they were ever removed by hand (#248).
- The try-again page said "Something went wrong reaching the sign-in
  service". In #240's cases the database failed, not the sign-in
  service, so it now says "Something went wrong while signing you in."
- A test with the real Supabase client shows that a local sign-out
  clears every cookie a sign-in earlier in the same request wrote,
  including a session split across cookies. Both try-again paths rely
  on that, and before, only a cookie that came with the request was
  tested.
- Comments that still said sign-in fails open, in lib/household.ts and
  seven tests, now say it lets an account through when it can't read
  the membership.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@smilne3
smilne3 force-pushed the fix/240-invitee-try-again branch from fb12c0d to 0596a6b Compare November 5, 2026 16:32
@smilne3
smilne3 merged commit 5b4fa0d into main Nov 5, 2026
6 checks passed
@smilne3
smilne3 deleted the fix/240-invitee-try-again branch November 5, 2026 17:22

This branch was successfully deployed

1 active deployment
Preview — 0596a6b1 Deployed Nov 5, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

An invited partner whose first sign-in hits a failed read gets in with no household, and the invite is never used

1 participant