@githolon/testing 0.17.0 → 0.18.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 +99 -20
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@githolon/testing",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.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
|
@@ -1001,6 +1001,9 @@ export async function admitIntentOffers(eng, ws, ledger, offers, { refuseDomains
|
|
|
1001
1001
|
const sessions = new Map();
|
|
1002
1002
|
const deadLetters = [];
|
|
1003
1003
|
let admittedTotal = 0;
|
|
1004
|
+
// BORN: the G3 birth offer-effect's child heads any `.births()` offer in this batch produced (the kernel
|
|
1005
|
+
// surfaced them on the admit verdict). Accumulated across the batch and relayed out for the host to persist.
|
|
1006
|
+
const born = [];
|
|
1004
1007
|
const timings = { spans: [], intents: 0, sessions: 0 };
|
|
1005
1008
|
// THE §5.2 SUMMARY CAPTURE on the OFFER LANE (offers are the only source of intents — this lane is the one
|
|
1006
1009
|
// admit, routed workspaces included). A shard (selfLabel set) with scoped reads captures the per-batch
|
|
@@ -1080,6 +1083,7 @@ export async function admitIntentOffers(eng, ws, ledger, offers, { refuseDomains
|
|
|
1080
1083
|
main.oids.add(res.head); main.head = res.head;
|
|
1081
1084
|
rec.admitted.push({ oid, head: res.head });
|
|
1082
1085
|
admittedTotal += 1;
|
|
1086
|
+
if (Array.isArray(res.born) && res.born.length) born.push(...res.born);
|
|
1083
1087
|
if (cap) finishSummaryCapture(eng, ws, summaryCtx, cap, res.head, intentId);
|
|
1084
1088
|
} else {
|
|
1085
1089
|
const error = `${String(res.error || "").slice(0, 300)} — dead-lettered; fix the law (or the payload), then POST /v1/workspaces/${ws}/dead-letters/retry`;
|
|
@@ -1133,7 +1137,7 @@ export async function admitIntentOffers(eng, ws, ledger, offers, { refuseDomains
|
|
|
1133
1137
|
} catch { /* fall back to the client's own GET /pack */ }
|
|
1134
1138
|
}
|
|
1135
1139
|
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 } : {}) };
|
|
1140
|
+
return { sessions: [...sessions.values()].map((s) => ({ ...s, ...(s.skipped.length ? {} : { skipped: undefined }) })), main: head, deadLetters, timings, ...(summary ? { summary } : {}), ...(born.length ? { born } : {}), ...(resultPackB64 ? { resultPackB64, resultBase: clientBase } : {}), ...(deferDurability && admittedTotal && head ? { deferred: true, head } : {}) };
|
|
1137
1141
|
}
|
|
1138
1142
|
|
|
1139
1143
|
/**
|
|
@@ -1171,7 +1175,9 @@ export async function authorOn(eng, ws, ledger, domain, directiveId, payload, la
|
|
|
1171
1175
|
}
|
|
1172
1176
|
if (res && res.ok === false) return { ok: false, error: String(res.error || "the law refused this intent").slice(0, 500) };
|
|
1173
1177
|
await commitAndPush(eng, ws, ledger);
|
|
1174
|
-
|
|
1178
|
+
// KEEP `born`: a `.births()` directive authored here ran the G3 birth offer-effect; surface the child
|
|
1179
|
+
// heads so the container author case → worker out.born relays them (the host persists the child custody).
|
|
1180
|
+
return { ok: true, head: res.head, ...(res.born ? { born: res.born } : {}) };
|
|
1175
1181
|
}
|
|
1176
1182
|
|
|
1177
1183
|
/**
|
|
@@ -1378,7 +1384,22 @@ export function author(eng, ws, domain, directiveId, payload, controllerHash, op
|
|
|
1378
1384
|
// costs 19 draws — see NOMOS_API_SHIM). 64 is the per-write default (3 mints of slack);
|
|
1379
1385
|
// a BATCH-creating directive needs 19×creates. COMMIT-ONLY-CONSUMED: only the consumed
|
|
1380
1386
|
// prefix is sealed onto the intent, so a generous buffer is request weight, not ledger weight.
|
|
1381
|
-
|
|
1387
|
+
// opts.validFromEpoch (VA Phase 4, TEST/ADVERSARIAL ONLY): force a CLAIMED signer epoch onto the
|
|
1388
|
+
// captured ports. The author lane preserves a NON-ZERO carried value (it only auto-stamps the prefix
|
|
1389
|
+
// epoch when 0) and signs over it (captured_ports ⊂ authored_core_bytes), so a smoke can mint a signed
|
|
1390
|
+
// intent whose claim is a deliberate backdate/forward-date — the kernel's epoch arm must refuse it.
|
|
1391
|
+
const capPorts = { clock: { physical: Date.now(), logical: 0, replica: eng.replica }, rng: osEntropyBuffer(opts.rngDraws ?? 64) };
|
|
1392
|
+
if (opts.validFromEpoch !== undefined) capPorts.valid_from_epoch = opts.validFromEpoch;
|
|
1393
|
+
// opts.principalVerified (VA — the verified-birth lane): stamp the offer's principal + verified verdict onto
|
|
1394
|
+
// the captured ports, exactly as the cloud offer gate does from a verified AuthProvider token. The birthHome
|
|
1395
|
+
// offer-effect reads `captured_ports.principal`/`principal_verified` as the GATE VERDICT and requires the
|
|
1396
|
+
// device-signed homeCert's `verified` to MATCH it (CAS-as-law). A test driving the verified lane sets this
|
|
1397
|
+
// so the kernel accepts a `verified:true` home cert; absent ⇒ the unverified lane (verified=false).
|
|
1398
|
+
if (opts.principalVerified !== undefined) {
|
|
1399
|
+
capPorts.principal = opts.actor ?? "";
|
|
1400
|
+
capPorts.principal_verified = !!opts.principalVerified;
|
|
1401
|
+
}
|
|
1402
|
+
const envelope = { payload: { domain, directiveId, payload }, captured_ports: capPorts, policy_version: 1, policy_domain: "Nomos", policy_gas: 0, policy_memory: 0 };
|
|
1382
1403
|
writeWork(eng, `payload-${seq}.json`, enc.encode(JSON.stringify(payload)));
|
|
1383
1404
|
writeWork(eng, `envelope-${seq}.json`, enc.encode(stringifyBig(envelope)));
|
|
1384
1405
|
const genesis = !controllerHash;
|
|
@@ -1398,14 +1419,36 @@ export function author(eng, ws, domain, directiveId, payload, controllerHash, op
|
|
|
1398
1419
|
// DRY-RUN (offer-kernel): `offer` with the commit withheld — run the plan + full gate, get the verdict,
|
|
1399
1420
|
// commit nothing. This is the home of the old `evolve_dryrun` verb (see `evolveDryRun`). Never defers
|
|
1400
1421
|
// projection (no commit to flush).
|
|
1401
|
-
const v = 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 ?? "", 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));
|
|
1402
|
-
|
|
1422
|
+
const v = 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));
|
|
1423
|
+
// KEEP `born`: the wasm offer ran the G3 birth offer-effect and surfaced the child heads; thread them
|
|
1424
|
+
// through the normalized shape so the relay (container author case → worker out.born) sees them.
|
|
1425
|
+
const res = v.outcome === "admitted" ? { ok: true, head: v.head, intentOut: v.intentOut, ...(v.born ? { born: v.born } : {}) }
|
|
1403
1426
|
: v.outcome === "refused" ? { ok: false, error: v.verdict?.reason ?? v.error }
|
|
1404
1427
|
: v; // defensive: a non-verdict shape passes through unchanged
|
|
1405
1428
|
if (defer && res.ok) (eng.pendingProjection ??= new Set()).add(ws);
|
|
1406
1429
|
return res;
|
|
1407
1430
|
}
|
|
1408
1431
|
|
|
1432
|
+
/** BIRTH SLICE 2 — the KERNEL produces the genesis. Fold a parent-authored genesis chain
|
|
1433
|
+
* (`[{domain,directiveId,payload,actor}]`) into `ws` in ONE atomic custody op (the kernel owns the fold;
|
|
1434
|
+
* the adapter delivered the opaque recipe + the impurity capability). `clockMs`/`rngSeed` are the
|
|
1435
|
+
* DETERMINISTIC injection — derive `rngSeed` per-birth-unique (e.g. from the child identity) so minted ids
|
|
1436
|
+
* never collide. Replaces the adapter's old per-step genesis-author loop. */
|
|
1437
|
+
export function materializeGenesis(eng, ws, genesisChain, opts = {}) {
|
|
1438
|
+
return JSON.parse(call(eng.ex, "materialize_genesis", {
|
|
1439
|
+
repoArg: repoArgOf(ws), workspace: ws, genesisChain,
|
|
1440
|
+
clockMs: opts.clockMs ?? 1700000000000, replica: eng.replica, rngSeed: opts.rngSeed ?? 1,
|
|
1441
|
+
branch: BRANCH,
|
|
1442
|
+
}, eng.STDERR));
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
/** TEST/HARNESS-ONLY (the `test-mint` wasm): pin the root-of-trust anchor `K_root` to a public key the
|
|
1446
|
+
* harness controls, so a parent-attested-birth refusal can be driven THROUGH the real kernel verb against a
|
|
1447
|
+
* real test anchor. `kRootPublicB64` = base64 of the 32 raw ed25519 public-key bytes of the harness's S_root. */
|
|
1448
|
+
export function setTestKRoot(eng, kRootPublicB64) {
|
|
1449
|
+
return JSON.parse(call(eng.ex, "set_test_k_root", { kRootPublicB64 }, eng.STDERR));
|
|
1450
|
+
}
|
|
1451
|
+
|
|
1409
1452
|
/** Catch one workspace's read projection up to head NOW (the deferred-ack flush). P3: rides the
|
|
1410
1453
|
* `query` verb (op:"refresh") — a non-effectful maintenance read, not a top-level adapter verb. */
|
|
1411
1454
|
export function refreshProjection(eng, ws) {
|
|
@@ -1437,8 +1480,11 @@ export function exportCheckpoint(eng, ws) {
|
|
|
1437
1480
|
/** Restore a checkpoint blob into the pool BEFORE the first read on a cold mount (no-op if the pool
|
|
1438
1481
|
* is already warm). The ADAPTER restores ONLY a blob whose stored lawHash matches the workspace's
|
|
1439
1482
|
* CURRENT law (schema parity); a mismatched/absent blob costs at most a cold fold, never a wrong read. */
|
|
1440
|
-
export function importCheckpoint(eng, ws, blobB64, frontierB64) {
|
|
1441
|
-
|
|
1483
|
+
export function importCheckpoint(eng, ws, blobB64, frontierB64, stateRoot) {
|
|
1484
|
+
// `stateRoot` (the kernel's deterministic projection state-root stamped at export) is passed back so the
|
|
1485
|
+
// kernel RE-DERIVES the restored blob's root and byte-compares — a corrupted/swapped blob is refused
|
|
1486
|
+
// (restored:false), the caller cold-folds. Absent (a pre-this-era checkpoint) ⇒ no check, cold-fold fallback.
|
|
1487
|
+
return JSON.parse(call(eng.ex, "checkpoint_import", { repoArg: repoArgOf(ws), workspace: ws, branch: BRANCH, blob: blobB64, ...(frontierB64 ? { frontier: frontierB64 } : {}), ...(stateRoot ? { stateRoot } : {}) }, eng.STDERR));
|
|
1442
1488
|
}
|
|
1443
1489
|
|
|
1444
1490
|
// ── CHECKPOINT IN CUSTODY (the adapter-agnostic cold-mount; compute placement is beneath the contract) ──
|
|
@@ -1478,19 +1524,27 @@ async function gunzip(bytes) {
|
|
|
1478
1524
|
* object layer is verifiable offline. */
|
|
1479
1525
|
export async function writeCheckpointObjects(eng, ws, ex, lawHash) {
|
|
1480
1526
|
const gitdir = gitdirOf(ws);
|
|
1481
|
-
|
|
1482
|
-
//
|
|
1483
|
-
//
|
|
1484
|
-
//
|
|
1485
|
-
|
|
1486
|
-
|
|
1527
|
+
// THE CHECKPOINT IS THE VERIFIED FOLD: the kernel now emits ONLY `ex.frontier` (the fold), NOT a
|
|
1528
|
+
// SQLite `ex.blob` (that image is non-deterministic). The host is a transparent byte-shuttle — it
|
|
1529
|
+
// stores whatever the kernel returns; a legacy export still carrying `ex.blob` is shuttled too (the
|
|
1530
|
+
// `checkpoint` file is absent when the kernel omits the blob). Gzipped.
|
|
1531
|
+
const files = [];
|
|
1532
|
+
let rawLen = 0, gzLen = 0;
|
|
1533
|
+
if (ex.blob) {
|
|
1534
|
+
const gz = await gzip(enc.encode(ex.blob));
|
|
1535
|
+
rawLen = ex.blob.length; gzLen = gz.length;
|
|
1536
|
+
files.push({ path: "checkpoint", bytes: gz });
|
|
1537
|
+
}
|
|
1538
|
+
// THE FOLD FRONTIER (the gate's Workspace state @cursor) IS the cold-mount artifact: a cold mount
|
|
1539
|
+
// re-projects the read model from it (kernel-verified against the oid-pinned trailer) and AUTHORS
|
|
1540
|
+
// forward on a shallow clone. Era-safe: an export without `ex.frontier` is shuttled as-is.
|
|
1487
1541
|
let fgzLen = 0;
|
|
1488
1542
|
if (ex.frontier) {
|
|
1489
1543
|
const fgz = await gzip(enc.encode(ex.frontier));
|
|
1490
1544
|
fgzLen = fgz.length;
|
|
1491
1545
|
files.push({ path: "frontier", bytes: fgz });
|
|
1492
1546
|
}
|
|
1493
|
-
files.push({ path: "meta", bytes: enc.encode(JSON.stringify({ cursor: ex.cursor, bytes: ex.bytes ?? 0, lawHash, codec: "gzip", raw:
|
|
1547
|
+
files.push({ path: "meta", bytes: enc.encode(JSON.stringify({ cursor: ex.cursor, bytes: ex.bytes ?? 0, lawHash, codec: "gzip", raw: rawLen, stored: gzLen, frontierStored: fgzLen, ...(ex.stateRoot ? { stateRoot: ex.stateRoot } : {}) })) });
|
|
1494
1548
|
const ref = CKPT_REF(lawHash);
|
|
1495
1549
|
// ONE kernel call: blobs→tree→parentless commit→force ref. Fixed timeSecs ⇒ deterministic (idempotent).
|
|
1496
1550
|
const commitOid = kgit.writeMetaCommit(eng, gitdir, { parents: [], files, message: `checkpoint ${ws} @${String(ex.cursor).slice(0, 16)}`, timeSecs: 0, ref });
|
|
@@ -1503,13 +1557,17 @@ export async function writeCheckpointObjects(eng, ws, ex, lawHash) {
|
|
|
1503
1557
|
* pre-this-era checkpoint (no `frontier` file). */
|
|
1504
1558
|
export async function readCheckpointBlob(eng, ws, commitOid) {
|
|
1505
1559
|
const gitdir = gitdirOf(ws);
|
|
1506
|
-
const blob = kgit.readBlob(eng, gitdir, commitOid, "checkpoint");
|
|
1507
1560
|
let codec = "gzip";
|
|
1508
|
-
|
|
1561
|
+
let stateRoot = null;
|
|
1562
|
+
try { const m = JSON.parse(dec.decode(kgit.readBlob(eng, gitdir, commitOid, "meta"))); codec = m.codec ?? "gzip"; stateRoot = m.stateRoot ?? null; } catch {}
|
|
1509
1563
|
const dezip = async (b) => dec.decode(codec === "gzip" ? await gunzip(b) : b);
|
|
1564
|
+
// THE FOLD FRONTIER is the cold-mount artifact ("the checkpoint IS the verified fold"); the legacy
|
|
1565
|
+
// SQLite `checkpoint` file is absent on current exports. Both reads are tolerant (a missing file ⇒ null).
|
|
1566
|
+
let blob = null;
|
|
1567
|
+
try { const b = kgit.readBlob(eng, gitdir, commitOid, "checkpoint"); if (b) blob = await dezip(b); } catch { /* current-era: no SQLite blob */ }
|
|
1510
1568
|
let frontier = null;
|
|
1511
1569
|
try { const f = kgit.readBlob(eng, gitdir, commitOid, "frontier"); if (f) frontier = await dezip(f); } catch { /* pre-this-era: no frontier */ }
|
|
1512
|
-
return { blob
|
|
1570
|
+
return { blob, frontier, stateRoot };
|
|
1513
1571
|
}
|
|
1514
1572
|
|
|
1515
1573
|
/** The checkpoint's schema-parity key: a hash of the workspace's CURRENT law map (every installed
|
|
@@ -1618,8 +1676,8 @@ export async function restoreCheckpointFromCustody(eng, ws, ledger, lawHash) {
|
|
|
1618
1676
|
if (!foundOid) return { restored: false, reason: "absent" };
|
|
1619
1677
|
// Fetch ONLY the checkpoint commit (parentless → O(checkpoint), never O(chain)) into ws's repo + apply_pack.
|
|
1620
1678
|
await custodyFetch(eng, ws, ledger, { remoteRef: ref });
|
|
1621
|
-
const { blob, frontier } = await readCheckpointBlob(eng, ws, foundOid);
|
|
1622
|
-
const r = importCheckpoint(eng, ws, blob, frontier);
|
|
1679
|
+
const { blob, frontier, stateRoot } = await readCheckpointBlob(eng, ws, foundOid);
|
|
1680
|
+
const r = importCheckpoint(eng, ws, blob, frontier, stateRoot);
|
|
1623
1681
|
if (r && r.restored === true && r.cursor) {
|
|
1624
1682
|
eng._ckptPushed ??= new Map();
|
|
1625
1683
|
eng._ckptPushed.set(ws, `${lawHash}:${r.cursor}`);
|
|
@@ -1775,12 +1833,31 @@ export const cryptoKeygen = (eng) => JSON.parse(call(eng.ex, "query", { queryByt
|
|
|
1775
1833
|
// on the author call). Returns { ok, secret, public } (both base64). `author_sign` is the lower-level
|
|
1776
1834
|
// standalone signer; the author DOOR signs internally from the injected secret, so callers use `author`.
|
|
1777
1835
|
export const authorKeygen = (eng) => JSON.parse(call(eng.ex, "query", { queryBytes: b64Json({ op: "authorKeygen" }) }, eng.STDERR));
|
|
1836
|
+
|
|
1837
|
+
// DESCRIBE (#43) — the workspace's self-describing API, DERIVED BY THE KERNEL from the installed law at
|
|
1838
|
+
// the FRONTIER (not a from-genesis fold): rpc_describe reads the active-domain set off the projection at
|
|
1839
|
+
// head and runs each active package's GENERIC `describe` verb over its OWN registered modules, merging
|
|
1840
|
+
// them (byte-identical to the compiler's <name>.openapi.json for a single package) + tagging
|
|
1841
|
+
// `x-nomos-described` (the hashes covered, for the host's thin staged-overlay fallback on a pre-describe
|
|
1842
|
+
// lump). The kernel returns the merged JSON. MUST live HERE (the adapter source) — deploy.sh syncs this
|
|
1843
|
+
// into container/src, so editing only the synced copy gets clobbered (the "unknown container op describe").
|
|
1844
|
+
export function describe(eng, ws) {
|
|
1845
|
+
return JSON.parse(call(eng.ex, "query", { repoArg: repoArgOf(ws), workspace: ws, queryBytes: b64Json({ op: "describe", workspace: ws }), branch: BRANCH }, eng.STDERR));
|
|
1846
|
+
}
|
|
1778
1847
|
// THE CROSS-CUSTODY ATTESTATION SIGNER (home_holons §3/§5) — the asserter's client produces a SIGNED QUOTE
|
|
1779
1848
|
// over the edge it is sharing (`attestation_sign`; the bytes are derived IN-wasm — the `author_sign` parity
|
|
1780
1849
|
// contract). The device `secret` (base64) is injected for THIS call only. Returns { ok, signature, publicKey }
|
|
1781
1850
|
// (base64) — the parts a `recordShare` payload carries; the subject's home gate verifies them (§3 gate-arm).
|
|
1782
1851
|
export const attestationSign = (eng, { secret, asserterWorkspace, object, relation, subject, attestedAt }) =>
|
|
1783
1852
|
JSON.parse(call(eng.ex, "query", { queryBytes: b64Json({ op: "attestationSign", secret, asserterWorkspace, object, relation, subject, attestedAt }) }, eng.STDERR));
|
|
1853
|
+
// THE BIRTH-CERT SIGNER (VA root-of-trust) — the SINGLE SOURCE OF TRUTH for the cert byte format. The
|
|
1854
|
+
// signer's client produces a SIGNED birth cert IN-wasm (`cert_sign` reuses `BirthCert::signed_bytes`/`sign`,
|
|
1855
|
+
// the SIBLING of `attestation_sign`) so no client re-implements the layout (drift-proof). The device
|
|
1856
|
+
// `secret` (base64) is injected for THIS call only; `parentKey` is the base64 ed25519 PUBLIC half matching
|
|
1857
|
+
// it (as the cert names it). Returns { ok, cert } where `cert` is the signed cert JSON (snake_case,
|
|
1858
|
+
// signature as a byte array) — the EXACT shape `verify_to_root` parses.
|
|
1859
|
+
export const certSign = (eng, { child, founder, verified, parentKey, parentId, epoch, secret }) =>
|
|
1860
|
+
JSON.parse(call(eng.ex, "query", { queryBytes: b64Json({ op: "certSign", child, founder, verified, parentKey, parentId, epoch, secret }) }, eng.STDERR)).cert;
|
|
1784
1861
|
export const cryptoWrapKey = (eng, { recipientPub, scopeKey }) => JSON.parse(call(eng.ex, "query", { queryBytes: b64Json({ op: "cryptoWrapKey", recipientPub, scopeKey }) }, eng.STDERR));
|
|
1785
1862
|
export const cryptoUnwrapKey = (eng, { secret, hpkeEpk, ct }) => JSON.parse(call(eng.ex, "query", { queryBytes: b64Json({ op: "cryptoUnwrapKey", secret, hpkeEpk, ct }) }, eng.STDERR)).scopeKey;
|
|
1786
1863
|
// THE READ-POSTURE PROBE (slice 5.1): the githolon's own verdict on whether the
|
|
@@ -1847,8 +1924,10 @@ export function offerIntent(eng, ws, bytes, opts) {
|
|
|
1847
1924
|
*/
|
|
1848
1925
|
export function offerAdmit(eng, ws, bytes, opts) {
|
|
1849
1926
|
const v = offerIntent(eng, ws, bytes, opts);
|
|
1927
|
+
// KEEP `born`: a SEALED `.births()` offer ran the G3 birth offer-effect in admit_core and surfaced the
|
|
1928
|
+
// child heads on the verdict; carry them through so the admit lane (admitIntentOffers) relays them.
|
|
1850
1929
|
return v.outcome === "admitted"
|
|
1851
|
-
? { ok: true, head: v.head }
|
|
1930
|
+
? { ok: true, head: v.head, ...(v.born ? { born: v.born } : {}) }
|
|
1852
1931
|
: { ok: false, error: v.verdict?.reason ?? v.error ?? "the offer was refused" };
|
|
1853
1932
|
}
|
|
1854
1933
|
|