githolon 0.100.6 → 0.101.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.
@@ -328,6 +328,13 @@ var init_custody_transport = __esm({
328
328
  }
329
329
  });
330
330
 
331
+ // ../adapter/managed-promotion.ts
332
+ var init_managed_promotion = __esm({
333
+ "../adapter/managed-promotion.ts"() {
334
+ "use strict";
335
+ }
336
+ });
337
+
331
338
  // ../adapter/engine.ts
332
339
  import { WASI, File, Directory, OpenFile, ConsoleStdout, PreopenDirectory } from "@bjorn3/browser_wasi_shim";
333
340
  function b64Bytes(bytes) {
@@ -598,7 +605,7 @@ function summaryOfCapture(ctx, fromOid, toOid) {
598
605
  rowsByHome: Object.fromEntries([...ctx.rowsByHome.entries()].sort((a, b) => a[0] < b[0] ? -1 : 1))
599
606
  };
600
607
  }
601
- async function admitIntentOffers(eng, ws, ledger, offers, { receiptFence = null, shardRouting = null, clientBase = null, defer = false } = {}) {
608
+ async function admitIntentOffers(eng, ws, ledger, offers, { receiptFence = null, shardRouting = null, clientBase = null } = {}) {
602
609
  const main = await mainIntentIds(eng, ws);
603
610
  const sessions = /* @__PURE__ */ new Map();
604
611
  const deadLetters = [];
@@ -665,8 +672,8 @@ async function admitIntentOffers(eng, ws, ledger, offers, { receiptFence = null,
665
672
  }
666
673
  const cap = summaryCtx ? beginSummaryCapture(eng, ws, summaryCtx, blob) : null;
667
674
  const _tOffer = Date.now();
668
- const res = offerAdmit(eng, ws, blob, { defer: !summaryCtx });
669
- log("offer-admit-ms", { ws, ms: Date.now() - _tOffer, deferred: !summaryCtx, ok: res.ok });
675
+ const res = offerAdmit(eng, ws, blob, { defer: false });
676
+ log("offer-admit-ms", { ws, ms: Date.now() - _tOffer, deferred: false, ok: res.ok });
670
677
  if (res.ok) {
671
678
  if (intentId) main.ids.add(intentId);
672
679
  main.oids.add(res.head);
@@ -689,7 +696,6 @@ async function admitIntentOffers(eng, ws, ledger, offers, { receiptFence = null,
689
696
  }
690
697
  timings.sessions = sessions.size;
691
698
  timings.intents = admittedTotal;
692
- if (admittedTotal && !summaryCtx) (eng.pendingProjection ??= /* @__PURE__ */ new Set()).add(ws);
693
699
  if (deadLetters.length) {
694
700
  try {
695
701
  await materializeRefused(eng, ws, ledger, deadLetters);
@@ -697,8 +703,7 @@ async function admitIntentOffers(eng, ws, ledger, offers, { receiptFence = null,
697
703
  log("refused-materialize-failed", { ws, error: String(e).slice(0, 200) });
698
704
  }
699
705
  }
700
- const deferDurability = defer && !summaryCtx;
701
- if (admittedTotal && !deferDurability) {
706
+ if (admittedTotal) {
702
707
  const sealDone = span("seal offered intents", "cseal", 1, { admitted: admittedTotal });
703
708
  await commitAndPush(eng, ws, ledger);
704
709
  sealDone();
@@ -716,7 +721,7 @@ async function admitIntentOffers(eng, ws, ledger, offers, { receiptFence = null,
716
721
  }
717
722
  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" });
718
723
  const bornPacked = born.length ? packBornChildren(eng, born) : born;
719
- return { sessions: [...sessions.values()].map((s) => ({ ...s, ...s.skipped.length ? {} : { skipped: void 0 } })), main: head, deadLetters, timings, summary: summary ?? null, born: bornPacked, birthOutcomes, ...resultPackB64 ? { resultPackB64, resultBase: clientBase } : {}, ...deferDurability && admittedTotal && head ? { deferred: true, head } : {} };
724
+ return { sessions: [...sessions.values()].map((s) => ({ ...s, ...s.skipped.length ? {} : { skipped: void 0 } })), main: head, deadLetters, timings, summary: summary ?? null, born: bornPacked, birthOutcomes, ...resultPackB64 ? { resultPackB64, resultBase: clientBase } : {} };
720
725
  }
721
726
  async function authorOn(eng, ws, ledger, domain, directiveId, payload, lawHash, opts = {}) {
722
727
  await mountWorkspace(eng, ws, ledger);
@@ -780,6 +785,9 @@ function evolveDryRun(eng, ws, usda, domainHash, dispositions = null) {
780
785
  function author(eng, ws, domain, directiveId, payload, controllerHash, opts = {}) {
781
786
  const seq = eng.seq++;
782
787
  const capPorts = { clock: { physical: Date.now(), logical: 0, replica: eng.replica }, rng: osEntropyBuffer(opts.rngDraws ?? 64) };
788
+ if (opts.__nomosConflictSnapshots !== void 0 && opts.__nomosConflictSnapshots.length > 0) {
789
+ capPorts.conflict_snapshots = opts.__nomosConflictSnapshots;
790
+ }
783
791
  if (opts.validFromEpoch !== void 0) capPorts.valid_from_epoch = opts.validFromEpoch;
784
792
  if (opts.principalVerified !== void 0) {
785
793
  capPorts.principal = opts.actor ?? "";
@@ -1376,26 +1384,89 @@ async function boot(eng, ws, ledger) {
1376
1384
  );
1377
1385
  }
1378
1386
  async function deploy(eng, ws, ledger, usda, domainHash, dispositions, opts = {}) {
1379
- const result = author(eng, ws, "nomos", "installDomain", installPayload(domainHash, usda, eng.installedBy, dispositions), eng.hashes.nomos, { actor: opts.actor ?? "", ...opts.authToken ? { authToken: opts.authToken } : {} });
1380
- if (result.ok === false) {
1387
+ const existing = qById(eng, ws, `domain-installation:${domainHash}`);
1388
+ if (existing.length > 0) {
1389
+ const phase = String(existing[0]?.data?.["status.phase"] ?? "");
1390
+ return {
1391
+ head: kgit.resolveRef(eng, gitdirOf(ws), BRANCH),
1392
+ installation: existing,
1393
+ staged: phase === "Pending",
1394
+ alreadyInstalled: true
1395
+ };
1396
+ }
1397
+ const before = currentLaw(eng, ws);
1398
+ const tenantHashes = [...new Set(Object.values(before).filter(
1399
+ (hash) => typeof hash === "string" && hash !== eng.hashes.bootstrap && hash !== eng.hashes.nomos
1400
+ ))];
1401
+ const upgrade = tenantHashes.length > 0;
1402
+ let supersedes = opts.supersedes?.trim() || void 0;
1403
+ if (supersedes !== void 0 && !tenantHashes.includes(supersedes)) {
1381
1404
  throw new Error(
1382
- `deploy-refused: installing ${domainHash.slice(0, 12)}\u2026 was REFUSED by the one gate (custody unchanged): ${result.error ?? "unknown refusal"}`
1405
+ `deploy-predecessor-changed: the client named ${supersedes.slice(0, 12)}\u2026 as the current model, but this workspace no longer serves it. Refresh and deploy again; nothing was committed.`
1383
1406
  );
1384
1407
  }
1385
- const installation = qById(eng, ws, `domain-installation:${domainHash}`);
1386
- const keys = installation[0]?.data?.domainKeys ?? installation[0]?.domainKeys ?? [];
1387
- if (keys.length > 0) {
1388
- const law = installedLaw(eng, ws);
1389
- const currentLaw2 = law?.currentLaw ?? {};
1390
- const stale = keys.filter((k) => currentLaw2[k] !== void 0 && currentLaw2[k] !== domainHash);
1391
- if (stale.length > 0) {
1408
+ if (upgrade && supersedes === void 0) {
1409
+ if (tenantHashes.length === 1) supersedes = tenantHashes[0];
1410
+ else {
1392
1411
  throw new Error(
1393
- `deploy-did-not-advance: the install of ${domainHash.slice(0, 12)}\u2026 ADMITTED but the workspace's current law still serves ${stale.map((k) => `'${k}' from ${String(currentLaw2[k]).slice(0, 12)}\u2026`).join(", ")} \u2014 refusing (custody unchanged) instead of a silent no-op. This usually means the existing installation's era/lineage prevents supersession: run \`githolon deploy --dry-run=evolve\` for the gate's verdict, supply #58 dispositions for a true removal/retype, or re-forge the workspace onto the current lineage.`
1412
+ `deploy-predecessor-ambiguous: this workspace currently serves ${tenantHashes.length} business-model packages. Nomos will not guess which one this candidate follows; use the generated deploy client, which binds the candidate to the current model before staging. Nothing was committed.`
1394
1413
  );
1395
1414
  }
1396
1415
  }
1397
- await commitAndPush(eng, ws, ledger);
1398
- return { head: result.head, installation };
1416
+ if (upgrade && dispositions && Object.keys(dispositions).length > 0) {
1417
+ throw new Error(
1418
+ "deploy-manual-evolution-refused: successor deployment no longer accepts caller-chosen schema dispositions. Schema evolution belongs to the candidate model's adoption proof; nothing was committed."
1419
+ );
1420
+ }
1421
+ const directiveId = upgrade ? "stageDomain" : "installDomain";
1422
+ const payload = upgrade ? stagePayload(domainHash, usda, eng.installedBy, supersedes) : installPayload(domainHash, usda, eng.installedBy, dispositions);
1423
+ const result = author(eng, ws, "nomos", directiveId, payload, eng.hashes.nomos, {
1424
+ actor: opts.actor ?? "",
1425
+ ...opts.authToken ? { authToken: opts.authToken } : {}
1426
+ });
1427
+ if (result.ok === false) {
1428
+ unmount(eng, ws);
1429
+ throw new Error(
1430
+ `deploy-refused: ${upgrade ? "staging" : "installing"} ${domainHash.slice(0, 12)}\u2026 was REFUSED by the one gate (custody unchanged): ${result.error ?? "unknown refusal"}`
1431
+ );
1432
+ }
1433
+ try {
1434
+ const installation = qById(eng, ws, `domain-installation:${domainHash}`);
1435
+ if (upgrade) {
1436
+ const phase = String(installation[0]?.data?.["status.phase"] ?? "");
1437
+ if (phase !== "Pending") {
1438
+ throw new Error(
1439
+ `deploy-did-not-stage: candidate ${domainHash.slice(0, 12)}\u2026 admitted but its lifecycle phase is '${phase || "missing"}', not Pending. Custody was not pushed.`
1440
+ );
1441
+ }
1442
+ const after = currentLaw(eng, ws);
1443
+ const moved = Object.entries(before).filter(([key, hash]) => after[key] !== hash);
1444
+ if (moved.length > 0 || Object.values(after).includes(domainHash)) {
1445
+ throw new Error(
1446
+ `deploy-activated-candidate: staging ${domainHash.slice(0, 12)}\u2026 changed served law (${moved.map(([key]) => key).join(", ") || "candidate became current"}). Nomos refuses to persist an upgrade that bypassed model.adopt().`
1447
+ );
1448
+ }
1449
+ await commitAndPush(eng, ws, ledger);
1450
+ return { head: result.head, installation, staged: true, supersedes };
1451
+ }
1452
+ const law = installedLaw(eng, ws);
1453
+ const installed = (law?.domains ?? []).find((row) => row?.domainHash === domainHash);
1454
+ const keys = installed?.domainKeys ?? installation[0]?.data?.domainKeys ?? installation[0]?.domainKeys ?? [];
1455
+ if (keys.length > 0) {
1456
+ const currentLaw2 = law?.currentLaw ?? {};
1457
+ const stale = keys.filter((k) => currentLaw2[k] !== domainHash);
1458
+ if (stale.length > 0) {
1459
+ throw new Error(
1460
+ `deploy-did-not-advance: the install of ${domainHash.slice(0, 12)}\u2026 ADMITTED but the workspace's current law still serves ${stale.map((k) => `'${k}' from ${String(currentLaw2[k]).slice(0, 12)}\u2026`).join(", ")} \u2014 refusing (custody unchanged) instead of a silent no-op. This usually means the existing installation's era/lineage prevents supersession: run \`githolon deploy --dry-run=evolve\` for the gate's verdict, supply #58 dispositions for a true removal/retype, or re-forge the workspace onto the current lineage.`
1461
+ );
1462
+ }
1463
+ }
1464
+ await commitAndPush(eng, ws, ledger);
1465
+ return { head: result.head, installation, staged: false };
1466
+ } catch (error) {
1467
+ unmount(eng, ws);
1468
+ throw error;
1469
+ }
1399
1470
  }
1400
1471
  function snapshot(eng, ws) {
1401
1472
  const wsDir = dirOf(eng.preopen.dir.contents.get("ws")).contents.get(ws);
@@ -1428,13 +1499,14 @@ async function ledgerStats(eng, ws, ledger = null) {
1428
1499
  if (mounted) mounted.ledgerStats = out;
1429
1500
  return out;
1430
1501
  }
1431
- var enc3, dec3, BRANCH, RESULT_PACK_INLINE_MAX, dirOf, repoArgOf, gitdirOf, unpack, log, repoArgOfGitdir, bytesFromB64, kgit, installPayload, routeTagHexOfHomeKey, SUMMARY_SEP, summaryKey, splitSummaryKey, NOMOS_SHARD_ROWS_READ, groupOf, tallyOf, isExtremumRead, extremumMonotone, pushVia, fullRef, applyPackInto, custodyLsRefs, qById, query, authorKeygen, attestedRead, certSign, readPosture, count, sum, pendingConflicts, spatialBboxParams, spatialWithin, extremum, nomosActive, refusedRefName, GENESIS_WARRANT_ID, isWarranted;
1502
+ var enc3, dec3, BRANCH, RESULT_PACK_INLINE_MAX, dirOf, repoArgOf, gitdirOf, unpack, log, repoArgOfGitdir, bytesFromB64, kgit, installPayload, stagePayload, routeTagHexOfHomeKey, SUMMARY_SEP, summaryKey, splitSummaryKey, NOMOS_SHARD_ROWS_READ, groupOf, tallyOf, isExtremumRead, extremumMonotone, pushVia, fullRef, applyPackInto, custodyLsRefs, qById, query, authorKeygen, attestedRead, certSign, readPosture, count, sum, pendingConflicts, pendingConflictSummary, spatialBboxParams, spatialWithin, extremum, nomosActive, refusedRefName, GENESIS_WARRANT_ID, isWarranted;
1432
1503
  var init_engine = __esm({
1433
1504
  "../adapter/engine.ts"() {
1434
1505
  "use strict";
1435
1506
  init_git_fs();
1436
1507
  init_tree();
1437
1508
  init_custody_transport();
1509
+ init_managed_promotion();
1438
1510
  enc3 = new TextEncoder();
1439
1511
  dec3 = new TextDecoder();
1440
1512
  BRANCH = "main";
@@ -1480,6 +1552,14 @@ var init_engine = __esm({
1480
1552
  }, eng.STDERR)).oid
1481
1553
  };
1482
1554
  installPayload = (hash, usda, installedBy, dispositions) => ({ domainHash: hash, packageUsda: usda, installedBy, dependencies: [], finalizers: [], ...dispositions ? { dispositions } : {} });
1555
+ stagePayload = (hash, usda, installedBy, supersedes) => ({
1556
+ domainHash: hash,
1557
+ packageUsda: usda,
1558
+ installedBy,
1559
+ dependencies: [],
1560
+ ...supersedes ? { supersedes } : {},
1561
+ finalizers: []
1562
+ });
1483
1563
  routeTagHexOfHomeKey = async (homeKey) => (await sha256hex(`nomos-route:${homeKey}`)).slice(0, 12);
1484
1564
  SUMMARY_SEP = "";
1485
1565
  summaryKey = (readId, group) => `${readId}${SUMMARY_SEP}${group}`;
@@ -1547,7 +1627,8 @@ var init_engine = __esm({
1547
1627
  readPosture = (eng, ws, principal = "", authToken = "", nowUnix = 0) => JSON.parse(call(eng.ex, "query", { repoArg: repoArgOf(ws), workspace: ws, queryBytes: b64Json({ op: "readPosture", authToken, nowUnix }), principal, branch: BRANCH }, eng.STDERR));
1548
1628
  count = (eng, ws, countId, groupKey, principal = "") => JSON.parse(call(eng.ex, "query", { repoArg: repoArgOf(ws), workspace: ws, queryBytes: b64Json({ op: "count", countId, groupKey }), principal, branch: BRANCH }, eng.STDERR));
1549
1629
  sum = (eng, ws, sumId, groupKey, principal = "") => JSON.parse(call(eng.ex, "query", { repoArg: repoArgOf(ws), workspace: ws, queryBytes: b64Json({ op: "sum", sumId, groupKey }), principal, branch: BRANCH }, eng.STDERR));
1550
- pendingConflicts = (eng, ws, principal = "") => JSON.parse(call(eng.ex, "query", { repoArg: repoArgOf(ws), workspace: ws, queryBytes: b64Json({ op: "pendingConflicts" }), principal, branch: BRANCH }, eng.STDERR));
1630
+ pendingConflicts = (eng, ws, principal = "", aggregateType = "") => JSON.parse(call(eng.ex, "query", { repoArg: repoArgOf(ws), workspace: ws, queryBytes: b64Json({ op: "pendingConflicts", aggregateType }), principal, branch: BRANCH }, eng.STDERR));
1631
+ pendingConflictSummary = (eng, ws, principal = "") => JSON.parse(call(eng.ex, "query", { repoArg: repoArgOf(ws), workspace: ws, queryBytes: b64Json({ op: "pendingConflictSummary" }), principal, branch: BRANCH }, eng.STDERR));
1551
1632
  spatialBboxParams = (bbox) => {
1552
1633
  const minX = bbox.minX ?? bbox.minLng, minY = bbox.minY ?? bbox.minLat, maxX = bbox.maxX ?? bbox.maxLng, maxY = bbox.maxY ?? bbox.maxLat;
1553
1634
  return { minX, minY, maxX, maxY, minLng: minX, minLat: minY, maxLng: maxX, maxLat: maxY };
@@ -1579,6 +1660,7 @@ var init_types = __esm({
1579
1660
  var bootstrap_exports = {};
1580
1661
  __export(bootstrap_exports, {
1581
1662
  bootstrapPlatform: () => bootstrapPlatform,
1663
+ completeDevAuthProviderPayload: () => completeDevAuthProviderPayload,
1582
1664
  homeDomainOf: () => homeDomainOf,
1583
1665
  isTestMint: () => isTestMint
1584
1666
  });
@@ -1592,10 +1674,42 @@ function isTestMint(eng) {
1592
1674
  return !/poisoned|unknown|adapter-visible API/.test(errMsg(e));
1593
1675
  }
1594
1676
  }
1677
+ function completeDevAuthProviderPayload(deployBody, homeDomain, initial, nowMillis = Date.now(), operator = "user:dev-operator") {
1678
+ const payload = { ...initial };
1679
+ const iface = deployBody?.interface ?? {};
1680
+ const legacy = iface.domains?.[homeDomain]?.directives?.setAuthProvider?.fields ?? iface[homeDomain]?.directives?.setAuthProvider?.fields ?? {};
1681
+ const openapi = deployBody?.openapi;
1682
+ const frameworkPaths = openapi?.["x-nomos-framework-routes"]?.paths ?? {};
1683
+ const setAuthOperation = Object.values(frameworkPaths).map((pathItem) => pathItem.post).filter((operation) => operation?.["x-nomos"]?.directiveId === "setAuthProvider").sort((a, b) => Number(b?.["x-nomos"]?.domain === homeDomain) - Number(a?.["x-nomos"]?.domain === homeDomain))[0] ?? frameworkPaths["/setAuthProvider"]?.post;
1684
+ const schema = setAuthOperation?.requestBody?.content?.["application/json"]?.schema;
1685
+ const required = new Set(schema?.required ?? []);
1686
+ const fields = { ...legacy };
1687
+ for (const [name, spec] of Object.entries(schema?.properties ?? {})) {
1688
+ fields[name] = {
1689
+ kind: spec.type === "integer" ? "int" : spec.type,
1690
+ optional: !required.has(name)
1691
+ };
1692
+ }
1693
+ for (const [name, spec] of Object.entries(fields)) {
1694
+ if (spec.optional === true || payload[name] !== void 0) continue;
1695
+ if (spec.kind === "int" && /At$/.test(name)) payload[name] = nowMillis;
1696
+ else if (spec.kind === "string" && /At$/.test(name)) payload[name] = new Date(nowMillis).toISOString();
1697
+ else if (spec.kind === "string" && /By$/.test(name)) payload[name] = operator;
1698
+ else if (spec.kind === "string" && /url$/i.test(name)) payload[name] = `${payload.issuer}/jwks.json`;
1699
+ else if (spec.kind === "string") payload[name] = "dev";
1700
+ else log2(`dev test IdP: required setAuthProvider field '${name}' (kind ${spec.kind}) is not synthesizable \u2014 the author below may refuse typed`);
1701
+ }
1702
+ return payload;
1703
+ }
1595
1704
  function homeDomainOf(opts) {
1596
1705
  if (!opts || !opts.deploy) return null;
1597
1706
  try {
1598
1707
  const body = JSON.parse(readFileSync(opts.deploy, "utf8"));
1708
+ const frameworkPaths = body.openapi?.["x-nomos-framework-routes"]?.paths ?? {};
1709
+ for (const pathItem of Object.values(frameworkPaths)) {
1710
+ const route = pathItem.post?.["x-nomos"];
1711
+ if (route?.directiveId === "birthHome" && typeof route.domain === "string") return route.domain;
1712
+ }
1599
1713
  const domains = body.summary && body.summary.domains || [];
1600
1714
  const hit = domains.find((d) => Array.isArray(d.directives) && d.directives.includes("seedBirthAttestation"));
1601
1715
  return hit ? hit.domain : null;
@@ -1655,6 +1769,19 @@ async function bootstrapPlatform(dev, opts) {
1655
1769
  setTestKRoot(eng, kRoot.public);
1656
1770
  log2(`K_root ceremony: pinned LOCAL test K_root ${kRoot.public.slice(0, 16)}\u2026`);
1657
1771
  const sP = authorKeygen(eng);
1772
+ const { generateKeyPairSync, sign: nodeSign } = await import("node:crypto");
1773
+ const { privateKey: idpPrivateKey, publicKey: idpPublicKey } = generateKeyPairSync("ec", { namedCurve: "P-256" });
1774
+ const idpJwk = idpPublicKey.export({ format: "jwk" });
1775
+ const idpIssuer = `https://dev-idp.local/${platform}`;
1776
+ const idpAudience = `${platform}-app`;
1777
+ const idpJwks = JSON.stringify({ keys: [{ kty: "EC", crv: "P-256", kid: "dev-idp", alg: "ES256", use: "sig", x: idpJwk.x, y: idpJwk.y }] });
1778
+ const b64url = (b) => Buffer.from(b).toString("base64url");
1779
+ const mintDevToken = (claims) => {
1780
+ const header = b64url(JSON.stringify({ alg: "ES256", typ: "JWT", kid: "dev-idp" }));
1781
+ const payload = b64url(JSON.stringify({ iss: idpIssuer, aud: idpAudience, nbf: 0, exp: 4102444800, ...claims }));
1782
+ const si = `${header}.${payload}`;
1783
+ return `${si}.${b64url(nodeSign("sha256", Buffer.from(si), { key: idpPrivateKey, dsaEncoding: "ieee-p1363" }))}`;
1784
+ };
1658
1785
  const platformCert = certSign(eng, {
1659
1786
  child: platform,
1660
1787
  founder: OPERATOR,
@@ -1663,6 +1790,9 @@ async function bootstrapPlatform(dev, opts) {
1663
1790
  // P_P — the onboarding signer the platform vouches for
1664
1791
  parentId: "root",
1665
1792
  epoch: 0,
1793
+ authProviderIssuer: idpIssuer,
1794
+ authProviderJwks: idpJwks,
1795
+ authProviderAudience: idpAudience,
1666
1796
  secret: kRoot.secret
1667
1797
  // signed by S_root
1668
1798
  });
@@ -1681,38 +1811,14 @@ async function bootstrapPlatform(dev, opts) {
1681
1811
  let devIdP;
1682
1812
  let pendingIdP;
1683
1813
  {
1684
- const { generateKeyPairSync, sign: nodeSign } = await import("node:crypto");
1685
- const { privateKey, publicKey } = generateKeyPairSync("ec", { namedCurve: "P-256" });
1686
- const jwk = publicKey.export({ format: "jwk" });
1687
- const ISS = `https://dev-idp.local/${platform}`;
1688
- const AUD = `${platform}-app`;
1689
- const JWKS = JSON.stringify({ keys: [{ kty: "EC", crv: "P-256", kid: "dev-idp", alg: "ES256", use: "sig", x: jwk.x, y: jwk.y }] });
1690
- const b64url = (b) => Buffer.from(b).toString("base64url");
1691
- const mint = (claims) => {
1692
- const header = b64url(JSON.stringify({ alg: "ES256", typ: "JWT", kid: "dev-idp" }));
1693
- const payload = b64url(JSON.stringify({ iss: ISS, aud: AUD, nbf: 0, exp: 4102444800, ...claims }));
1694
- const si = `${header}.${payload}`;
1695
- return `${si}.${b64url(nodeSign("sha256", Buffer.from(si), { key: privateKey, dsaEncoding: "ieee-p1363" }))}`;
1696
- };
1697
- const apPayload = { issuer: ISS, keys: JWKS, audience: AUD, principalClaim: "sub", deviceBindingClaim: "nonce" };
1814
+ let apPayload = { issuer: idpIssuer, keys: idpJwks, audience: idpAudience, principalClaim: "sub", deviceBindingClaim: "nonce" };
1698
1815
  try {
1699
1816
  const deployBody = opts.deploy ? JSON.parse(readFileSync(opts.deploy, "utf8")) : null;
1700
- const iface = deployBody?.interface ?? {};
1701
- const domIface = iface.domains?.[homeDomain] ?? iface[homeDomain];
1702
- const fields = domIface?.directives?.["setAuthProvider"]?.fields ?? {};
1703
- for (const [name, spec] of Object.entries(fields)) {
1704
- if (spec?.optional === true || apPayload[name] !== void 0) continue;
1705
- if (spec?.kind === "int" && /At$/.test(name)) apPayload[name] = Date.now();
1706
- else if (spec?.kind === "string" && /At$/.test(name)) apPayload[name] = (/* @__PURE__ */ new Date()).toISOString();
1707
- else if (spec?.kind === "string" && /By$/.test(name)) apPayload[name] = OPERATOR;
1708
- else if (spec?.kind === "string" && /url$/i.test(name)) apPayload[name] = `${ISS}/jwks.json`;
1709
- else if (spec?.kind === "string") apPayload[name] = "dev";
1710
- else log2(`dev test IdP: required setAuthProvider field '${name}' (kind ${spec?.kind}) is not synthesizable \u2014 the author below may refuse typed`);
1711
- }
1817
+ apPayload = completeDevAuthProviderPayload(deployBody, homeDomain, apPayload, Date.now(), OPERATOR);
1712
1818
  } catch (e) {
1713
1819
  log2(`dev test IdP: BYO-shape fill failed (${errMsg(e).slice(0, 200)}) \u2014 the canonical payload stands`);
1714
1820
  }
1715
- pendingIdP = { ISS, AUD, JWKS, mint, apPayload };
1821
+ pendingIdP = { ISS: idpIssuer, AUD: idpAudience, JWKS: idpJwks, mint: mintDevToken, apPayload };
1716
1822
  }
1717
1823
  const sOp = authorKeygen(eng);
1718
1824
  const opKeyHash = createHash("sha256").update(Buffer.from(sOp.public, "base64")).digest("hex");
@@ -1890,6 +1996,12 @@ function resolveGatewayOperation(spec, opName, method) {
1890
1996
  return { op: null, ambiguous: null };
1891
1997
  }
1892
1998
 
1999
+ // ../cloud/cloudflare-shell/src/kernel-registry.generated.ts
2000
+ var DEPLOYED_KERNELS = [
2001
+ { prefix: "cf01b3ae", hash: "cf01b3ae327618b26da3af8eb6abe5e16a7f050e8a9d9b6ca92e2a1d78dd280b", version: "kernel-cf01b3ae", note: "production (this candidate)", features: ["compoundKeys", "capturedReads", "invariantGate", "surfacedMerge", "fieldProvenance", "nullSemantics", "attestedReads", "conflictSnapshots", "ownedAudience"] },
2002
+ { prefix: "4f8ffb62", hash: "4f8ffb623c3717d973b1ced653e23f7a8f63fe73b83aa5a0f83f4dd8c46bd81f", version: "kernel-4f8ffb62", note: "test-mint (this candidate) \u2014 feature-equivalent to production", features: ["compoundKeys", "capturedReads", "invariantGate", "surfacedMerge", "fieldProvenance", "nullSemantics", "attestedReads", "conflictSnapshots", "ownedAudience"] }
2003
+ ];
2004
+
1893
2005
  // ../cloud/cloudflare-shell/src/staged-intents.ts
1894
2006
  var STAGE_THRESHOLD_CHARS = 4 * 1024 * 1024;
1895
2007
  var MAX_INLINE_INTENT_CHARS = 8 * 1024 * 1024;
@@ -2108,7 +2220,13 @@ function firstExisting(...paths) {
2108
2220
  }
2109
2221
  var TEST_MINT_MARKER = Buffer.from("set_test_k_root");
2110
2222
  var isTestMintBytes = (bytes) => bytes.includes(TEST_MINT_MARKER);
2111
- var KERNEL_CAPABILITY_REGISTRY = [
2223
+ var HISTORICAL_KERNEL_CAPABILITY_REGISTRY = [
2224
+ {
2225
+ prefix: "f50d0cc5",
2226
+ version: "kernel-f50d0cc5",
2227
+ note: "current local production build",
2228
+ features: ["compoundKeys", "capturedReads", "invariantGate", "surfacedMerge", "fieldProvenance", "nullSemantics", "attestedReads"]
2229
+ },
2112
2230
  {
2113
2231
  prefix: "846c6bf8",
2114
2232
  version: "kernel-846c6bf8",
@@ -2128,6 +2246,10 @@ var KERNEL_CAPABILITY_REGISTRY = [
2128
2246
  features: ["capturedReads", "invariantGate", "surfacedMerge", "fieldProvenance", "nullSemantics", "attestedReads"]
2129
2247
  }
2130
2248
  ];
2249
+ var KERNEL_CAPABILITY_REGISTRY = [
2250
+ ...DEPLOYED_KERNELS,
2251
+ ...HISTORICAL_KERNEL_CAPABILITY_REGISTRY
2252
+ ];
2131
2253
  function capabilitiesForKernelHash(hash) {
2132
2254
  const h = String(hash || "").toLowerCase();
2133
2255
  const hit = KERNEL_CAPABILITY_REGISTRY.find((e) => h.startsWith(e.prefix) || e.prefix.startsWith(h.slice(0, 8)));
@@ -2367,7 +2489,10 @@ async function startDevCloud(opts = {}) {
2367
2489
  dataDir,
2368
2490
  wasmPath,
2369
2491
  workspaces: custody.list(),
2370
- ...devSelf?.platformReady !== void 0 ? { platformReady: devSelf.platformReady } : {}
2492
+ ...devSelf?.platformReady !== void 0 ? { platformReady: devSelf.platformReady } : {},
2493
+ // DEV/HARNESS ONLY: every peer in this ephemeral trust universe must pin the same K_root before
2494
+ // replaying or birthing descendants. Production bakes the one real anchor into the kernel.
2495
+ ...devSelf?.testKRoot?.public ? { testKRootPublic: devSelf.testKRoot.public } : {}
2371
2496
  });
2372
2497
  }
2373
2498
  if (url.pathname === "/dev/mint-token" && req.method === "POST") {
@@ -2500,10 +2625,19 @@ async function startDevCloud(opts = {}) {
2500
2625
  const authToken = authTokenOf(req);
2501
2626
  try {
2502
2627
  const out = await deploy(eng, ws, ledger, usda, domainHash, dispositions, { actor, ...authToken ? { authToken } : {} });
2503
- sendJson(res, { ok: true, ws, domainHash, head: out.head, installation: out.installation }, 201);
2628
+ sendJson(res, {
2629
+ ok: true,
2630
+ ws,
2631
+ domainHash,
2632
+ head: out.head,
2633
+ installation: out.installation,
2634
+ staged: out.staged === true,
2635
+ ...out.supersedes ? { supersedes: out.supersedes } : {},
2636
+ ...out.alreadyInstalled ? { alreadyInstalled: true } : {}
2637
+ }, 201);
2504
2638
  } catch (e) {
2505
2639
  const msg = errMsg(e);
2506
- const status = /deploy-did-not-advance/.test(msg) ? 409 : 422;
2640
+ const status = /deploy-did-not-advance|deploy-did-not-stage|deploy-predecessor|deploy-activated-candidate/.test(msg) ? 409 : 422;
2507
2641
  sendJson(res, { ok: false, refused: true, error: msg.slice(0, 600) }, status);
2508
2642
  }
2509
2643
  });
@@ -2535,6 +2669,15 @@ async function startDevCloud(opts = {}) {
2535
2669
  }
2536
2670
  if (sub[0] === "intent-offers" && req.method === "POST") {
2537
2671
  return await serialize(async () => {
2672
+ if (!custody.get(`holon-${ws}`)) {
2673
+ sendJson(res, {
2674
+ ok: false,
2675
+ retryable: true,
2676
+ ws,
2677
+ error: `custody-provisioning: workspace '${ws}' is awaiting its parent birth; Nomos will retry automatically`
2678
+ }, 409);
2679
+ return;
2680
+ }
2538
2681
  const ledger = ledgerFor(ws);
2539
2682
  await mountWorkspace(eng, ws, ledger);
2540
2683
  const body = JSON.parse((await readBody(req)).toString("utf8") || "{}");
@@ -2721,7 +2864,8 @@ async function startDevCloud(opts = {}) {
2721
2864
  if (x.kind === "sum") return sendJson(res, { ok: true, ws, ...sum(eng, ws, x.sumId, group, principal) });
2722
2865
  if (x.kind === "extremum") return sendJson(res, { ok: true, ws, ...extremum(eng, ws, x.extremumId, x.extremumKind || url.searchParams.get("kind") || "", group, principal) });
2723
2866
  if (x.kind === "spatial") return sendJson(res, { ok: true, ws, ...spatialWithin(eng, ws, x.spatialId, url.searchParams.get("bbox") || {}, principal) });
2724
- if (x.kind === "pendingConflicts") return sendJson(res, { ok: true, ws, rows: pendingConflicts(eng, ws, principal) });
2867
+ if (x.kind === "pendingConflicts") return sendJson(res, { ok: true, ws, rows: pendingConflicts(eng, ws, principal, url.searchParams.get("aggregateType") || "") });
2868
+ if (x.kind === "pendingConflictSummary") return sendJson(res, { ok: true, ws, ...pendingConflictSummary(eng, ws, principal) });
2725
2869
  } catch (e) {
2726
2870
  return sendJson(res, { ok: false, error: errMsg(e).slice(0, 600) }, 403);
2727
2871
  }