githolon 0.100.5 → 0.101.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/dist/cli.mjs +597 -85
- package/dist/dev-server.mjs +184 -47
- package/dist/framework/domain_nomos.package.usda +2 -2
- package/package.json +3 -3
package/dist/cli.mjs
CHANGED
|
@@ -329,6 +329,131 @@ var init_custody_transport = __esm({
|
|
|
329
329
|
}
|
|
330
330
|
});
|
|
331
331
|
|
|
332
|
+
// vendor/engine/managed-promotion.ts
|
|
333
|
+
function prepareManagedPromotion(report, candidateHash, domain, opts = {}) {
|
|
334
|
+
if (!report.sourceVerified || !report.complete || !report.evolve?.ok) {
|
|
335
|
+
const reason = !report.sourceVerified ? "the source ledger did not verify" : !report.complete ? "some historical premises could not be re-derived" : "the candidate fails deterministic schema evolution";
|
|
336
|
+
return { ok: false, stage: "preflight", report, error: `promotion refused: ${reason}` };
|
|
337
|
+
}
|
|
338
|
+
const acceptanceReason = opts.acceptanceReason?.trim();
|
|
339
|
+
if (!report.promotable && !acceptanceReason) {
|
|
340
|
+
return {
|
|
341
|
+
ok: false,
|
|
342
|
+
stage: "acceptance",
|
|
343
|
+
report,
|
|
344
|
+
error: "exact history changes under the candidate; provide an acceptanceReason to make that business decision accountable"
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
if (!report.atStateRoot || !report.historyHash || !report.reportHash || !report.projection) {
|
|
348
|
+
return {
|
|
349
|
+
ok: false,
|
|
350
|
+
stage: "preflight",
|
|
351
|
+
report,
|
|
352
|
+
error: "the complete pre-flight report is missing its state, projection, or content proof"
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
const provedDomains = report.domains?.length ? report.domains : [report.domain];
|
|
356
|
+
if (!provedDomains.includes(domain)) {
|
|
357
|
+
return {
|
|
358
|
+
ok: false,
|
|
359
|
+
stage: "preflight",
|
|
360
|
+
report,
|
|
361
|
+
error: `the package-wide report does not cover the generated business area '${domain}'`
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
const reportEvidence = JSON.parse(JSON.stringify(report));
|
|
365
|
+
if (Array.isArray(reportEvidence.divergences)) {
|
|
366
|
+
for (const divergence of reportEvidence.divergences) {
|
|
367
|
+
if (divergence && typeof divergence === "object") {
|
|
368
|
+
delete divergence.atCommit;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
const preflight = {
|
|
373
|
+
candidateHash,
|
|
374
|
+
// A package may be reached through any one of its generated domain clients. The
|
|
375
|
+
// kernel chooses one canonical domain for the private receipt so the exact same
|
|
376
|
+
// package/history proof has one identity regardless of that entry point.
|
|
377
|
+
domain: report.domain,
|
|
378
|
+
atHash: report.atHash,
|
|
379
|
+
atStateRoot: report.atStateRoot,
|
|
380
|
+
historyHash: report.historyHash,
|
|
381
|
+
reportHash: report.reportHash,
|
|
382
|
+
reportJson: JSON.stringify(reportEvidence),
|
|
383
|
+
complete: true,
|
|
384
|
+
evolveOk: true,
|
|
385
|
+
rawPromotable: report.promotable,
|
|
386
|
+
projectionEqual: report.projection.equal,
|
|
387
|
+
replayedIntents: report.replayedIntents,
|
|
388
|
+
candidateIntents: report.candidateIntents,
|
|
389
|
+
divergenceCount: report.divergences.length,
|
|
390
|
+
baselineRoot: report.projection.baselineRoot,
|
|
391
|
+
candidateRoot: report.projection.candidateRoot,
|
|
392
|
+
...!report.promotable && acceptanceReason ? { acceptanceReason } : {}
|
|
393
|
+
};
|
|
394
|
+
return {
|
|
395
|
+
ok: true,
|
|
396
|
+
stage: "ready",
|
|
397
|
+
report,
|
|
398
|
+
receiptId: `${RELEASE_RECEIPT_PREFIX}${report.reportHash}`,
|
|
399
|
+
payload: {
|
|
400
|
+
domainHash: candidateHash,
|
|
401
|
+
...opts.replaces ? { replaces: opts.replaces } : {},
|
|
402
|
+
retireReplaced: opts.retireReplaced ?? false,
|
|
403
|
+
...opts.dispositions ? { dispositions: opts.dispositions } : {},
|
|
404
|
+
preflight
|
|
405
|
+
}
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
function prepareManagedRestoration(report, currentHash, priorHash, domain, opts = {}) {
|
|
409
|
+
if (!report.dispositions || typeof report.dispositions !== "object") {
|
|
410
|
+
return {
|
|
411
|
+
ok: false,
|
|
412
|
+
stage: "preflight",
|
|
413
|
+
report,
|
|
414
|
+
error: "restoration refused: the exact-history proof did not derive its predecessor dispositions"
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
const acceptanceReason = opts.acceptanceReason?.trim();
|
|
418
|
+
const prepared = prepareManagedPromotion(report, priorHash, domain, {
|
|
419
|
+
dispositions: report.dispositions,
|
|
420
|
+
...acceptanceReason ? { acceptanceReason } : {}
|
|
421
|
+
});
|
|
422
|
+
if (!prepared.ok) {
|
|
423
|
+
return {
|
|
424
|
+
...prepared,
|
|
425
|
+
stage: prepared.stage === "acceptance" ? "acceptance" : "preflight"
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
if (!acceptanceReason) {
|
|
429
|
+
return {
|
|
430
|
+
ok: false,
|
|
431
|
+
stage: "acceptance",
|
|
432
|
+
report,
|
|
433
|
+
error: "restoring previous law needs a business reason even when historical outcomes are unchanged"
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
return {
|
|
437
|
+
ok: true,
|
|
438
|
+
stage: "ready",
|
|
439
|
+
report,
|
|
440
|
+
receiptId: prepared.receiptId,
|
|
441
|
+
payload: {
|
|
442
|
+
candidateHash: currentHash,
|
|
443
|
+
priorHash,
|
|
444
|
+
dispositions: report.dispositions,
|
|
445
|
+
preflight: prepared.payload.preflight
|
|
446
|
+
}
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
var RELEASE_RECEIPT_PREFIX;
|
|
450
|
+
var init_managed_promotion = __esm({
|
|
451
|
+
"vendor/engine/managed-promotion.ts"() {
|
|
452
|
+
"use strict";
|
|
453
|
+
RELEASE_RECEIPT_PREFIX = "nomos-release-receipt:";
|
|
454
|
+
}
|
|
455
|
+
});
|
|
456
|
+
|
|
332
457
|
// vendor/engine/engine.ts
|
|
333
458
|
var engine_exports = {};
|
|
334
459
|
__export(engine_exports, {
|
|
@@ -360,6 +485,10 @@ __export(engine_exports, {
|
|
|
360
485
|
countTenantRowsByHome: () => countTenantRowsByHome,
|
|
361
486
|
createEngine: () => createEngine,
|
|
362
487
|
cryptoKeygen: () => cryptoKeygen,
|
|
488
|
+
cryptoOwnedDeviceRequest: () => cryptoOwnedDeviceRequest,
|
|
489
|
+
cryptoOwnedPrepareApproval: () => cryptoOwnedPrepareApproval,
|
|
490
|
+
cryptoOwnedPrepareRecovery: () => cryptoOwnedPrepareRecovery,
|
|
491
|
+
cryptoOwnedScopeKey: () => cryptoOwnedScopeKey,
|
|
363
492
|
cryptoSealField: () => cryptoSealField,
|
|
364
493
|
cryptoUnwrapKey: () => cryptoUnwrapKey,
|
|
365
494
|
cryptoWrapKey: () => cryptoWrapKey,
|
|
@@ -383,6 +512,8 @@ __export(engine_exports, {
|
|
|
383
512
|
flushDeferredProjections: () => flushDeferredProjections,
|
|
384
513
|
gitdirOf: () => gitdirOf,
|
|
385
514
|
globalAggregates: () => globalAggregates,
|
|
515
|
+
historyPreflight: () => historyPreflight,
|
|
516
|
+
historyRestorePreflight: () => historyRestorePreflight,
|
|
386
517
|
importCheckpoint: () => importCheckpoint,
|
|
387
518
|
ingestPackAsCustody: () => ingestPackAsCustody,
|
|
388
519
|
installPayload: () => installPayload,
|
|
@@ -405,9 +536,11 @@ __export(engine_exports, {
|
|
|
405
536
|
packBornChildren: () => packBornChildren,
|
|
406
537
|
packDelta: () => packDelta,
|
|
407
538
|
parseAttestedReadNeed: () => parseAttestedReadNeed,
|
|
539
|
+
pendingConflictSummary: () => pendingConflictSummary,
|
|
408
540
|
pendingConflicts: () => pendingConflicts,
|
|
409
541
|
placementDirectives: () => placementDirectives,
|
|
410
542
|
projectionStats: () => projectionStats,
|
|
543
|
+
promotePreflighted: () => promotePreflighted,
|
|
411
544
|
pushCheckpoint: () => pushCheckpoint,
|
|
412
545
|
pushShape: () => pushShape,
|
|
413
546
|
pushStagedCheckpoint: () => pushStagedCheckpoint,
|
|
@@ -425,6 +558,7 @@ __export(engine_exports, {
|
|
|
425
558
|
replicateIntents: () => replicateIntents,
|
|
426
559
|
repoArgOf: () => repoArgOf,
|
|
427
560
|
restoreCheckpointFromCustody: () => restoreCheckpointFromCustody,
|
|
561
|
+
restorePreviousPreflighted: () => restorePreviousPreflighted,
|
|
428
562
|
scopedReads: () => scopedReads,
|
|
429
563
|
sealAttestationBatches: () => sealAttestationBatches,
|
|
430
564
|
sealHomes: () => sealHomes,
|
|
@@ -435,6 +569,7 @@ __export(engine_exports, {
|
|
|
435
569
|
spatialBboxParams: () => spatialBboxParams,
|
|
436
570
|
spatialWithin: () => spatialWithin,
|
|
437
571
|
stageCheckpoint: () => stageCheckpoint,
|
|
572
|
+
stagePayload: () => stagePayload,
|
|
438
573
|
stats: () => stats,
|
|
439
574
|
sum: () => sum,
|
|
440
575
|
summaryCloseAgainstHeld: () => summaryCloseAgainstHeld,
|
|
@@ -1415,6 +1550,9 @@ function mintId(eng, typeTag) {
|
|
|
1415
1550
|
function author(eng, ws, domain, directiveId, payload, controllerHash, opts = {}) {
|
|
1416
1551
|
const seq = eng.seq++;
|
|
1417
1552
|
const capPorts = { clock: { physical: Date.now(), logical: 0, replica: eng.replica }, rng: osEntropyBuffer(opts.rngDraws ?? 64) };
|
|
1553
|
+
if (opts.__nomosConflictSnapshots !== void 0 && opts.__nomosConflictSnapshots.length > 0) {
|
|
1554
|
+
capPorts.conflict_snapshots = opts.__nomosConflictSnapshots;
|
|
1555
|
+
}
|
|
1418
1556
|
if (opts.validFromEpoch !== void 0) capPorts.valid_from_epoch = opts.validFromEpoch;
|
|
1419
1557
|
if (opts.principalVerified !== void 0) {
|
|
1420
1558
|
capPorts.principal = opts.actor ?? "";
|
|
@@ -2214,6 +2352,120 @@ async function verifyChain(eng, ws, ledger) {
|
|
|
2214
2352
|
function verifyChainLocal(eng, ws) {
|
|
2215
2353
|
return JSON.parse(call(eng.ex, "query", { repoArg: repoArgOf(ws), workspace: ws, queryBytes: b64Json({ op: "verifyChain" }), branch: BRANCH }, eng.STDERR));
|
|
2216
2354
|
}
|
|
2355
|
+
function historyPreflight(eng, ws, domain, candidateHash, atHash, dispositions) {
|
|
2356
|
+
return JSON.parse(call(eng.ex, "query", {
|
|
2357
|
+
repoArg: repoArgOf(ws),
|
|
2358
|
+
workspace: ws,
|
|
2359
|
+
branch: BRANCH,
|
|
2360
|
+
queryBytes: b64Json({
|
|
2361
|
+
op: "historyPreflight",
|
|
2362
|
+
domain,
|
|
2363
|
+
candidateHash,
|
|
2364
|
+
atHash,
|
|
2365
|
+
...dispositions ? { dispositions } : {}
|
|
2366
|
+
})
|
|
2367
|
+
}, eng.STDERR));
|
|
2368
|
+
}
|
|
2369
|
+
function historyRestorePreflight(eng, ws, domain, currentHash, priorHash, atHash, actor) {
|
|
2370
|
+
return JSON.parse(call(eng.ex, "query", {
|
|
2371
|
+
repoArg: repoArgOf(ws),
|
|
2372
|
+
workspace: ws,
|
|
2373
|
+
branch: BRANCH,
|
|
2374
|
+
queryBytes: b64Json({
|
|
2375
|
+
op: "historyPreflight",
|
|
2376
|
+
domain,
|
|
2377
|
+
candidateHash: priorHash,
|
|
2378
|
+
atHash,
|
|
2379
|
+
restorePreviousOf: currentHash,
|
|
2380
|
+
ackBy: actor
|
|
2381
|
+
})
|
|
2382
|
+
}, eng.STDERR));
|
|
2383
|
+
}
|
|
2384
|
+
function promotePreflighted(eng, ws, domain, candidateHash, opts = {}) {
|
|
2385
|
+
const actingPrincipal = opts.actor?.trim() || String(eng.installedBy || "").trim();
|
|
2386
|
+
if (!actingPrincipal && !opts.authToken) {
|
|
2387
|
+
return {
|
|
2388
|
+
ok: false,
|
|
2389
|
+
stage: "identity",
|
|
2390
|
+
error: "promotion needs the stateful client's current principal so its business decision is attributable"
|
|
2391
|
+
};
|
|
2392
|
+
}
|
|
2393
|
+
const atHash = kgit.resolveRef(eng, gitdirOf(ws), BRANCH);
|
|
2394
|
+
if (!atHash) {
|
|
2395
|
+
return { ok: false, stage: "preflight", error: "workspace has no history to prove" };
|
|
2396
|
+
}
|
|
2397
|
+
let report;
|
|
2398
|
+
try {
|
|
2399
|
+
report = historyPreflight(eng, ws, domain, candidateHash, atHash, opts.dispositions);
|
|
2400
|
+
} catch (error) {
|
|
2401
|
+
return { ok: false, stage: "preflight", error: String(error?.message || error) };
|
|
2402
|
+
}
|
|
2403
|
+
const prepared = prepareManagedPromotion(report, candidateHash, domain, opts);
|
|
2404
|
+
if (!prepared.ok) return prepared;
|
|
2405
|
+
const {
|
|
2406
|
+
replaces: _replaces,
|
|
2407
|
+
retireReplaced: _retireReplaced,
|
|
2408
|
+
dispositions: _dispositions,
|
|
2409
|
+
acceptanceReason: _acceptance,
|
|
2410
|
+
...authorOpts
|
|
2411
|
+
} = opts;
|
|
2412
|
+
const result = author(eng, ws, "nomos", "promoteDomain", prepared.payload, eng.hashes.nomos, {
|
|
2413
|
+
...authorOpts,
|
|
2414
|
+
...actingPrincipal ? { actor: actingPrincipal } : {}
|
|
2415
|
+
});
|
|
2416
|
+
return result.ok ? { ...result, stage: "promoted", report, receiptId: prepared.receiptId } : { ...result, stage: "admission", report, receiptId: prepared.receiptId };
|
|
2417
|
+
}
|
|
2418
|
+
function restorePreviousPreflighted(eng, ws, domain, currentHash, opts = {}) {
|
|
2419
|
+
const actingPrincipal = opts.actor?.trim() || String(eng.installedBy || "").trim();
|
|
2420
|
+
if (!actingPrincipal) {
|
|
2421
|
+
return {
|
|
2422
|
+
ok: false,
|
|
2423
|
+
stage: "identity",
|
|
2424
|
+
error: "model restoration needs the stateful client's current principal so its business decision is attributable"
|
|
2425
|
+
};
|
|
2426
|
+
}
|
|
2427
|
+
const resolved = currentLaw(eng, ws)[domain];
|
|
2428
|
+
if (resolved !== currentHash) {
|
|
2429
|
+
return {
|
|
2430
|
+
ok: false,
|
|
2431
|
+
stage: "preflight",
|
|
2432
|
+
error: "the generated model is no longer current; nothing changed [nomos.rollout.restore-current-changed]"
|
|
2433
|
+
};
|
|
2434
|
+
}
|
|
2435
|
+
const current = qById(eng, ws, `domain-installation:${currentHash}`)[0]?.data;
|
|
2436
|
+
const priorHash = typeof current?.["spec.supersedes"] === "string" ? current["spec.supersedes"] : "";
|
|
2437
|
+
if (!priorHash) {
|
|
2438
|
+
return {
|
|
2439
|
+
ok: false,
|
|
2440
|
+
stage: "preflight",
|
|
2441
|
+
error: "this model has no previous model to restore [nomos.rollout.restore-no-previous]"
|
|
2442
|
+
};
|
|
2443
|
+
}
|
|
2444
|
+
const atHash = kgit.resolveRef(eng, gitdirOf(ws), BRANCH);
|
|
2445
|
+
if (!atHash) return { ok: false, stage: "preflight", error: "workspace has no history to prove" };
|
|
2446
|
+
let report;
|
|
2447
|
+
try {
|
|
2448
|
+
report = historyRestorePreflight(
|
|
2449
|
+
eng,
|
|
2450
|
+
ws,
|
|
2451
|
+
domain,
|
|
2452
|
+
currentHash,
|
|
2453
|
+
priorHash,
|
|
2454
|
+
atHash,
|
|
2455
|
+
actingPrincipal
|
|
2456
|
+
);
|
|
2457
|
+
} catch (error) {
|
|
2458
|
+
return { ok: false, stage: "preflight", error: String(error?.message || error) };
|
|
2459
|
+
}
|
|
2460
|
+
const prepared = prepareManagedRestoration(report, currentHash, priorHash, domain, opts);
|
|
2461
|
+
if (!prepared.ok) return prepared;
|
|
2462
|
+
const { acceptanceReason: _acceptance, ...authorOpts } = opts;
|
|
2463
|
+
const result = author(eng, ws, "nomos", "rollbackDomain", prepared.payload, eng.hashes.nomos, {
|
|
2464
|
+
...authorOpts,
|
|
2465
|
+
...actingPrincipal ? { actor: actingPrincipal } : {}
|
|
2466
|
+
});
|
|
2467
|
+
return result.ok ? { ...result, stage: "restored", report, receiptId: prepared.receiptId } : { ...result, stage: "admission", report, receiptId: prepared.receiptId };
|
|
2468
|
+
}
|
|
2217
2469
|
async function rebirthCompact(eng, ws, ledger, { reason = "", supersededAt = 0, parent = "" } = {}) {
|
|
2218
2470
|
const incWs = `${ws}__rebirth`;
|
|
2219
2471
|
try {
|
|
@@ -2526,26 +2778,89 @@ async function boot(eng, ws, ledger) {
|
|
|
2526
2778
|
);
|
|
2527
2779
|
}
|
|
2528
2780
|
async function deploy(eng, ws, ledger, usda, domainHash, dispositions, opts = {}) {
|
|
2529
|
-
const
|
|
2530
|
-
if (
|
|
2781
|
+
const existing = qById(eng, ws, `domain-installation:${domainHash}`);
|
|
2782
|
+
if (existing.length > 0) {
|
|
2783
|
+
const phase = String(existing[0]?.data?.["status.phase"] ?? "");
|
|
2784
|
+
return {
|
|
2785
|
+
head: kgit.resolveRef(eng, gitdirOf(ws), BRANCH),
|
|
2786
|
+
installation: existing,
|
|
2787
|
+
staged: phase === "Pending",
|
|
2788
|
+
alreadyInstalled: true
|
|
2789
|
+
};
|
|
2790
|
+
}
|
|
2791
|
+
const before = currentLaw(eng, ws);
|
|
2792
|
+
const tenantHashes = [...new Set(Object.values(before).filter(
|
|
2793
|
+
(hash) => typeof hash === "string" && hash !== eng.hashes.bootstrap && hash !== eng.hashes.nomos
|
|
2794
|
+
))];
|
|
2795
|
+
const upgrade = tenantHashes.length > 0;
|
|
2796
|
+
let supersedes = opts.supersedes?.trim() || void 0;
|
|
2797
|
+
if (supersedes !== void 0 && !tenantHashes.includes(supersedes)) {
|
|
2531
2798
|
throw new Error(
|
|
2532
|
-
`deploy-
|
|
2799
|
+
`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.`
|
|
2533
2800
|
);
|
|
2534
2801
|
}
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
const law = installedLaw(eng, ws);
|
|
2539
|
-
const currentLaw2 = law?.currentLaw ?? {};
|
|
2540
|
-
const stale = keys.filter((k) => currentLaw2[k] !== void 0 && currentLaw2[k] !== domainHash);
|
|
2541
|
-
if (stale.length > 0) {
|
|
2802
|
+
if (upgrade && supersedes === void 0) {
|
|
2803
|
+
if (tenantHashes.length === 1) supersedes = tenantHashes[0];
|
|
2804
|
+
else {
|
|
2542
2805
|
throw new Error(
|
|
2543
|
-
`deploy-
|
|
2806
|
+
`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.`
|
|
2544
2807
|
);
|
|
2545
2808
|
}
|
|
2546
2809
|
}
|
|
2547
|
-
|
|
2548
|
-
|
|
2810
|
+
if (upgrade && dispositions && Object.keys(dispositions).length > 0) {
|
|
2811
|
+
throw new Error(
|
|
2812
|
+
"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."
|
|
2813
|
+
);
|
|
2814
|
+
}
|
|
2815
|
+
const directiveId = upgrade ? "stageDomain" : "installDomain";
|
|
2816
|
+
const payload = upgrade ? stagePayload(domainHash, usda, eng.installedBy, supersedes) : installPayload(domainHash, usda, eng.installedBy, dispositions);
|
|
2817
|
+
const result = author(eng, ws, "nomos", directiveId, payload, eng.hashes.nomos, {
|
|
2818
|
+
actor: opts.actor ?? "",
|
|
2819
|
+
...opts.authToken ? { authToken: opts.authToken } : {}
|
|
2820
|
+
});
|
|
2821
|
+
if (result.ok === false) {
|
|
2822
|
+
unmount(eng, ws);
|
|
2823
|
+
throw new Error(
|
|
2824
|
+
`deploy-refused: ${upgrade ? "staging" : "installing"} ${domainHash.slice(0, 12)}\u2026 was REFUSED by the one gate (custody unchanged): ${result.error ?? "unknown refusal"}`
|
|
2825
|
+
);
|
|
2826
|
+
}
|
|
2827
|
+
try {
|
|
2828
|
+
const installation = qById(eng, ws, `domain-installation:${domainHash}`);
|
|
2829
|
+
if (upgrade) {
|
|
2830
|
+
const phase = String(installation[0]?.data?.["status.phase"] ?? "");
|
|
2831
|
+
if (phase !== "Pending") {
|
|
2832
|
+
throw new Error(
|
|
2833
|
+
`deploy-did-not-stage: candidate ${domainHash.slice(0, 12)}\u2026 admitted but its lifecycle phase is '${phase || "missing"}', not Pending. Custody was not pushed.`
|
|
2834
|
+
);
|
|
2835
|
+
}
|
|
2836
|
+
const after = currentLaw(eng, ws);
|
|
2837
|
+
const moved = Object.entries(before).filter(([key, hash]) => after[key] !== hash);
|
|
2838
|
+
if (moved.length > 0 || Object.values(after).includes(domainHash)) {
|
|
2839
|
+
throw new Error(
|
|
2840
|
+
`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().`
|
|
2841
|
+
);
|
|
2842
|
+
}
|
|
2843
|
+
await commitAndPush(eng, ws, ledger);
|
|
2844
|
+
return { head: result.head, installation, staged: true, supersedes };
|
|
2845
|
+
}
|
|
2846
|
+
const law = installedLaw(eng, ws);
|
|
2847
|
+
const installed = (law?.domains ?? []).find((row) => row?.domainHash === domainHash);
|
|
2848
|
+
const keys = installed?.domainKeys ?? installation[0]?.data?.domainKeys ?? installation[0]?.domainKeys ?? [];
|
|
2849
|
+
if (keys.length > 0) {
|
|
2850
|
+
const currentLaw2 = law?.currentLaw ?? {};
|
|
2851
|
+
const stale = keys.filter((k) => currentLaw2[k] !== domainHash);
|
|
2852
|
+
if (stale.length > 0) {
|
|
2853
|
+
throw new Error(
|
|
2854
|
+
`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.`
|
|
2855
|
+
);
|
|
2856
|
+
}
|
|
2857
|
+
}
|
|
2858
|
+
await commitAndPush(eng, ws, ledger);
|
|
2859
|
+
return { head: result.head, installation, staged: false };
|
|
2860
|
+
} catch (error) {
|
|
2861
|
+
unmount(eng, ws);
|
|
2862
|
+
throw error;
|
|
2863
|
+
}
|
|
2549
2864
|
}
|
|
2550
2865
|
function snapshot(eng, ws) {
|
|
2551
2866
|
const wsDir = dirOf(eng.preopen.dir.contents.get("ws")).contents.get(ws);
|
|
@@ -2645,13 +2960,14 @@ function sealAttestationBatches(eng, ws, domain, controllerHash, opts = {}) {
|
|
|
2645
2960
|
}
|
|
2646
2961
|
return outcomes;
|
|
2647
2962
|
}
|
|
2648
|
-
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, CKPT_REF, pushVia, fullRef, applyPackInto, custodyLsRefs, qById, query, check, expand, cryptoSealField, cryptoKeygen, authorKeygen, eraCertSign, delegationCertSign, attestationSign, attestedRead, certSign, cryptoWrapKey, cryptoUnwrapKey, readPosture, count, sum, pendingConflicts, spatialBboxParams, spatialWithin, extremum, nomosActive, refusedRefName, outboxRefName, GENESIS_WARRANT_ID, isWarranted, projectionStats;
|
|
2963
|
+
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, CKPT_REF, pushVia, fullRef, applyPackInto, custodyLsRefs, qById, query, check, expand, cryptoSealField, cryptoOwnedScopeKey, cryptoOwnedDeviceRequest, cryptoOwnedPrepareApproval, cryptoOwnedPrepareRecovery, cryptoKeygen, authorKeygen, eraCertSign, delegationCertSign, attestationSign, attestedRead, certSign, cryptoWrapKey, cryptoUnwrapKey, readPosture, count, sum, pendingConflicts, pendingConflictSummary, spatialBboxParams, spatialWithin, extremum, nomosActive, refusedRefName, outboxRefName, GENESIS_WARRANT_ID, isWarranted, projectionStats;
|
|
2649
2964
|
var init_engine = __esm({
|
|
2650
2965
|
"vendor/engine/engine.ts"() {
|
|
2651
2966
|
"use strict";
|
|
2652
2967
|
init_git_fs();
|
|
2653
2968
|
init_tree();
|
|
2654
2969
|
init_custody_transport();
|
|
2970
|
+
init_managed_promotion();
|
|
2655
2971
|
enc3 = new TextEncoder();
|
|
2656
2972
|
dec3 = new TextDecoder();
|
|
2657
2973
|
BRANCH = "main";
|
|
@@ -2697,6 +3013,14 @@ var init_engine = __esm({
|
|
|
2697
3013
|
}, eng.STDERR)).oid
|
|
2698
3014
|
};
|
|
2699
3015
|
installPayload = (hash, usda, installedBy, dispositions) => ({ domainHash: hash, packageUsda: usda, installedBy, dependencies: [], finalizers: [], ...dispositions ? { dispositions } : {} });
|
|
3016
|
+
stagePayload = (hash, usda, installedBy, supersedes) => ({
|
|
3017
|
+
domainHash: hash,
|
|
3018
|
+
packageUsda: usda,
|
|
3019
|
+
installedBy,
|
|
3020
|
+
dependencies: [],
|
|
3021
|
+
...supersedes ? { supersedes } : {},
|
|
3022
|
+
finalizers: []
|
|
3023
|
+
});
|
|
2700
3024
|
routeTagHexOfHomeKey = async (homeKey) => (await sha256hex(`nomos-route:${homeKey}`)).slice(0, 12);
|
|
2701
3025
|
SUMMARY_SEP = "";
|
|
2702
3026
|
summaryKey = (readId, group) => `${readId}${SUMMARY_SEP}${group}`;
|
|
@@ -2727,6 +3051,105 @@ var init_engine = __esm({
|
|
|
2727
3051
|
check = (eng, ws, object, relation, subject) => JSON.parse(call(eng.ex, "query", { repoArg: repoArgOf(ws), workspace: ws, queryBytes: b64Json({ op: "check", object, relation, subject }), branch: BRANCH }, eng.STDERR));
|
|
2728
3052
|
expand = (eng, ws, object, relation) => JSON.parse(call(eng.ex, "query", { repoArg: repoArgOf(ws), workspace: ws, queryBytes: b64Json({ op: "expand", object, relation }), branch: BRANCH }, eng.STDERR));
|
|
2729
3053
|
cryptoSealField = (eng, { scopeKey, scope, epoch, aggSid, fieldSid, plaintext }) => JSON.parse(call(eng.ex, "query", { queryBytes: b64Json({ op: "cryptoSealField", scopeKey, scope, epoch, aggSid, fieldSid, plaintext }) }, eng.STDERR)).envelope;
|
|
3054
|
+
cryptoOwnedScopeKey = (eng, workspace, authorSecret, scope, principal = "", requireSeat = true, record, recordEpoch = 0, recordWrap) => {
|
|
3055
|
+
const recordObject = record === void 0 ? void 0 : `${record.type}:${record.id}`;
|
|
3056
|
+
const derived = JSON.parse(call(eng.ex, "query", {
|
|
3057
|
+
queryBytes: b64Json({
|
|
3058
|
+
op: "cryptoOwnedScopeKey",
|
|
3059
|
+
workspace,
|
|
3060
|
+
principal,
|
|
3061
|
+
authorSecret,
|
|
3062
|
+
scope,
|
|
3063
|
+
...recordObject === void 0 ? {} : { recordObject, recordEpoch },
|
|
3064
|
+
...recordWrap === void 0 ? {} : { recordWrap }
|
|
3065
|
+
})
|
|
3066
|
+
}, eng.STDERR));
|
|
3067
|
+
const ownedKeySubject = String(derived.ownedKeySubject || "");
|
|
3068
|
+
if (!requireSeat) {
|
|
3069
|
+
return {
|
|
3070
|
+
scope: String(derived.scope || scope),
|
|
3071
|
+
epoch: Number(derived.epoch) || 0,
|
|
3072
|
+
key: String(derived.scopeKey || ""),
|
|
3073
|
+
ownedKeySubject,
|
|
3074
|
+
ownedCustody: typeof derived.ownedCustody === "string" ? derived.ownedCustody : void 0,
|
|
3075
|
+
keyCommitment: typeof derived.keyCommitment === "string" ? derived.keyCommitment : void 0,
|
|
3076
|
+
principalWrappingPublic: typeof derived.principalWrappingPublic === "string" ? derived.principalWrappingPublic : void 0
|
|
3077
|
+
};
|
|
3078
|
+
}
|
|
3079
|
+
if (principal) {
|
|
3080
|
+
let hex = "";
|
|
3081
|
+
for (const byte of enc3.encode(principal)) hex += byte.toString(16).padStart(2, "0");
|
|
3082
|
+
const object = `nomos-owned-principal:${hex || "00"}`;
|
|
3083
|
+
const rows = qById(eng, workspace, `reltuple-${object}-nomos_internal_owned_device_key_7c1f5e`);
|
|
3084
|
+
const row = Array.isArray(rows) ? rows[0] : rows?.rows?.[0];
|
|
3085
|
+
const leaves = row?.data?.subjects ?? row?.subjects ?? {};
|
|
3086
|
+
const leaf = (raw) => {
|
|
3087
|
+
if (raw && typeof raw === "object") return raw;
|
|
3088
|
+
try {
|
|
3089
|
+
return typeof raw === "string" ? JSON.parse(raw) : {};
|
|
3090
|
+
} catch {
|
|
3091
|
+
return {};
|
|
3092
|
+
}
|
|
3093
|
+
};
|
|
3094
|
+
const active = Object.entries(leaves).filter(([, raw]) => leaf(raw).status === "active").map(([subject]) => subject);
|
|
3095
|
+
if (active.length === 0 && Object.keys(leaves).length === 0) {
|
|
3096
|
+
return {
|
|
3097
|
+
scope: String(derived.scope || scope),
|
|
3098
|
+
epoch: Number(derived.epoch) || 0,
|
|
3099
|
+
key: String(derived.scopeKey || ""),
|
|
3100
|
+
ownedKeySubject,
|
|
3101
|
+
ownedCustody: typeof derived.ownedCustody === "string" ? derived.ownedCustody : void 0,
|
|
3102
|
+
keyCommitment: typeof derived.keyCommitment === "string" ? derived.keyCommitment : void 0,
|
|
3103
|
+
principalWrappingPublic: typeof derived.principalWrappingPublic === "string" ? derived.principalWrappingPublic : void 0
|
|
3104
|
+
};
|
|
3105
|
+
}
|
|
3106
|
+
if (!active.includes(ownedKeySubject)) {
|
|
3107
|
+
throw new Error(
|
|
3108
|
+
"this device is waiting for approval \u2014 approve its opaque request on an already-working device"
|
|
3109
|
+
);
|
|
3110
|
+
}
|
|
3111
|
+
const custody = String(leaf(leaves[ownedKeySubject]).ownedCustody || "");
|
|
3112
|
+
if (!custody) throw new Error("the approved device has no owned-data handoff");
|
|
3113
|
+
const opened = JSON.parse(call(eng.ex, "query", {
|
|
3114
|
+
queryBytes: b64Json({
|
|
3115
|
+
op: "cryptoOwnedScopeKey",
|
|
3116
|
+
workspace,
|
|
3117
|
+
principal,
|
|
3118
|
+
authorSecret,
|
|
3119
|
+
scope,
|
|
3120
|
+
ownedCustody: custody,
|
|
3121
|
+
...recordObject === void 0 ? {} : { recordObject, recordEpoch },
|
|
3122
|
+
...recordWrap === void 0 ? {} : { recordWrap }
|
|
3123
|
+
})
|
|
3124
|
+
}, eng.STDERR));
|
|
3125
|
+
return {
|
|
3126
|
+
scope: String(opened.scope || scope),
|
|
3127
|
+
epoch: Number(opened.epoch) || 0,
|
|
3128
|
+
key: String(opened.scopeKey || ""),
|
|
3129
|
+
ownedKeySubject,
|
|
3130
|
+
keyCommitment: typeof opened.keyCommitment === "string" ? opened.keyCommitment : void 0,
|
|
3131
|
+
principalWrappingPublic: typeof opened.principalWrappingPublic === "string" ? opened.principalWrappingPublic : void 0
|
|
3132
|
+
};
|
|
3133
|
+
}
|
|
3134
|
+
return {
|
|
3135
|
+
scope: String(derived.scope || scope),
|
|
3136
|
+
epoch: Number(derived.epoch) || 0,
|
|
3137
|
+
key: String(derived.scopeKey || ""),
|
|
3138
|
+
ownedKeySubject,
|
|
3139
|
+
ownedCustody: typeof derived.ownedCustody === "string" ? derived.ownedCustody : void 0,
|
|
3140
|
+
keyCommitment: typeof derived.keyCommitment === "string" ? derived.keyCommitment : void 0,
|
|
3141
|
+
principalWrappingPublic: typeof derived.principalWrappingPublic === "string" ? derived.principalWrappingPublic : void 0
|
|
3142
|
+
};
|
|
3143
|
+
};
|
|
3144
|
+
cryptoOwnedDeviceRequest = (eng, workspace, principal, authorSecret, scope) => String(JSON.parse(call(eng.ex, "query", {
|
|
3145
|
+
queryBytes: b64Json({ op: "cryptoOwnedDeviceRequest", workspace, principal, authorSecret, scope })
|
|
3146
|
+
}, eng.STDERR)).request || "");
|
|
3147
|
+
cryptoOwnedPrepareApproval = (eng, args) => JSON.parse(call(eng.ex, "query", {
|
|
3148
|
+
queryBytes: b64Json({ op: "cryptoOwnedPrepareApproval", ...args })
|
|
3149
|
+
}, eng.STDERR));
|
|
3150
|
+
cryptoOwnedPrepareRecovery = (eng, args) => JSON.parse(call(eng.ex, "query", {
|
|
3151
|
+
queryBytes: b64Json({ op: "cryptoOwnedPrepareRecovery", ...args })
|
|
3152
|
+
}, eng.STDERR));
|
|
2730
3153
|
cryptoKeygen = (eng) => JSON.parse(call(eng.ex, "query", { queryBytes: b64Json({ op: "cryptoKeygen" }) }, eng.STDERR));
|
|
2731
3154
|
authorKeygen = (eng) => JSON.parse(call(eng.ex, "query", { queryBytes: b64Json({ op: "authorKeygen" }) }, eng.STDERR));
|
|
2732
3155
|
eraCertSign = (eng, args) => JSON.parse(call(eng.ex, "query", { queryBytes: b64Json({ op: "eraCertSign", ...args }) }, eng.STDERR));
|
|
@@ -2774,7 +3197,8 @@ var init_engine = __esm({
|
|
|
2774
3197
|
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));
|
|
2775
3198
|
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));
|
|
2776
3199
|
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));
|
|
2777
|
-
pendingConflicts = (eng, ws, principal = "") => JSON.parse(call(eng.ex, "query", { repoArg: repoArgOf(ws), workspace: ws, queryBytes: b64Json({ op: "pendingConflicts" }), principal, branch: BRANCH }, eng.STDERR));
|
|
3200
|
+
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));
|
|
3201
|
+
pendingConflictSummary = (eng, ws, principal = "") => JSON.parse(call(eng.ex, "query", { repoArg: repoArgOf(ws), workspace: ws, queryBytes: b64Json({ op: "pendingConflictSummary" }), principal, branch: BRANCH }, eng.STDERR));
|
|
2778
3202
|
spatialBboxParams = (bbox) => {
|
|
2779
3203
|
const minX = bbox.minX ?? bbox.minLng, minY = bbox.minY ?? bbox.minLat, maxX = bbox.maxX ?? bbox.maxLng, maxY = bbox.maxY ?? bbox.maxLat;
|
|
2780
3204
|
return { minX, minY, maxX, maxY, minLng: minX, minLat: minY, maxLng: maxX, maxLat: maxY };
|
|
@@ -2820,15 +3244,28 @@ async function fetchJsonCached(url, cacheFile) {
|
|
|
2820
3244
|
}
|
|
2821
3245
|
}
|
|
2822
3246
|
async function fetchRuntime(cloud, kind = "production") {
|
|
2823
|
-
const cache = join2(configDir(), "runtime");
|
|
3247
|
+
const cache = process.env["NOMOS_OFFLINE_RUNTIME"] || join2(configDir(), "runtime");
|
|
2824
3248
|
let wasmBytes;
|
|
2825
3249
|
const wasmName = kind === "test-mint" ? "holon-testmint.wasm" : "holon.wasm";
|
|
2826
3250
|
const wasmUrl = kind === "test-mint" ? "holon-testmint.wasm" : "holon.wasm";
|
|
2827
3251
|
const wasmCache = join2(cache, wasmName);
|
|
3252
|
+
const packagesCache = join2(cache, "packages.json");
|
|
3253
|
+
const refresh = String(process.env["NOMOS_RUNTIME_REFRESH"] || "auto").toLowerCase();
|
|
3254
|
+
if (refresh === "never") {
|
|
3255
|
+
if (!existsSync2(wasmCache) || !existsSync2(packagesCache)) {
|
|
3256
|
+
throw new Error(
|
|
3257
|
+
`offline runtime cache missing at ${cache} (${wasmName} + packages.json); build or warm that exact runtime before running with NOMOS_RUNTIME_REFRESH=never`
|
|
3258
|
+
);
|
|
3259
|
+
}
|
|
3260
|
+
return {
|
|
3261
|
+
wasmBytes: readFileSync(wasmCache),
|
|
3262
|
+
packages: JSON.parse(readFileSync(packagesCache, "utf8"))
|
|
3263
|
+
};
|
|
3264
|
+
}
|
|
2828
3265
|
const localWasm = process.env["NOMOS_LOCAL_WASM"];
|
|
2829
3266
|
if (localWasm) {
|
|
2830
3267
|
const bytes = readFileSync(localWasm);
|
|
2831
|
-
const packages2 = await fetchJsonCached(`${cloud}/v1/runtime/packages`,
|
|
3268
|
+
const packages2 = await fetchJsonCached(`${cloud}/v1/runtime/packages`, packagesCache);
|
|
2832
3269
|
return { wasmBytes: bytes, packages: packages2 };
|
|
2833
3270
|
}
|
|
2834
3271
|
try {
|
|
@@ -2841,7 +3278,7 @@ async function fetchRuntime(cloud, kind = "production") {
|
|
|
2841
3278
|
if (!existsSync2(wasmCache)) throw e;
|
|
2842
3279
|
wasmBytes = readFileSync(wasmCache);
|
|
2843
3280
|
}
|
|
2844
|
-
const packages = await fetchJsonCached(`${cloud}/v1/runtime/packages`,
|
|
3281
|
+
const packages = await fetchJsonCached(`${cloud}/v1/runtime/packages`, packagesCache);
|
|
2845
3282
|
return { wasmBytes, packages };
|
|
2846
3283
|
}
|
|
2847
3284
|
function atomicWriteRuntime(target, data) {
|
|
@@ -2852,8 +3289,9 @@ function atomicWriteRuntime(target, data) {
|
|
|
2852
3289
|
function runtimeDirIsWarm(runtimeDir) {
|
|
2853
3290
|
try {
|
|
2854
3291
|
const w = statSync(join2(runtimeDir, "holon.wasm")).mtimeMs;
|
|
3292
|
+
const t = statSync(join2(runtimeDir, "holon-testmint.wasm")).mtimeMs;
|
|
2855
3293
|
const p = statSync(join2(runtimeDir, "packages.json")).mtimeMs;
|
|
2856
|
-
return Date.now() - Math.min(w, p) < RUNTIME_FRESH_MS;
|
|
3294
|
+
return Date.now() - Math.min(w, t, p) < RUNTIME_FRESH_MS;
|
|
2857
3295
|
} catch {
|
|
2858
3296
|
return false;
|
|
2859
3297
|
}
|
|
@@ -2869,11 +3307,15 @@ async function refreshRuntimeDir(cloud, runtimeDir) {
|
|
|
2869
3307
|
const r = await fetch(`${cloud}/v1/runtime/holon.wasm`);
|
|
2870
3308
|
if (!r.ok) throw new Error(`runtime wasm \u2192 ${r.status}`);
|
|
2871
3309
|
const wasmBytes = new Uint8Array(await r.arrayBuffer());
|
|
3310
|
+
const testmint = await fetch(`${cloud}/v1/runtime/holon-testmint.wasm`);
|
|
3311
|
+
if (!testmint.ok) throw new Error(`test-mint runtime wasm \u2192 ${testmint.status}`);
|
|
3312
|
+
const testmintBytes = new Uint8Array(await testmint.arrayBuffer());
|
|
2872
3313
|
const pkgs = await fetch(`${cloud}/v1/runtime/packages`);
|
|
2873
3314
|
if (!pkgs.ok) throw new Error(`runtime packages \u2192 ${pkgs.status}`);
|
|
2874
3315
|
const pkgText = await pkgs.text();
|
|
2875
3316
|
mkdirSync2(runtimeDir, { recursive: true });
|
|
2876
3317
|
atomicWriteRuntime(join2(runtimeDir, "holon.wasm"), wasmBytes);
|
|
3318
|
+
atomicWriteRuntime(join2(runtimeDir, "holon-testmint.wasm"), testmintBytes);
|
|
2877
3319
|
atomicWriteRuntime(join2(runtimeDir, "packages.json"), pkgText);
|
|
2878
3320
|
_refreshedDirsThisProcess.add(runtimeDir);
|
|
2879
3321
|
return true;
|
|
@@ -4975,14 +5417,14 @@ function negotiateDeployRoute(caps, opts) {
|
|
|
4975
5417
|
if (opts.signed) {
|
|
4976
5418
|
if (caps.offerLane === false) {
|
|
4977
5419
|
return {
|
|
4978
|
-
fail: `${caps.cloud}
|
|
4979
|
-
\u2192
|
|
5420
|
+
fail: `${caps.cloud} cannot accept an authenticated deployment for this workspace \u2014 POST /v2/workspaces/${opts.ws}/${opts.route.domain}/${opts.route.directiveId} is not routed because the workspace serves no self-describing gateway.
|
|
5421
|
+
\u2192 target a current Nomos cloud that supports attributed deployment.`
|
|
4980
5422
|
};
|
|
4981
5423
|
}
|
|
4982
5424
|
if (caps.offerLane === true && caps.routesTarget === false) {
|
|
4983
5425
|
return {
|
|
4984
|
-
fail: `${caps.cloud} serves the offer gateway for ${opts.ws}, but its OpenAPI does not name the route ${opts.route.domain}/${opts.route.directiveId} \u2014 the ${opts.route.domain} controller is not installed here, so
|
|
4985
|
-
\u2192 confirm the workspace is born and
|
|
5426
|
+
fail: `${caps.cloud} serves the offer gateway for ${opts.ws}, but its OpenAPI does not name the route ${opts.route.domain}/${opts.route.directiveId} \u2014 the ${opts.route.domain} controller is not installed here, so the lifecycle request would 404.
|
|
5427
|
+
\u2192 confirm the workspace is born and its current Nomos controller is installed.`
|
|
4986
5428
|
};
|
|
4987
5429
|
}
|
|
4988
5430
|
if (opts.sealedSizeChars > INLINE_OFFER_CAP_CHARS && caps.stage === false) {
|
|
@@ -5060,7 +5502,7 @@ function domainKeysOf(body) {
|
|
|
5060
5502
|
function packageHashOf(packageUsda) {
|
|
5061
5503
|
return createHash2("sha256").update(Buffer.from(packageUsda, "utf8")).digest("hex");
|
|
5062
5504
|
}
|
|
5063
|
-
function resolveDeployPlan(domainKeys, currentLaw2, targetHash
|
|
5505
|
+
function resolveDeployPlan(domainKeys, currentLaw2, targetHash) {
|
|
5064
5506
|
const decisions = [];
|
|
5065
5507
|
const priors = /* @__PURE__ */ new Set();
|
|
5066
5508
|
for (const key of domainKeys) {
|
|
@@ -5069,21 +5511,18 @@ function resolveDeployPlan(domainKeys, currentLaw2, targetHash, opts = {}) {
|
|
|
5069
5511
|
decisions.push({ key, action: "first" });
|
|
5070
5512
|
} else if (currentHash === targetHash) {
|
|
5071
5513
|
decisions.push({ key, currentHash, action: "idempotent" });
|
|
5072
|
-
} else if (opts.keepBeside === true) {
|
|
5073
|
-
decisions.push({ key, currentHash, action: "keep-beside" });
|
|
5074
5514
|
} else {
|
|
5075
|
-
decisions.push({ key, currentHash, action: "
|
|
5515
|
+
decisions.push({ key, currentHash, action: "successor" });
|
|
5076
5516
|
priors.add(currentHash);
|
|
5077
5517
|
}
|
|
5078
5518
|
}
|
|
5079
|
-
const
|
|
5519
|
+
const predecessorCandidates = [...priors];
|
|
5080
5520
|
const idempotent = domainKeys.length > 0 && decisions.every((d) => d.action === "idempotent");
|
|
5081
5521
|
return {
|
|
5082
5522
|
decisions,
|
|
5083
|
-
...
|
|
5084
|
-
retireReplaced: opts.retireReplaced === true,
|
|
5523
|
+
...predecessorCandidates.length > 0 ? { supersedes: predecessorCandidates[0] } : {},
|
|
5085
5524
|
idempotent,
|
|
5086
|
-
|
|
5525
|
+
predecessorCandidates
|
|
5087
5526
|
};
|
|
5088
5527
|
}
|
|
5089
5528
|
function describeDeployPlan(plan, targetHash) {
|
|
@@ -5092,10 +5531,8 @@ function describeDeployPlan(plan, targetHash) {
|
|
|
5092
5531
|
switch (d.action) {
|
|
5093
5532
|
case "first":
|
|
5094
5533
|
return ` ${d.key}: ${t} installed (first)`;
|
|
5095
|
-
case "
|
|
5096
|
-
return ` ${d.key}: ${t}
|
|
5097
|
-
case "keep-beside":
|
|
5098
|
-
return ` ${d.key}: ${t} kept beside ${short(d.currentHash)}`;
|
|
5534
|
+
case "successor":
|
|
5535
|
+
return ` ${d.key}: ${t} is the candidate after ${short(d.currentHash)}`;
|
|
5099
5536
|
case "idempotent":
|
|
5100
5537
|
return ` ${d.key}: unchanged \u2014 ${t} is already active`;
|
|
5101
5538
|
}
|
|
@@ -5566,7 +6003,7 @@ async function wsCreate(name, opts) {
|
|
|
5566
6003
|
return 1;
|
|
5567
6004
|
}
|
|
5568
6005
|
out4(`\u2713 createWorkspace '${name}' requested via signed governance offer to ${opts.via} on ${cloud}`);
|
|
5569
|
-
out4(` the worker provisions it on first touch;
|
|
6006
|
+
out4(` the worker provisions it on first touch; then run githolon deploy ${name}`);
|
|
5570
6007
|
out4(` (want the direct birth instead? drop --via: githolon ws create ${name})`);
|
|
5571
6008
|
return 0;
|
|
5572
6009
|
}
|
|
@@ -5609,7 +6046,7 @@ async function wsCreate(name, opts) {
|
|
|
5609
6046
|
}
|
|
5610
6047
|
if (opts.principal !== void 0) setPrincipal(opts.principal);
|
|
5611
6048
|
out4(`\u2713 workspace ${name} created on ${cloud}`);
|
|
5612
|
-
out4(` deploy
|
|
6049
|
+
out4(` deploy its first model: githolon deploy ${name}`);
|
|
5613
6050
|
return 0;
|
|
5614
6051
|
}
|
|
5615
6052
|
async function wsStatus(name, opts) {
|
|
@@ -5811,14 +6248,18 @@ async function deploy2(ws, opts) {
|
|
|
5811
6248
|
try {
|
|
5812
6249
|
const body = readDeployBody3(file);
|
|
5813
6250
|
targetHash = packageHashOf2(body.packageUsda);
|
|
5814
|
-
plan = resolveDeployPlan2(domainKeysOf2(body), currentLaw2, targetHash
|
|
5815
|
-
|
|
5816
|
-
|
|
5817
|
-
|
|
5818
|
-
}
|
|
5819
|
-
|
|
5820
|
-
|
|
6251
|
+
plan = resolveDeployPlan2(domainKeysOf2(body), currentLaw2, targetHash);
|
|
6252
|
+
} catch (error) {
|
|
6253
|
+
err4(`deploy '${ws}' needs the current generated deploy body: ${error.message}`);
|
|
6254
|
+
return 1;
|
|
6255
|
+
}
|
|
6256
|
+
if ((plan?.predecessorCandidates.length ?? 0) > 1) {
|
|
6257
|
+
err4(
|
|
6258
|
+
`deploy '${ws}' refused: this candidate spans ${plan.predecessorCandidates.length} different current models; Nomos will not guess one predecessor. Compile one coherent workspace model and try again.`
|
|
6259
|
+
);
|
|
6260
|
+
return 1;
|
|
5821
6261
|
}
|
|
6262
|
+
let expectsPending = plan !== void 0 && plan.predecessorCandidates.length === 1 && !plan.idempotent;
|
|
5822
6263
|
const principal = opts.principal ?? activePrincipal();
|
|
5823
6264
|
const signed = opts.principal !== void 0 || principal !== void 0 && getDeviceKey(principal) !== void 0;
|
|
5824
6265
|
let phaseSuffix = "";
|
|
@@ -5837,8 +6278,14 @@ async function deploy2(ws, opts) {
|
|
|
5837
6278
|
return 1;
|
|
5838
6279
|
}
|
|
5839
6280
|
const targetHash2 = createHash3("sha256").update(Buffer.from(packageUsda, "utf8")).digest("hex");
|
|
6281
|
+
if (expectsPending && body.dispositions !== void 0 && body.dispositions !== null) {
|
|
6282
|
+
err4(
|
|
6283
|
+
`deploy '${ws}' refused: successor models cannot carry caller-chosen schema dispositions; evolution must be proved by model.adopt(), not smuggled into deployment`
|
|
6284
|
+
);
|
|
6285
|
+
return 1;
|
|
6286
|
+
}
|
|
5840
6287
|
const { probeCloudCapabilities: probeCloudCapabilities2, negotiateDeployRoute: negotiateDeployRoute2 } = await Promise.resolve().then(() => (init_capabilities(), capabilities_exports));
|
|
5841
|
-
const route = { domain: "nomos", directiveId: "installDomain" };
|
|
6288
|
+
const route = { domain: "nomos", directiveId: expectsPending ? "stageDomain" : "installDomain" };
|
|
5842
6289
|
const caps = await probeCloudCapabilities2(cloud, ws, route);
|
|
5843
6290
|
const refusal = negotiateDeployRoute2(caps, { signed: true, ws, sealedSizeChars: packageUsda.length, route });
|
|
5844
6291
|
if (refusal !== void 0) {
|
|
@@ -5850,17 +6297,16 @@ async function deploy2(ws, opts) {
|
|
|
5850
6297
|
let v;
|
|
5851
6298
|
try {
|
|
5852
6299
|
const who = resolveGovernancePrincipal2(opts);
|
|
5853
|
-
const
|
|
6300
|
+
const lifecyclePayload = {
|
|
5854
6301
|
domainHash: targetHash2,
|
|
5855
6302
|
packageUsda,
|
|
5856
6303
|
installedBy: `user:${who}`,
|
|
5857
6304
|
dependencies: [],
|
|
5858
6305
|
finalizers: [],
|
|
5859
|
-
|
|
5860
|
-
|
|
5861
|
-
...body.dispositions !== void 0 && body.dispositions !== null ? { dispositions: body.dispositions } : {}
|
|
6306
|
+
...expectsPending && plan?.supersedes !== void 0 ? { supersedes: plan.supersedes } : {},
|
|
6307
|
+
...!expectsPending && body.dispositions !== void 0 && body.dispositions !== null ? { dispositions: body.dispositions } : {}
|
|
5862
6308
|
};
|
|
5863
|
-
v = await signAndPostOffer2(ws, "nomos",
|
|
6309
|
+
v = await signAndPostOffer2(ws, "nomos", route.directiveId, lifecyclePayload, opts);
|
|
5864
6310
|
} catch (e) {
|
|
5865
6311
|
err4(e.message);
|
|
5866
6312
|
return 1;
|
|
@@ -5882,7 +6328,7 @@ async function deploy2(ws, opts) {
|
|
|
5882
6328
|
const txt = d ? JSON.stringify(d) : "no body";
|
|
5883
6329
|
err4(`deploy '${ws}' failed (${r.status}): ${txt}`);
|
|
5884
6330
|
if (r.status === 401 || r.status === 403 || r.status === 422 || /warrant|signed|signer|unsigned|authorship|forged|relation|installDomain/i.test(txt)) {
|
|
5885
|
-
err4(` this workspace looks WARRANTED \u2014 re-run with --as <principal> to author a
|
|
6331
|
+
err4(` this workspace looks WARRANTED \u2014 re-run with --as <principal> to author a signed lifecycle offer`);
|
|
5886
6332
|
err4(` (import the admin signing key first if needed: githolon key import --principal <uid> --secret <key>)`);
|
|
5887
6333
|
}
|
|
5888
6334
|
return 1;
|
|
@@ -5890,6 +6336,7 @@ async function deploy2(ws, opts) {
|
|
|
5890
6336
|
const phase = d.installation?.[0]?.data?.["status.phase"];
|
|
5891
6337
|
phaseSuffix = phase === "Active" ? " (active)" : typeof phase === "string" ? ` (${phase.toLowerCase()})` : "";
|
|
5892
6338
|
deployedHash = typeof d.domainHash === "string" ? d.domainHash : void 0;
|
|
6339
|
+
expectsPending = d.staged === true || expectsPending;
|
|
5893
6340
|
}
|
|
5894
6341
|
const after = await fetch(`${cloud}/v2/workspaces/${ws}/domains`).then((ar) => ar.json()).then((ad) => ad.ok === true ? ad : {}).catch(() => ({}));
|
|
5895
6342
|
const currentHashes = new Set(Object.values(after.currentLaw ?? {}));
|
|
@@ -5898,13 +6345,28 @@ async function deploy2(ws, opts) {
|
|
|
5898
6345
|
const emitPlan = () => {
|
|
5899
6346
|
if (plan === void 0 || targetHash === void 0 || plan.decisions.length === 0) return;
|
|
5900
6347
|
for (const line of describeDeployPlan2(plan, targetHash)) out4(line);
|
|
5901
|
-
if (plan.replaceCandidates.length > 1) {
|
|
5902
|
-
out4(` \u26A0 the package's keys were active on ${plan.replaceCandidates.length} different installs \u2014 installDomain supersedes one (${plan.replaces.slice(0, 16)}\u2026); this deploy is active for every key.`);
|
|
5903
|
-
}
|
|
5904
|
-
if (!signed && plan.replaces !== void 0 && !opts.keepBeside) {
|
|
5905
|
-
out4(` note: the OPEN (unsigned) lane installs beside \u2014 the new law is active, and the prior install is effectively superseded but not marked Superseded. Sign with --as <uid> to record the supersession.`);
|
|
5906
|
-
}
|
|
5907
6348
|
};
|
|
6349
|
+
if (expectsPending && deployedHash !== void 0) {
|
|
6350
|
+
const row = (after.domains ?? []).find((x) => x.domainHash === deployedHash);
|
|
6351
|
+
const unchanged = Object.entries(currentLaw2).every(([key, hash]) => after.currentLaw?.[key] === hash);
|
|
6352
|
+
if (row?.phase !== "Pending" || !unchanged || isCurrent) {
|
|
6353
|
+
err4(`deploy '${ws}' refused its own outcome: a successor must be Pending while the current model keeps serving`);
|
|
6354
|
+
err4(` observed phase=${row?.phase ?? "missing"}; current law ${unchanged && !isCurrent ? "unchanged" : "changed"}`);
|
|
6355
|
+
return 2;
|
|
6356
|
+
}
|
|
6357
|
+
if (beforeDurableHead !== void 0) {
|
|
6358
|
+
const durableHead = await waitForDurableMainAdvance(cloud, ws, beforeDurableHead);
|
|
6359
|
+
if (durableHead === void 0) {
|
|
6360
|
+
err4(`deploy '${ws}' staged the candidate, but canonical Git main did not advance within 30000ms`);
|
|
6361
|
+
return 2;
|
|
6362
|
+
}
|
|
6363
|
+
}
|
|
6364
|
+
out4(`\u2713 staged ${fileName} \u2192 ${ws} (pending)`);
|
|
6365
|
+
if (plan?.supersedes) out4(` current model ${plan.supersedes.slice(0, 16)}\u2026 keeps serving`);
|
|
6366
|
+
out4(` candidate ${deployedHash.slice(0, 16)}\u2026 is in custody but cannot serve yet`);
|
|
6367
|
+
out4(` next: use the candidate generated client and call model.adopt()`);
|
|
6368
|
+
return 0;
|
|
6369
|
+
}
|
|
5908
6370
|
if (deployedHash !== void 0 && isCurrent) {
|
|
5909
6371
|
const wasCurrentBefore = Object.values(currentLaw2).includes(deployedHash);
|
|
5910
6372
|
if (!wasCurrentBefore && beforeDurableHead !== void 0) {
|
|
@@ -6311,6 +6773,39 @@ async function runOfflineLegs(eng, ws, lawHash, legs, frameworkHash, deployUsda)
|
|
|
6311
6773
|
}
|
|
6312
6774
|
return done(true, lines);
|
|
6313
6775
|
}
|
|
6776
|
+
function sealOwnedBusinessBirth(eng, payload, encryption, authorSecret, principal) {
|
|
6777
|
+
const key = payload[encryption.keyField];
|
|
6778
|
+
const digest = createHash4("sha256").update(`${encryption.namespace}${String(key)}`).digest("hex");
|
|
6779
|
+
const childWorkspace = `${encryption.namespace}-${digest.slice(0, 40)}`;
|
|
6780
|
+
const scopeKey = cryptoOwnedScopeKey(
|
|
6781
|
+
eng,
|
|
6782
|
+
childWorkspace,
|
|
6783
|
+
authorSecret,
|
|
6784
|
+
encryption.scope,
|
|
6785
|
+
principal,
|
|
6786
|
+
false
|
|
6787
|
+
);
|
|
6788
|
+
const sealed = {
|
|
6789
|
+
[OWNED_KEY_PAYLOAD_FIELD]: scopeKey.ownedKeySubject,
|
|
6790
|
+
...scopeKey.ownedCustody ? { [OWNED_CUSTODY_PAYLOAD_FIELD]: scopeKey.ownedCustody } : {}
|
|
6791
|
+
};
|
|
6792
|
+
for (const [field, slot] of Object.entries(encryption.fields)) {
|
|
6793
|
+
const value = payload[field];
|
|
6794
|
+
if (value === void 0 || value === null) continue;
|
|
6795
|
+
sealed[field] = cryptoSealField(eng, {
|
|
6796
|
+
scopeKey: scopeKey.key,
|
|
6797
|
+
scope: encryption.scope,
|
|
6798
|
+
epoch: scopeKey.epoch,
|
|
6799
|
+
aggSid: slot.aggSid,
|
|
6800
|
+
fieldSid: slot.fieldSid,
|
|
6801
|
+
plaintext: String(value)
|
|
6802
|
+
});
|
|
6803
|
+
}
|
|
6804
|
+
payload[BUSINESS_BIRTH_SEED_PAYLOAD_FIELD] = JSON.stringify(sealed);
|
|
6805
|
+
payload[OWNED_KEY_PAYLOAD_FIELD] = scopeKey.ownedKeySubject;
|
|
6806
|
+
if (scopeKey.ownedCustody) payload[OWNED_CUSTODY_PAYLOAD_FIELD] = scopeKey.ownedCustody;
|
|
6807
|
+
return { childWorkspace, scopeKey };
|
|
6808
|
+
}
|
|
6314
6809
|
function warrantParentForBirth(eng, parentWs, parentDomain, lawHash, genesisOwner, birthActor, dev2, stamp) {
|
|
6315
6810
|
const authorFrameworkAs = (directiveId, payload, actor) => {
|
|
6316
6811
|
for (const dom of [parentDomain, "nomos"]) {
|
|
@@ -6334,15 +6829,6 @@ function warrantParentForBirth(eng, parentWs, parentDomain, lawHash, genesisOwne
|
|
|
6334
6829
|
const root = authorKeygen(eng);
|
|
6335
6830
|
setTestKRoot(eng, root.public);
|
|
6336
6831
|
const parentCert = certSign(eng, {
|
|
6337
|
-
child: parentWs,
|
|
6338
|
-
founder: genesisOwner,
|
|
6339
|
-
verified: true,
|
|
6340
|
-
parentKey: dev2.public,
|
|
6341
|
-
parentId: "root",
|
|
6342
|
-
epoch: 0,
|
|
6343
|
-
secret: dev2.secret
|
|
6344
|
-
});
|
|
6345
|
-
const rootDelegation = certSign(eng, {
|
|
6346
6832
|
child: parentWs,
|
|
6347
6833
|
founder: genesisOwner,
|
|
6348
6834
|
verified: true,
|
|
@@ -6377,7 +6863,7 @@ function warrantParentForBirth(eng, parentWs, parentDomain, lawHash, genesisOwne
|
|
|
6377
6863
|
parentId: parentWs,
|
|
6378
6864
|
parentKey: dev2.public,
|
|
6379
6865
|
epoch: 0,
|
|
6380
|
-
certChain: JSON.stringify({ links: [parentCert
|
|
6866
|
+
certChain: JSON.stringify({ links: [parentCert] })
|
|
6381
6867
|
}, genesisOwner);
|
|
6382
6868
|
const hasParentAttestation = !(sba.ok === false && /no directive registered/i.test(sba.error ?? ""));
|
|
6383
6869
|
if (sba.ok === false && !/already|create-once|attest|no directive registered/i.test(sba.error ?? "")) return { ok: false, error: `seedBirthAttestation refused: ${sba.error}` };
|
|
@@ -6386,7 +6872,10 @@ function warrantParentForBirth(eng, parentWs, parentDomain, lawHash, genesisOwne
|
|
|
6386
6872
|
return { ok: true, attestationVerified: hasDelegation && hasParentAttestation };
|
|
6387
6873
|
}
|
|
6388
6874
|
function attestedBirthOffer(eng, parentWs, parentDomain, directiveId, payloadNoCert, lawHash, founder, dev2, verified = true) {
|
|
6389
|
-
const probe = author(eng, parentWs, parentDomain, directiveId, payloadNoCert, lawHash, {
|
|
6875
|
+
const probe = author(eng, parentWs, parentDomain, directiveId, payloadNoCert, lawHash, {
|
|
6876
|
+
actor: founder,
|
|
6877
|
+
authorSecret: dev2.secret
|
|
6878
|
+
});
|
|
6390
6879
|
if (probe.ok !== false) {
|
|
6391
6880
|
return { res: probe };
|
|
6392
6881
|
}
|
|
@@ -6476,6 +6965,10 @@ async function runChildBirthLeg(eng, ws, lawHash, cb, frameworkHash) {
|
|
|
6476
6965
|
}
|
|
6477
6966
|
const bornParent = (setupRes.born ?? []).map((b) => b?.workspace).find((w) => typeof w === "string" && w.length > 0);
|
|
6478
6967
|
if (bornParent === void 0) {
|
|
6968
|
+
const failed = (setupRes.birthOutcomes ?? []).find((o) => o?.status === "failed" || o?.status === "refused");
|
|
6969
|
+
if (failed !== void 0) {
|
|
6970
|
+
return done(false, `parent setup ${setup.parentDomain}/${setup.birthDirectiveId} child genesis failed: ${failed.reason ?? "unknown"}`);
|
|
6971
|
+
}
|
|
6479
6972
|
return done(false, `parent setup ${setup.parentDomain}/${setup.birthDirectiveId} admitted but spawned no parent workspace (born=${JSON.stringify(setupRes.born ?? [])})`);
|
|
6480
6973
|
}
|
|
6481
6974
|
parentWs = bornParent;
|
|
@@ -6489,6 +6982,7 @@ async function runChildBirthLeg(eng, ws, lawHash, cb, frameworkHash) {
|
|
|
6489
6982
|
return done(true);
|
|
6490
6983
|
}
|
|
6491
6984
|
}
|
|
6985
|
+
const ownedBirth = cb.businessEncryption !== void 0 ? sealOwnedBusinessBirth(eng, payload, cb.businessEncryption, dev2.secret, founder) : void 0;
|
|
6492
6986
|
const { res } = attestedBirthOffer(
|
|
6493
6987
|
eng,
|
|
6494
6988
|
parentWs,
|
|
@@ -6603,10 +7097,29 @@ async function runChildBirthLeg(eng, ws, lawHash, cb, frameworkHash) {
|
|
|
6603
7097
|
return done(false, `the recovered child ${childWs} FAILED verify_chain from its own custody: ${recoveredVerify.error ?? "invalid"}`);
|
|
6604
7098
|
}
|
|
6605
7099
|
if (cb.childSeedInstanceId !== void 0) {
|
|
6606
|
-
const recoveredRows = qById(
|
|
7100
|
+
const recoveredRows = qById(
|
|
7101
|
+
eng,
|
|
7102
|
+
childWs,
|
|
7103
|
+
cb.childSeedInstanceId,
|
|
7104
|
+
ownedBirth === void 0 ? "" : founder,
|
|
7105
|
+
ownedBirth === void 0 ? [] : [ownedBirth.scopeKey]
|
|
7106
|
+
);
|
|
6607
7107
|
if (recoveredRows.length < 1) {
|
|
6608
7108
|
return done(false, `the recovered child ${childWs} verified but its business root ${cb.childSeedInstanceId} was missing`);
|
|
6609
7109
|
}
|
|
7110
|
+
if (ownedBirth !== void 0 && cb.businessEncryption !== void 0) {
|
|
7111
|
+
if (childWs !== ownedBirth.childWorkspace) {
|
|
7112
|
+
return done(false, `the born child '${childWs}' differs from the deterministic owned-custody address '${ownedBirth.childWorkspace}'`);
|
|
7113
|
+
}
|
|
7114
|
+
const data = recoveredRows[0]?.data ?? {};
|
|
7115
|
+
for (const field of Object.keys(cb.businessEncryption.fields)) {
|
|
7116
|
+
const expected = cb.birthPayload[field];
|
|
7117
|
+
if (expected !== void 0 && data[field] !== expected) {
|
|
7118
|
+
return done(false, `the recovered owned ${cb.businessAggregateId ?? "aggregate"} did not decrypt '${field}' back to its business fact`);
|
|
7119
|
+
}
|
|
7120
|
+
}
|
|
7121
|
+
lines.push(`\u2713 owned custody \u2014 recovered business facts decrypted under the creator's framework-managed device key`);
|
|
7122
|
+
}
|
|
6610
7123
|
}
|
|
6611
7124
|
if (cb.businessAggregateId !== void 0) {
|
|
6612
7125
|
lines.push(`\u2713 persistence + recovery \u2014 evicted, restored from durable custody, and ${cb.businessAggregateId} read back`);
|
|
@@ -6870,7 +7383,7 @@ OFFLINE PROOF GREEN (${Math.round(v.ms)}ms) \u2014 the same legs rerun on every
|
|
|
6870
7383
|
console.log(`Run the same generated business proof against Nomos Cloud when ready: githolon proof --live`);
|
|
6871
7384
|
return 0;
|
|
6872
7385
|
}
|
|
6873
|
-
var keyHashOf, OFFLINE_PROOF_VERIFIER;
|
|
7386
|
+
var keyHashOf, OFFLINE_PROOF_VERIFIER, OWNED_KEY_PAYLOAD_FIELD, OWNED_CUSTODY_PAYLOAD_FIELD, BUSINESS_BIRTH_SEED_PAYLOAD_FIELD;
|
|
6874
7387
|
var init_proof_offline = __esm({
|
|
6875
7388
|
"src/proof_offline.ts"() {
|
|
6876
7389
|
"use strict";
|
|
@@ -6878,6 +7391,9 @@ var init_proof_offline = __esm({
|
|
|
6878
7391
|
init_local_holon();
|
|
6879
7392
|
keyHashOf = (pubB64) => createHash4("sha256").update(Buffer.from(pubB64, "base64")).digest("hex");
|
|
6880
7393
|
OFFLINE_PROOF_VERIFIER = "nomos:test-mint";
|
|
7394
|
+
OWNED_KEY_PAYLOAD_FIELD = "__nomos_owned_device_key_subject_7c1f5e";
|
|
7395
|
+
OWNED_CUSTODY_PAYLOAD_FIELD = "__nomos_owned_device_custody_7c1f5e";
|
|
7396
|
+
BUSINESS_BIRTH_SEED_PAYLOAD_FIELD = "__nomos_birth_seed_payload_7c1f5e";
|
|
6881
7397
|
}
|
|
6882
7398
|
});
|
|
6883
7399
|
|
|
@@ -7227,11 +7743,11 @@ async function harnessInstall(opts) {
|
|
|
7227
7743
|
const refreshed = await refreshRuntimeDir(cloudBase(), runtimeDir);
|
|
7228
7744
|
if (refreshed) process.stderr.write(`harness-install: refreshed runtime cache from the cloud \u2192 ${runtimeDir}
|
|
7229
7745
|
`);
|
|
7230
|
-
const wasmFile = join15(runtimeDir, "holon.wasm");
|
|
7746
|
+
const wasmFile = join15(runtimeDir, "holon-testmint.wasm");
|
|
7231
7747
|
const pkgsFile = join15(runtimeDir, "packages.json");
|
|
7232
7748
|
if (!existsSync13(wasmFile) || !existsSync13(pkgsFile)) {
|
|
7233
7749
|
die(
|
|
7234
|
-
`runtime cache missing at ${runtimeDir} (holon.wasm + packages.json). Warm it once with a \`githolon\` run (it fetches + caches the runtime), then re-run offline.`
|
|
7750
|
+
`test runtime cache missing at ${runtimeDir} (holon-testmint.wasm + packages.json). Warm it once with a \`githolon\` run (it fetches + caches the runtime), then re-run offline.`
|
|
7235
7751
|
);
|
|
7236
7752
|
}
|
|
7237
7753
|
const wasm = readFileSync14(wasmFile);
|
|
@@ -8694,7 +9210,7 @@ export const ${n.pascal} = aggregate("${n.pascal}", {
|
|
|
8694
9210
|
status: t.enum(${n.statusesConst}).merge(Lww),
|
|
8695
9211
|
tags: t.set(t.string()).merge(AddWins),
|
|
8696
9212
|
customFields: t.map(t.string()).merge(MapOf(Lww)),
|
|
8697
|
-
});`;
|
|
9213
|
+
}).public();`;
|
|
8698
9214
|
}
|
|
8699
9215
|
function domainTemplate(raw) {
|
|
8700
9216
|
const n = namesFor(raw);
|
|
@@ -8766,7 +9282,7 @@ import { z, aggregate, directive, t, Conflict, set } from "@githolon/dsl";
|
|
|
8766
9282
|
// Stub target \u2014 in a real domain, import the existing aggregate handle instead.
|
|
8767
9283
|
export const ${n.pascal} = aggregate("${n.pascal}", {
|
|
8768
9284
|
label: t.string().merge(Conflict),
|
|
8769
|
-
});
|
|
9285
|
+
}).public();
|
|
8770
9286
|
|
|
8771
9287
|
/** ${n.camel} \u2014 .mutates the target aggregate. */
|
|
8772
9288
|
export const ${n.camel} = directive("${n.camel}")
|
|
@@ -9481,21 +9997,19 @@ var HELP = {
|
|
|
9481
9997
|
examples: ["githolon revoke creation 32c7100e-\u2026", "githolon revoke admin 32c7100e-\u2026"]
|
|
9482
9998
|
},
|
|
9483
9999
|
deploy: {
|
|
9484
|
-
usage: "githolon deploy [<ws>] [--as <uid>] [--
|
|
9485
|
-
what: "
|
|
10000
|
+
usage: "githolon deploy [<ws>] [--as <uid>] [--file <deploy.json>] [--cloud <url>] [--target <name>]",
|
|
10001
|
+
what: "Put the compiled model in the workspace's verified custody. There is one lifecycle: the first\nmodel becomes active so a blank application can start; every successor stays Pending while the current\nmodel keeps serving. The candidate generated client then runs the exact-history proof through\n`model.adopt()` and either adopts immediately or returns a business-readable decision requiring\n`decision.accept(reason)`. Deployment cannot choose a replacement mode or bypass that proof.\nRe-deploying the same content hash is idempotent. With no <ws>, the project's workspace binding resolves it.",
|
|
9486
10002
|
flags: [
|
|
9487
|
-
["--as <uid>", "
|
|
9488
|
-
["--keep-beside", "install beside the prior law (the old multi-version default; prior becomes effectively superseded by recency)"],
|
|
9489
|
-
["--retire-replaced", "supersede via Retired \u2014 the prior install is explicitly withdrawn"],
|
|
10003
|
+
["--as <uid>", "attribute the deployment to this principal (needs its enrolled signing key)"],
|
|
9490
10004
|
["--file <path>", "an explicit deploy body (default: the one build/*.deploy.json)"],
|
|
9491
10005
|
["--target <name>", "pick among named targets (workspace: { dev: \u2026, prod: \u2026 })"],
|
|
9492
10006
|
["--cloud <url>", "target cloud"]
|
|
9493
10007
|
],
|
|
9494
|
-
examples: ["githolon deploy", "githolon deploy my-guestbook", "githolon deploy co2-platform --as <admin-uid>"
|
|
10008
|
+
examples: ["githolon deploy", "githolon deploy my-guestbook", "githolon deploy co2-platform --as <admin-uid>"]
|
|
9495
10009
|
},
|
|
9496
10010
|
domains: {
|
|
9497
10011
|
usage: "githolon domains <status <ws> [--explain-current-interface] | retire <ws> <hashOrKey> [--with <hashOrKey>]>",
|
|
9498
|
-
what: "
|
|
10012
|
+
what: "Framework lifecycle inspection and explicit withdrawal.\n\u2022 status: per domain KEY, the active hash, then the superseded/retired lineage behind it.\n Lifecycle vocabulary: active = served now; superseded = replaced by a newer install for the same domain\n key, replayable, not served; retired = explicitly withdrawn, replayable, not served.\n --explain-current-interface spells out why active reads/dispatch use only that active map.\n\u2022 retire: mark an install Retired via a signed installDomain offer. The framework retires only as the\n consequence of installing a SUCCESSOR \u2014 by default the local compiled package (build/*.deploy.json),\n or --with <hashOrKey> names an already-installed successor. A key the successor does not cover is left\n with NO active law \u2014 WARNED loudly, never blocked. A key resolves to its active hash; a 64-hex arg is\n taken as the install hash.",
|
|
9499
10013
|
flags: [
|
|
9500
10014
|
["--explain-current-interface", "status: also explain the frontier resolution (why the interface is what it is)"],
|
|
9501
10015
|
["--with <hashOrKey>", "retire: the retiring successor package \u2014 an already-installed hash or served key"],
|
|
@@ -9506,7 +10020,7 @@ var HELP = {
|
|
|
9506
10020
|
},
|
|
9507
10021
|
secret: {
|
|
9508
10022
|
usage: "githolon secret <set <ws> <push-password> | rotate <ws>> [--cloud <url>]",
|
|
9509
|
-
what: "The git push-password store (~/.holon/credentials.json, 0600) for authenticated git sync to the\ncloud host.
|
|
10023
|
+
what: "The git push-password store (~/.holon/credentials.json, 0600) for authenticated git sync to the\ncloud host. Deployment has no host secret. `set` imports a push password you already hold;\n`rotate` is RETIRED (the host holds no ownership credential to rotate \u2014 410). (There is no\npush-to-create birth: a workspace is born by its parent authoring its birth.)",
|
|
9510
10024
|
examples: ["githolon secret set my-ws holon_v1_\u2026"]
|
|
9511
10025
|
},
|
|
9512
10026
|
git: {
|
|
@@ -10052,15 +10566,13 @@ function cloudArgs(rest) {
|
|
|
10052
10566
|
const pos = [];
|
|
10053
10567
|
const opts = {};
|
|
10054
10568
|
const VALUE_FLAGS = ["--cloud", "--principal", "--as", "--file", "--target", "--parent", "--via", "--max", "--label", "--secret", "--payload", "--payload-file", "--save", "--format", "--with", "--out", "--reason", "--oid", "--seed-secret", "--gcp-secret", "--controller-hash", "--plan", "--depth", "--domain", "--directive"];
|
|
10055
|
-
const BOOL_FLAGS = ["--sha256", "--stamp", "--yes", "--clear", "--
|
|
10569
|
+
const BOOL_FLAGS = ["--sha256", "--stamp", "--yes", "--clear", "--explain-current-interface", "--dry-run", "--json", "--full"];
|
|
10056
10570
|
for (let i = 0; i < rest.length; i++) {
|
|
10057
10571
|
const a = rest[i];
|
|
10058
10572
|
if (BOOL_FLAGS.includes(a)) {
|
|
10059
10573
|
if (a === "--sha256") opts.sha256 = true;
|
|
10060
10574
|
else if (a === "--stamp") opts.stamp = true;
|
|
10061
10575
|
else if (a === "--clear") opts.clear = true;
|
|
10062
|
-
else if (a === "--keep-beside") opts.keepBeside = true;
|
|
10063
|
-
else if (a === "--retire-replaced") opts.retireReplaced = true;
|
|
10064
10576
|
else if (a === "--explain-current-interface") opts.explain = true;
|
|
10065
10577
|
else if (a === "--dry-run") opts.dryRun = true;
|
|
10066
10578
|
else if (a === "--json") opts.json = true;
|