@githolon/testing 0.34.1 → 0.36.0
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/package.json +1 -1
- package/vendor/engine/engine.mjs +120 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@githolon/testing",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.36.0",
|
|
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/vendor/engine/engine.mjs
CHANGED
|
@@ -44,7 +44,7 @@ function osEntropyBuffer(n) { const bytes = new Uint8Array(n * 8); for (let o =
|
|
|
44
44
|
function stringifyBig(o) { return JSON.stringify(o, (_k, v) => (typeof v === "bigint" ? `@@B:${v}@@` : v)).replace(/"@@B:(\d+)@@"/g, "$1"); }
|
|
45
45
|
const log = (evt, fields = {}) => console.log(JSON.stringify({ evt, t: Date.now(), ...fields }));
|
|
46
46
|
|
|
47
|
-
function call(ex, mode, fields, STDERR) {
|
|
47
|
+
export function call(ex, mode, fields, STDERR) {
|
|
48
48
|
const req = enc.encode(JSON.stringify({ mode, ...fields }));
|
|
49
49
|
const reqPtr = ex.git_holon_alloc(req.length);
|
|
50
50
|
try {
|
|
@@ -1411,9 +1411,31 @@ export function author(eng, ws, domain, directiveId, payload, controllerHash, op
|
|
|
1411
1411
|
capPorts.principal_verified = !!opts.principalVerified;
|
|
1412
1412
|
}
|
|
1413
1413
|
const envelope = { payload: { domain, directiveId, payload }, captured_ports: capPorts, policy_version: 1, policy_domain: "Nomos", policy_gas: 0, policy_memory: 0 };
|
|
1414
|
+
// ATTESTED READS (slice B stage 1 — attested_reads_design.md §4.1): the PRE-FETCHED foreign
|
|
1415
|
+
// envelopes injected on the author request (`[{queryId, result, attestation}]`). The wasm author
|
|
1416
|
+
// door serves a plan's `read(q, args, {from})` from these AFTER verifying each (never mid-plan
|
|
1417
|
+
// I/O); unconsumed entries are dropped (COMMIT-ONLY-CONSUMED). Absent ⇒ byte-identical envelope
|
|
1418
|
+
// (the era rule). The DO→DO/HTTPS pre-fetch that POPULATES this is stage 2 — this is the seam.
|
|
1419
|
+
if (opts.attestations !== undefined) envelope.attestations = opts.attestations;
|
|
1414
1420
|
writeWork(eng, `payload-${seq}.json`, enc.encode(JSON.stringify(payload)));
|
|
1415
1421
|
writeWork(eng, `envelope-${seq}.json`, enc.encode(stringifyBig(envelope)));
|
|
1416
1422
|
const genesis = !controllerHash;
|
|
1423
|
+
// THE COLOCATION SHORT-CIRCUIT (stage 2): when the declared foreign SOURCE is already MOUNTED in
|
|
1424
|
+
// THIS engine (the container pool colocates workspaces; the engine plane is multi-workspace — the
|
|
1425
|
+
// birth-effect precedent), a missing attested read never leaves the kernel: the gate's typed
|
|
1426
|
+
// `attested-read-unreachable` refusal names {queryId, from, args}; we serve + sign it via the SAME
|
|
1427
|
+
// `attestedRead` op (secret injected per call from `opts.attestorSecrets[from]` — operator config
|
|
1428
|
+
// the host passes through blindly), inject the envelope, and retry. Zero HTTP, zero host decision.
|
|
1429
|
+
// The envelope is BYTE-IDENTICAL to one fetched over ?attest=1 (same signed bytes, same verify arm).
|
|
1430
|
+
// A CARRIED attestation always wins — the refusal only fires for a read no injected entry answers,
|
|
1431
|
+
// so nothing is ever silently replaced. Non-colocated / secret-less sources fall through to the
|
|
1432
|
+
// caller with the kernel's own instruction (the client-carried ?attest=1 dance).
|
|
1433
|
+
const attestorSecretFor = (from) => {
|
|
1434
|
+
const s = opts.attestorSecrets;
|
|
1435
|
+
if (!s) return null;
|
|
1436
|
+
if (typeof s === "string") return s;
|
|
1437
|
+
return typeof s[from] === "string" ? s[from] : null;
|
|
1438
|
+
};
|
|
1417
1439
|
// THE DEFERRED-PROJECTION ACK (#47, sharding slice 7): the read-projection
|
|
1418
1440
|
// catch-up (incl. the derive/combine materialize) moves OFF the author ack path
|
|
1419
1441
|
// by default — every read op self-heals to head, and the post-ack warm lane
|
|
@@ -1430,7 +1452,28 @@ export function author(eng, ws, domain, directiveId, payload, controllerHash, op
|
|
|
1430
1452
|
// DRY-RUN (offer-kernel): `offer` with the commit withheld — run the plan + full gate, get the verdict,
|
|
1431
1453
|
// commit nothing. This is the home of the old `evolve_dryrun` verb (see `evolveDryRun`). Never defers
|
|
1432
1454
|
// projection (no commit to flush).
|
|
1433
|
-
const
|
|
1455
|
+
const offerOnce = () =>
|
|
1456
|
+
JSON.parse(call(eng.ex, "offer", { repoArg: repoArgOf(ws), workspace: ws, domain, directiveId, payloadFile: `/work/payload-${seq}.json`, envelopeFile: `/work/envelope-${seq}.json`, seq, actor: opts.actor ?? "", ...(opts.authToken ? { authToken: opts.authToken } : {}), domainFile: genesis ? "/work/domain.package.usda" : "", domainHash: genesis ? "" : controllerHash, branch: BRANCH, ...(opts.authorSecret ? { authorSecret: opts.authorSecret } : {}), ...(opts.dryRun ? { dryRun: true } : (defer ? { deferProjection: true } : {})) }, eng.STDERR));
|
|
1457
|
+
let v = offerOnce();
|
|
1458
|
+
// COLOCATED foreign reads: bounded loop (a plan may declare several) — each pass answers exactly the
|
|
1459
|
+
// read the kernel named, so it terminates in ≤ #declared-foreign-reads passes (cap 8, defensive).
|
|
1460
|
+
for (let pass = 0; pass < 8 && v.outcome === "refused"; pass++) {
|
|
1461
|
+
const need = parseAttestedReadNeed(v.verdict?.reason ?? v.error);
|
|
1462
|
+
if (!need || !eng.mounted.has(need.from)) break;
|
|
1463
|
+
const secret = attestorSecretFor(need.from);
|
|
1464
|
+
if (!secret) break;
|
|
1465
|
+
const served = attestedRead(eng, need.from, {
|
|
1466
|
+
queryId: need.queryId, paramsJson: JSON.stringify(need.args), attestorSecret: secret,
|
|
1467
|
+
nowMs: opts.attestNowMs ?? Date.now(),
|
|
1468
|
+
// K3 (§1.5.3): colocated custody is in-memory — always ask for the carried enrollment
|
|
1469
|
+
// proof; the kernel produces-or-omits under its own bounds (the adapter decides nothing).
|
|
1470
|
+
includeRosterProof: true,
|
|
1471
|
+
});
|
|
1472
|
+
if (!served || served.ok !== true) break; // the kernel's original instruction stands for the caller
|
|
1473
|
+
envelope.attestations = [...(envelope.attestations ?? []), { queryId: need.queryId, result: served.rows, attestation: served.attestation }];
|
|
1474
|
+
writeWork(eng, `envelope-${seq}.json`, enc.encode(stringifyBig(envelope)));
|
|
1475
|
+
v = offerOnce();
|
|
1476
|
+
}
|
|
1434
1477
|
// KEEP `born`: the wasm offer ran the G3 birth offer-effect and surfaced the child heads; thread them
|
|
1435
1478
|
// through the normalized shape so the relay (container author case → worker out.born) sees them.
|
|
1436
1479
|
const res = v.outcome === "admitted" ? { ok: true, head: v.head, intentOut: v.intentOut, ...(v.born ? { born: v.born } : {}) }
|
|
@@ -1861,6 +1904,36 @@ export function describe(eng, ws) {
|
|
|
1861
1904
|
// (base64) — the parts a `recordShare` payload carries; the subject's home gate verifies them (§3 gate-arm).
|
|
1862
1905
|
export const attestationSign = (eng, { secret, asserterWorkspace, object, relation, subject, attestedAt }) =>
|
|
1863
1906
|
JSON.parse(call(eng.ex, "query", { queryBytes: b64Json({ op: "attestationSign", secret, asserterWorkspace, object, relation, subject, attestedAt }) }, eng.STDERR));
|
|
1907
|
+
|
|
1908
|
+
// THE ATTESTED READ (slice B stage 2 — attested_reads_design.md §4.1, the source side). Serve + SIGN a
|
|
1909
|
+
// DECLARED query read over this workspace's own certified fold: the KERNEL derives the rows, pins
|
|
1910
|
+
// {genesis, head, fold_root, signer epoch, time} and signs with the PER-CALL-INJECTED read-attestor
|
|
1911
|
+
// secret (the `attestationSign` pattern — never persisted). The adapter/host transports the secret and
|
|
1912
|
+
// relays the returned `{rows, attestation, leafCount}` OPAQUE — it never constructs, inspects, or
|
|
1913
|
+
// modifies the envelope (the bailiff line). `nowMs` = the source clock at serve, injected by the caller.
|
|
1914
|
+
export const attestedRead = (eng, ws, { queryId, paramsJson, attestorSecret, nowMs, includeRosterProof }) =>
|
|
1915
|
+
JSON.parse(call(eng.ex, "query", {
|
|
1916
|
+
repoArg: repoArgOf(ws), workspace: ws, branch: BRANCH,
|
|
1917
|
+
queryBytes: b64Json({ op: "attestedRead", queryId, paramsJson: paramsJson || "{}", attestorSecret, nowMs: nowMs ?? Date.now(), sourceWorkspace: ws, ...(includeRosterProof ? { includeRosterProof: true } : {}) }),
|
|
1918
|
+
}, eng.STDERR));
|
|
1919
|
+
|
|
1920
|
+
// THE KERNEL-INSTRUCTED MISSING-EVIDENCE PARSE (stage 2 §4.1): the one gate's typed
|
|
1921
|
+
// `attested-read-unreachable` refusal NAMES the exact fetch — queryId + source + args. This parses it so
|
|
1922
|
+
// a caller (the colocation short-circuit below; the web client's pre-fetch convenience) can fulfil the
|
|
1923
|
+
// instruction and retry. Returns { queryId, from, args } or null. The kernel instructs; nobody guesses.
|
|
1924
|
+
export function parseAttestedReadNeed(error) {
|
|
1925
|
+
const m = /attested-read-unreachable: read\('([^']+)', \{from: '([^']+)'\}\) args=(.*?) has no injected attestation/
|
|
1926
|
+
.exec(String(error || ""));
|
|
1927
|
+
if (!m) return null;
|
|
1928
|
+
// The refusal may surface through a JSON-quoting layer (the engine's Threw detail) — the args
|
|
1929
|
+
// blob's quotes then arrive backslash-escaped. Unescape a level at a time until it parses.
|
|
1930
|
+
let blob = m[3];
|
|
1931
|
+
for (let i = 0; i < 4; i++) {
|
|
1932
|
+
try { return { queryId: m[1], from: m[2], args: JSON.parse(blob) }; }
|
|
1933
|
+
catch { blob = blob.replace(/\\(["\\])/g, "$1"); }
|
|
1934
|
+
}
|
|
1935
|
+
return null;
|
|
1936
|
+
}
|
|
1864
1937
|
// THE BIRTH-CERT SIGNER (VA root-of-trust) — the SINGLE SOURCE OF TRUTH for the cert byte format. The
|
|
1865
1938
|
// signer's client produces a SIGNED birth cert IN-wasm (`cert_sign` reuses `BirthCert::signed_bytes`/`sign`,
|
|
1866
1939
|
// the SIBLING of `attestation_sign`) so no client re-implements the layout (drift-proof). The device
|
|
@@ -2746,3 +2819,48 @@ export function warmEngine(eng) {
|
|
|
2746
2819
|
// not a top-level adapter verb. Still post-ack (the adapter calls warmEngine off the write critical path).
|
|
2747
2820
|
return JSON.parse(call(eng.ex, "query", { repoArg: "/work", workspace: "root", queryBytes: b64Json({ op: "warm" }), branch: BRANCH }, eng.STDERR));
|
|
2748
2821
|
}
|
|
2822
|
+
|
|
2823
|
+
/**
|
|
2824
|
+
* ATTESTED READS §5.2 (stage 3) — THE BATCH-SEAL DRIVER. The adapter's ONLY roles here are
|
|
2825
|
+
* SCHEDULING (when to ask) and TRANSPORT (carrying the kernel's own snapshot back as an offer)
|
|
2826
|
+
* — the debounced-admission-alarm precedent: the kernel decides WHAT a seal is (the
|
|
2827
|
+
* `attestationOpenBatch` snapshot + `shouldSeal` verdict + the gate's Merkle-root demand);
|
|
2828
|
+
* this function decides nothing. Call it on a timer / after serves / on unmount
|
|
2829
|
+
* (`{unmounting: true}` forces pending batches to seal — a batch never dies silently).
|
|
2830
|
+
* A failed seal offer LEAVES the accumulator intact (retry next tick, never a silent drop);
|
|
2831
|
+
* only an ADMITTED seal clears the sealed snapshot (`attestationBatchClear`).
|
|
2832
|
+
*
|
|
2833
|
+
* `domain` names the installed law that exports `recordAttestationBatch` (the framework
|
|
2834
|
+
* directive rides the composing law); `controllerHash` is that law's content hash. The offer
|
|
2835
|
+
* is authored AS `workspace:read-attestor` (the enrolled signer — §1.2's "one key, two
|
|
2836
|
+
* duties"); on a warranted workspace pass `opts.authorOpts` with the signing material.
|
|
2837
|
+
*/
|
|
2838
|
+
export function sealAttestationBatches(eng, ws, domain, controllerHash, opts = {}) {
|
|
2839
|
+
const snap = JSON.parse(call(eng.ex, "query", {
|
|
2840
|
+
repoArg: repoArgOf(ws), workspace: ws, branch: BRANCH,
|
|
2841
|
+
queryBytes: b64Json({ op: "attestationOpenBatch", repoArg: repoArgOf(ws), nowMs: opts.nowMs ?? Date.now(), unmounting: !!opts.unmounting }),
|
|
2842
|
+
}, eng.STDERR));
|
|
2843
|
+
const outcomes = [];
|
|
2844
|
+
for (const b of snap.batches ?? []) {
|
|
2845
|
+
if (b.leafCount === 0) continue;
|
|
2846
|
+
if (!(b.shouldSeal || opts.force)) continue;
|
|
2847
|
+
const payload = {
|
|
2848
|
+
batchId: b.batchId, batchRoot: b.batchRoot, leafCount: b.leafCount, leaves: b.leaves,
|
|
2849
|
+
firstAt: b.firstAt, lastAt: b.lastAt, headAtSeal: b.headAtSeal,
|
|
2850
|
+
foldRootAtSeal: b.foldRootAtSeal, signerKeyHash: b.signerKeyHash,
|
|
2851
|
+
};
|
|
2852
|
+
const r = author(eng, ws, domain, "recordAttestationBatch", payload, controllerHash, {
|
|
2853
|
+
actor: "workspace:read-attestor", ...(opts.authorOpts ?? {}),
|
|
2854
|
+
});
|
|
2855
|
+
if (!r.ok) {
|
|
2856
|
+
outcomes.push({ batchId: b.batchId, ok: false, error: r.error }); // retained — retries next call
|
|
2857
|
+
continue;
|
|
2858
|
+
}
|
|
2859
|
+
JSON.parse(call(eng.ex, "query", {
|
|
2860
|
+
repoArg: repoArgOf(ws), workspace: ws, branch: BRANCH,
|
|
2861
|
+
queryBytes: b64Json({ op: "attestationBatchClear", batchId: b.batchId, leafCount: b.leafCount }),
|
|
2862
|
+
}, eng.STDERR));
|
|
2863
|
+
outcomes.push({ batchId: b.batchId, ok: true, leafCount: b.leafCount, intent: r.intentOut });
|
|
2864
|
+
}
|
|
2865
|
+
return outcomes;
|
|
2866
|
+
}
|