# W3DS skill additions

Seven reference files to add to the published W3DS agent skill
(`https://docs.w3ds.metastate.foundation/skill/SKILL.md`, read at version of 2026-09-18).

They follow the published skill's conventions — frontmatter with `name` and `description`,
`reference/*.md` naming, routing by keyword — and are meant to sit beside its existing
references, not replace any of them.

Every claim carries the evidence that produced it. Where a claim is a measurement it says
so and gives the date; where it is a platform's declaration it says that instead. Nothing
here is recalled.

## What the published skill already covers well

Worth stating so this package is not read as a correction. The published skill is accurate
on: the authority of the docs site over itself; the reconstructability test; the pre-flight
four questions; never inventing a `schemaId`; the two coexisting ACL models; at-least-once
webhook delivery with idempotency on `eventId` rather than MetaEnvelope `id`; and
"do not mirror what you can already observe". Several of those match findings we reached
independently, and where they overlap the published wording is fine.

## The gap these seven fill

The published skill is, almost entirely, a guide to **writing new data on a platform you
control**. A developer who instead **meets data someone else wrote**, or who has to say
whether a record is actually private, or who is debugging a login, finds no rung to stand on.

| File | Gap it closes |
|---|---|
| `reference/reading-existing-data.md` | The registry is treated as the vocabulary. Measured on one day: 42 schemas served, 64 in the repo, 136 ontology ids actually carried by live envelopes. "Never invent a schemaId" is right for writing and produces a confident wrong answer when reading. Also: one label under several ids, references vs canonicals, names that live one hop away. |
| `reference/access-and-exposure.md` | What `X-ENAME` and ACL actually do. `X-ENAME` selects the **tenant**, so ACL grants nothing across tenants and is not a sharing mechanism; legacy `acl` cannot be read back, so every ACL bug is invisible; **file bytes are public and ACL never touches them**; only an eID signature is a boundary. |
| `reference/destructive-writes.md` | eVault has no history and no undo (8 queries, 12 mutations, zero history types). An update replaces the whole payload **and rebuilds the audience** — with opposite consequences under the two ACL models. Plus: uploading a file is two operations; record the outcome of the remote write, not the intent. |
| `reference/auth-in-practice.md` | The measured reality of `w3ds://auth`. **eID login cannot work on `localhost`** — the wallet calls back from the phone — so a publicly reachable base URL (a tunnel, while there is no hosting) is a precondition of the first line of auth code, and nothing in the published skill says so. The same-device return is hard-coded by the wallet to `/deeplink-login` regardless of `redirect=`, mobile browsers sever SSE while the user is in the wallet, and the return page must relay-or-poll against a session id kept in `localStorage` — which is why same-device login on a phone has never worked first time. Plus: the wallet sends **GET or POST**, ignores your `redirect` and hard-codes its own path, and reads only your HTTP status. The public key in a key-binding certificate is **`0x`-prefixed hex of an uncompressed SEC1 point**, which is in none of the documented signature formats. And an empty `keyBindingCertificates` array must be a hard refusal — the reference behaviour of returning valid is exploitable. |
| `reference/platform-self-description.md` | The user's question "how should a platform describe itself" has no answer in the published skill. Rests on a hard fact: an envelope does not record which platform wrote it, so a self-description is the only channel. Covers what to declare, the `handles` convention, and the reader's obligations. |
| `reference/verification-method.md` | The published skill has "When you cannot verify". This is the other half: how to know when you **have**. The authority order `told > declared > measured > inferred`, an empty result is not a fact, a failed probe is re-thought not re-run, a constraint nobody executed is not a constraint. |
| `reference/identity-forms.md` | Three identity forms — `@<uuid>`, a bare `User.metaEnvelopeId`, the envelope id — treated as interchangeable, which mints phantom people. Includes the measured case of one person's profile duplicated 39 times by an upsert keyed on a presigned URL. |

## How to wire them in

### 1. Routing rules

Add to the routing table in `SKILL.md`:

