Decide which firm domain is canonical — accounts exist on hoganlovells.com while the live domain is hlc.com, and three products key off the pair #159
Reference in New Issue
Block a user
No description provided.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Surfaced 2026-07-27 while checking whether a user (Cedric Rohr) had a Paliad account. He does —
cedric.rohr@hoganlovells.com, created 2026-04-26. That resolved his question, but it exposed a risk nobody owns.The problem
Since the merger the firm is Hogan Lovells Cadwalader and
hoganlovells.com301-redirects tohlc.com(verified directly — fetchinghttps://www.hoganlovells.com/de/legal-notices/disclaimerlands onwww.hlc.com/...).Paliad's
ALLOWED_EMAIL_DOMAINSallowlists both forms (hoganlovells.com,hlc.com,hlc.de). So a colleague can sign up under either, and paliad has no merge story for the two identities. Concretely:@hoganlovells.comaccount who later signs up as@hlc.comgets a second, empty account — same human, no projects, no deadlines, no team memberships. From their side the product simply looks broken.hlc.com, while thehoganlovells.comform is the stale one. So both directions are live.Today there is exactly one user per human and no duplicates (checked). This is a latent problem, not a current outage — but it becomes real the first time someone signs up with the other form.
Why this is not a paliad-local decision
The same domain pair is load-bearing in at least three products:
ALLOWED_EMAIL_DOMAINSgate, 51 users today, all onhoganlovells.com.hlc.comandhoganlovells.com, reusing the youpc accounts.If each product decides independently which form is canonical, they drift apart, and a user's identity depends on which product they signed into first. That is a worse failure than any single product getting it wrong consistently.
What needs deciding
hlc.com(the live domain) orhoganlovells.com(where the existing accounts are)? These pull in opposite directions: the live domain is the future, the existing accounts are the present.Suggested shape, not a decision
Accepting both at the gate but normalising to one canonical form at account creation would stop new duplicates without locking anyone out mid-transition, and is reversible. That is a guess, not a recommendation — the cross-product owner should decide before anyone builds.
Not urgent
No current duplicate accounts. Filing it because it is exactly the class of finding that dissolves when a chat scrolls, and it bites silently — the symptom is a colleague seeing an empty product and concluding the tool does not work, not an error anyone gets paged about.
Filed by paliad/head at otto/head's request. Cross-references: otto message 5652; m/hihlc#11, m/hihlc#7.
Three of the four items are done. The fourth is the cross-product one and I cannot answer it from paliad.
What I ran — read-only queries against prod, plus the auth and
internal/emaildomaincode paths. Going through the issue's own list rather than assuming m's ruling settled all of it.1. Which form is canonical — DONE
m ruled 2026-07-27:
hlc.comcanonical,hoganlovells.comalias,hlc.dedropped.internal/emaildomaincarries the split.2. What happens to accounts on the non-canonical form — DONE, and the migration has already run
The issue records "51 users today, all on
hoganlovells.com". That is no longer the state. On prod now:hlc.comhoganlovells.comAnd the reconciliation is clean:
paliad.usersonhoganlovells.com: 0; onhlc.com: 47paliad.users↔auth.usersemail mirror drift: 0The accounts were renamed rather than duplicated, and
cmd/canonicalize-emailsis the machinery that did it. The concrete risk the issue was filed about — "a second, empty account… same human, no projects" — has zero instances.Sign-in still accepts the alias and says so rather than failing:
handleAPILoginreturns anoticetelling the user their address moved to@hlc.comand that the old one keeps working.3. Whether signup should refuse the non-canonical form — DONE
This is the item that would have let the problem regrow, so it is worth spelling out. There are two gates, deliberately different:
isAllowedEmailDomain— sign-IN, still acceptshoganlovells.com, so no existing holder is locked out.isCreatableEmailDomain— every path that mints a new identity (register, both admin-create paths, invitation recipients). It filtersAllowedEmailDomains()throughemaildomain.IsAlias(), so only the canonical form can create.A new
@hoganlovells.comsignup is refused with a message that names what to do instead: "Neue Zugänge nur mit @hlc.com-Adresse. Wenn Sie bereits ein Konto haben, melden Sie sich mit Ihrer bisherigen Adresse an — die funktioniert unverändert weiter."That is the "accept both at the gate, normalise at creation" shape this issue suggested, implemented.
4. Who owns the decision across the three products — STILL OPEN, and I cannot answer it here
This is the part the issue itself says "makes it an issue rather than a paliad ticket". paliad is settled; m/hihlc and youpc are not something I can measure from this repo, and guessing at their state is exactly what would make this comment worse than silence. Someone with those two repos has to say whether they canonicalised the same way, and whether anyone owns the pair going forward.
One side effect worth naming
Dropping
hlc.debites on sign-IN, not just registration, so its holders are locked out at their next login. There is exactly 1@hlc.deaccount on prod — a dormanttester@global_admin. m's own account is not affected. Noting it so it is a known consequence rather than a surprise.Verdict: partially resolved. Items 1-3 done and measured; item 4 open and cross-product. Not closing — that is m's.
Re-measured 2026-07-31. Question 3 is still yes — a duplicate can be created today, and the door is in hihlc, not in paliad.
Building on the 2026-07-29 comment rather than repeating it. That comment marked items 1-3 done and item 4 open, and it was right about paliad. It also said hihlc and youpc "are not something I can measure from this repo" and did not look further. There is a checkout of
m/hihlcon this machine, and reading it changes the answer to question 3.1. Which form is canonical — settled, and actually consumed
hlc.comcanonical,hoganlovells.comalias, viainternal/emaildomain(EMAIL_CANONICAL_DOMAIN/EMAIL_ALIAS_DOMAINS).A package nothing calls answers nothing, so the call sites, all in non-test code:
internal/handlers/auth.go:56internal/handlers/auth.go:197CreatableEmailDomains()= allowed minus aliasesinternal/handlers/users.go:56internal/services/paliadin.go:66EqualIdentityinternal/services/user_service.go:144SyncEmailFromClaimrepairs thepaliad.usersmirrorinternal/services/password_reset_service.go:94,155internal/services/email_canonicalization_service.gocmd/canonicalize-emails/main.goConsumed, not shelf-ware.
2. Accounts on the non-canonical form — migrated, and still clean today
Read-only against prod, 2026-07-31:
hlc.comhoganlovells.comhlc.deauth.userspaliad.userspaliad.users↔auth.usersmirror drift: 0auth.users: 0 of 73auth.usersrows in the last 7 days: 0The issue's "51 users, all on hoganlovells.com" is history. So is the earlier note about
auth.usersrows withcreated_at IS NULL: there are none now.3. Can a duplicate still be created today? — YES. Not through paliad.
paliad's own creation paths are closed. Three of them, all gated on
isCreatableEmailDomain(=ALLOWED_EMAIL_DOMAINSminus aliases):POST /api/register—auth.go:123POST /api/admin/users/full—admin_users.go:85main.go:229wireshandlers.CreatableEmailDomainsintoInviteServicePOST /api/admin/usersis deliberately allowed-only, and correctly so: it attaches a paliad profile to anauth.usersrow that already exists and mints no identity.PATCH /api/admin/users/{id}cannot change an address —AdminUpdateInputhas no email field. Pinned byTestCreatableEmailDomains_ExcludesAliasesand friends ininternal/handlers/auth_test.go.The store is shared, and hihlc still creates on the alias domain.
m/hihlcauthenticates against the same GoTrue (ydb.youpc.org,auth.users) — its ownlanding/docs/auth-gate.mdsays so. Its magic-link path:gated on
SIGNUP_EMAIL_DOMAINS, whose committed default inlanding/.env.example:15and in the README ishlc.com,hoganlovells.com— both forms.hihlc.de/loginandhlcq.de/loginboth answer 200 right now. (Read atorigin/main1b5a35c; I did not read hihlc's live Dokploy value, so the deployed allowlist is assumed to match the committed default.)The chain, end to end. A colleague whose first firm login anywhere is hihlc, entering
firstname.lastname@hoganlovells.com:auth.usersrow on the alias domain. paliad's gates never see it.handleAPILogincanonicalises to@hlc.comfirst, GoTrue finds no such row, and they get "Ungültige E-Mail-Adresse oder Passwort". This is design §3 Option B's lockout, reappearing for every alias identity minted after the rename.@hlc.com. paliad accepts it, because the address is creatable and nohlc.comrow exists. Second identity, second uuid, empty Paliad. Exactly the failure this issue was filed about.For someone who already has a paliad account the direction is inverted but the store still ends up with two rows: paliad canonicalises and keeps returning them to their real account, so paliad masks the duplicate while hihlc sees the new one.
paliad cannot close this from inside.
SignUpgoes to GoTrue; nothing in paliad looks for an alias twin before creating, and nothing could stop a row hihlc mints directly.Secondary, unresolved, much smaller:
handleAPIRegisterdoes not lowercase beforeSignUp, andauth.users' unique indexusers_email_partial_keyis exact-case (thelower(email)index is non-unique). Whether a case-variant twin is possible therefore depends on GoTrue normalising, which I did not verify — settling it needs a write, and prod was read-only for this task. Evidence such as it is: 0 mixed-case rows out of 73. hihlc lowercases before its call; paliad does not.4. Cross-product ownership — still open, and now measurably divergent
hoganlovells.comisCreatableEmailDomainshouldCreateUser: true, allowlist includes the aliaspaliad and hihlc have diverged, and the divergence is the mechanism keeping question 3 alive. hihlc#11 and #7 are both still open.
I could not establish youpc's signup-domain policy:
/home/m/dev/youpc.orgholds only a.mcp.json, and the Gitea tree listing truncates at 1000 entries without hitting an auth path. What is measured is that the shared store carries 12 non-firm-domain accounts across 8 domains (gmail.com4,youpc.org2, then one each ofhotmail.com,curevac.com,eip.com,tilmann.eu,msbls.de,flexsiebels.de), so the store itself imposes no domain policy — every gate in this cluster is application-side, and there are at least two of them over one table.Summary
Questions 1 and 2 are answered and measured. Question 3's answer changed from what the 2026-07-29 comment concluded: paliad closed its own doors, and the problem can still grow through hihlc's. Question 4 is the reason — one identity store, two independent allowlists, opposite policies.
The smallest thing that would close question 3 is dropping
hoganlovells.comfrom hihlc'sSIGNUP_EMAIL_DOMAINSfor the creating path while keeping it for sign-in, which is the same split paliad already implements. That is a statement of what the measurement points at, not a recommendation — the cross-product owner decides, and this is hihlc's code, not paliad's.Not closing. Measured read-only; nothing was written to prod and no code changed.
paliad/ritchie, t-paliad-issue-159-canonical-domain-measure.