In a real product, the same person does not arrive as one user. They arrive through a browser session, a Telegram Mini App, a Slack command, a delegated external app, a webhook, an API key — and tomorrow through a channel that does not exist yet. Each arrival carries its own verified identity and its own user id. None of them is "the" user.

A platform has two tempting ways to handle this, and both are wrong. It can flatten every arrival into one user_id — and lose track of which identity an action actually came from. Or it can keep the identities unrelated — and the product fragments, so the memory you wrote from your phone is invisible in the browser. Connection Hub holds the shape in between: many verified identities, connected by explicit edges, with the platform asking different questions of that connected set depending on the boundary a request is crossing.

The thesis of this piece — and the foundation for the rest of the series — is one sentence:

The same person is not the same as one user id. The platform keeps the identities as separate ids, links them into a family, and asks different questions of that family: who is this for? and what may this execution do?

Those two questions have different answers, even though they read the same links. This article defines the vocabulary the rest of the Connection Hub series builds on: actor, platform identity, connection edge, identity family, authority projection, provenance.

The vocabulary

Six terms. Each is a different fact about a request, and the rest of the series assumes you can tell them apart.

Actor — the runtime identity a request arrives as. It is whatever authenticated proof the request carried: a Telegram Mini App arrives as telegram_434804821; a browser session arrives as a platform uuid like 02e53484-…; a future provider arrives as provider:subject. The actor is the ground truth of "who started this." It is never rewritten.

Platform identity — the KDCube platform user (authority_id = "platform"). This is the identity that owns platform roles, economics, and platform-protected operations. A Telegram actor is not a platform identity; it may be linked to one.

Connection edge — a stored, proven link from one identity to another, carrying the grants that link allows. It is the one graph primitive Connection Hub stores. An edge says: this verified identity may be treated as connected to that identity, in these ways. It does not erase the identity that entered the system, and it does not, by itself, mint roles.

Identity family — the resolved set of runtime user ids that are the same person, for product aggregation. This is what a memory feature needs to show "all my memories" after a phone and a browser are linked. It answers: which user ids is this for?

Authority projection — the roles, permissions, and economics subject that apply at a protected boundary. It answers a different question: what may this execution do, and who pays? It reads the same edges, but it is not the identity family.

Provenance — which identity an action or record actually came from. The actor is preserved through every projection so that a record written from Telegram stays attributable to Telegram, not silently rewritten to the platform user.

The whole article is these six terms and how they relate. If you remember one relationship, remember that identity family and authority projection are two different questions asked of the same connected set.

One person, many ids, linked

One person arrives as several separate verified identities, each linked by a connection edge that carries its grants. Connection Hub resolves them into one platform identity and one identity family — the set of runtime user ids that are the same person.

ONE PERSON — SEPARATE IDS, LINKED INTO ONE FAMILY ACTOR IDENTITIES CONNECTION EDGES PLATFORM IDENTITY + FAMILY telegram_4821 Telegram Mini App actor google:acct_7c provider account actor 02e53484-… browser session = the platform user edge · proof + grants identity:family economics edge · proof + grants identity:family is the target authority platform principal platform identity 02e53484-… identity family memory_user_ids 02e53484-… telegram_4821 google:acct_7c The edge connects the ids; it does not erase them. The family is the resolved set — and a runtime id joins it only when its edge carries the identity:family grant.
The edge connects the ids; it does not erase them. The family is the resolved set — and a runtime id joins it only when its edge carries the identity:family grant.

Three identities in one request

When a Telegram user opens the chat app, three distinct facts are in play. They look similar and are routinely confused; keeping them apart is the entire point.

actor identity
  who started this request?
  telegram_434804821

platform identity
  which platform user is this actor connected to?
  02e53484-0081-70ce-11c1-e96706b1a182

authority projection
  which roles / economics subject apply at this boundary?
  platform grants selected on the connection edge

The actor identity is not rewritten. The request stays attributable to telegram_434804821 — for audit, conversation binding, product provenance, and debugging. But when the request reaches a platform-protected boundary, Connection Hub can answer, for that boundary only:

Can telegram_434804821 represent a platform identity here?
If yes, which platform identity?
Which selected grants may be projected?
Which economics subject should pay?

This is the difference between a connected identity and an impersonated session. Connection Hub does not turn the Telegram actor into the browser session. It keeps Telegram as the actor and projects platform authority only through the explicit edge, only at the boundary that needs it. In the projected runtime shape, both facts are still visible:

identity_authority
  actor_user_id     = telegram_434804821      (who started it / where storage lives)
  platform_user_id  = 02e53484-...            (linked platform principal)
  economics_user_id = 02e53484-...            (who pays)
  platform_roles    = [...]                   (only roles both held AND on the edge)

