---
name: w3ds-identity-forms
description: "Use when code stores, compares or looks up a reference to a person — a message author, a task assignee, a chat participant, a profile — or when duplicate people appear in a list, an author renders as unknown, or a lookup by name fails. The base skill's W3ID-vs-eName anchor names the forms; this is what happens when they are treated as interchangeable."
license: Apache 2.0
---

# Three identity forms, and none of them substitute

The base skill notes that all eNames are W3IDs and both use `@<UUID>` when global. In practice code meets **three** different identifiers for a person, and they are not interchangeable:

| Form | What it is | Scope |
|---|---|---|
| `@<uuid>` | **eName** — the person, registered and resolvable | global |
| `<uuid>` (bare) | usually a **`User.metaEnvelopeId`** — one profile envelope | local to a vault |
| the envelope's own id | the record, not the person | global |

Put every incoming reference through a single resolver before comparing it or creating a node from it. Without that, a graph grows duplicate person-nodes and every deduplication afterwards collapses the wrong pairs.

## One body, one eName — but many profiles

A physical person is **one subject with one eName**. A `User` envelope is a **profile**, and a person may keep several: for friends, for colleagues, for officials, with different name spellings and different photos.

Both identifiers are meaningful, and one resolves to the other. So: count people by eName; render them from whichever profile the audience should see. Counting profiles gives you more people than exist; keying on one profile loses the person when they use another.

Measured consequence of getting the direction wrong: one vault held a single person's own profile duplicated **39 times**, because an integration keyed on a value that changed on every sync — a presigned URL in `avatarUrl` — and so created instead of updated. The duplicates were real records, correctly written, all about one person.

## Prefer the eName when the body carries both

Bodies often carry a pair for the same role: `senderId` / `senderEName`, `authorId` / `authorEName`.

**Key on the eName.** The bare id is a `User.metaEnvelopeId`, local to a vault; using it **mints phantom people** — a node per vault per profile, none of which is the person.

If only the bare id is present, resolve it through the holding vault before using it, and if it cannot be resolved, leave the author unknown rather than inventing a subject. An unknown author is visibly unknown; a phantom one looks like a real person and gets counted, messaged and deduplicated against.

## An envelope carries two ids, and applications search by the second

Every envelope has:

- the **eVault's own envelope id** (the `w3id` you address it by), and
- **`body.id`**, generated by the writing application.

Applications frequently search by `body.id`. When telling anyone where a record is — a log line, a bug report, a message to another agent — **quote both**. One of them will be the only one the other side can find it with, and which one that is depends on their reader.

## Do not assume which form a foreign application expects

Measured, and it splits the ecosystem:

- Some platforms key on the **canonical eName**.
- Others key on the **`User` ontology `w3id`** and do **not** understand an eName substituted for it.

So there is no single correct form to write into a cross-platform reference. Read the target platform's self-description, or look at a record it already accepted, and match that. Substituting the form you prefer produces a record that stores fine and resolves to nobody.

## A person is not found by the `User` type

`User` is the ontology name for a **profile**. In one live graph there were **zero** nodes of that type — people had been normalised to a `Person` kind, with the authoritative mapping in a dedicated identity table carrying eName, name, avatar and every alias observed.

Resolve a person through the identity layer **first**. Matching node labels against a name is the fallback, not the method.

### Names arrive in forms no exact match will catch

Cross-script and short-form variants are normal, not edge cases: the same person appears as a Russian short form, a full transliteration, a patronymic, a nickname. Build the alias set as you observe it, and resolve identity **before** searching content — a better matcher is worthless if the code path never calls it.

## Checklist

- [ ] Every incoming person reference passes through one resolver before comparison or node creation.
- [ ] People are counted by eName; profiles are counted as profiles.
- [ ] Where a body offers both, the eName is used; an unresolvable bare id leaves the author unknown rather than inventing one.
- [ ] Nothing keys an upsert on a value that changes between syncs (presigned URLs, timestamps, derived labels).
- [ ] Cross-platform references use the form the target platform actually accepts, taken from its declaration or from a record it already holds.
- [ ] Log lines and hand-offs quote both the envelope id and `body.id`.
