@githolon/testing 0.16.0 → 0.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build.mjs CHANGED
@@ -1,31 +1,22 @@
1
- // Vendor THE ENGINE PLANE (cloud/cloudflare-shell/src/{engine,git-fs,tree}.mjs — the
2
- // exact machinery the edge DO and the heavy container run) into this package so
3
- // `testHolon()` boots holons in-process with the same code path the cloud uses.
4
- // Sync-at-build keeps it un-forked (the cli/build.mjs / deploy.sh pattern); the
5
- // published package ships the vendored copies and skips the sync when the
6
- // monorepo source is absent.
1
+ // Vendor THE SHARED ADAPTER (adapter/{engine,custody-transport,git-fs,tree}.mjs — the one JS plumbing the
2
+ // Cloudflare shell, the CLI, and this harness all wrap) into this package so `testHolon()` boots holons
3
+ // in-process with the same code path the cloud uses. The CLI/testing/cloud all consume the ADAPTER, never a
4
+ // platform shell. Sync-at-build keeps it un-forked; the published package ships the vendored copies and skips
5
+ // the sync when the monorepo source is absent. engine.mjs imports its siblings by `./`, so they vendor flat.
7
6
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
8
7
  import { dirname, join } from "node:path";
9
8
  import { fileURLToPath } from "node:url";
10
9
 
11
10
  const HERE = dirname(fileURLToPath(import.meta.url));
12
- const ENGINE_SRC = join(HERE, "..", "cloud", "cloudflare-shell", "src");
13
- const ADAPTER_SRC = join(HERE, "..", "adapter"); // git-fs.mjs + tree.mjs are the SHARED adapter now
11
+ const ADAPTER_SRC = join(HERE, "..", "adapter");
14
12
  const VENDOR = join(HERE, "vendor", "engine");
15
13
 
