Skip to content

AUTH-MAIL-002C2A — Bind verification results to the current identity service #571

Closed

Description

@daliu

Outcome

Bind every deliberate email-verification attempt and displayed result to the exact ready identity service that started it. If that identity context changes after a provider request begins, retire the private link instead of reusing its code.

This is browser source, synthetic tests, and an officer source-review update only. It is NOT LIVE until the exact website revision is published and verified separately.

Why this matters

The verification page correctly makes a visitor click before applying a Firebase action code. It also ignores results after the page unmounts or the capability route changes.

It does not currently invalidate an in-flight request when Firebase readiness is lost or when the app replaces identity service A with identity service B. A late completion from A can therefore show a terminal result while the page belongs to B. Reusing the same one-time code through B would also cross an identity-service authority boundary that this browser cannot prove safe.

Invariant

  1. Derive one effective identity service only while the Firebase service locator is ready.
  2. Before any provider request starts, a readiness or service-object change may select the current ready service. No automatic request occurs.
  3. Once verifyEmailAction is invoked, bind that attempt and capability to the exact committed service object and context generation.
  4. A later readiness loss, missing service, or service-object replacement retires the code for this page, immediately hides its pending or displayed result, and shows only the fixed unusable outcome. The replacement service receives no call. The member must request one new verification email.
  5. A late obsolete resolve, rejection, or cleanup must not:
    • set or focus a provider result;
    • change the current fixed state;
    • inspect, format, log, or serialize a rejection;
    • navigate or start another provider request.
  6. Temporary A → unavailable → A after a request began is a new generation and remains unusable. The first request may already have consumed the code.
  7. Replacing a service-locator wrapper around the same identity-service object does not reset a valid current result and does not start a request.
  8. A → B → A is a new context generation. The first A completion remains obsolete.
  9. Within one unchanged service generation, preserve the existing offline behavior and fixed temporary retry. A click rejected locally while offline makes no provider request and does not bind the code.
  10. Preserve capability scrubbing, rapid-repeat protection, fixed public states, Identity-service provider-operation validation, same-route invalidation, and unmount behavior.

A provider request already sent through an obsolete service cannot be cancelled by this browser change. This slice makes browser truth fail closed; it does not undo or prove any provider-side mutation.

Exact scope

  1. src/pages/login/VerifyEmailAction.tsx
    • Only the effective ready identity-service context, committed generation/fence, attempt token, capability retirement, and result display gates.
  2. Existing src/pages/login/VerifyEmailAction.test.tsx
    • One separately named AUTH-MAIL-002C2A block plus the minimum controllable service helpers.
    • No new test file and no lint-ledger change.
  3. docs/officers/EMERGENCY_AND_RECOVERY.md
    • Only the existing Verification link page — SOURCE ONLY, NOT LIVE section, diagram, source-review steps, stop conditions, and proof needed to describe current-service invalidation.

Required tests

  • Attempt on A, then readiness becomes false before A succeeds; returning to A does not reuse the code.
  • Attempt on A, then services become unavailable before A succeeds.
  • Attempt on A, switch to B, and prove B receives no call while late A success remains inert.
  • Late hostile A rejection remains inert without property reads, logging, or serialization.
  • A → B → A after a provider request remains unusable and makes no second call.
  • Terminal A result followed by readiness loss or service replacement is hidden and exposes no enabled retry.
  • A wrapper-only change with the same identity-service object preserves current state and starts no second request.
  • Service replacement before the first provider request permits one deliberate call through the current service.
  • An offline click makes no provider request and does not prevent a later current-service call.
  • Current-service success and fixed same-context unavailable/retry behavior remain correct.
  • Existing route scrub, rapid-repeat, provider-operation, and unmount tests remain green.

Use synthetic action codes and service doubles only. Do not call Firebase or an email provider.

