@githolon/testing 0.14.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/vendor/engine/engine.mjs +65 -156
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@githolon/testing",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "@githolon/testing — law TDD for Nomos domains: boot the REAL engine plane in-process (the exact machinery every cloud DO, heavy container and web client runs), dispatch directives, assert rows, assert TYPED REFUSALS, fork for what-ifs — fully offline inside vitest.",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE.md",
|
package/vendor/engine/engine.mjs
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// from the container instance base, ledgers ARRIVE on each op (containers have no
|
|
13
13
|
// Workers bindings — the control-plane DO mints tokens and sends them), runs in Node.
|
|
14
14
|
//
|
|
15
|
-
// CONTROL PLANE STAYS IN THE DO: ownership secrets,
|
|
15
|
+
// CONTROL PLANE STAYS IN THE DO: ownership secrets, the DLQ store,
|
|
16
16
|
// quotas/rates, alarms. The engine RETURNS data (e.g. dead-letter entries with intent
|
|
17
17
|
// bytes) and the host persists. Runtime-neutral: workerd + Node 22 (globalThis.crypto,
|
|
18
18
|
// fetch, TextEncoder are the only ambient dependencies).
|
|
@@ -55,9 +55,9 @@ function call(ex, mode, fields, STDERR) {
|
|
|
55
55
|
} finally { ex.git_holon_dealloc(reqPtr, req.length); }
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
function seedManifests(
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
function seedManifests(_m, _strings) {
|
|
59
|
+
// Runtime manifests are committed inside USDA packages and derived by the holon
|
|
60
|
+
// from active installed law. Hosts must not seed admission/projection sidecars.
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
// (#39 BAILIFF: no host-chosen `authorityScope` literal. It was a dead, hardcoded "workspace/root" stamped
|
|
@@ -68,13 +68,14 @@ export const installPayload = (hash, usda, installedBy, dispositions) => ({ doma
|
|
|
68
68
|
|
|
69
69
|
/**
|
|
70
70
|
* Boot the resident wasm + /work tree. `wasmModule` is a PRECOMPILED WebAssembly.Module
|
|
71
|
-
* (the host compiles its way); `
|
|
72
|
-
*
|
|
71
|
+
* (the host compiles its way); `replica` = the host's unique 63-bit id.
|
|
72
|
+
*
|
|
73
|
+
* Runtime read/admission metadata is sovereign holon state: committed USDA packages
|
|
74
|
+
* are folded by the githolon, and the host never stages manifest sidecars.
|
|
73
75
|
*/
|
|
74
|
-
export async function createEngine({ wasmModule, bootstrapPkg, nomosPkg,
|
|
76
|
+
export async function createEngine({ wasmModule, bootstrapPkg, nomosPkg, replica, installedBy = "nomos-cloud" }) {
|
|
75
77
|
const hashes = { bootstrap: await sha256hex(bootstrapPkg), nomos: await sha256hex(nomosPkg) };
|
|
76
78
|
const root = new Map();
|
|
77
|
-
seedManifests(root, manifestStrings);
|
|
78
79
|
root.set("domain.package.usda", new File(enc.encode(bootstrapPkg)));
|
|
79
80
|
root.set("ws", new Directory(new Map()));
|
|
80
81
|
const preopen = new PreopenDirectory("/work", root);
|
|
@@ -87,39 +88,19 @@ export async function createEngine({ wasmModule, bootstrapPkg, nomosPkg, manifes
|
|
|
87
88
|
for (const n of ["memory", "git_holon_alloc", "git_holon_dealloc", "git_holon_call"]) if (!inst.exports[n]) throw new Error(`missing export ${n}`);
|
|
88
89
|
const eng = {
|
|
89
90
|
ex: inst.exports, preopen, STDERR, seq: 0, replica, hashes,
|
|
90
|
-
bootstrapPkg, nomosPkg,
|
|
91
|
+
bootstrapPkg, nomosPkg, installedBy,
|
|
91
92
|
fs: makeGitFs(preopen, "/work", { File, Directory }),
|
|
92
93
|
mounted: new Map(), // ws -> { restored, remoteMain, restoreError }
|
|
93
94
|
mainIntents: new Map(), // ws -> { head, ids:Set, oids:Set } (admission idempotence)
|
|
94
|
-
knownDomainsCache: null,
|
|
95
95
|
};
|
|
96
96
|
return eng;
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
eng.scopedReadsCache = null;
|
|
105
|
-
eng.placementDirectivesCache = null;
|
|
106
|
-
eng.tenantTypesCache = null;
|
|
107
|
-
eng.globalAggregatesCache = null;
|
|
108
|
-
const root = eng.preopen.dir.contents;
|
|
109
|
-
seedManifests(root, strings);
|
|
110
|
-
const wsRoot = root.get("ws");
|
|
111
|
-
for (const ws of eng.mounted.keys()) {
|
|
112
|
-
const wsDir = wsRoot.contents.get(ws);
|
|
113
|
-
if (wsDir) seedManifests(wsDir.contents, strings);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/** The domains DEPLOYED to this workspace = the effective identity map's keys. */
|
|
118
|
-
export function knownDomains(eng) {
|
|
119
|
-
if (eng.knownDomainsCache) return eng.knownDomainsCache;
|
|
120
|
-
eng.knownDomainsCache = new Set(Object.keys(JSON.parse(eng.manifestStrings.identity)));
|
|
121
|
-
return eng.knownDomainsCache;
|
|
122
|
-
}
|
|
99
|
+
// There is NO host→holon manifest channel. The wasm derives every read/identity
|
|
100
|
+
// manifest from the FOLDED ledger (installed_read_manifest_bytes_from_state) and
|
|
101
|
+
// refuses a package lacking nomosReadProjection. A host cannot provide a manifest:
|
|
102
|
+
// the op does not exist (Read Confinement — the kernel's transition function, not a
|
|
103
|
+
// host convention). `setManifests` is gone, not no-op'd, so the lie is unrepresentable.
|
|
123
104
|
|
|
124
105
|
// ── TRANSPARENT SHARDING: the WRONG-HOME GATE (the edge bailiff — sharding slice 2) ──
|
|
125
106
|
//
|
|
@@ -135,18 +116,10 @@ export function knownDomains(eng) {
|
|
|
135
116
|
|
|
136
117
|
/** directive routes off the effective identity manifests: `${domain} ${directiveId}` → route. */
|
|
137
118
|
export function directiveRoutes(eng) {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
for (const [domain, manifestJson] of Object.entries(identity)) {
|
|
143
|
-
try {
|
|
144
|
-
const m = typeof manifestJson === "string" ? JSON.parse(manifestJson) : manifestJson;
|
|
145
|
-
for (const r of (m && m.routes) || []) routes.set(`${domain} ${r.directive}`, r);
|
|
146
|
-
} catch {}
|
|
147
|
-
}
|
|
148
|
-
eng.directiveRoutesCache = routes;
|
|
149
|
-
return routes;
|
|
119
|
+
void eng;
|
|
120
|
+
// Host-side manifest taxonomy is retired. Shard routing needs a holon-owned
|
|
121
|
+
// taxonomy API before it can be re-enabled without leaking law into the host.
|
|
122
|
+
return new Map();
|
|
150
123
|
}
|
|
151
124
|
|
|
152
125
|
/** The 48-bit route tag of a home key (must agree byte-for-byte with the client mint). */
|
|
@@ -246,39 +219,15 @@ const FRAMEWORK_AGG_TYPES = new Set([
|
|
|
246
219
|
* the suffix re-derivation, deep-verify's recount): control-plane rows (PolicyBundle,
|
|
247
220
|
* DomainInstallation) and framework law-state never skew the capacity metric. */
|
|
248
221
|
function tenantTypes(eng) {
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
try { readManifest = JSON.parse(eng.manifestStrings.read); } catch {}
|
|
252
|
-
// §5.4 (slice 4): GLOBAL reference data is replicated custody on every shard —
|
|
253
|
-
// its rows arrive by the reverse lane (replicateIntents — a host leg the §5.2
|
|
254
|
-
// capture never sees), so counting them as tenant load would let the three
|
|
255
|
-
// row-count lanes drift (capture vs suffix vs deep-verify recount). Excluded
|
|
256
|
-
// from the capacity metric on EVERY lane, by the one shared definition here.
|
|
257
|
-
const globals = globalAggregates(eng);
|
|
258
|
-
const out = new Set(Object.keys(readManifest.aggregateFieldKinds || {}).filter((t) => !FRAMEWORK_AGG_TYPES.has(t) && !globals.has(t)));
|
|
259
|
-
eng.tenantTypesCache = out;
|
|
260
|
-
return out;
|
|
222
|
+
void eng;
|
|
223
|
+
return new Set();
|
|
261
224
|
}
|
|
262
225
|
|
|
263
226
|
/** The derived PLACEMENT directives off the effective identity manifests:
|
|
264
227
|
* packed type `site` ⇒ `birthSite` keyed by payload field `siteId` (the law's naming). */
|
|
265
228
|
export function placementDirectives(eng) {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
const pascal = (s) => s.replace(/[_\s-]+(\w)/g, (_m, c) => c.toUpperCase()).replace(/^./, (c) => c.toUpperCase());
|
|
269
|
-
let identity = {};
|
|
270
|
-
try { identity = JSON.parse(eng.manifestStrings.identity); } catch {}
|
|
271
|
-
for (const manifestJson of Object.values(identity)) {
|
|
272
|
-
let m;
|
|
273
|
-
try { m = typeof manifestJson === "string" ? JSON.parse(manifestJson) : manifestJson; } catch { continue; }
|
|
274
|
-
for (const t of (m && m.workspaceTypes) || []) {
|
|
275
|
-
if (!t || t.mode !== "packed") continue;
|
|
276
|
-
const p = pascal(String(t.id));
|
|
277
|
-
out.set(`birth${p}`, { axis: t.id, keyField: `${p.length ? p[0].toLowerCase() + p.slice(1) : p}Id` });
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
eng.placementDirectivesCache = out;
|
|
281
|
-
return out;
|
|
229
|
+
void eng;
|
|
230
|
+
return new Map();
|
|
282
231
|
}
|
|
283
232
|
|
|
284
233
|
/** The ESTATE-SCOPED maintained reads off the effective identity manifests.
|
|
@@ -287,31 +236,8 @@ export function placementDirectives(eng) {
|
|
|
287
236
|
* predicate-aware in the kernel); the SUFFIX re-derivation evaluates it host-side
|
|
288
237
|
* ({@link evalCanonicalPred}) so both lanes agree byte-for-byte. */
|
|
289
238
|
export function scopedReads(eng) {
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
let identity = {};
|
|
293
|
-
try { identity = JSON.parse(eng.manifestStrings.identity); } catch {}
|
|
294
|
-
for (const manifestJson of Object.values(identity)) {
|
|
295
|
-
let m;
|
|
296
|
-
try { m = typeof manifestJson === "string" ? JSON.parse(manifestJson) : manifestJson; } catch { continue; }
|
|
297
|
-
for (const c of (m && m.counts) || []) {
|
|
298
|
-
if (c && typeof c.scope === "string") out.push({ id: c.id, kind: "count", of: c.of, by: c.by ?? null, ...(c.where ? { where: c.where } : {}) });
|
|
299
|
-
}
|
|
300
|
-
for (const s of (m && m.sums) || []) {
|
|
301
|
-
if (s && typeof s.scope === "string") out.push({ id: s.id, kind: "sum", of: s.of, by: s.by ?? null, field: s.sumField, ...(s.where ? { where: s.where } : {}) });
|
|
302
|
-
}
|
|
303
|
-
// SLICE 8 — scoped EXTREMUMS: per-shard min/max ride the same delta lane
|
|
304
|
-
// (events carry post-intent ABSOLUTES; the gate extremizes-on-monotone and
|
|
305
|
-
// requires declared re-derivation on retractions). The oracle is the
|
|
306
|
-
// projection's long-maintained extrema lane (#47's `extremum` RPC).
|
|
307
|
-
for (const [key, kind] of [["mins", "min"], ["maxes", "max"]]) {
|
|
308
|
-
for (const e of (m && m[key]) || []) {
|
|
309
|
-
if (e && typeof e.scope === "string") out.push({ id: e.id, kind, of: e.of, by: e.by ?? null, field: e.valueField, ...(e.where ? { where: e.where } : {}) });
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
eng.scopedReadsCache = out;
|
|
314
|
-
return out;
|
|
239
|
+
void eng;
|
|
240
|
+
return [];
|
|
315
241
|
}
|
|
316
242
|
|
|
317
243
|
/**
|
|
@@ -340,19 +266,8 @@ export function evalCanonicalPred(pred, get) {
|
|
|
340
266
|
* DOWNWARD into every shard chain by re-admission (the reverse delta lane).
|
|
341
267
|
*/
|
|
342
268
|
export function globalAggregates(eng) {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
let identity = {};
|
|
346
|
-
try { identity = JSON.parse(eng.manifestStrings.identity); } catch {}
|
|
347
|
-
for (const manifestJson of Object.values(identity)) {
|
|
348
|
-
let m;
|
|
349
|
-
try { m = typeof manifestJson === "string" ? JSON.parse(manifestJson) : manifestJson; } catch { continue; }
|
|
350
|
-
for (const t of (m && m.workspaceTypes) || []) {
|
|
351
|
-
for (const g of (t && t.globals) || []) if (typeof g === "string") out.add(g);
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
eng.globalAggregatesCache = out;
|
|
355
|
-
return out;
|
|
269
|
+
void eng;
|
|
270
|
+
return new Set();
|
|
356
271
|
}
|
|
357
272
|
|
|
358
273
|
/** Parse an intent blob's sealed events: [{aggregate, ops: Map(field -> {Str|Int})}]. */
|
|
@@ -1066,12 +981,6 @@ export async function admitIntentOffers(eng, ws, ledger, offers, { refuseDomains
|
|
|
1066
981
|
rec.rejected.push({ oid, error: `session lane refuses ${dom ? `'${dom}'` : "non-authored"} intents — law deploys go through POST /v1/workspaces/${ws}/domains with the workspace secret` });
|
|
1067
982
|
continue;
|
|
1068
983
|
}
|
|
1069
|
-
if (!knownDomains(eng).has(dom)) {
|
|
1070
|
-
const error = `domain '${dom}' is not deployed to this workspace — deploy its law (POST /v1/workspaces/${ws}/domains with the workspace secret), then POST /v1/workspaces/${ws}/dead-letters/retry`;
|
|
1071
|
-
rec.rejected.push({ oid, error, deadLettered: true });
|
|
1072
|
-
deadLetters.push({ intentId, oid, session: cid, error, blob, domain: dom, directiveId: dirId });
|
|
1073
|
-
continue;
|
|
1074
|
-
}
|
|
1075
984
|
if (receiptFence && dirId && Array.isArray(receiptFence[dom]) && receiptFence[dom].includes(dirId)) {
|
|
1076
985
|
const error = `'${dom}/${dirId}' is a capability RECEIPT — receipts are executor/owner writes, never open-session writes. Author it via POST /v1/workspaces/${ws}/author (owner Bearer), or — if this parked receipt is sanctioned — the owner unjams it: POST /v1/workspaces/${ws}/dead-letters/retry`;
|
|
1077
986
|
rec.rejected.push({ oid, error, deadLettered: true });
|
|
@@ -1214,7 +1123,6 @@ export async function deepVerifyShard(eng, shardWs, shardLedger, coordinatorRows
|
|
|
1214
1123
|
|
|
1215
1124
|
function stageWorkspaceDir(eng, ws) {
|
|
1216
1125
|
const wsContents = new Map();
|
|
1217
|
-
seedManifests(wsContents, eng.manifestStrings);
|
|
1218
1126
|
eng.preopen.dir.contents.get("ws").contents.set(ws, new Directory(wsContents));
|
|
1219
1127
|
}
|
|
1220
1128
|
|
|
@@ -1704,7 +1612,7 @@ async function mainIntentIds(eng, ws) {
|
|
|
1704
1612
|
* engine has no durable store), obvious attacks drop. Admitted intents merge to main,
|
|
1705
1613
|
* durably push, the branch is consumed.
|
|
1706
1614
|
*/
|
|
1707
|
-
export async function admitAll(eng, ws, ledger, { refuseDomains = [], receiptFence = null, shardRouting = null, sessionRefs = null } = {}) {
|
|
1615
|
+
export async function admitAll(eng, ws, ledger, { refuseDomains = [], receiptFence = null, shardRouting = null, sessionRefs = null, defer = false } = {}) {
|
|
1708
1616
|
const refuse = new Set(refuseDomains);
|
|
1709
1617
|
const routes = shardRouting ? directiveRoutes(eng) : null;
|
|
1710
1618
|
const gitdir = gitdirOf(ws);
|
|
@@ -1823,14 +1731,6 @@ export async function admitAll(eng, ws, ledger, { refuseDomains = [], receiptFen
|
|
|
1823
1731
|
rejected.push({ oid: oid.slice(0, 10), error: `session lane refuses ${dom ? `'${dom}'` : "non-authored"} intents — law deploys go through POST /v1/workspaces/${ws}/domains with the workspace secret` });
|
|
1824
1732
|
continue;
|
|
1825
1733
|
}
|
|
1826
|
-
// LAW-FENCE part 2: the domain must be DEPLOYED to this workspace. An
|
|
1827
|
-
// undeployed domain's write is the canonical LEGITIMATE JAM — dead-letter.
|
|
1828
|
-
if (!knownDomains(eng).has(dom)) {
|
|
1829
|
-
const error = `domain '${dom}' is not deployed to this workspace — deploy its law (POST /v1/workspaces/${ws}/domains with the workspace secret), then POST /v1/workspaces/${ws}/dead-letters/retry`;
|
|
1830
|
-
rejected.push({ oid: oid.slice(0, 10), error, deadLettered: true });
|
|
1831
|
-
deadLetters.push({ intentId, oid: oid.slice(0, 10), session: cid, error, blob, domain: dom, directiveId: dirId });
|
|
1832
|
-
continue;
|
|
1833
|
-
}
|
|
1834
1734
|
// THE RECEIPT FENCE (capability_marketplace.md slice 1.5 — the ratified
|
|
1835
1735
|
// authz condition): a capability RECEIPT (complete/fail/block/deadLetter)
|
|
1836
1736
|
// is an EXECUTOR/OWNER write — the open session lane never folds one, so
|
|
@@ -1984,8 +1884,17 @@ export async function admitAll(eng, ws, ledger, { refuseDomains = [], receiptFen
|
|
|
1984
1884
|
// the ws fs); we then SKIP the branch deletes so every offered intent re-admits next cycle (idempotent by
|
|
1985
1885
|
// id). On success, delete the consumed session branches (best-effort cleanup; a stale branch is a harmless
|
|
1986
1886
|
// re-fetch). Single-client workspaces were already one push/cycle; this collapses collaborative bursts.
|
|
1887
|
+
// THE BAILIFF SEAM: when the HOST asked us to `defer` (the open session admit lane on a
|
|
1888
|
+
// non-coordinator workspace), we DO NOT push or delete consumed branches inline — the fold
|
|
1889
|
+
// is already on resident main (truth), and the host backs it up to custody off the critical
|
|
1890
|
+
// path (engine.backupToCustody, debounced + coalesced). This is sound because the SESSION
|
|
1891
|
+
// BRANCHES are themselves durable in custody (the durable inbox) and admit is idempotent by
|
|
1892
|
+
// intent id: a crash before backup just re-derives the SAME sealed main from the same offers.
|
|
1893
|
+
// Coordinator/sharded admits (any §5.2/§5.4/placement/split follow-up) stay durable-before-ack.
|
|
1894
|
+
const hasCoordination = !!(summaryCtx || placements.length || splits.length || globalsOut.length);
|
|
1895
|
+
const deferDurability = defer && !hasCoordination;
|
|
1987
1896
|
let _sealed = true;
|
|
1988
|
-
if (totalAdmitted) {
|
|
1897
|
+
if (totalAdmitted && !deferDurability) {
|
|
1989
1898
|
const _sealDone = _span(`seal (batch)`, "cseal", 1, { sessions: consumed.length, admitted: totalAdmitted });
|
|
1990
1899
|
const _s = Date.now();
|
|
1991
1900
|
try {
|
|
@@ -1998,7 +1907,7 @@ export async function admitAll(eng, ws, ledger, { refuseDomains = [], receiptFen
|
|
|
1998
1907
|
_sealDone();
|
|
1999
1908
|
}
|
|
2000
1909
|
}
|
|
2001
|
-
if (_sealed) {
|
|
1910
|
+
if (_sealed && !deferDurability) {
|
|
2002
1911
|
for (const { ref } of consumed) {
|
|
2003
1912
|
try { await pushVia(ledger, () => git.push({ fs: eng.fs, http, gitdir, url: ledger.remote, ref: BRANCH, remoteRef: ref, delete: true, headers: ledger.headers })); } catch {}
|
|
2004
1913
|
}
|
|
@@ -2017,9 +1926,33 @@ export async function admitAll(eng, ws, ledger, { refuseDomains = [], receiptFen
|
|
|
2017
1926
|
...(placements.length ? { placements } : {}),
|
|
2018
1927
|
...(splits.length ? { splits } : {}),
|
|
2019
1928
|
...(globalsOut.length ? { globals: globalsOut } : {}),
|
|
1929
|
+
// The host's backup lane consumes these: `deferred` ⇒ resident main carries totalAdmitted
|
|
1930
|
+
// un-backed-up commits and `consumed` are the session branches to delete AFTER the push lands.
|
|
1931
|
+
...(deferDurability && totalAdmitted ? { deferred: true, consumed, admitted: totalAdmitted } : {}),
|
|
2020
1932
|
};
|
|
2021
1933
|
}
|
|
2022
1934
|
|
|
1935
|
+
// THE BAILIFF'S BACKUP — push resident main to custody when quiet, NEVER on a write's critical
|
|
1936
|
+
// path and NEVER destructive. Unlike commitAndPush (durability-before-ack: unmounts on failure),
|
|
1937
|
+
// a failed backup leaves the resident holon mounted and the session branches intact, so the host
|
|
1938
|
+
// just retries on the next quiet tick. Append-only main means an off-lock push of an older head
|
|
1939
|
+
// concurrent with a fresh fold is always a sound fast-forward subset (the newer head backs up next).
|
|
1940
|
+
export async function backupToCustody(eng, ws, ledger, { consumed = [] } = {}) {
|
|
1941
|
+
if (!eng.mounted.has(ws)) return { ok: false, error: "not mounted" };
|
|
1942
|
+
const gitdir = gitdirOf(ws);
|
|
1943
|
+
let head = null;
|
|
1944
|
+
try { head = await git.resolveRef({ fs: eng.fs, gitdir, ref: BRANCH }); } catch { return { ok: false, error: "no local main" }; }
|
|
1945
|
+
try {
|
|
1946
|
+
await pushVia(ledger, () => git.push({ fs: eng.fs, http, gitdir, url: ledger.remote, ref: BRANCH, remoteRef: BRANCH, force: false, headers: ledger.headers }));
|
|
1947
|
+
} catch (e) {
|
|
1948
|
+
return { ok: false, error: String(e).slice(0, 200), head };
|
|
1949
|
+
}
|
|
1950
|
+
for (const { ref } of consumed) {
|
|
1951
|
+
try { await pushVia(ledger, () => git.push({ fs: eng.fs, http, gitdir, url: ledger.remote, ref: BRANCH, remoteRef: ref, delete: true, headers: ledger.headers })); } catch {}
|
|
1952
|
+
}
|
|
1953
|
+
return { ok: true, head };
|
|
1954
|
+
}
|
|
1955
|
+
|
|
2023
1956
|
/**
|
|
2024
1957
|
* VERIFY AN UPLOADED LEDGER — "the githolon executes and thus validates it". Fresh-mounts
|
|
2025
1958
|
* the workspace from custody (never a cached mount — the bytes under judgment are the
|
|
@@ -2095,32 +2028,8 @@ export async function deploy(eng, ws, ledger, usda, domainHash, dispositions) {
|
|
|
2095
2028
|
// adjudicates the stable-id diff against. Absent for the common (non-destructive)
|
|
2096
2029
|
// upgrade; the gate's typed refusal names the remedy when one is needed.
|
|
2097
2030
|
const result = author(eng, ws, "nomos", "installDomain", installPayload(domainHash, usda, eng.installedBy, dispositions), eng.hashes.nomos);
|
|
2098
|
-
//
|
|
2099
|
-
//
|
|
2100
|
-
// (`NomosShardIdentity`, law-state in the shard's own chain). The worker is the
|
|
2101
|
-
// bailiff: it records the CUSTODY fact (this workspace's name ⇒ its shard label)
|
|
2102
|
-
// through the chain's own gate right after the law lands — attributed, replayable,
|
|
2103
|
-
// idempotent (an Ensure; re-deploys re-assert the same state). Coordinator ⇒ label ""
|
|
2104
|
-
// (no homing claim — the invariant holds vacuously there).
|
|
2105
|
-
try {
|
|
2106
|
-
eng.directiveRoutesCache = null; // the just-staged overlay may add routes
|
|
2107
|
-
const routed = new Set([...directiveRoutes(eng).keys()].map((k) => k.split(" ")[0]));
|
|
2108
|
-
if (routed.size) {
|
|
2109
|
-
const m = ws.match(/^(.*)--(s\d+)$/);
|
|
2110
|
-
const label = m ? m[2] : "";
|
|
2111
|
-
const coordinator = m ? m[1] : ws;
|
|
2112
|
-
const existing = qById(eng, ws, "nomos-shard-identity:self");
|
|
2113
|
-
const current = existing.length ? existing[0].data : null;
|
|
2114
|
-
if (!current || current.label !== label || current.coordinator !== coordinator) {
|
|
2115
|
-
for (const dom of routed) {
|
|
2116
|
-
try {
|
|
2117
|
-
const declared = author(eng, ws, dom, "nomosDeclareShardIdentity", { label, coordinator, declaredAt: new Date().toISOString() }, domainHash);
|
|
2118
|
-
if (declared && declared.ok !== false) break; // one declaration IS the workspace's identity
|
|
2119
|
-
} catch {} // a routed domain owned by an earlier law: its own deploy declared it
|
|
2120
|
-
}
|
|
2121
|
-
}
|
|
2122
|
-
}
|
|
2123
|
-
} catch {}
|
|
2031
|
+
// Shard identity used to be inferred from host-side taxonomy. That is retired:
|
|
2032
|
+
// if sharding needs declaration, the holon must derive and author it itself.
|
|
2124
2033
|
await commitAndPush(eng, ws, ledger);
|
|
2125
2034
|
return { head: result.head, installation: qById(eng, ws, `domain-installation:${domainHash}`) };
|
|
2126
2035
|
}
|