docs: le contrat passe en 1.0.0-dev.9, et ce qu'une lecture echouee repond est consigne
Majeur : trois appels existants se resserrent. `useShapeQuery` publie `isError` pour un document NOMME qu'il ne peut pas lire, la ou il rendait `isSuccess` avec `data: []` - la seule image que cette surface reserve a « ce scope ne contient rien ». `inbox.postToDocument`, `readForDocument` et `readSyncedForDocument` rejettent la ou elles annoncaient « pas d'inbox ». Rien de ce qui etait deja une reponse ne bouge : un document vide, `graphs: []`, un document sans inbox, un document public qui n'expose aucune cle. Deux non-garanties corrigees parce que le changement les rend fausses : « aucune des deux lectures par forme ne va chercher la cle d'un store public » ne vaut plus que pour `useShape` et pour `did:ng:i`, et le pending eternel d'un demarrage refuse se referme sur le cas nomme. Nouveau `knowledge_what-a-failed-read-answers-upstream` : ce que la cible repond pour un document injoignable, non synchronise ou vide, et les deux collisions que l'appelant ne peut pas demeler - « n'existe pas » contre « pas connu de moi » d'un cote, « non synchronise » contre « vraiment vide » de l'autre. C'est le fait durable qui justifie la direction prise, et il vaut quel que soit le remede. `docs/internal-contract.md`, section open-repo seulement : numeros de ligne, `ensurePhysicalRepoOpen` qui n'a jamais ete un export de ce module, `ensureReposOpen` supprime, `openRepoUnguarded` absent, et le second parametre de `ensureRepoOpen`. Le reste du document porte une derive du meme age, laissee.
This commit is contained in:
+17
-11
@@ -95,27 +95,33 @@ export function subscribePhysicalDoc(nuri: Nuri, onChange: (r: DocChange, type:
|
||||
## 6. Bootstrap repo opening — `emulated-verifier/open-repo.ts`
|
||||
|
||||
```ts
|
||||
// open-repo.ts:75
|
||||
// open-repo.ts:90
|
||||
export type SyncState = "syncing" | "synced" | "timed-out";
|
||||
// open-repo.ts:104 — TEST-ONLY
|
||||
// open-repo.ts:120 - TEST-ONLY
|
||||
export function setOpenTimeoutForTests(ms: number): void;
|
||||
// open-repo.ts:110
|
||||
// open-repo.ts:127
|
||||
export function resetOpenedRepos(): void;
|
||||
// open-repo.ts:135
|
||||
// open-repo.ts:162
|
||||
export function getSyncState(nuri: Nuri): SyncState | "unknown";
|
||||
// open-repo.ts:167
|
||||
export async function ensureRepoOpen(nuri: Nuri): Promise<void>;
|
||||
// open-repo.ts:184
|
||||
export async function ensurePhysicalRepoOpen(nuri: Nuri): Promise<void>;
|
||||
// open-repo.ts:259
|
||||
export async function ensureReposOpen(nuris: Nuri[]): Promise<void>;
|
||||
// open-repo.ts:210
|
||||
export async function ensureRepoOpen(nuri: Nuri, holderKey?: string): Promise<void>;
|
||||
// open-repo.ts:234 - the unguarded core, for ONE importer (`shared-wallet/physical.ts`)
|
||||
export async function openRepoUnguarded(nuri: Nuri): Promise<void>;
|
||||
```
|
||||
|
||||
> Corrected 2026-09-21 (`1.0.0-dev.9`), for this module only. The listing above used to name
|
||||
> an `ensurePhysicalRepoOpen` export that this module has never had - it lives in
|
||||
> `shared-wallet/physical.ts:134`, the machinery's door - and an `ensureReposOpen(nuris)`
|
||||
> batch that was deleted as dead code. It also missed `openRepoUnguarded` and
|
||||
> `ensureRepoOpen`'s second parameter. The rest of this document carries drift of the same
|
||||
> age and was deliberately left alone.
|
||||
|
||||
Heals the cold-start defect of the anchored read path: on a fresh session a not-yet-open repo reads empty, so before an anchored read the repo is opened by subscribing (`subscribePhysicalDoc`) and awaiting the first `State` push — the sync barrier — with a bounded timeout. The subscription is held for the session; per-nuri `SyncState` keeps `synced` and `timed-out` apart.
|
||||
|
||||
- The opening mechanism is **level 2, VERIFIED as a composition**: `doc_subscribe` exists (`sdk/js/lib-wasm/src/lib.rs:1908`), and the push variants `TabInfo`/`State`/`Patch` are the engine's `AppResponseV0` (`engine/net/src/app_protocol.rs:1354-1358`). The ORDER (TabInfo first, then the initial State) and "first State = presence guaranteed, absence definitive" are **empirical, pinned by the in-repo e2e CONTRACT-3 probe — an ASSUMPTION about ordering as far as upstream is concerned**: no upstream statement fixes the push order, so a future reordering upstream would silently break the barrier. Bound: the e2e probe fails loudly if the order changes.
|
||||
- "Hold a live subscription to keep the repo open" — **ASSUMPTION** (nothing upstream documents subscription lifetime as what retains a repo in `self.repos`); observed to work, bounded by the same probe.
|
||||
- **Defect — the header's mechanism claim is contradicted at the source (see Findings F2).** `open-repo.ts:10-12` says an anchored `sparql_query` on a repo absent from `self.repos` "silently returns 0 rows (never a `RepoNotFound`)". Verified upstream: absence from `self.repos` yields `Err(NgError::RepoNotFound)` (`request_processor.rs:264,269`), the ReadQuery arm converts it into `AppResponse::error` (`:1293-1296`), and the web binding REJECTS the JS promise with it (`sdk/js/lib-wasm/src/lib.rs:606`). The observed 0-rows-no-error behaviour has two candidate explanations that the source does support: a persistent verifier reloads every known repo into `self.repos` at `Verifier::load` (`engine/verifier/src/verifier.rs:535-560`) so the repo is present-but-unsynced (a genuine 0-row read), and/or the lib's own per-doc tolerance (`readUserStore`, and the `surface/read-model.ts` per-doc catch until `1.0.0-dev.8` removed it) converts a rejection into an empty result. The healed symptom is real and the fix correct; the stated mechanism is not established, and a maintainer reasoning from it would mispredict behaviour whenever the verifier is not persistent.
|
||||
- **`ensureRepoOpen` THROWS when the public store could not be asked** (`1.0.0-dev.9`). It calls `emulated-verifier/public-store.ts`'s `fetchReadCap` first - a document in a public store hands its key to whoever asks, so the question has to be put before the boundary decides - and that call used to answer `false` for a download that had REJECTED, which is the same value a document exposing no key answers with. The open then declined silently and the anchored read that followed refused the reader for holding no key: a true statement, made out of an outage, and the wrong one to act on. The rejection now reaches the caller. The open itself still never throws (a `doc_subscribe` that never pushes is bounded by the fallback timeout), and `holderKey` skips the fetch entirely, so the processor's door is unaffected.
|
||||
- **Defect, SINCE REPAIRED in the code — the header's mechanism claim was contradicted at the source (see Findings F2).** The header was corrected on 2026-08-03 and now states the mechanism below itself; what follows is kept as the record of what was wrong and how it was established. `open-repo.ts:10-12` says an anchored `sparql_query` on a repo absent from `self.repos` "silently returns 0 rows (never a `RepoNotFound`)". Verified upstream: absence from `self.repos` yields `Err(NgError::RepoNotFound)` (`request_processor.rs:264,269`), the ReadQuery arm converts it into `AppResponse::error` (`:1293-1296`), and the web binding REJECTS the JS promise with it (`sdk/js/lib-wasm/src/lib.rs:606`). The observed 0-rows-no-error behaviour has two candidate explanations that the source does support: a persistent verifier reloads every known repo into `self.repos` at `Verifier::load` (`engine/verifier/src/verifier.rs:535-560`) so the repo is present-but-unsynced (a genuine 0-row read), and/or the lib's own per-doc tolerance (`readUserStore`, and the `surface/read-model.ts` per-doc catch until `1.0.0-dev.8` removed it) converts a rejection into an empty result. The healed symptom is real and the fix correct; the stated mechanism is not established, and a maintainer reasoning from it would mispredict behaviour whenever the verifier is not persistent.
|
||||
- `SyncState` and `getSyncState` are lib-invented vocabulary — **NO COUNTERPART** (upstream has no consumer-facing "sync state of a repo" API at any level; `OrmSubscription.readyPromise`, `sdk/js/orm/src/connector/GraphOrmSubscription.ts:260`, is the closest level-3 signal, per-subscription not per-repo).
|
||||
- At migration the whole module becomes "open the store by cap at bootstrap" (native) and is removed with the shim.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user