Explicit exclusions

  • src/services/identity/Identity.ts and its tests.
  • Login form, password reset, Google sign-in, account linking, roles, or membership authority.
  • App routes, Firebase configuration, App Check, Sentry, Analytics, CSS, or storage.
  • Firebase email templates, global action-handler configuration, DNS, sender authentication, spam/delivery, provider consoles, or live email.
  • Functions, Firestore Rules, packages, locks, workflows, deployment, production data, or live verification.
  • Active dependency-security paths and SECURITY.md.
  • Coordinating parent MEMBERS-DIRECTORY-001 — Add a private opt-in officer photo directory #504 and draft rollback PR Rollback: prepare exact pre-header Netlify artifact #462.

Dependencies and residuals

Acceptance evidence

  • Trustworthy RED against the old component.
  • Focused GREEN tests and relevant full frontend checks.
  • TypeScript, lint ledger, SPA/repository safety checks, and diagnostic build.
  • Exact path/diff review plus independent privacy/lifecycle, test/mutation, and backup-officer reviews.
  • Hosted PR CI and exact-main CI.
  • Separate evidence for source changed, tests passed, merged, website published, runmprc.com verified, Firebase/provider configured, and production behavior verified.

Officer impact: No live procedure changes. The source-review guide explains that losing or changing the identity service after Checking verification... begins makes the private link unusable and requires one new verification email.

Officer documentation: docs/officers/EMERGENCY_AND_RECOVERY.md — only the existing verification-link source-review section and diagram.

Deployment evidence: None at issue creation. Source or CI must not be described as website publication, Firebase configuration, provider delivery, or live verification.

