feat(client): discovery via a global index (special @index account)
Add a generic discovery-index surface: submitToIndex(ref) deposits a reference into the index document's inbox; readIndex() returns the materialized entries. A reserved special account (@index) owns the index document; deposits flow through the emulated inbox and are materialized by the emulated curator (the dedup/ moderation point). This replaces cross-account fan-out as the discovery path and is more faithful to the target (a single owned index fed via its inbox). Generic (the consumer supplies the reference to index). 79 tests pass; tsc rc=0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -274,6 +274,51 @@ the deferred global-index note in the top-level README and
|
||||
watcher is the ONE deposit/materialization mechanism reused for BOTH meeting-point
|
||||
registration AND submission to a discovery index — same `post` API, same watcher.
|
||||
|
||||
## Emulated discovery index + special account (`discovery.ts`)
|
||||
|
||||
Discovery is a **surface on top of the inbox**, not a new primitive. **Access ≠
|
||||
discovery**: a public entity is world-readable *with its NURI*; the discovery
|
||||
index is how a client learns that NURI **exists** without holding a connection
|
||||
to its creator (see [`decisions/discovery-model.md`](./decisions/discovery-model.md)).
|
||||
The model is: ONE global index = an **owned document** (public read), **fed via
|
||||
ITS inbox**, **materialized by a curator**. Nobody writes the index directly — a
|
||||
creator DEPOSITS a reference into the index's inbox; the curator ingests deposits
|
||||
into entries. Materialization is the natural **dedup / moderation point**.
|
||||
|
||||
- **The special account (polyfill owner).** "Who owns the global index" is
|
||||
undecided in the target (NextGraph is mono-user with no global data — a
|
||||
singleton app is the only glimpsed path). So the polyfill parks ownership on a
|
||||
**RESERVED SPECIAL ACCOUNT** in the shim — `INDEX_ACCOUNT = "@index"`. It is a
|
||||
normal shim account (so its 3 scope documents are created on first sight like
|
||||
any other), but never a real user; it only HOSTS the index document. Its
|
||||
`public` scope document IS the index document, and its inbox receives the
|
||||
deposits — a **stable NURI**: every client opening the same shared wallet
|
||||
resolves the same account → same document, so all clients read/write ONE
|
||||
shared index.
|
||||
- **`submitToIndex(ref, opts?)`** — the SDK act "make this discoverable".
|
||||
Deposits `ref` into the index document's inbox via `inbox.post`. `from` follows
|
||||
the inbox convention (anonymous when `null`). `ref` is **opaque** here — the
|
||||
consumer serializes whatever locates the entity (e.g. an entity document NURI +
|
||||
discovery metadata).
|
||||
- **`readIndex()`** — the EMULATED CURATOR. Reads every submission, **dedups by
|
||||
serialized `ref`** (the moderation point: a duplicate submission surfaces
|
||||
once), returns entries sorted by `ts`. `watchIndex(onEntries, opts?)` is the
|
||||
emulated watcher (polls `readIndex`).
|
||||
|
||||
**This REPLACES the cross-account fan-out** (`store-registry.ts`
|
||||
`listEntityDocs('public')` / `resolveReadGraphs`) as the app-facing discovery
|
||||
path: the app submits public entities to the index and reads the index, instead
|
||||
of fanning out over every account's public documents. The fan-out survives only
|
||||
as an **internal lib fallback** — kept for the per-scope listing it also powers
|
||||
(e.g. `resolveReadGraphs`), never the app's discovery route.
|
||||
|
||||
GENERIC: `discovery.ts` knows no application domain — the consumer defines the
|
||||
`ref` shape and its meaning. At migration the special account disappears:
|
||||
ownership moves to the decided global-index owner, `submitToIndex` becomes the
|
||||
native `inbox_post_link` on the index's inbox, and `readIndex` queries the real
|
||||
materialized index document. The consumer surface (`submitToIndex` / `readIndex`)
|
||||
is designed to survive that swap unchanged.
|
||||
|
||||
## Emulated write guard (`ng-proxy.ts`)
|
||||
|
||||
The public `ng` proxy overrides `sparql_update` to enforce an emulated **write
|
||||
|
||||
Reference in New Issue
Block a user