| User question mentions... | Load |
|---|---|
| reading an existing vault, "what types does this vault have", "there is no ontology for X", resolving a `schemaId` you did not write, duplicate records, a record with no name, reference vs canonical envelopes | `reference/reading-existing-data.md` |
| setting an ACL, sharing with several parties, "is this private", confidential files, proving who wrote a record, `X-ENAME` semantics, cross-tenant visibility | `reference/access-and-exposure.md` |
| `updateMetaEnvelope`, editing an existing record, changing an audience, attaching a signature to a published event, uploading a file to a vault, confirming a vault write | `reference/destructive-writes.md` |
| `w3ds://auth`, login QR or deeplink, same-device login on a phone, "works on desktop but not on iPhone", `/deeplink-login`, running on `localhost` or a tunnel with no hosting, the callback endpoint, "Authentication failed", key-binding certificates, `unrecognised public key encoding`, signature verification | `reference/auth-in-practice.md` |
| publishing what a platform can do, `.well-known/w3ds-platform.json`, `handles`, `selfDescription`, learning another platform's model, "which platform wrote this" | `reference/platform-self-description.md` |
| an empty query result, a probe that found nothing, "does X exist", declaring a task done, "I don't have that feature" | `reference/verification-method.md` |
| storing a reference to a person, message author, assignee, duplicate people, author renders as unknown, looking someone up by name | `reference/identity-forms.md` |

### 2. Two lines for the Non-negotiables

Both are corrections of an over-strong reading of what is already there:

> 5. **The registry is the narrowest circle of types that exist, not the vocabulary.**
>    Resolve a `schemaId` before writing; never conclude a type is absent from the registry
>    alone. Check platform self-descriptions and live data before saying "there is no
>    ontology for X". See `reference/reading-existing-data.md`.
>
> 6. **Confidentiality is not something the platform provides.** ACL records intended
>    audience; it does not gate listing, cannot be read back in its legacy form, and does
>    not touch file bytes at all — those sit on a public-read CDN. Encrypt before upload.
>    See `reference/access-and-exposure.md`.

### 3. Four lines for the Definition-of-done checklist

- [ ] No claim that a type or record does not exist rests on a single query, or on the registry alone.
- [ ] Any update to an existing record read the full body first, and states what happens to its audience under the ACL model that record uses.
- [ ] Any file whose content is confidential was encrypted **before** upload.
- [ ] Verification reached the record the way a real reader reaches it, and asserted something the code did not itself write.

### 4. One line for "Do not guess"

- **Key and signature encodings on the wire** — a key-binding certificate's `publicKey` was
  measured as `0x`-prefixed hex of a 65-byte uncompressed SEC1 point; signatures arrive as
  base64 raw, multibase base58btc **and** DER. Decode by content, never by the documented
  happy path. See `reference/auth-in-practice.md`.

## Provenance and caveats

- Measurements come from one live deployment over 2026-06 … 2026-09, and the dated ones
  say when. Counts (42/64/136 schemas, 48-of-48 `_acl`, 159 grants at `perms: 15`) will
  drift; the **shape** of each finding is the durable part, and each says how to re-measure.
- Two items are declarations by other parties rather than our measurements, and are marked
  as such in place: the `_acl` decision order, and the `handles` convention.
- One hazard described in `access-and-exposure.md` — a write helper defaulting an empty
  audience to `["*"]` — is live in our own code at the time of writing and is documented
  as a pattern to refuse, not as something we have fixed.
- The public-address and same-device sections of `auth-in-practice.md` were added on
  2026-09-23 from a different source than the rest of the file: roughly twenty applications
  built in this ecosystem, in none of which same-device login worked on the first, second
  or third attempt. That is a report of a repeated outcome, not a single measurement — the
  fixes it prescribes are each individually measured, but the claim "this always breaks" is
  experience.
- `auth-in-practice.md` reports two real wallet callbacks from production logs. Two is
  enough to prove both shapes occur; it is not enough to enumerate every build's behaviour.
  Treat the path list as "at least these", not "exactly these".
