feat!: useShapeQuery lit par la requete de forme du SDK

This commit is contained in:
Sylvain Duchesne
2026-09-21 11:41:31 +02:00
parent a5e553e65b
commit 77e78ec81d
29 changed files with 1190 additions and 971 deletions
+17 -60
View File
@@ -2,43 +2,33 @@
* Does a live `useShape` read reach the DEPLOYED broker, and does deleting from the set it
* returns reach the document?
*
* Standalone, and deliberately outside `e2e/run.ts`: this is the one measurement that needs
* `@ng-org/orm`, an OPTIONAL PEER this package does not install (`bun.lock`,
* `optionalPeers`). Folding it into the 42-check suite would make that suite unbuildable on
* a checkout without it. Here, a missing ORM fails the build of this runner alone, with the
* reason said out loud — which is the honest outcome, because a measurement that did not
* run must not be reported as a verdict either way.
* Standalone, and deliberately outside `e2e/run.ts`: what it measures is the PUBLISHED
* `useShape` - the bare `DeepSignalSet` the ORM hook hands an application, and a
* `.delete()` on it reaching the document. `e2e/run.ts` exercises the other shape read,
* `useShapeQuery`, which since `1.0.0-dev.6` reads through the SDK's shape query too. Two
* surfaces, two runs.
*
* Run: `bun run e2e/orm-live-read.ts` from `packages/polyfill`.
*
* ── What it decides ────────────────────────────────────────────────────────
* -- What it decides ----------------------------------------
* The verdict is readable in one number: does `readyPromise` settle. It does on one path
* only — the arrival of an initial payload from the engine
* (`GraphOrmSubscription.ts:handleInitialResponse`) — so a refused start leaves it pending
* for ever, which is exactly why the failure is silent and why a bound, not an await, is
* what turns it into a report. Nothing here infers a verdict from a version string.
*
* ── What it found, 2026-09-16, and why the last row exists ─────────────────
* The read does NOT start, and the reason is not the one
* `bug_useshape-live-read-needs-a-newer-broker` names. That leaf's mechanism — a broker
* built before `orm_start` was renamed `orm_start_graph` — is REFUTED here: the method
* resolves, and the call fails INSIDE it, on an argument. The engine answers
* `Deserialization error of config Error: invalid type: JsValue(Function), expected any
* valid JSON value`.
* -- What it found, and the row that went with the answer ----------------
* On 2026-09-16 the read did not start: the engine answered `Deserialization error of
* config`, and a sixth row of this run established WHERE that `config` sits - position 4,
* before the callback, where the five-argument client of the day landed its callback. The
* deployment was AHEAD of the pinned client packages, not behind them.
*
* The last row establishes where that `config` sits, because the position is the whole
* diagnosis: calling the SDK member directly with `{}` in position 4 is ACCEPTED, and the
* engine then streams back. So the deployed `orm_start_graph` is
* `(graph_scope, subject_scope, shapeType, session_id, config, callback)`, and the
* five-argument call the published `@ng-org/orm` makes lands its callback in `config`.
* That arity is in no commit of `nextgraph-rs` at the read revision — the one window that
* had a `config` at all (2026-04-12 to 2026-04-21) put it LAST, after the callback. The
* deployment is therefore AHEAD of the client packages this repository pins, not behind
* them, which inverts what the leaf says to do about it.
*
* The run is EXPECTED TO EXIT NON-ZERO while that holds: it is a measurement of a
* deployment, not a gate on this package. Green again means the two ends agree, and the
* bug leaf can close.
* Updating them answered it: `@ng-org/web@0.1.2-alpha.14` declares six arguments with
* `config` at index 4 and `@ng-org/orm@0.1.2-alpha.21` sends six to match, and the run
* measured `6 passed, 0 failed` with the read ready in 16ms and the delete reaching the
* document. The characterisation row was retired with the question it answered: there is
* nothing left for it to find out, and a row that always prints the same sentence teaches
* whoever reads this report to skip it.
*/
import * as fs from "node:fs";
@@ -107,7 +97,6 @@ const CHECKS: readonly string[] = [
"the initial payload carries the seeded object, with its `@id` and `@graph`",
"`.delete()` on that set is accepted",
"the deletion reached the DOCUMENT: the seeded subject's triples are gone",
"[finding] the ARITY the deployed `orm_start_graph` expects",
];
type Check = { name: string; ok: boolean; detail?: string };
@@ -116,17 +105,6 @@ function check(name: string, ok: boolean, detail?: string): void {
results.push({ name, ok, detail });
console.log(` [${ok ? "PASS" : "FAIL"}] ${name}${detail ? " — " + detail : ""}`);
}
/**
* A row that REPORTS rather than judges — `e2e/run.ts`'s convention for characterising the
* broker rather than asserting about this package. The last row is one: whichever arity the
* deployment expects, it is upstream's to change, so failing on it would only teach whoever
* reads the report to ignore this file.
*/
function record(name: string, detail: string): void {
results.push({ name, ok: true, detail });
console.log(` [INFO] ${name} — ${detail}`);
}
/** The bridge as the browser side of `frame.evaluate` sees it — no `any`, and no import
* the serialized callback could not carry across. */
type Bridge = Record<string, (...a: unknown[]) => unknown>;
@@ -261,27 +239,6 @@ async function main(): Promise<void> {
}
check(CHECKS[4]!, remaining === 0, `triples left for the seeded subject: ${remaining}`);
// Only worth asking when the published call did NOT start: it is the diagnosis of
// that failure, and a deployment that answers the published arity has nothing to
// characterise. Since `@ng-org/web@0.1.2-alpha.14` the published call is itself the
// six-argument one, so this asks whether the engine refuses a start the client got
// right - no longer whether the client was sending the wrong number.
if (readyMs === null) {
const withConfig = await sdk<{ doc: string; error: string | null }>(
frame,
"liveStartWithConfig",
);
record(
CHECKS[5]!,
withConfig.error === null
? "six arguments with `{}` in position 4 are ACCEPTED — the deployed " +
"`orm_start_graph` takes a `config` BEFORE the callback, which is what the " +
"published client now sends, so the refusal is not an arity mismatch"
: `six arguments were refused too: ${withConfig.error}`,
);
} else {
record(CHECKS[5]!, "not asked — the published six-argument call started");
}
} finally {
if (page) await closeQuietly("the ORM live-read page", () => page!.close());
if (ctx) await closeContext("orm-live", ctx);