docs: dire partout que la lecture par lot n'existe plus

Le contrat publie et l'api-contract etaient traites avec le retrait lui-meme ;
restaient les documents qui decrivaient readUnion comme la primitive de
lecture du paquet, ou qui nommaient le module disparu.

Ce que les lecteurs apprennent maintenant : lire un document, c'est
docs.sparqlQuery ancre dessus, et lire plusieurs documents, c'est cet appel
une fois par document -- avec la decision sur une lecture qui echoue ecrite
au point d'appel. Deux consequences sont dites plutot que decouvertes : une
lecture refusee leve au lieu de rendre une liste vide, et les sujets sous le
prefixe reserve urn:ng-eventually: reviennent dans le resultat, a l'appelant
de les ignorer -- sans aucun gain de droits, les deux registres qu'un
document ordinaire porte etant l'adresse de sa boite et, pour un document
public, la cle que son magasin sert deja a qui la demande.

Les briefs dates ne sont pas touches : ils decrivent un etat de juillet, et
le reecrire falsifierait ce qui avait ete decide alors.
This commit is contained in:
Sylvain Duchesne
2026-09-21 14:11:35 +02:00
parent 0c21adebf2
commit 0a2b8b1fbf
29 changed files with 90 additions and 77 deletions
@@ -232,7 +232,8 @@ export async function readStoreCaps(storeDoc: Nuri): Promise<ReadCap[]> {
* store it was created in ({@link holdOwnCap}) — and until 2026-08-16 exactly one path
* read it back: `listMyEntityDocs`. So a creator that reloaded the page and went straight
* to the document it had just made, without listing that scope first, held nothing for it:
* the read was refused, the batch read (`readUnion`) dropped it silently, and the write
* the read was refused, the batch read of the day (`readUnion`, removed in `1.0.0-dev.8`)
* dropped it silently, and the write
* was refused. Its own document, denied to its own author, on the first refresh.
*
* Restoring what a user HOLDS is already what connecting means here — that is what the
@@ -288,7 +288,7 @@ async function applyLink(payload: unknown, ctx: Applying): Promise<boolean> {
// reports the whole inbox, and everything not yet popped is preserved for the next
// attempt. That is the rule stated beside {@link report}, and BOTH arms follow it — but
// the reference arm only since its `unreadable` outcome was split out of `refused` on the
// same day. It had been the opposite: `read-model.readDoc` swallows a failed read and
// same day. It had been the opposite: the batch read of the day swallowed a failed read and
// answers `[]`, so an outage arrived as an ordinary refusal and the drain walked the
// whole queue destroying it. Correcting one arm and leaving the other is precisely how
// that survived a round of review.
@@ -32,7 +32,7 @@
* nothing had to tell an absence from a failure. **That is no longer true, and it is the
* sharpest consequence of consuming.** An absence is deterministic and costs its own deposit;
* a silent broker is transient and must stop the drain, or one outage walks the queue and
* destroys every reference in it. `read-model.readDoc` answers `[]` for both, so this module
* destroys every reference in it. An anchored read answers `[]` for both, so this module
* passes it an `onUnreadable` reporter and asks which one happened.
*
* What it no longer means, since deposits became consumed on 2026-08-26, is "and a later
@@ -2,7 +2,7 @@
* open-repo — cold-start repo opening for the ANCHORED read path (polyfill-era).
*
* ── The cold-start defect this heals ──────────────────────────────────────
* The anchored read path (`surface/read-model.ts` `readDoc`,
* The anchored read path (`surface/read-document.ts` `readDocumentSubjects`,
* `shared-wallet/account-registry.ts` `readUserStore`) assumes the target repo is
* already usable by the verifier — true within the session that CREATED the doc
* (every `doc_create` opens it), but FALSE on a FRESH session over the same
@@ -19,9 +19,10 @@
* the verifier: on a persistent profile `Verifier::load` repopulates `self.repos` from
* user storage at construction (`engine/verifier/src/verifier.rs:535-560`), so the repo
* is PRESENT but unsynced and the anchored query legitimately matches nothing; and this
* library's own `readDoc` catches every error and returns `[]`
* (`surface/read-model.ts:122`), so anything that did throw would reach the caller as
* emptiness anyway. The fix below is right; the diagnosis written beside it was not.
* library's own per-document read caught every error and returned `[]`
* (`surface/read-model.ts`'s `readDoc`, until `1.0.0-dev.8` removed it along with the
* batch it served), so anything that did throw reached the caller as emptiness anyway.
* It no longer does: `surface/read-document.ts` lets the rejection through. The fix below is right; the diagnosis written beside it was not.
*
* The circularity that made this self-inflicted: `doc_subscribe` WOULD open the
* repo, but the reactive layer only subscribes AFTER the listing produced NURIs —
@@ -165,7 +165,7 @@ export async function assertMayWrite(nuri: Nuri, op: string): Promise<void> {
}
/**
* **Rule 2 — do not even attempt**, at the CALLERS (`read-model`, `open-repo`,
* **Rule 2 — do not even attempt**, at the CALLERS (`open-repo`,
* `subscribe`'s callers…).
*
* A reader that does not hold a document's cap must not issue the operation at all.
@@ -17,7 +17,8 @@
* It is SYNCHRONOUS and decides from what the holder holds at that instant. A document
* in a PUBLIC store hands its cap to whoever asks (`public-store.ts`), but asking is a
* round-trip - so this filter drops such a document until some read path has asked.
* The paths that DO ask are the ones this library still reads with (`readUnion`,
* The paths that DO ask are the ones this library still reads with (the anchored
* document read,
* `docs.sparqlQuery`, `ensureRepoOpen`, `documentInboxAddress`). The two SHAPE reads
* ask nothing: `useShape` because its signature is the real ORM's and has no await to
* spend, and `useShapeQuery` since `1.0.0-dev.6`, because it reads through the SDK's