basquetWi + New ticket
mars MARS-532

EVO-79 mars leg: access-request dedup PREVENTION — attach Google identity to existing pre-created account on confident match, not a 2nd user

Done high cmcoder-mars-cc

EVO-79 (Class-A, design-first, via pmmaster). EVO-74 found the dominant dupe class = a pre-created admin_manual account + the student's self-registered Google login spawning a SECOND account instead of linking. Fix mars's access-request match/completion flow to ATTACH the Google identity (supabaseAuthId, canonical email) to the existing pre-created user on a confident match (legajo/DNI/canonical-email/name), NOT create a new user. Design Q to settle FIRST with audit: what match confidence auto-links vs routes to /solicitar-acceso human-match. Respects live-DB Role Resolution rule (gate reads userRoles, never JWT claim). audit-mars-ca design-ping BEFORE implement + diff review BEFORE push (Class-A: auth/identity path).

Sub-tickets

No sub-tickets.
+ Add sub-ticket

Questions

No questions.

Activity

  • wi-cli-venus created · 4w ago
  • wi-cli-venus commented · 4w ago
    Elazar directive (via pmmaster): the EVO-79 design-ping thread must INCLUDE pm-enamel-cc alongside audit-mars-ca, and share Mars's dedup/identity-linking findings (EVO-74 merge/dup analysis). Enamel's future user-mgmt SSOT depends on the access-request identity-linking model designed here. Coder: when you open the design-ping to audit, add pm-enamel-cc to the thread + hand over the EVO-74 dedup findings.
  • wi-cli-venus commented · 4w ago
    EVO-79 AUTO-LINK RULING (converged fleet-wide via pmmaster, no Elazar fork — Mars's framing became the ruling): (1) LOCKED: NEVER auto-link on a human-entered/asserted key (DNI/legajo/name) — human attach only, unanimous. (2) ONLY auto-linkable signal = OAuth-proven canonical-email exact match to exactly ONE live (deletedAt IS NULL) pre-created account, with genuine-Google (EVO-68 provider+sub) RE-VERIFIED at approve time. (3) Match-engine-then-admin-attach unforked for lower-confidence. Design carries this in; audit-mars-ca ratifies the email-only tier at the design-ping. pluto revised off DNI/legajo, venus added the email carve-out — all 4 pods aligned on 'does OAuth prove it or does the user assert it'.
  • wi-cli-venus commented · 4w ago
    EVO-79 CORE ADDENDUM (audit-pluto, fork-independent — REQUIRED in design): the match/admin-attach UI alone does NOT close EVO-74. Dominant dup path = the CREATE paths (unmatched-approval + nuevo?solicitud), NOT the match UI. Real closer = a CENTRALIZED CANDIDATE RESOLVER interlocking EVERY access-request-sourced users-INSERT, fail-closed on any strong candidate/conflict, + durable identity persistence on accessRequests + atomic CAS attach. The email-exact-only auto-link standard also applies at the callback BIND point (atomic CAS + conflict-check + genuine-Google re-verify). Design MUST include the INSERT-interlock, not just the candidate surface — coder+audit design-ping covers both.
  • wi-cli-venus commented · 4w ago
    EVO-79 FINAL RULING — SUPERSEDES the earlier email-only auto-link tier (fleet reversed via pmmaster, no rework, design unstarted): NO auto-link at ANY tier — HUMAN-CONFIRM-ALL. Refutation (audit-venus-ca, TARGET-side): the requester email is OAuth-proven, but the pre-created users.email it matches is IMPORT-entered and documented-dirty (placeholder/reassigned/mistyped). The unique index proves ≤1 live canonical(G) row exists, NOT that it's the right person — a reassigned/mistyped roster email binds the authenticated G-owner into the WRONG clinical record. Uniqueness ≠ personhood. So every access-request identity bind routes to human confirm; no auto-link. UNCHANGED and IS the real EVO-74 closer: centralized candidate RESOLVER + create-path (unmatched-approval + nuevo?solicitud) users-INSERT INTERLOCK fail-closed on strong-candidate/conflict + atomic CAS attach + durable identity persistence on accessRequests + genuine-Google re-verify at bind. This event is the current spec; the prior email-only-tier event is void.
  • wi-cli-venus commented · 4w ago
    EVO-79 identity-DDL addendum (enamel sub ruling, via pmmaster): add nullable users.googleSub to the same identity DDL. Backfill from auth.users identities[].sub; stamp at create / attach / first-login. CORRELATION KEY ONLY — never an authz input (Role Resolution stays userRoles / live-DB, per the fleet rule). Class-A pre-apply audit at the design-ping. (Re item 1: the email-exact auto-link tier is already DROPPED — see the FINAL RULING event above; MARS-532 = human-confirm-all + resolver/INSERT-interlock/CAS/identity-persistence core. The 04:03 confirm that still carried the tier is void.)
  • wi-cli-venus commented · 4w ago
    EVO-79 interlock-coverage addendum (venus code-read, via pmmaster): (1) the resolver's fail-closed MUST cover ALL strong signals — canonical-EMAIL AND doc/DNI/legajo — not email-only. Venus's prior create branch failed closed on email collision ONLY, so an import-email != Google-email (E!=G) case slipped a dup through. KEY DISTINCTION (no contradiction with the no-auto-link-on-asserted-keys ruling): asserted keys (DNI/legajo/name) can never AUTO-BIND, but a doc/DNI match IS a strong-candidate signal that must HALT the create and route to human-confirm. Fail-closed DETECTION on doc/DNI is required; auto-LINK on doc/DNI stays banned. (2) Both create paths covered: unmatched-approval AND nuevo?solicitud. (3) googleSub in THIS batch = nullable-additive, NO unique index — the unique index is a LATER WI dependent on EVO-74 dedup completing first (it fails on existing dups). Coder: do NOT add a unique constraint on googleSub in this DDL.
  • wi-cli-venus commented · 4w ago
    EVO-79 googleSub-index CORRECTION (pmmaster, supersedes the 'nullable-additive-no-unique this batch' line — that was venus-specific, venus has real same-sub dups): rule is DATA-DEPENDENT. Dry-run mars's googleSub live-collision check FIRST (any auth.users google sub mapping to >1 live users row). ZERO collisions (like pluto's 316-clean) → ship the UNIQUE PARTIAL INDEX NOW in this DDL (stronger Class-A invariant, prevents future same-sub dup binds). >0 live same-sub dups → defer the index to a post-EVO-74-dedup WI. googleSub is exact-opaque so a collision is a genuine same-identity dup (trustworthy), not a naive-join false positive. Fleet uniformity NOT required — the index is a local integrity guarantee. db-mars-cc running the collision dry-run now.
  • wi-cli-venus commented · 4w ago
    googleSub collision dry-run RESULT (db-mars-cc): ZERO collisions — 353 live users carry a genuine-Google sub, 353 distinct, 0 excess. → SHIP the UNIQUE PARTIAL INDEX in this DDL: WHERE deletedAt IS NULL AND googleSub IS NOT NULL. NULL-handling confirmed: 11 live users (never-signed-in/pre-created, no Google identity yet — the EVO-73 11) get googleSub NULL; the IS NOT NULL predicate excludes them so no shared-NULL collision. Consistent with the existing uq_users_supabaseAuthId partial unique (this googleSub index is the stronger identity anchor). No post-dedup WI needed. So MARS-532 identity DDL = add users.googleSub (nullable) + backfill from auth.users identities[].sub + the unique partial index, all this batch. Class-A pre-apply audit at design-ping.
  • wi-cli-venus commented · 4w ago
    EVO-79 login-branch policy — ON HOLD, Elazar re-deciding (pmmaster): the 'human-confirm-all' ruling is now scoped to HOLD for the LOGIN/callback auto-link branch ONLY. Elazar thinks human-confirm-all likely OVERCORRECTED — batch-imported emails exist specifically so they auto-link on login; misbind risk is narrow (dirty-target email), not blanket. Likely landing = KEEP auto-link + async review of ONLY the Google-name-vs-roster-name mismatch subset. So: do NOT lock the callback branch to human-confirm-all yet; await Elazar's relayed decision. UNAFFECTED and PROCEED NOW: the CORE — centralized candidate resolver + create-path (unmatched-approval + nuevo?solicitud) fail-closed dup-detection on ALL strong signals (email+doc/DNI) + atomic CAS attach + accessRequests identity persistence + users.googleSub nullable+backfill+UNIQUE partial index (0 collisions confirmed). Design/build the core; leave the callback auto-link tier as a TBD pending Elazar.
  • wi-cli-venus commented · 4w ago
    EVO-79 login-link policy FINAL — Elazar-ruled, SUPERSEDES the interim human-confirm-all. This is the buildable spec: (1) EXACT OAuth-proven canonical-email match to exactly ONE live account -> AUTO-LINK at the callback bind, with genuine-Google re-verify (EVO-68 provider+sub). Do NOT gate to human-confirm — auto-link on exact email is the POINT of batch-importing emails. (2) SIMILARITY (name/DNI/legajo/fuzzy) -> NEVER auto-link; build the SUGGESTED-USER workflow: surface look-alike existing user(s) as a suggestion -> human confirm-link -> never duplicate. (3) Create-path fail-closed INTERLOCK STAYS: resolver halts a silent users-create on a plausible match -> routes to suggest/confirm (both create paths: unmatched-approval + nuevo?solicitud). (4) UNCHANGED: centralized resolver + atomic CAS attach + users.googleSub nullable+backfill+UNIQUE partial index (0 collisions). Elazar EXPLICITLY ACCEPTS the narrow mistyped/reassigned-target-email residual for the exact-email fast path (the audit-venus-ca objection is acknowledged and overruled as an accepted tradeoff). audit-mars-ca ratifies at the design-ping. Prior events (email-only-tier, human-confirm-all) are void; THIS is current.
  • wi-cli-venus completed · 4w ago
    EVO-79 identity-attach: access-request approval + first login now attach a proven Google identity (googleSub) to the pre-created account instead of minting a 2nd user. Exact OAuth-proven canonical-email auto-links; similarity (doc/legajo/name) routes to operator confirm via widened vAccessRequestsForReview; fail-closed create-path interlock on all strong signals; centralized identity-resolver + 64-bit locks; callback CAS-idempotence; revalidate hoisted out of lock-tx. DDL migs 075 (identity cols + 8-user EVO-73 heal) + 076 (view resolver-signal vocab). Shipped 3b547a3→1ba6fce v2.48.1, audit PASS. Follow-ups: MARS-537 doc-pair/legajo partial-uniques (db-lead), MARS-538 import-preview (parked), MARS-536 completar raw-email.
task
4w ago by wi-cli-venus
4w ago
2026-07-20 09:38