fix!: la garde circulaire disparait, et une nouvelle tentative se fait au nom de qui a ete refuse

Troisieme tour de revue adversariale, trois constats, tous reproduits avant
correction.

1. La garde etait CIRCULAIRE, et c'etait structurel. `namedDocumentsReachable`
   demandait si la capacite est DETENUE. Pour un document en store public, le seul
   canal qui puisse jamais la deposer est `fetchReadCap` - l'appel meme que la
   garde retenait. Elle attendait une reponse que seule l'action qu'elle bloquait
   pouvait produire, et toute cette classe restait irrecuperable.

   La bonne question n'est pas une meilleure garde, c'est de RETENTER. Les deux
   facons d'etre refuse se reparent par des choses opposees, et le memo les
   distingue deja : un echec n'est deliberement pas memoise, donc une nouvelle
   tentative redemande vraiment au reseau - c'est la reparation de cette classe,
   pas un cout a eviter ; une absence est memoise, donc une nouvelle tentative ne
   demande a personne et coute un instantane, jusqu'au jour ou la capacite arrive
   d'ailleurs, seule chose qui repare celle-la. La garde est supprimee : le module
   est plus petit qu'au tour precedent.

2. La reouverture faisait un ACCES sous la mauvaise identite. Republier REFILTRE
   une requete existante ; rouvrir EMET un abonnement et une requete au store
   public pour un document que cet abonne a nomme. C'est un acte neuf, pas un
   ancien qui ressort, et l'etat final etait `isSuccess` avec `data: []` pour un
   document illisible - le mensonge que cette tache supprime, par la porte du
   correctif. `refusedFor` retient QUI a ete refuse ; on ne retente que tant que
   c'est encore lui le connecte.

   Etabli plutot qu'affirme : une application ne peut pas changer d'identite en
   cours de session. `ensureIdentity` est le seul appel publie qui en etablit une,
   et `resolveIdentity` commence par `getCurrentUser()`. Corrige quand meme.

3. `Promise.all` court-circuite a la premiere rejection ARRIVEE, et un fetch qui
   rejette n'attend pas la barriere de synchronisation : il double un refus portant
   sur un document nomme avant lui. Le comportement est corrige plutot que le
   commentaire - `allSettled` puis parcours dans l'ordre du scope.

Et le quatrieme controle e2e est retire, pas repare : il passait avec toute la
machinerie de reprise supprimee. Un controle qui ne peut echouer pour aucune
regression de ce qu'il garde se lit comme de la couverture et vaut moins que rien.
This commit is contained in:
Sylvain Duchesne
2026-09-21 16:28:24 +02:00
parent aecb7cf2e8
commit f875047099
5 changed files with 234 additions and 90 deletions
+8 -21
View File
@@ -517,27 +517,14 @@ async function main(): Promise<void> {
`snap=${JSON.stringify(publicSnap)}`,
);
// That fetch FILED a cap, which fires `CapRegistry.onChange` - the channel a
// refused scope is re-opened on since `1.0.0-dev.9`, because the barrier aborts
// before any query exists and `publish` has nothing to re-filter. This cap says
// nothing about the protected document, so the refusal must stand.
//
// What this measures, exactly, and it is less than it might look: the OUTCOME is
// unchanged. It does not separate "no re-open was attempted" from "one was
// attempted and refused again" - both end here - so the targeting itself is
// measured in the unit suite, by the notification count (`use-shape-query.test.ts`
// (s)). Saying which of the two a green check proves is the whole lesson of the
// round that shipped this barrier with no named-scope coverage at all.
//
// The positive direction - the cap for the refused document ITSELF arriving, and
// the view converging - needs a second actor delivering it, and belongs in the
// applicative suite; `use-shape-query.test.ts` (r) is its unit form.
const afterOtherCap = await sdkGet<any>(frame, "useShapeQuerySnapshot", refused);
check(
"a cap landing for ANOTHER document leaves a refused scope refused",
afterOtherCap.isError && !afterOtherCap.isSuccess && afterOtherCap.dataLen === 0,
`snap=${JSON.stringify(afterOtherCap)}`,
);
// A fourth check stood here until 2026-09-21: "a cap landing for ANOTHER document
// leaves a refused scope refused". It was REMOVED rather than repaired, because it
// passed with the whole re-attempt machinery deleted - the outcome is a standing
// refusal either way, so nothing it could observe told the two apart. A check that
// cannot fail for any regression of the thing it guards is worse than no check: it
// reads as coverage. The re-attempt is measured in `test/use-shape-query.test.ts`
// - (v) for the class repaired by re-asking the network, (s) for the one that is
// not and for what a doomed re-attempt costs, (w) for the holder it is made as.
await sdk(frame, "useShapeQueryStop", refused);
await sdk(frame, "useShapeQueryStop", publicRef);
});