Grounded in the Authority Projection doc: "The actor and the authority source can be different… an app keeps Telegram-scoped storage or product behavior while platform role checks and economics use the linked platform principal."

The edge is the load-bearing object

A connection edge is the one thing Connection Hub actually stores. A "linked identity" and a "delegation" are not two storage models — they are two resolver views of the same edge graph. The edge has a direction (from an actor identity, to a target authority identity), a relationship, a proof, and a list of grants.

from authority identity
    -- relationship + grants + proof -->
to authority identity

The grants are why an edge is more than an alias table. It is tempting to say "if Telegram is linked to the platform user, Telegram can do everything the platform user can." That is too broad. Linking proves a relationship between identities; the grants decide what may be derived through that relationship. The edge stores only what the target identity allowed the source identity to derive — roles, permissions, and economics authority still come from the authority that owns the target identity, intersected with the edge grants.

A platform edge typically carries grants like these:

Common platform-edge grants — what each one allows the source identity to derive.
Grant What it allows
identity:family product reads may aggregate across the target platform user's connected runtime identities
economics:platform-user economics may charge/check the target platform user while preserving the external actor as provenance
kdcube:role:* the external actor may derive this platform role — only if the platform identity currently holds it and it is on the edge
platform permission strings the external actor may derive this platform permission under the same rule

So a concrete edge looks like a link and a consent record at once:

{
  "schema": "connection_hub.edge.v1",
  "relationship": "delegates_to",
  "from": {
    "authority_id": "telegram.kdcube_ref",
    "provider": "telegram",
    "subject": "434804821",
    "user_id": "telegram_434804821"
  },
  "to": {
    "authority_id": "platform",
    "user_id": "02e53484-0081-70ce-11c1-e96706b1a182"
  },
  "grants": ["identity:family", "economics:platform-user", "kdcube:role:chat-user"],
  "proof": { "challenge_id": "..." }
}

The edge is written only when both sides are proven: the actor proves its provider identity, and a browser claim proves the platform identity, with an explicit consent step that selects the grants. The Telegram Mini App never silently becomes the browser platform session.

Identity family: one product view, many owners

The first question the platform asks of a connected set is the product one: which user ids belong to this person, so a feature can show one coherent view? That is the identity family.

The clearest example is memory. A user creates memories from the browser and from Telegram. Each record keeps its original owner, because that is where provenance lives:

memory created in browser
  user_id = 02e53484-...

memory created in Telegram
  user_id = telegram_434804821

After the accounts are connected, the user expects one memory list. The memory feature should not hardcode "Telegram" or parse provider prefixes. It asks the Identity Family Resolver — SDK code in ...connections.hub.resolver — a single question:

Given this actor/session, which runtime user ids are the same person
for product reads?

The resolver returns schema connection_hub.identity_family.v1:

{
  "ok": true,
  "schema": "connection_hub.identity_family.v1",
  "linked": true,
  "platform_user_id": "02e53484-0081-70ce-11c1-e96706b1a182",
  "identities": [
    { "kind": "authority", "authority_id": "platform",
      "user_id": "02e53484-0081-70ce-11c1-e96706b1a182" },
    { "kind": "integration", "provider": "telegram",
      "provider_subject": "434804821", "user_id": "telegram_434804821" }
  ],
  "memory_user_ids": [
    "02e53484-0081-70ce-11c1-e96706b1a182",
    "telegram_434804821"
  ]
}

The feature then reads with a server-resolved scope:

WHERE user_id IN memory_user_ids

The client never chooses the user ids. The backend resolves the family and uses the result as a read scope. That is the whole pattern for features that store records under runtime actors but need one user-visible view.

An edge is not enough — the grant gates the family

This is the subtle, load-bearing rule, and it is easy to get wrong. An edge linking Telegram to a platform user does not, by itself, let memory reads cross identities. The edge must carry the identity:family grant. Without it, the resolver returns only the actor's own one-id family:

edge exists, grants = []                  -> family = [telegram_434804821]
edge exists, grants = [identity:family]   -> family = [telegram_434804821, 02e53484-...]
no edge at all                            -> family = [telegram_434804821]

The reasoning is exact: a connection edge means "these identities were proven and connected"; the identity:family grant means "this source identity may use the target platform user's family for product reads." Aggregation requires the grant, not merely the existence of a link. (If a linked memory request shows only the Telegram id when you expected both, the usual cause is an old edge with "grants": [].)

Writes stay actor-scoped — that is provenance

Identity family is a read behavior. Writes are where provenance is created, and provenance is the reason the platform refuses to flatten identities in the first place.

A write records the actor that caused it:

