Conversation
A founder who reaches qm through Slack, an email magic link, and a trusted OIDC provider gets three principal ids and is treated as three people. A secret drop minted from Slack belonged to the email principal, and the same person signed in through OIDC was told the link was for someone else. Add principal links: an org admin records that a sign-in id belongs to a canonical principal, with evidence. personKey and samePerson fold a linked sign-in to its canonical id, so ownership recorded under either id belongs to the person: keychain credentials, admin grants, approvals, secret drops, sessions. New writes use the canonical id: the identity service classifies a linked sign-in as its canonical principal, the portal resolves the session subject before proxying, core canonicalizes the verified portal actor, and the keychain saves under the canonical owner. Links live in the principal_links durable map and refresh with the identity service. The directory member stays canonical; the admin API refuses a link whose linked side is a directory member, refuses chains, and requires evidence. Links are portal-only like grants and impersonation. Deleting a link restores two separate principals.
The directory-member guard now also refuses a Slack id, since a roster row carries both ids and personKeys would otherwise merge two people. A sign-in that holds an org admin grant can only be linked to a canonical principal that is already an admin, so a link never grants admin silently. Deactivations and external members are stored under the raw folded id and folded to the person only in memory, so a deactivation recorded before a link stays reversible and an external member can still be removed afterwards. Directory-sync protection is evaluated at check time for the same reason. Credential ids derive from the canonical owner, so the same person saving the same service from either sign-in rotates one record. The canonical lookup forces an identity refresh. The portal refuses to proxy when core cannot resolve the session subject instead of acting as the raw subject, and the impersonation self-check compares canonically.
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.
People who start on the web and later message QM in Slack can end up with separate identities, losing access to the connectors they already authorized. Add a dedicated personal Slack OAuth flow that verifies workspace and user identity, preserves the web account as canonical, and refuses conflicting accounts with existing credentials or connections.
Onboarding now presents Add to Slack first, then a compact installation checkmark and the personal linking card. The agent can recall the card with
::link-slack-account{}. Trusted Bookface entry failures no longer offer an alternate email login. Includes principal-link concurrency, deactivation, and stale portal identity fixes.This includes the principal-link implementation from the existing principal-links proposal, rebased on main.
Validation: all public CI checks passed at
928afc6c; fleet tests 828 passed, 3 skipped; fleet config check passed. Independent identity, portal, full infrastructure, and staged application-plan reviews found no blockers. Deployed the exact clean source to Styleup with digest-pinned core, web-ui, and portal images. Infrastructure is unchanged; the existing deployment instruction bundle was preserved.Live browser QA verified the installed-bot checkmark and personal linking card, working app catalog, a real model response rendering
::link-slack-account{}, and the personal button reaching Composio's Slack user OAuth. The managed bot re-install button also reaches Slack consent. No installation/account-link status is mocked. OAuth completion remains unverified: this browser is signed into YC, which restricts Composio; completing the test requires a Development YC login. No Slack consent or install request was submitted.Hosted test: https://styleup.qm.ycombinator.com/s/cf810776-de84-4a1f-a64c-038e959edaf1