feat!: curer n'est plus un appel, c'est ce que fait le traitement de l'inbox

This commit is contained in:
Sylvain Duchesne
2026-08-20 11:04:31 +02:00
parent 2ce2113157
commit e2ed970cbd
21 changed files with 956 additions and 273 deletions
+38 -49
View File
@@ -126,12 +126,11 @@ const { check, journey, finish } = declareSuite({
],
},
{
name: "Bob hands the index a reference, and Alice curates it",
name: "Bob hands the index a reference, and Alice's next connection curates it",
checks: [
"a stranger's deposit into the index's inbox is accepted",
"curation reports Bob's object as indexed",
"the indexed value was read off Bob's object, and never travelled in his deposit",
"a stranger's deposit into the index's inbox reached its owner and became an entry",
"the entry is stored under Bob's object's own reference as its subject",
"the indexed value was read off Bob's object, and never travelled in his deposit",
],
},
{
@@ -145,8 +144,7 @@ const { check, journey, finish } = declareSuite({
{
name: "An object carrying nothing for the field is not indexed",
checks: [
"curation reports it skipped for want of the field, rather than indexed",
"the index still holds exactly one entry",
"the unrelated object is not indexed, and the index still holds exactly one entry",
],
},
{
@@ -365,7 +363,7 @@ async function main(): Promise<void> {
});
await journey({
name: "Bob hands the index a reference, and Alice curates it",
name: "Bob hands the index a reference, and Alice's next connection curates it",
needs: [
aliceIsUp,
bobIsUp,
@@ -379,30 +377,11 @@ async function main(): Promise<void> {
bob!.frame.evaluate((o) => window.__indexing.referConfigured(o), bobsObject!),
);
const report = await step("Alice curating", BRIDGE_MS, () =>
alice!.frame.evaluate((i) => window.__indexing.curate(i), index!),
);
// The deposit is proven ARRIVED, by the only person who can see it. That the post
// did not throw is a weaker claim entirely — it says the call returned, not that
// anything crossed the identity boundary — and asserting it would be asserting a
// constant. Alice reads her own inbox; one outcome means one deposit reached it.
check(
"a stranger's deposit into the index's inbox is accepted",
report.outcomes.length === 1,
`from=${BOB} outcomes=${report.outcomes.length}`,
);
const forBob = report.outcomes.find(
(o) => "object" in o && o.object === bobsObject,
);
check(
"curation reports Bob's object as indexed",
forBob?.result === "indexed",
`outcomes=${JSON.stringify(report.outcomes)}`,
);
check(
"the indexed value was read off Bob's object, and never travelled in his deposit",
forBob?.result === "indexed" && forBob.value === "2026-08-17T09:00:00Z",
`value=${forBob !== undefined && "value" in forBob ? forBob.value : "(none)"}`,
// NOBODY CURATES: there is nothing on the surface to call. Alice's page connects
// again — what a page load does — and her session processes the inboxes of the
// indexes she owns, this one among them.
await step("Alice connecting again", BRIDGE_MS, () =>
alice!.frame.evaluate(() => window.__indexing.reconnect()),
);
// THE WRITE FORM, answered. An entry is a triple whose subject is another
@@ -412,11 +391,27 @@ async function main(): Promise<void> {
alice!.frame.evaluate((d) => window.__indexing.readRaw(d), index!),
);
const entry = raw.find((s) => s.subject === bobsObject);
// The deposit is proven ARRIVED by its only possible effect: nobody but Alice
// reads that inbox, so an entry for Bob's object means his deposit crossed the
// identity boundary and her session found it. That the post did not throw is a
// weaker claim entirely — it says the call returned, and nothing more.
check(
"a stranger's deposit into the index's inbox reached its owner and became an entry",
entry !== undefined,
`from=${BOB} subjects=${JSON.stringify(raw.map((s) => s.subject))}`,
);
check(
"the entry is stored under Bob's object's own reference as its subject",
(entry?.props[ENTRY_VALUE] ?? []).includes("2026-08-17T09:00:00Z"),
entry !== undefined && Object.hasOwn(entry.props, ENTRY_VALUE),
`subjects=${JSON.stringify(raw.map((s) => s.subject))}`,
);
// The value never travelled: a deposit is the reference and nothing else, so its
// presence here means the curation read it off Bob's object itself.
check(
"the indexed value was read off Bob's object, and never travelled in his deposit",
(entry?.props[ENTRY_VALUE] ?? []).includes("2026-08-17T09:00:00Z"),
`entry=${JSON.stringify(entry?.props ?? {})}`,
);
},
});
@@ -446,16 +441,16 @@ async function main(): Promise<void> {
// Deposits are never retired, so every run sees every deposit again. Convergence
// is what makes that affordable.
const again = await step("Alice curating a second time", BRIDGE_MS, () =>
alice!.frame.evaluate((i) => window.__indexing.curate(i), index!),
await step("Alice connecting a second time", BRIDGE_MS, () =>
alice!.frame.evaluate(() => window.__indexing.reconnect()),
);
const still = await step("Alice reading the index again", BRIDGE_MS, () =>
alice!.frame.evaluate((i) => window.__indexing.read(i), index!),
);
check(
"curating a second time changes nothing, and the index still holds one entry",
again.outcomes.every((o) => o.result === "unchanged") && still.length === 1,
`outcomes=${JSON.stringify(again.outcomes)} entries=${still.length}`,
"connecting a second time changes nothing, and the index still holds one entry",
still.length === 1 && still[0]?.object === bobsObject,
`entries=${JSON.stringify(still)}`,
);
},
});
@@ -478,22 +473,16 @@ async function main(): Promise<void> {
bob!.frame.evaluate((o) => window.__indexing.referConfigured(o), other),
);
const report = await step("Alice curating the unrelated reference", BRIDGE_MS, () =>
alice!.frame.evaluate((i) => window.__indexing.curate(i), index!),
);
const forOther = report.outcomes.find((o) => "object" in o && o.object === other);
check(
"curation reports it skipped for want of the field, rather than indexed",
forOther?.result === "skipped" && forOther.reason === "no-field",
`outcome=${JSON.stringify(forOther)}`,
await step("Alice connecting after the unrelated reference", BRIDGE_MS, () =>
alice!.frame.evaluate(() => window.__indexing.reconnect()),
);
const entries = await step("Alice reading the index once more", BRIDGE_MS, () =>
alice!.frame.evaluate((i) => window.__indexing.read(i), index!),
);
check(
"the index still holds exactly one entry",
entries.length === 1,
"the unrelated object is not indexed, and the index still holds exactly one entry",
entries.length === 1 && !entries.some((e) => e.object === other),
`entries=${JSON.stringify(entries)}`,
);
},
@@ -593,8 +582,8 @@ async function main(): Promise<void> {
await step("Bob depositing the hostile reference", BRIDGE_MS, () =>
bob!.frame.evaluate((o) => window.__indexing.referConfigured(o), object),
);
await step("Alice curating the hostile reference", BRIDGE_MS, () =>
alice!.frame.evaluate((i) => window.__indexing.curate(i), index!),
await step("Alice connecting after the hostile reference", BRIDGE_MS, () =>
alice!.frame.evaluate(() => window.__indexing.reconnect()),
);
// Read the index document RAW: it must still declare its own field. An injected