docs: inbox_post_link est notre nom, pas une API NextGraph annoncée

Le symbole n'existe nulle part dans `nextgraph-rs`, et aucune méthode de
`@ng-org/web` ne contient « inbox ». Il vient de notre propre plan de fork
(`docs/fork-inbox-fallback.md:32` — « expose `pub async fn inbox_post_link` »),
d'où il a essaimé dans huit autres endroits, cité comme une API « proposed/
future » de NextGraph. Une proposition interne devenue un fait par répétition —
le même mécanisme que « chaque document a une inbox native » et que l'inbox
mutualisée.

Corrigé partout sauf dans le plan de fork, où le nom est légitime puisque c'est
lui qui le propose. Et l'énoncé exact est désormais posé : on ne connaît NI le
nom NI la forme de la future surface JS pour les inbox — ce n'est pas
« non implémenté », c'est inconnu.

Ce qui est réellement vérifié côté moteur : `AppRequestCommandV0::InboxPost`
existe et `AppRequest::inbox_post()` le construit, mais le request_processor n'a
aucun arm pour lui — l'envoyer ne déclenche rien. Le seul dépôt qu'un client JS
peut provoquer aujourd'hui passe par `import_contact_from_qrcode`, qui appelle
`post_to_inbox(InboxPost::new_contact_details(...))` avec `with_readcap = false`
— la variante `true` étant `unimplemented!()`.
This commit is contained in:
Sylvain Duchesne
2026-08-03 17:04:30 +02:00
parent fba0128a7e
commit 4f5c3ed03b
8 changed files with 21 additions and 15 deletions
+1 -1
View File
@@ -182,7 +182,7 @@ Not started. It changes the consumer contract in the right direction (one less o
- **`open(nuri, scope)` was kept** (it is in neither the §6 table nor the removals) as the single "this document is mine, in this scope" act — `mint` for protected/private, `publishRepoLink` for public. It no longer touches write caps: arming that guard would be enforcement this batch does not do.
- **`grantWrite` / `canWrite` were left exactly as they were** (an authorization list, decorative, guard bypassed by every internal writer) and now have to be called explicitly — `open` used to set them as a side effect. They belong to P1b.
- **`shareCap` is implemented in `inbox.ts`** and re-exported from `/polyfill`, so it is reachable both as `inbox.shareCap` (SDK-identical entry, via `export * as inbox`) and from the polyfill surface. Deliberate: sharing a cap **is** an inbox deposit upstream, and at migration this call becomes `inbox_post_link` — a real SDK method — so hiding it from the SDK entry would have been the less faithful choice. §7's boundary holds where it matters: the registry, `capFor` and `CapRegistry` stay on the polyfill side, and every signature is a plain string.
- **`shareCap` is implemented in `inbox.ts`** and re-exported from `/polyfill`, so it is reachable both as `inbox.shareCap` (SDK-identical entry, via `export * as inbox`) and from the polyfill surface. Deliberate: sharing a cap **is** an inbox deposit upstream, and at migration this call becomes the native sealed deposit — a real SDK method, whatever it ends up being called (`inbox_post_link` was our own proposed name, not an announced API) — so hiding it from the SDK entry would have been the less faithful choice. §7's boundary holds where it matters: the registry, `capFor` and `CapRegistry` stay on the polyfill side, and every signature is a plain string.
- **The stand-in key is the constant `OK`** (`nuri.ts`; it was a derived FNV-1a digest until the PO simplified it on 2026-07-30). The only question the emulation answers is *do I hold this cap or not*, so the value says that and nothing more — a digest merely looked like a key. Possession is a shape here, not a protection; P1b replaces the constant with a real key.
- **`resetCaps()` clears in place** rather than rebuilding the registry, so a `watchShape` subscribed to the change signal does not end up holding a listener on an orphaned instance.
- **The scope-index feed is holder-scoped** (`fileOwnCaps` compares through the shim key): the cross-account fan-out `listEntityDocs` files nothing, because other accounts' caps are emphatically not ours to hold.
+2 -2
View File
@@ -27,7 +27,7 @@ this step swaps the *emulated* key for the real one, not the model:
`r:{base64url(serde_bare(ObjectRef))}`. It is **one function** (`mintCap`), because
every path now READS a stored cap instead of recomputing one. `hasReadCap` /
`targetOf` stay meaningful: the `r:` discriminant is upstream grammar, not ours.
- `shareCap(cap, toInbox)` becomes the native sealed delivery (`inbox_post_link`
- `shareCap(cap, toInbox)` becomes the native sealed delivery (whatever the SDK ends up naming it — see the note below
and `ContactDetails.read_cap`), and `inbox.read`'s inline absorption becomes the
recipient's own verifier applying queued messages. **The consumer's call does not
change.**
@@ -73,7 +73,7 @@ per-user wallets replace the shared one.
### 4. Real inbox → drop the in-lib read emulation
Replace the emulated `inbox.ts` deposit (`docs.sparqlUpdate` into a shared-wallet
document) with the native `inbox_post_link` (proposed/future). On the read side the
document) with the native sealed deposit, once one is exposed to JS. **Its name and shape are NOT known**: no inbox method exists in `@ng-org/web`, the verifier has no `InboxPost` arm, and `inbox_post_link` is OUR proposed name (`fork-inbox-fallback.md`), not an announced API. On the read side the
recipient's own verifier unseals each queued sealed message and applies it inline
when it processes its inbox — there is no separate curator to build; the in-lib read
emulation simply goes away. *(There is no global index to replace the cross-account fan-out: both were removed on 2026-07-30 — you cannot discover in NextGraph, you follow links.)*
+5 -2
View File
@@ -151,8 +151,11 @@ it processes its inbox — there is no separate curator or materialization servi
`QrCodeProfile(Import)`, `Header`, `Create`, `FilePut`). Sending an `InboxPost`
triggers nothing.
- Building an `InboxPost` requires crypto sealing on the Rust side; no wasm
helper exposes it. A high-level `inbox_post_link` is a proposed/future API, not
yet present.
helper exposes it, and **no `inbox` method exists in `@ng-org/web` at all**.
*(`inbox_post_link`, named across this repo's docs, is OUR proposed name from
[`fork-inbox-fallback.md`](./fork-inbox-fallback.md) — grep `nextgraph-rs` and it
is nowhere. Nothing is announced about the eventual JS surface for inboxes: its
name and shape are unknown, not merely unimplemented.)*
- Inbox deposit is only triggered internally by `QrCodeProfileImport`
(`post_to_inbox(new_contact_details)`) and `social_query_start` (contact
propagation via inbox).
+5 -4
View File
@@ -464,7 +464,7 @@ fork the broker ([`fork-inbox-fallback.md`](./fork-inbox-fallback.md)), the lib
emulates the inbox on the shared wallet:
- **Target vs polyfill.** In the target, `post` seals a reference into the owner's
native inbox (`inbox_post_link(...)`, a proposed/future API) and the recipient's
native inbox — through a JS call that **does not exist and is not announced** — and the recipient's
own verifier unseals each queued message and applies it inline when it processes
its inbox — there is no separate curator or materialization process. Here,
everything is readable, so the lib emulates the read side in-lib.
@@ -507,9 +507,10 @@ At migration this guard disappears into cryptography: an inbox is sealed to its
owner's key.
The module knows no domain — the consumer application supplies the inbox document
NURI and interprets `payload`. At migration `post` becomes the native
`inbox_post_link` (proposed/future) and the read side is served by the recipient's
own verifier unsealing queued messages inline.
NURI and interprets `payload`. At migration `post` becomes the native sealed
deposit — **whose JS name and signature are not known**, since none is exposed or
announced — and the read side is served by the recipient's own verifier unsealing
queued messages inline.
The inbox + watcher is the one deposit/read mechanism a consumer reuses for its own
purposes — a registration/deposit, a cap delivery (`shareCap`), a link handed to
someone — same `post` API, same watcher.