fix(iam): waitlist mails wait for a verified email address (Phase C, C11 reader) - #784
Merged
Merged
Conversation
yahyafakhroji
force-pushed
the
feat/passkey-phase-c-api
branch
from
September 10, 2026 13:18
0c9ca10 to
ba56271
Compare
yahyafakhroji
force-pushed
the
feat/passkey-phase-c-reader
branch
from
September 10, 2026 13:29
840b680 to
219c480
Compare
JoseSzycho
previously approved these changes
Sep 14, 2026
JoseSzycho
left a comment
Contributor
There was a problem hiding this comment.
Nice touch. Good that you noticed this.
yahyafakhroji
changed the base branch from
feat/passkey-phase-c-api
to
main
September 14, 2026 15:26
yahyafakhroji
dismissed
JoseSzycho’s stale review
September 14, 2026 15:26
The base branch was changed.
JoseSzycho
approved these changes
Sep 14, 2026
yahyafakhroji
force-pushed
the
feat/passkey-phase-c-reader
branch
from
September 17, 2026 00:58
c5e1094 to
7ed9da1
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase C of the passkey program (datum-cloud/auth-ui#112), milo PR 2 of 2 — C11 reader.
What
One guard in
user_waitlist_controller.go: before sending, require theUser'sEmailVerificationstatus field to beVerified.Approved(welcome) mail and theRejectedmail. Every mail this controller sends.Verified(empty orUnverified) ⇒ logwaiting for email verificationand returnctrl.Result{}, nilwithout requeue. The controller already watchesUser, so the field flip re-triggers reconcile; polling would be redundant.Pendingstays disabled — unchanged, it still returns early on the pre-existing empty-condition path.The exactly-once sent-condition guard, the deterministic
Emailname and the second idempotency layer are untouched — the controller diff is +16/−0. The gate sits deliberately after the sent-condition check, so users already mailed before this change short-circuit exactly as they do today rather than logging "waiting" on every resync. The mail goes out once, when bothApprovedandVerifiedhold, whichever arrives last.Tests —
user_waitlist_controller_test.go, this controller's first, four fake-client cases:Unverified) sends nothing, does not requeue, and does not set the sent-condition;Why
user_waitlist_controllersent the welcome mail onPlatformAccess: Approvedalone. An account that never verified its email address received the welcome mail (milo-os/zitadel-provider#134, gap 2), because nothing onUsersaid whether the address had been proven — the chain fromPlatformAccessthroughStatus.PlatformAccesstogetEmailStatusConditionhad no verification signal to consult. #782 adds that signal as a typed status field; this PR reads it.Spec:
2026-09-08-passkey-phase-c-recovery-design.md§7.2.Rollout
Safe to MERGE now: nothing here depends on zitadel-provider code, only on the
EmailVerificationStateconstants from #782.NOT safe to DEPLOY before milo-os/zitadel-provider#135's sweeper has completed one pass in the target environment — until then existing users carry an empty field and every welcome/rejection mail would wait.
Stacking
Stacks on #782 (
feat/passkey-phase-c-api), which carries theEmailVerificationstatus field this PR consumes. Retarget tomainwhen #782 merges.E2E
No chainsaw fixture changed. Across all 37 chainsaw cases, none asserts a
notification.miloapis.comEmailobject, and none drivesPlatformAccesspastPending— everystate:intest/isPending, which returns early on the pre-existing empty-condition path, before the new gate is ever evaluated. So no chainsaw outcome can change. The controller's coverage is the new unit tests.Review
Sonnet review: APPROVE, no findings to fix; the gate was mutation-tested.