16
- if (existsSync(ENGINE_SRC)) {
14
+ if (existsSync(ADAPTER_SRC)) {
17
15
  mkdirSync(VENDOR, { recursive: true });
18
- // The shell's engine plane (engine.mjs + its custody-transport sibling). Rewrite the repo-relative adapter
19
- // import (../../../adapter/) to local so the vendored copies resolve side-by-side (the deploy.sh pattern).
20
- for (const f of ["engine.mjs", "custody-transport.mjs"]) {
21
- const body = readFileSync(join(ENGINE_SRC, f), "utf8").replace(/\.\.\/\.\.\/\.\.\/adapter\//g, "./");
22
- writeFileSync(join(VENDOR, f), `// AUTO-SYNCED from cloud/cloudflare-shell/src/${f} by testing/build.mjs — DO NOT EDIT HERE.\n${body}`, "utf8");
23
- }
24
- // The shared adapter primitives the engine imports.
25
- for (const f of ["git-fs.mjs", "tree.mjs"]) {
16
+ for (const f of ["engine.mjs", "custody-transport.mjs", "git-fs.mjs", "tree.mjs"]) {
26
17
  const body = readFileSync(join(ADAPTER_SRC, f), "utf8");
27
18
  writeFileSync(join(VENDOR, f), `// AUTO-SYNCED from adapter/${f} by testing/build.mjs — DO NOT EDIT HERE.\n${body}`, "utf8");
28
19
  }
29
20
  } else if (!existsSync(join(VENDOR, "engine.mjs"))) {
30
- throw new Error("engine plane not found: neither ../cloud/cloudflare-shell/src nor vendor/engine exists");
21
+ throw new Error("the shared adapter (../adapter) is not present and no vendored engine exists");
31
22
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@githolon/testing",
3
- "version": "0.16.0",
3
+ "version": "0.16.1",
4
4
  "type": "module",
5
5
  "description": "@githolon/testing — law TDD for Nomos domains: boot the REAL engine plane in-process (the exact machinery every cloud DO, heavy container and web client runs), dispatch directives, assert rows, assert TYPED REFUSALS, fork for what-ifs — fully offline inside vitest.",
6
6
  "license": "SEE LICENSE IN LICENSE.md",
package/src/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  // @githolon/testing — LAW TDD for Nomos domains.
2
2
  //
3
3
  // `testHolon({ deploy })` boots THE ENGINE PLANE in-process (the vendored
4
- // cloud/cloudflare-shell/src/engine.mjs — the exact machinery every cloud DO, heavy
4
+ // adapter/engine.mjs — the exact machinery every cloud DO, heavy
5
5
  // container and web client runs) over the one wasm32-wasip1 artifact, installs
6
6
  // your compiled law at genesis, and hands back a holon you drive from a test:
7
7
  // dispatch directives, read rows/queries/counts/sums, assert TYPED REFUSALS
@@ -1,4 +1,4 @@
1
- // AUTO-SYNCED from cloud/cloudflare-shell/src/custody-transport.mjs by testing/build.mjs — DO NOT EDIT HERE.
1
+ // AUTO-SYNCED from adapter/custody-transport.mjs by testing/build.mjs — DO NOT EDIT HERE.
2
2
  // THE CLOUD SHELL'S DUMB-PIPE CUSTODY TRANSPORT — raw git smart-HTTP over fetch(), ZERO isomorphic-git.
3
3
  //
4
4
  // Custody (Cloudflare Artifacts) is a git smart-HTTP remote. The KERNEL owns all git semantics (gix builds
@@ -1,4 +1,4 @@
1
- // AUTO-SYNCED from cloud/cloudflare-shell/src/engine.mjs by testing/build.mjs — DO NOT EDIT HERE.
1
+ // AUTO-SYNCED from adapter/engine.mjs by testing/build.mjs — DO NOT EDIT HERE.
2
2
  // Nomos — THE CLOUDFLARE SHELL's ENGINE PLANE (the adapter logic that boots + drives the offer-kernel).
3
3
  //
4
4
  // Everything that boots the offer-kernel wasm + drives its /work tree lives HERE (the adapter the
@@ -21,6 +21,9 @@ import { lsRefs, fetchPack, pushPack, ZERO_OID } from "./custody-transport.mjs";
21
21
 
22
22
  const enc = new TextEncoder(), dec = new TextDecoder();
23
23
  const BRANCH = "main";
24
+ // The largest result-delta the offer response will carry inline (settle perf — saves the client a second
25
+ // round-trip). A normal write's delta is a few KiB; a far-behind client exceeds this and falls back to GET /pack.
26
+ const RESULT_PACK_INLINE_MAX = 256 * 1024;
24
27
  export const repoArgOf = (ws) => `/work/ws/${ws}`;
25
28
  export const gitdirOf = (ws) => `/work/ws/${ws}/nomos.git`;
26
29
  function b64Bytes(bytes) {
@@ -1115,10 +1118,22 @@ export async function admitIntentOffers(eng, ws, ledger, offers, { refuseDomains
1115
1118
  // The coalesced §5.2 delta of this batch (null when no scoped read moved) — the adapter closes it onto the
1116
1119
  // coordinator (`_postAdmissionHooks` → `_emitSummary`), exactly as the session-branch lane does.
1117
1120
  const summary = summaryCtx ? summaryOfCapture(summaryCtx, headBefore, head) : null;
1118
- // (The legacy inline `mainDelta` perf hack is GONE: the client pulls the delta itself via GET /pack +
1119
- // the kernel's gix apply_pack one byte-pipe lane, no adapter-side loose-object walk.)
1120
- log("admit-intent-offers", { ws, sessions: sessions.size, admitted: admittedTotal, rejected: [...sessions.values()].reduce((n, s) => n + s.rejected.length, 0) });
1121
- return { sessions: [...sessions.values()].map((s) => ({ ...s, ...(s.skipped.length ? {} : { skipped: undefined }) })), main: head, deadLetters, timings, ...(summary ? { summary } : {}), ...(deferDurability && admittedTotal && head ? { deferred: true, head } : {}) };
1121
+ // RESULT-PACK PIGGYBACK (settle perf): the offer RE-SEALS the intent onto main (a NEW commit oid the
1122
+ // client lacks), so the client otherwise makes a SECOND round-trip (GET /pack?have=base) just to pull
1123
+ // what this admit produced the ~500ms "prefetch" phase. Since we already hold every object, carry that
1124
+ // exact delta (base→head) BACK in the offer response so the client applies it with zero extra network.
1125
+ // Bounded: only inline a small delta (a normal write is one commit + tree); a far-behind client's large
1126
+ // delta falls back to GET /pack (no worse than today). The kernel odb has `head` post-fold even under
1127
+ // deferred durability (custody push is write-behind; the objects are resident), so this is available now.
1128
+ let resultPackB64 = null;
1129
+ if (admittedTotal && head && /^[0-9a-f]{40}$/i.test(clientBase || "") && clientBase !== head) {
1130
+ try {
1131
+ const p = servePack(eng, ws, clientBase);
1132
+ if (p && p.packB64 && p.bytes && p.bytes <= RESULT_PACK_INLINE_MAX) resultPackB64 = p.packB64;
1133
+ } catch { /* fall back to the client's own GET /pack */ }
1134
+ }
1135
+ log("admit-intent-offers", { ws, sessions: sessions.size, admitted: admittedTotal, rejected: [...sessions.values()].reduce((n, s) => n + s.rejected.length, 0), resultPack: resultPackB64 ? "inline" : "none" });
1136
+ return { sessions: [...sessions.values()].map((s) => ({ ...s, ...(s.skipped.length ? {} : { skipped: undefined }) })), main: head, deadLetters, timings, ...(summary ? { summary } : {}), ...(resultPackB64 ? { resultPackB64, resultBase: clientBase } : {}), ...(deferDurability && admittedTotal && head ? { deferred: true, head } : {}) };
1122
1137
  }
1123
1138
 
1124
1139
  /**
@@ -2489,10 +2504,18 @@ export async function deploy(eng, ws, ledger, usda, domainHash, dispositions) {
2489
2504
  // adjudicates the stable-id diff against. Absent for the common (non-destructive)
2490
2505
  // upgrade; the gate's typed refusal names the remedy when one is needed.
2491
2506
  const result = author(eng, ws, "nomos", "installDomain", installPayload(domainHash, usda, eng.installedBy, dispositions), eng.hashes.nomos);
2507
+ // ATOMICITY: VALIDATE the post-install projection BEFORE committing to custody. The install's
2508
+ // read manifest is re-derived on this read; if it cannot fold (e.g. a divergent read-projection
2509
+ // declaration the kernel refuses), this THROWS — and because we have NOT yet pushed, custody
2510
+ // stays clean (the durable source of truth never holds an unfoldable install; the in-memory mount
2511
+ // is evicted + re-mounted from clean custody on the error). A bad install must FAIL CLOSED, never
2512
+ // persist in the chain. (Was: commitAndPush THEN qById — a fold failure left the install pushed,
2513
+ // wedging every later fold. See read-manifest-evolution-gap.)
2514
+ const installation = qById(eng, ws, `domain-installation:${domainHash}`);
2492
2515
  // Shard identity used to be inferred from adapter-side taxonomy. That is retired:
2493
2516
  // if sharding needs declaration, the holon must derive and author it itself.
2494
2517
  await commitAndPush(eng, ws, ledger);
2495
- return { head: result.head, installation: qById(eng, ws, `domain-installation:${domainHash}`) };
2518
+ return { head: result.head, installation };
2496
2519
  }
2497
2520
 
2498
2521
  export function snapshot(eng, ws) {