Telegram-originated write   -> user_id = telegram_434804821
Browser-originated write    -> user_id = 02e53484-...

This keeps the system honest. If a note was created from a Telegram bot, the record says so. Connected views aggregate those records later without rewriting history. Reads widen across the family; writes never do.

Deletes follow the read rule, then act on the real owner:

1. Resolve the identity family.
2. Load the requested record where its owner is in that family.
3. Delete the actual stored owner record.

The delete must not trust a client-supplied owner id. The backend resolves the family and uses the stored record's real owner. Provenance is preserved at every step: even when a delegated external app reads across the family, the projection carries explicit provenance (delegate identity, grantor, credential) so the record of "who did this" is never lost.

Authority projection: same links, a different question

The second question the platform asks of the connected set is not "who is this for" but "what may this execution do, and who pays?" That is authority projection, and it is deliberately separate from the identity family.

SAME LINKS — TWO DIFFERENT QUESTIONS connection edges one connected set, one set of grants Identity Family "who is this for?" returns a product read scope WHERE user_id IN memory_user_ids aggregation scope · not an authorization grant Authority Projection "what may this execution do? who pays?" returns execution authority roles / permissions economics subject checked per boundary · never the read scope The edges are the same. The family scope answers a product question; authority answers an execution question — one is never the other.
Same edges, two answers. The family scope answers a product question; authority answers an execution question — one is never the other.
Identity Family Resolver
  "which user ids belong to this person for product data?"
  -> read scope: memory_user_ids

Authority Projection
  "which roles / permissions / economics authority may this execution use?"
  -> roles, permissions, economics subject

They often read the same connection edges. They are still different answers, and one must never substitute for the other. memory_user_ids is a product read scope; it is not a set of authorization grants. A product record that happens to fall inside the family still gets its normal access checks. Conversely, holding a platform role does not widen which records a feature reads — that is the family's job.

Keeping them separate is what lets a request stay precise. A single request may cross several boundaries, and each boundary asks only for the authority it needs:

incoming request
  actor = telegram_434804821 (verified by Telegram authenticator)
      |
      v
Boundary: memory read        -> identity family resolves memory_user_ids
      |
      v
Boundary: economics          -> projects the platform user as the charge subject
      |
      v
Boundary: platform-admin op  -> checks the selected role grant on the edge

The request does not eagerly become every identity it is connected to. It resolves only the identity or authority required at the boundary it is crossing. That keeps latency low and avoids accidental privilege expansion — a request that only reads memory never acquires admin authority along the way.

One note for the rest of the series: an external app calling KDCube through a delegated credential uses this same model — it remains its own actor, and the consenting platform user is the grantor reached through a stored edge. The mechanics of delegated credentials and MCP connectors are their own pieces; here it is enough that delegation is one more edge-shaped relationship asking the same two questions.

Identity edges are not transport sessions

One last distinction, because it is a common category error. Connection Hub stores identity and delegation facts. That is not the same as protocol session memory.

identity edge (Connection Hub):
  telegram:434804821 -> platform:02e53484-...
  selected grants / identity-family scope
  durable, proven, consent-backed

transport session (ingress layer):
  websocket connection
  SSE stream
  MCP mcp-session-id
  per-connection, ephemeral

A request carries its identity authority through Connection Hub credentials and runtime context on each request; it does not depend on a long-lived protocol session to know who the actor is or what platform identity it is connected to. Where stateful protocol sessions are needed, that state belongs to a platform-owned ingress layer, not to the identity graph. The identity graph answers "who, connected to whom, with what grants" — and stays the same whether the transport is stateful or not.

What this buys the series

This is the foundation. With these six terms fixed, the rest of the Connection Hub series can build without re-deriving them:

  • An actor is preserved as provenance through every projection.
  • A connection edge is the one stored primitive — a proven link plus consented grants.
  • The identity family answers who is this for (product read scope), gated by the identity:family grant.
  • Authority projection answers what may this do, and who pays — same links, a different question, never a substitute for the family.
  • Same person ≠ one user id. The platform keeps the ids separate, links them into a family, and asks each boundary only the question it needs.

Related publications

Delegating A KDCube Service To An External App — the external app keeps its own actor; the platform user is the grantor reached through a stored edge.
Protecting KDCube Surfaces With Managed Credentials — where these identity facts become enforcement: the surface guard checks authority, grants, tools, and identity scope before product code runs.
Authenticated MCP In KDCube: Delegated Credentials, Not Shared Secrets — applies connected identity and authority projection to MCP connectors.
Named services can now leave KDCube through a delegated MCP connector — identity scope in practice for external access to mem, task, and cnv namespaces.
KDCube Deep · 29.06.2026