Activity

  1. added
    priority:P1High-priority follow-up
    type:securitySecurity or privacy boundary
    area:authAuthentication and authorization
    area:firebaseFirebase services and data
    area:webWeb application and hosting
    size:XSOwner decision or very narrow change
    status:readyDependencies complete and ready to claim
    type:testingTest infrastructure and quality gates
    status:in-progressClaimed and actively being implemented
    and removed
    status:readyDependencies complete and ready to claim
    on Aug 1, 2026
  2. self-assigned this
    on Aug 1, 2026
  3. daliu commented on Aug 1, 2026

    @daliu
    ContributorAuthor

    CLAIMED by /root at 2026-08-01T22:21:47Z on branch codex/issue-571-verification-context, exact released base 7a9f7647d40c6846015605d25e43f9e87c4653d0.

    Exact ownership:

    1. src/pages/login/VerifyEmailAction.tsx
      • only the effective ready identity-service context, context generation/fence, attempt token, and outcome-display gates;
    2. src/pages/login/VerifyEmailAction.test.tsx
      • one separately named AUTH-MAIL-002C2A current identity-service boundary block plus minimum controllable service helpers;
    3. docs/officers/EMERGENCY_AND_RECOVERY.md
      • only the existing Verification link page — SOURCE ONLY, NOT LIVE section, diagram, steps, stop conditions, proof, and text alternative needed for current-service loss/change truth.

    Invariant: an attempt and its visible result belong only to the exact ready identity-service object and generation that started it. Readiness/service loss or service identity change invalidates the prior browser result synchronously. A late obsolete completion cannot change/focus UI, clear the capability, unlock/overwrite a newer attempt, inspect/log a rejection, navigate, or start provider work. A same-service wrapper change is not a new context. A → B → A is a new generation. The visitor must deliberately retry on the current service.

    Immutable exclusions: Identity.ts and its tests; LoginForm/password reset/Google/account linking; App/routes/Firebase config/App Check/Sentry/Analytics/CSS/storage; Functions/Rules/packages/locks/workflows; provider templates/configuration/delivery; membership/roles; deployment/data/live work; every #566 listMyRegistrations/SECURITY path; coordinating #504; draft #462.

    The empty remote branch was pushed before this marker. Live issue/PR/branch/path searches found no competing claim. No source, test, or documentation edit preceded this claim. Claim remains active through RED, implementation, independent exact-head review, hosted CI, merge, exact-main/deployment audit, closure, and explicit release.

    Officer impact: source-review clarity only; no live officer procedure or provider step.

    Officer documentation: only the named section in docs/officers/EMERGENCY_AND_RECOVERY.md.

    Deployment evidence: none at claim time; source/CI will not be described as website publication, Firebase/provider configuration, delivery, or live behavior.

  4. daliu commented on Aug 1, 2026

    @daliu
    ContributorAuthor

    TRUSTWORTHY RED — before runtime or officer-guide edits

    • Exact untouched runtime/base: 7a9f7647d40c6846015605d25e43f9e87c4653d0.
    • Only changed path: src/pages/login/VerifyEmailAction.test.tsx.
    • Test-only binary diff SHA-256: 0a57c1daf082ff7d050d8452eef29295cc229eec8ff2680355db63ec90c95e48.
    • Runtime: Node v20.20.2 with its binary directory pinned in PATH.
    • Focused command: the committed frontend Jest command, in band, limited to the named AUTH-MAIL-002C2A block.

    Expected RED observed: 6 failed / 1 passed / 27 skipped.

    The six intended failures prove exact current source:

    • keeps Checking verification... after readiness is lost;
    • keeps it after services become unavailable;
    • blocks a deliberate current-service retry while old service A is pending;
    • lets the old pending attempt control the page after switching services;
    • fails to treat A → B → A as a new context generation;
    • keeps a terminal Email verified. result after service replacement.

    The same-identity-service wrapper control passed, proving the tests do not require every service-locator wrapper change to reset valid state.

    No runtime, officer documentation, Firebase/provider configuration, email, account, data, website, deployment, or live behavior changed. All values and services are synthetic; no network call occurred.

  5. daliu commented on Aug 1, 2026

    @daliu
    ContributorAuthor

    SECURITY/SCOPE AMENDMENT — 2026-08-01T22:38:42Z, before the corrective runtime/test/guide edits

    Independent privacy review found that the original retry invariant was too permissive. A change from identity service A to a distinct service B is an authority boundary. This source slice has no proof that both objects represent the same Firebase project or trust context. Sending the same private one-time action code through B after it was already sent through A would therefore reuse a bearer capability across unproven authorities.

    The safer amended invariant is:

    1. Before any provider request starts, readiness or service-object changes may select the current ready service. The code remains private in memory and no automatic request occurs.
    2. Once verifyEmailAction has been invoked through one service, the capability is bound to that committed service generation.
    3. Any later committed readiness loss, missing service, or service-object replacement retires the capability for this page, immediately hides the old/pending result, and shows only the existing fixed unusable outcome. The page must not offer or perform a retry with that code. The member requests one new verification email.
    4. A temporary A → unavailable → A sequence is still a new generation after a request began. A late A result remains inert because the earlier request may already have consumed the code.
    5. A same-service wrapper-only render is not a context change. Within one unchanged service generation, the existing fixed transient/offline retry remains available.
    6. Context identity is committed in a layout effect. Render-time ref mutation and useMemo token identity are not security guarantees.
    7. Because cross-context retry is removed, the original requirements for a newer B attempt and an old A finally not unlocking B are superseded. Late obsolete resolve/reject/finally paths still must not alter UI, clear current state, inspect/log rejection values, navigate, or start provider work.

    Required test corrections within the already claimed test block:

    • prove A pending → B and A terminal → B both retire the code, expose no enabled retry, and call B zero times;
    • prove A pending → readiness loss → A remains unusable and does not resubmit;
    • prove service replacement before the first click still permits exactly one deliberate request through the current service;
    • preserve same-service wrapper, late hostile result, route scrub, same-context fixed retry, and unmount coverage.

    The already claimed officer-guide section will replace its same-link retry instructions with plain observable steps: if Preparing verification or the fixed unusable result appears after a click, do not reuse the link; request one new verification email. It will also keep one action per numbered step.

    Exact three-file ownership and every exclusion remain unchanged. This amendment narrows provider calls and capability use; it adds no provider configuration, deployment, data, or live action.

    Officer impact: source-review wording becomes safer and simpler; no live procedure changes.

    Officer documentation: the already claimed Verification link page — SOURCE ONLY, NOT LIVE section only.

    Deployment evidence: none; this is an issue-contract correction before final implementation.

  6. daliu commented on Aug 1, 2026

    @daliu
    ContributorAuthor

    AMENDED TRUSTWORTHY RED — 2026-08-01T22:49:43Z

    This supersedes the earlier 6-failure/1-control RED because the 2026-08-01T22:38:42Z security amendment removed unsafe cross-context capability reuse and added the offline/no-provider boundary.

    • Exact untouched runtime/base: 7a9f7647d40c6846015605d25e43f9e87c4653d0.
    • Only changed path in the independent RED clone: src/pages/login/VerifyEmailAction.test.tsx.
    • Current test-only binary diff SHA-256: 12fe6d7023e58260e16ec9614c64491160a9c94e985ef27031c43500c71da000.
    • Synthetic services and action codes only; no network, Firebase, email, account, or data action.

    Independent old-source reproduction: 8 intended failures / 2 controls passed / 27 skipped in the named AUTH-MAIL-002C2A block.

    The failures prove current main does not yet:

    • let a replacement service become current after an offline click made zero provider requests;
    • retire the code after either pending readiness loss or missing services;
    • retire it on pending A → B replacement;
    • keep a late hostile rejection inert across that replacement;
    • keep A → B → A retired after the first provider request;
    • hide terminal results and retire the code after readiness loss or service replacement.

    The controls prove the test does not reset a same-service wrapper and still permits a service replacement before the first provider attempt.

    No runtime, officer documentation, website, Firebase/provider configuration, deployment, production data, or live behavior changed during RED.

  7. daliu commented on Aug 13, 2026

    @daliu
    ContributorAuthor

    RECOVERY / BRANCH AMENDMENT — 2026-08-13T05:05:37Z, before reconstructed edits

    The original uncommitted candidate worktree under /private/tmp was removed by external temporary-file cleanup. No #571 source commit or pull request existed; the original remote branch still contains only the old base.

    I recovered the exact reviewed patch sequence and final diff hash from the durable Codex session log. Recovery now continues on empty branch codex/issue-571-verification-context-v2, published before edits from exact current main b94622bd42775d84704d5fc05ee87da81f5a76e0.

    The three claimed file blobs on current main are byte-identical to the original base 7a9f7647d40c6846015605d25e43f9e87c4653d0:

    • VerifyEmailAction.tsx: 227b8dde853dc3fc843e6d8841ec183bca22839d
    • VerifyEmailAction.test.tsx: 900896be5312001df103c2178049fa2e9434eb94
    • EMERGENCY_AND_RECOVERY.md: d76187ffbd459996c7e2464546b050f4d6d7a889

    The recovered old-base exact three-file binary diff was ab79ef9ca2809a1d65e71d9ceae525af7274896a9ece28677a9efb24f65448ce. I will reconstruct it with the same amended fail-closed invariant, then require a fresh exact-current-main diff review and all current gates. I will not treat the deleted candidate's prior green checks as current acceptance evidence.

    Exact ownership and exclusions are unchanged. Active #616, #617, coordinating #504, and draft #462 remain immutable and path-disjoint.

    Officer impact: source-review clarity only; no live procedure or provider step.

    Officer documentation: only the already claimed verification-link section in docs/officers/EMERGENCY_AND_RECOVERY.md.

    Deployment evidence: none. Branch publication is not website publication, Firebase/provider configuration, email delivery, account/data action, or live proof.

  8. daliu commented on Aug 13, 2026

    @daliu
    ContributorAuthor

    EXACT REVIEWED CANDIDATE / PR

    PR #619 is open from exact current-main parent b94622bd42775d84704d5fc05ee87da81f5a76e0 at exact reviewed head 5ecdbf4c08097921399031f861711d3cfd926148, tree b3b6bf5999bf5bb96f4071fc822306472e6daa6a.

    Exact three-file binary diff SHA-256: deb47b0a8451ec4b07c0c6498fbfe7252b83ca3dfa824f6156da9e5703798025.

    Current Node 20 evidence:

    • amended trustworthy RED: 10 intended failures / 2 controls;
    • focused VerifyEmailAction: 39/39;
    • full frontend: 18 suites / 1,052 tests;
    • TypeScript and exact-file ESLint: pass;
    • lint ledger: 118 files / 113 errors / 6 warnings;
    • SPA safety: 11/11;
    • workflow/release/artifact/dependency safety: 93/93;
    • diagnostic production build: pass;
    • three independent final exact-diff reviews: GO.

    The initial reconstructed diff exactly matched the prior recovered hash; one independent mutation review then found and drove two additional provider-unavailable/context-retirement tests before this final commit. The exact runtime and officer-guide blobs remain the reviewed recovered versions.

    Claim remains active through exact-head hosted CI, base-fresh merge, exact-main CI/deployment audit, issue closure, and explicit release.

    PR: #619

    Deployment evidence: source/test/PR only. No website publication, runmprc.com verification, Firebase/provider configuration, email, account/data action, or live behavior proof.

  9. removed their assignment
    on Aug 13, 2026
  10. daliu commented on Aug 13, 2026

    @daliu
    ContributorAuthor

    FINAL COMPLETE / CLOSED / CLAIM RELEASED

    #571 AUTH-MAIL-002C2A is complete. All exact claims are released.

    PR #619 admin-squash-merged exact independently reviewed head 5ecdbf4c08097921399031f861711d3cfd926148 as exact main 3af585077d665d7720b35b5b89505b1d90d9a007. Head and merge tree are identical: b3b6bf5999bf5bb96f4071fc822306472e6daa6a. Exact merged three-file patch SHA-256: deb47b0a8451ec4b07c0c6498fbfe7252b83ca3dfa824f6156da9e5703798025.

    Evidence:

    • amended trustworthy RED: 10 intended failures / 2 valid controls;
    • focused VerifyEmailAction: 39/39;
    • full frontend: 18 suites / 1,052 tests;
    • TypeScript, direct ESLint, lint ledger 118/113/6, SPA 11/11, workflow/release/artifact/dependency safety 93/93, and diagnostic build passed;
    • three independent final exact-diff reviews returned GO;
    • exact-head PR CI 31669859505 passed all five required jobs;
    • exact-main CI 31670041767 passed all five required jobs;
    • exact-main workflow audit found CI only; GitHub deployments are [].

    Netlify truth: PR preview 6a7d5390868d870008a6dc36 is an isolated ready preview with published_at: null. Exact-main attempt 6a7d5456776e57000898dc05 is error with published_at: null. Public runmprc.com still reports the separate #473 containment marker (control 9ad6837, source 39ab864, tree d76b496, 60 files, digest 07b10c7d…). Therefore #571 is merged but not published/live.

    No protected release, Firebase deployment/configuration, email-provider action, account/data action, migration, or live verification occurred. A provider request already sent through an obsolete service remains outside browser cancellation and proof.

    Released paths/hunks:

    • src/pages/login/VerifyEmailAction.tsx;
    • named AUTH-MAIL-002C2A block/support in src/pages/login/VerifyEmailAction.test.tsx;
    • named verification-link source-review section/diagram in docs/officers/EMERGENCY_AND_RECOVERY.md.

    Future work may refresh from exact released main 3af585077d665d7720b35b5b89505b1d90d9a007 or later and must preserve #571 behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:authAuthentication and authorizationarea:firebaseFirebase services and dataarea:webWeb application and hostingpriority:P1High-priority follow-upsize:XSOwner decision or very narrow changetype:reliabilityReliability and recoverytype:securitySecurity or privacy boundarytype:testingTest infrastructure and quality gates

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions