refactor(comments): retirer les raisonnements sur l'état de NextGraph du code app
Application de la règle qu'on vient de durcir : l'app IGNORE entièrement l'état d'implémentation de NextGraph. Le CODE était légitime — `inbox.readSynced` est une surface SDK exportée ; ce sont les JUSTIFICATIONS qui fautaient, en expliquant les choix par des internes du cœur. Réécrit en termes de CONTRAT : - registration.ts / FestipodDataContext : « barrier-gated read, le repo d'inbox n'est pas encore ouvert dans le verifier, un read ancré renverrait 0 » devient « `read` rend ce qui est connu localement maintenant, `readSynced` rend une fois les dépôts synchronisés visibles ; ce site a besoin du second parce qu'il lit depuis une session froide ». - ngBootstrap : « le verifier sérialise les créations » devient « `docCreate` est un aller-retour qui ne recouvre pas le suivant, donc le coût du seed croît LINÉAIREMENT avec le nombre de documents ». Le ~2s mesuré est conservé, mais explicitement comme une observation, pas comme un contrat. - entityWrites : description de lecture périmée (ORM fan-out, ngSet couplé au scope) remplacée par la vue réactive. La distinction read/readSynced vit désormais là où elle est légitime : knowledge_sdk-surface, avec le critère de choix (`read` dans une session qui observe déjà l'inbox, `readSynced` dès que la justesse dépend d'une session froide voyant le dépôt d'une autre identité). knowledge_context-internals cesse d'expliquer le fix par `ensureRepoOpen`/premier `State` et pointe le contrat. Laissé tel quel : `src/shared/support/hooks.ts` et les steps e2e — le harness de test connaît légitimement la plomberie ; la règle vise l'app. Et le « no cross-account fan-out » de FestipodDataContext, qui décrit le périmètre de l'app et non NextGraph. tsc : 0 erreur. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014GbGgNEHRejVKoREvFuDFg
This commit is contained in:
@@ -599,10 +599,9 @@ function useNgData(): FestipodDataContextValue {
|
||||
` — participantCount before write (as currently read) = ${knownCount ?? '(unknown)'}`,
|
||||
);
|
||||
// (1) COUNT — derive the distinct active-registration set for this event
|
||||
// and write it on MY OWN event doc (only when it changed). The read inside
|
||||
// `materializeAttendance` is BARRIER-GATED (`inbox.readSynced`): at the
|
||||
// owner's connection it waits for the inbox sync barrier before reading, so
|
||||
// a registrant's already-synced deposit IS seen (no premature 0).
|
||||
// and write it on MY OWN event doc (only when it changed). `materializeAttendance`
|
||||
// reads through the synced-view contract (`inbox.readSynced`), so a
|
||||
// registrant's deposit is visible even on a cold session.
|
||||
const active = await materializeAttendance(targetInbox, evId);
|
||||
const nextCount = active.length; // no host baseline (creator not auto-in)
|
||||
const prevCount = materializedCountRef.current.get(evId);
|
||||
@@ -663,11 +662,11 @@ function useNgData(): FestipodDataContextValue {
|
||||
}
|
||||
};
|
||||
|
||||
// (A) RELIABLE-AT-CONNECTION: run one barrier-gated materialization directly on
|
||||
// this trigger ([ready, ownedKey]). This is the spec's core — the owner, at its
|
||||
// NEXT CONNECTION, deterministically processes its owned events' inbox (the read
|
||||
// waits for the inbox sync barrier, so a registrant's synced deposit is seen).
|
||||
// It does NOT depend on a cross-session inbox push arriving.
|
||||
// (A) RELIABLE-AT-CONNECTION: run one materialization directly on this trigger
|
||||
// ([ready, ownedKey]). This is the spec's core — the owner, at its NEXT
|
||||
// CONNECTION, deterministically processes its owned events' inbox, reading
|
||||
// through the synced-view contract. It does NOT depend on a cross-session
|
||||
// inbox push arriving.
|
||||
void materialize('connection');
|
||||
|
||||
// (B) SAME-SESSION LIVE: `inbox.watch` fires on the initial state push and on
|
||||
|
||||
@@ -16,10 +16,9 @@
|
||||
* `docs.sparqlUpdate` primitive (the real injected `ng`) — the same direct-write
|
||||
* path `insertNotification` already uses. The document was just created and is
|
||||
* openable, so the write lands immediately. The READ stays reactive: the document
|
||||
* NURI is registered into the scope's `useShape({ graphs })`, and the ORM reads
|
||||
* the entity back. Write (direct, per-document) and read (reactive fan-out) are
|
||||
* decoupled — the model (one document per entity, per-document isolation) is
|
||||
* unchanged; only the write mechanism moves off the scope-coupled ngSet.
|
||||
* NURI joins the scope's reactive view, which reads the entity back. Write
|
||||
* (direct, per-document) and read (reactive) are decoupled — the model (one
|
||||
* document per entity, per-document isolation) is unchanged.
|
||||
*
|
||||
* TYPED TERMS. The ORM reads back via the SHEX shapes (festipodShapes.shex), so
|
||||
* each field must be written with the RIGHT RDF term: xsd:integer/float/boolean
|
||||
|
||||
@@ -250,14 +250,13 @@ export async function materializeAttendance(
|
||||
targetInbox: string,
|
||||
eventId: string,
|
||||
): Promise<ActiveRegistration[]> {
|
||||
// BARRIER-GATED read (`inbox.readSynced`, not `inbox.read`): the owner
|
||||
// materializes at its NEXT CONNECTION, and on a fresh session the event inbox
|
||||
// repo is not yet open in the verifier — a plain anchored read would silently
|
||||
// return 0 deposits even for a registrant's deposit already synced to the broker
|
||||
// (the premature-0 that made the owner stick at count 0). `readSynced` awaits the
|
||||
// inbox's first `State` (deterministic sync barrier) before reading, so the
|
||||
// synced deposits ARE visible. No polling (rule_no-broker-polling): one barrier
|
||||
// wait, then one read.
|
||||
// `inbox.readSynced`, not `inbox.read` — the two differ by CONTRACT, and this
|
||||
// call site needs the stronger one. `read` returns what is known locally right
|
||||
// now; `readSynced` returns once the deposits synced to this inbox are visible.
|
||||
// The owner materializes at its NEXT CONNECTION, i.e. from a cold session where
|
||||
// "known locally right now" is not yet the truth — so the synced view is the
|
||||
// only correct one here. Single wait, single read: no polling
|
||||
// (see `rule_no-broker-polling`).
|
||||
const deposits = await inbox.readSynced(targetInbox);
|
||||
// Match deposits to this event on the CANONICAL id-form (base repo id, stripping
|
||||
// any `:v:<overlay>` suffix). On the current tree the forms already agree, but
|
||||
|
||||
@@ -38,8 +38,7 @@ export interface BootstrapResult {
|
||||
* model's doc set for the union READ.
|
||||
*
|
||||
* `walletHasData` tells the seed whether the wallet already carries entities (a
|
||||
* returning user → skip). The caller computes it from the union read (no ORM set
|
||||
* needed — the read side is now the one-shot union query, not a reactive fan-out).
|
||||
* returning user → skip). The caller computes it from what it has already read.
|
||||
*/
|
||||
export async function bootstrapWallet(
|
||||
walletHasData: boolean,
|
||||
@@ -70,9 +69,10 @@ export async function bootstrapWallet(
|
||||
// OWNER is shared). Falls back to the fixture username when no login is present.
|
||||
const seedOwner = owner ?? (seedUsers[0] ? normalizeIdentifier(seedUsers[0].username) : 'seed');
|
||||
|
||||
// SEED FOOTPRINT (perf). Each entity is its OWN document, and each `docCreate`
|
||||
// is a SERIAL ~2s broker round-trip (the verifier serializes creations — they
|
||||
// do NOT parallelize), so the seed cost is ~2s × (#docs). Seeding the full
|
||||
// SEED FOOTPRINT (perf). Each entity is its OWN document, and `docCreate` is a
|
||||
// round-trip that does not overlap with the next one, so the seed cost grows
|
||||
// LINEARLY with the number of documents (measured around 2s each on our test
|
||||
// setup — an observation, not a contract). Seeding the full
|
||||
// fixture (14 users + 5 events + 5 participations = 24 docs) blows past the test
|
||||
// step budget. So the CONNECTED seed writes only what the app/@data needs to be
|
||||
// exercised: ALL events (looked up by title), a FEW user profiles ("wallet has
|
||||
|
||||
Reference in New Issue
Block a user