@githolon/dsl 0.103.9 → 0.103.10

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/dart/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ ## 0.64.10
2
+
3
+ - Single-flight each generated child open on the process-wide kernel plane, reuse resident sibling custody
4
+ for foreign reads, and restore every generated child from framework-owned local custody before consulting
5
+ cloud transport. Typed kernel refusals and the offer gate remain the only authority path.
6
+
7
+ ## 0.64.9
8
+
9
+ - Cache the installed structural law interface across generated domain binding, eliminating repeated
10
+ full-interface kernel reads while retaining governed invalidation on replay and law changes.
11
+
1
12
  ## 0.64.8
2
13
 
3
14
  - Deduplicate structurally identical workspace and application status snapshots while still seeding every
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // <define:__NOMOS_KERNEL_RELEASE__>
4
- var define_NOMOS_KERNEL_RELEASE_default = { production: { hash: "b40b537a66fe971c86ace3e0f8f2c1ff4087bdb0f7e50d2c9e5d5798633f41a6", version: "kernel-b40b537a", features: ["compoundKeys", "capturedReads", "invariantGate", "surfacedMerge", "fieldProvenance", "nullSemantics", "attestedReads", "conflictSnapshots", "ownedAudience"], protocol: 1 }, testMint: { hash: "fd8eeca068dabc11c84825a181062df5958fb9322c945e623753494f760fdc37", version: "kernel-fd8eeca0", features: ["compoundKeys", "capturedReads", "invariantGate", "surfacedMerge", "fieldProvenance", "nullSemantics", "attestedReads", "conflictSnapshots", "ownedAudience"], protocol: 1 } };
4
+ var define_NOMOS_KERNEL_RELEASE_default = { production: { hash: "d512065a204a4b5ac59dd8dfc262d98e49d9e47823582a6123351f4668c68c8b", version: "kernel-d512065a", features: ["compoundKeys", "capturedReads", "invariantGate", "surfacedMerge", "fieldProvenance", "nullSemantics", "attestedReads", "conflictSnapshots", "ownedAudience"], protocol: 1 }, testMint: { hash: "1c66f90d98e71f451b5d3505bba09b66694a22674845e2fd499468854c1a0aae", version: "kernel-1c66f90d", features: ["compoundKeys", "capturedReads", "invariantGate", "surfacedMerge", "fieldProvenance", "nullSemantics", "attestedReads", "conflictSnapshots", "ownedAudience"], protocol: 1 } };
5
5
 
6
6
  // runner/node-entry.ts
7
7
  import { createInterface } from "node:readline";
@@ -427,7 +427,15 @@ function createWebviewRunner({ post: post2, openRealm: openRealm2 }) {
427
427
  async refreshCredentials(a) {
428
428
  const rec = pickSession(a);
429
429
  const holon = await liveHolon(rec);
430
- if (typeof holon.refreshAuthToken !== "function") throw new Error("connected holon cannot refresh identity proof in place");
430
+ if (typeof holon.refreshCredentials === "function") {
431
+ const result2 = holon.refreshCredentials({
432
+ ...a.authToken !== void 0 ? { authToken: String(a.authToken) } : {},
433
+ ...a.authorSecret !== void 0 ? { authorSecret: String(a.authorSecret) } : {}
434
+ });
435
+ if (rec.autoStop?.trigger) rec.autoStop.trigger("credential-refresh");
436
+ return result2;
437
+ }
438
+ if (typeof holon.refreshAuthToken !== "function") throw new Error("connected holon cannot refresh credentials in place");
431
439
  const result = holon.refreshAuthToken(String(a.authToken ?? ""));
432
440
  if (rec.autoStop?.trigger) rec.autoStop.trigger("credential-refresh");
433
441
  return result;
@@ -6811,7 +6819,7 @@ function providerOperation(mode, rawFields, workBytes) {
6811
6819
  else throw new Error(`no typed protobuf operation for provider call '${mode}'`);
6812
6820
  return { case: "custody", value: create(CustodyRequestSchema, { operation: custody }) };
6813
6821
  }
6814
- function nmsInternalReportProviderTransport(host, encoded, phases, responseBytes) {
6822
+ function nmsInternalReportProviderTransport(host, encoded, phases, responseBytes, context = {}) {
6815
6823
  const rounded = Object.fromEntries(Object.entries({ encode: encoded.encodeMs, ...phases }).map(([key, value]) => [key, Math.round(value * 1e3) / 1e3]));
6816
6824
  const totalMs = Object.values(rounded).reduce((sum, value) => sum + value, 0);
6817
6825
  const debug2 = globalThis.__NOMOS_PROFILE_TRANSPORT__ === true || globalThis.process?.env?.NOMOS_PROFILE_TRANSPORT === "1";
@@ -6819,10 +6827,13 @@ function nmsInternalReportProviderTransport(host, encoded, phases, responseBytes
6819
6827
  console.warn(`[nomos-transport-perf] ${JSON.stringify({
6820
6828
  host,
6821
6829
  mode: encoded.mode,
6830
+ detail: encoded.detail,
6831
+ requestId: encoded.requestId,
6822
6832
  totalMs: Math.round(totalMs * 1e3) / 1e3,
6823
6833
  phases: rounded,
6824
6834
  requestBytes: encoded.bytes.length,
6825
- responseBytes
6835
+ responseBytes,
6836
+ ...context
6826
6837
  })}`);
6827
6838
  }
6828
6839
  function nmsInternalEncodeProviderCall(mode, fields, workBytes, requestPrefix = "browser") {
@@ -6839,7 +6850,9 @@ function nmsInternalEncodeTypedProviderCall(operation, requestPrefix = "browser"
6839
6850
  requestId,
6840
6851
  operation
6841
6852
  }));
6842
- return { requestId, mode: operation.case || "empty", bytes, encodeMs: monotonicMs() - started };
6853
+ const query = operation.case === "query" ? operation.value.query : void 0;
6854
+ const detail = query?.case === "named" ? `query:named:${String(query.value.operation)}` : query?.case ? `query:${query.case}` : operation.case || "empty";
6855
+ return { requestId, mode: operation.case || "empty", detail, bytes, encodeMs: monotonicMs() - started };
6843
6856
  }
6844
6857
  function nmsInternalDecodeProviderResponse(bytes, requestId, stderr = []) {
6845
6858
  const response = fromBinary(CallResponseSchema, bytes);
@@ -6900,7 +6913,8 @@ function nmsInternalDecodeProviderResponse(bytes, requestId, stderr = []) {
6900
6913
  verdictDecodeUs: Number(result.value.spans.verdictDecodeUs),
6901
6914
  promoteAndCleanupRefsUs: Number(result.value.spans.promoteAndCleanupRefsUs),
6902
6915
  frontierRebuildUs: Number(result.value.spans.frontierRebuildUs),
6903
- frontierStoreUs: Number(result.value.spans.frontierStoreUs)
6916
+ frontierStoreUs: Number(result.value.spans.frontierStoreUs),
6917
+ verification: result.value.spans.verification ? jsVerifyChainDiagnostics(result.value.spans.verification) : void 0
6904
6918
  } : void 0
6905
6919
  });
6906
6920
  case "repoStats":
@@ -6969,7 +6983,15 @@ function jsVerifyChainDiagnostics(diagnostics) {
6969
6983
  typedInstallVerifierUs: Number(step.phases.typedInstallVerifierUs),
6970
6984
  admissionUs: Number(step.phases.admissionUs),
6971
6985
  foldUs: Number(step.phases.foldUs)
6972
- } : void 0
6986
+ } : void 0,
6987
+ engineTimings: step.engineTimings.map((timing) => ({
6988
+ phase: timing.phase,
6989
+ totalUs: Number(timing.totalUs)
6990
+ }))
6991
+ })),
6992
+ engineTimings: diagnostics.engineTimings.map((timing) => ({
6993
+ phase: timing.phase,
6994
+ totalUs: Number(timing.totalUs)
6973
6995
  }))
6974
6996
  };
6975
6997
  }
@@ -7017,7 +7039,7 @@ function nmsInternalParseSnapshot(bytes) {
7017
7039
  return { treeBytes: bytes, ckpt: null, frontier: null, cursor: null, stateRoot: null, syncedBase: null };
7018
7040
  }
7019
7041
  function nmsInternalBuildSnapshot(treeBytes, ckpt, syncedBase) {
7020
- const hasCheckpoint = !!(ckpt && (ckpt.blob || ckpt.frontier || ckpt.cursor && ckpt.stateRoot));
7042
+ const hasCheckpoint = !!(ckpt && (ckpt.blob || ckpt.frontier || ckpt.cursor));
7021
7043
  if (!hasCheckpoint && !syncedBase) return treeBytes;
7022
7044
  return enc2.encode(JSON.stringify({
7023
7045
  v: 2,
@@ -7163,7 +7185,7 @@ function createWasmEnginePlane({ span } = {}) {
7163
7185
  const view = {
7164
7186
  /** The parsed restore checkpoint (so index.mjs can drive checkpoint_import after boot, exactly as before). */
7165
7187
  get restoreCheckpoint() {
7166
- return _ckptBlobStr || _ckptFrontierStr || _ckptCursor && _ckptStateRoot ? { blob: _ckptBlobStr, frontier: _ckptFrontierStr, cursor: _ckptCursor, stateRoot: _ckptStateRoot } : null;
7188
+ return _ckptBlobStr || _ckptFrontierStr || _ckptCursor ? { blob: _ckptBlobStr, frontier: _ckptFrontierStr, cursor: _ckptCursor, stateRoot: _ckptStateRoot } : null;
7167
7189
  },
7168
7190
  /** The converged fork point persisted in the restoreFrom snapshot (null for old/tree-only snapshots). */
7169
7191
  get restoreSyncedBase() {
@@ -7337,7 +7359,7 @@ function createWasmEnginePlane({ span } = {}) {
7337
7359
  const treeBytes = serializeTree(wsDirNode);
7338
7360
  return nmsInternalBuildSnapshot(
7339
7361
  treeBytes,
7340
- ckpt && (ckpt.blob || ckpt.frontier || ckpt.cursor && ckpt.stateRoot) ? ckpt : null,
7362
+ ckpt && (ckpt.blob || ckpt.frontier || ckpt.cursor) ? ckpt : null,
7341
7363
  opts.syncedBase || null
7342
7364
  );
7343
7365
  }
@@ -8605,7 +8627,7 @@ async function connectSingle({ cloud, workspace, clientId, authToken, restoreFro
8605
8627
  if (salvageOnly) allowUnborn = true;
8606
8628
  if (!cloud || !workspace) throw new Error("connect({ cloud, workspace }) required");
8607
8629
  const _fetch = typeof fetchImpl === "function" ? fetchImpl : globalThis.fetch;
8608
- const deviceSecret = authorSecret || "";
8630
+ let deviceSecret = authorSecret || "";
8609
8631
  const base = cloud.replace(/\/+$/, "");
8610
8632
  const localOnly = /^local:\/\//i.test(base);
8611
8633
  const historicSnapshotConfig = historicSnapshots === false ? null : historicSnapshots && typeof historicSnapshots === "object" ? historicSnapshots : {};
@@ -8849,9 +8871,11 @@ ${String(commit).toLowerCase()}`;
8849
8871
  const watchStops = /* @__PURE__ */ new Set();
8850
8872
  let installedLawRowsCache;
8851
8873
  let installedLawCurrentCache;
8852
- const invalidateInstalledLawRows = () => {
8874
+ let installedInterfaceCache;
8875
+ const invalidateInstalledLawMetadata = () => {
8853
8876
  installedLawRowsCache = void 0;
8854
8877
  installedLawCurrentCache = void 0;
8878
+ installedInterfaceCache = void 0;
8855
8879
  };
8856
8880
  let _disposed = false;
8857
8881
  const nudgeWatches = () => {
@@ -9196,10 +9220,13 @@ ${String(commit).toLowerCase()}`;
9196
9220
  const compatGuardWrite = (directiveId, force) => assertWriteShippable(compatState, directiveId, { force, workspace });
9197
9221
  let _lastInterfaceReadError = null;
9198
9222
  const installedInterfaceInner = () => {
9223
+ if (installedInterfaceCache !== void 0) return installedInterfaceCache;
9199
9224
  try {
9200
9225
  const compact2 = JSON.parse(call("query", { queryBytes: qBytes({ op: "interfaceOffer" }) }));
9201
9226
  _lastInterfaceReadError = null;
9202
- return compact2 && typeof compact2 === "object" && !Array.isArray(compact2) && Object.keys(compact2).length ? compact2 : null;
9227
+ const installedInterface = compact2 && typeof compact2 === "object" && !Array.isArray(compact2) && Object.keys(compact2).length ? compact2 : null;
9228
+ installedInterfaceCache = installedInterface;
9229
+ return installedInterface;
9203
9230
  } catch (error) {
9204
9231
  _lastInterfaceReadError = error instanceof Error ? error : new Error(String(error));
9205
9232
  return null;
@@ -9339,7 +9366,7 @@ ${String(commit).toLowerCase()}`;
9339
9366
  }
9340
9367
  }
9341
9368
  }
9342
- invalidateInstalledLawRows();
9369
+ invalidateInstalledLawMetadata();
9343
9370
  nudgeWatches();
9344
9371
  return {
9345
9372
  upToDate: false,
@@ -9481,22 +9508,35 @@ ${String(commit).toLowerCase()}`;
9481
9508
  };
9482
9509
  return err;
9483
9510
  };
9484
- if (ckptBlobStr || ckptFrontierStr || ckptStagedFrontierFile || ckptCursor && ckptStateRoot) {
9511
+ if (ckptBlobStr || ckptFrontierStr || ckptStagedFrontierFile || ckptCursor) {
9485
9512
  const _ckptSpan = span("receive", restoreFrom ? "boot: restore folded state (snapshot)" : "boot: restore checkpoint", "boot");
9513
+ let checkpointResult = null;
9486
9514
  try {
9487
- call("checkpoint_import", {
9515
+ checkpointResult = JSON.parse(call("checkpoint_import", {
9488
9516
  ...ckptBlobStr ? { blob: ckptBlobStr } : {},
9489
9517
  ...ckptFrontierStr ? { frontier: ckptFrontierStr } : {},
9490
9518
  ...ckptStagedFrontierFile ? { stagedFrontierFile: ckptStagedFrontierFile } : {},
9491
9519
  ...ckptCursor ? { cursor: ckptCursor } : {},
9492
- ...ckptStateRoot ? { stateRoot: ckptStateRoot } : {}
9493
- });
9520
+ ...ckptStateRoot ? { stateRoot: ckptStateRoot } : {},
9521
+ // Cold-open latency is a public runtime property. Ask the kernel for
9522
+ // its bounded phase table so tenant tooling can distinguish custody,
9523
+ // schema, SQLite hydration and policy-cache work without profiling the
9524
+ // opaque host bridge or weakening the kernel boundary.
9525
+ spans: true
9526
+ }));
9494
9527
  } catch (error) {
9495
9528
  if (typeof process !== "undefined" && process.env?.NOMOS_DEBUG_RAW) {
9496
9529
  console.error("[nomos] checkpoint restore refused", error);
9497
9530
  }
9498
9531
  }
9499
- _ckptSpan.end();
9532
+ _ckptSpan.end(checkpointResult ? {
9533
+ restored: checkpointResult.restored,
9534
+ reason: checkpointResult.reason,
9535
+ aggregates: checkpointResult.aggregates,
9536
+ readOnly: checkpointResult.readOnly,
9537
+ lazyReadIndex: checkpointResult.lazyReadIndex,
9538
+ kernelSpans: checkpointResult.kernelSpans
9539
+ } : {});
9500
9540
  }
9501
9541
  const remoteUnavailableAtConnect = (cause) => {
9502
9542
  const msg = String(cause?.message || cause);
@@ -9972,7 +10012,7 @@ ${String(commit).toLowerCase()}`;
9972
10012
  affected = Array.isArray(res.affected) ? res.affected : [];
9973
10013
  }
9974
10014
  if ((domain === "nomos" || domain === "bootstrap") && ["installDomain", "stageDomain", "promoteDomain", "rollbackDomain"].includes(directiveId)) {
9975
- invalidateInstalledLawRows();
10015
+ invalidateInstalledLawMetadata();
9976
10016
  }
9977
10017
  scheduleMaintenanceSoon();
9978
10018
  nudgeWatchesSoon();
@@ -12617,6 +12657,29 @@ ${String(commit).toLowerCase()}`;
12617
12657
  authHeaders = packAuthHeaders({ authToken: activeAuthToken, principal: connectionPrincipal });
12618
12658
  return { refreshed: true };
12619
12659
  },
12660
+ /** Refresh the client-held identity proof and/or default signing key without disposing, remounting or
12661
+ * refolding this resident holon. The kernel remains the authority: changing the client key grants
12662
+ * nothing; the next offer still has to prove that key is enrolled under the workspace law. */
12663
+ refreshCredentials: ({ authToken: token, authorSecret: secret } = {}) => {
12664
+ if (token !== void 0) {
12665
+ const next = typeof token === "string" ? token.trim() : "";
12666
+ if (next) {
12667
+ const subjectClaim = jwtClaim(next, "sub");
12668
+ const nextSubject = canonicalPrincipal(
12669
+ typeof subjectClaim === "string" ? subjectClaim : ""
12670
+ );
12671
+ if (!nextSubject || nextSubject !== connectionPrincipal) {
12672
+ throw new Error("credential refresh changed the signed-in identity; reopen the application explicitly");
12673
+ }
12674
+ }
12675
+ activeAuthToken = next;
12676
+ authHeaders = packAuthHeaders({ authToken: activeAuthToken, principal: connectionPrincipal });
12677
+ }
12678
+ if (secret !== void 0) {
12679
+ deviceSecret = typeof secret === "string" ? secret.trim() : "";
12680
+ }
12681
+ return { refreshed: true };
12682
+ },
12620
12683
  /**
12621
12684
  * THE ONE ENCODER as the public offer entrypoint. A generated client (TS or Dart-via-bridge) calls THIS
12622
12685
  * with the planned payload + the verified `actor` — it NEVER re-encodes the v2 envelope itself. The bytes
@@ -6,7 +6,7 @@ var __export = (target, all) => {
6
6
  };
7
7
 
8
8
  // <define:__NOMOS_KERNEL_RELEASE__>
9
- var define_NOMOS_KERNEL_RELEASE_default = { production: { hash: "b40b537a66fe971c86ace3e0f8f2c1ff4087bdb0f7e50d2c9e5d5798633f41a6", version: "kernel-b40b537a", features: ["compoundKeys", "capturedReads", "invariantGate", "surfacedMerge", "fieldProvenance", "nullSemantics", "attestedReads", "conflictSnapshots", "ownedAudience"], protocol: 1 }, testMint: { hash: "fd8eeca068dabc11c84825a181062df5958fb9322c945e623753494f760fdc37", version: "kernel-fd8eeca0", features: ["compoundKeys", "capturedReads", "invariantGate", "surfacedMerge", "fieldProvenance", "nullSemantics", "attestedReads", "conflictSnapshots", "ownedAudience"], protocol: 1 } };
9
+ var define_NOMOS_KERNEL_RELEASE_default = { production: { hash: "d512065a204a4b5ac59dd8dfc262d98e49d9e47823582a6123351f4668c68c8b", version: "kernel-d512065a", features: ["compoundKeys", "capturedReads", "invariantGate", "surfacedMerge", "fieldProvenance", "nullSemantics", "attestedReads", "conflictSnapshots", "ownedAudience"], protocol: 1 }, testMint: { hash: "1c66f90d98e71f451b5d3505bba09b66694a22674845e2fd499468854c1a0aae", version: "kernel-1c66f90d", features: ["compoundKeys", "capturedReads", "invariantGate", "surfacedMerge", "fieldProvenance", "nullSemantics", "attestedReads", "conflictSnapshots", "ownedAudience"], protocol: 1 } };
10
10
 
11
11
  // runner/offline-install.ts
12
12
  import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync } from "node:fs";
@@ -8817,7 +8817,7 @@ async function countRemoteCommits(eng2, ledger) {
8817
8817
  }
8818
8818
  }
8819
8819
  }
8820
- var projectionStats = (eng2, ws) => namedQueryProto(eng2, ws || "root", QueryOperation.PROJECTION_STATS);
8820
+ var projectionStats = (eng2, ws = "root", options = {}) => namedQueryProto(eng2, ws || "root", QueryOperation.PROJECTION_STATS, options.deep ? { deep: true } : {});
8821
8821
  var memoryDropProbe = (eng2, ws) => namedQueryProto(eng2, ws, QueryOperation.MEMORY_DROP_PROBE);
8822
8822
  var readiness = (eng2, ws) => namedQueryProto(eng2, ws, QueryOperation.READINESS);
8823
8823
  function warmEngine(eng2, opts = {}) {
@@ -1176,6 +1176,15 @@ class NomosSessionCredentials {
1176
1176
  });
1177
1177
  }
1178
1178
 
1179
+ /// Framework-owned local custody lookup for generated child workspaces.
1180
+ ///
1181
+ /// The callback returns an opaque snapshot string. The bridge never interprets
1182
+ /// it; the kernel authenticates and restores it through the ordinary connect
1183
+ /// path. Keeping this hook on the process-wide bridge lets every generated
1184
+ /// child share the root scope's persistence lifecycle without giving tenant
1185
+ /// code another repository or workspace-opening API.
1186
+ typedef NomosLocalCustodyLoader = Future<String?> Function(String workspace);
1187
+
1179
1188
  final class _NomosRetainedCloudAccess {
1180
1189
  final String cloud;
1181
1190
  final Future<String?> Function() signIn;
@@ -1258,6 +1267,7 @@ class NomosBridge {
1258
1267
  // without asking tenant code for cloud URLs, tokens, sessions or signing keys. Kept per source
1259
1268
  // session so one local plane may safely host applications from different clouds/identities.
1260
1269
  final Map<String, _NomosRetainedCloudAccess> _sessionCloudAccess = {};
1270
+ NomosLocalCustodyLoader? _localCustodyLoader;
1261
1271
  // One model-decision policy follows the generated application through its
1262
1272
  // child sessions. The callback receives only the typed review object; child
1263
1273
  // addresses, archives, credentials and lifecycle directives remain private.
@@ -2353,6 +2363,27 @@ class NomosBridge {
2353
2363
  }
2354
2364
  return ready(session(workspace));
2355
2365
  }
2366
+ String? restoreFrom;
2367
+ final loadLocalCustody = plane._localCustodyLoader;
2368
+ if (loadLocalCustody != null) {
2369
+ try {
2370
+ restoreFrom = await loadLocalCustody(workspace);
2371
+ } catch (_) {
2372
+ // A cache-store failure is absence, never authority. The ordinary
2373
+ // cloud open below remains the correctness path.
2374
+ restoreFrom = null;
2375
+ }
2376
+ }
2377
+ if (ifAbsentCredentials == null && restoreFrom != null) {
2378
+ await connect(
2379
+ workspace: workspace,
2380
+ session: workspace,
2381
+ authorSecret: authorSecret,
2382
+ restoreFrom: restoreFrom,
2383
+ allowUnborn: true,
2384
+ );
2385
+ return ready(session(workspace));
2386
+ }
2356
2387
  if (ifAbsentCredentials == null) {
2357
2388
  throw StateError(
2358
2389
  'acquireSession("$workspace"): the workspace is not on this device\'s plane and no '
@@ -2366,6 +2397,7 @@ class NomosBridge {
2366
2397
  clientId: c.clientId,
2367
2398
  authToken: c.authToken,
2368
2399
  authorSecret: c.authorSecret ?? authorSecret,
2400
+ restoreFrom: restoreFrom,
2369
2401
  allowUnborn: c.allowUnborn,
2370
2402
  );
2371
2403
  return ready(session(workspace));
@@ -2376,6 +2408,16 @@ class NomosBridge {
2376
2408
  });
2377
2409
  }
2378
2410
 
2411
+ /// @internal Attach the generated application's opaque local-custody store
2412
+ /// to this process-wide plane. Child opens consult it before cloning from
2413
+ /// cloud; the kernel remains the only component that can authenticate or
2414
+ /// interpret the returned bytes.
2415
+ void nomosInternalRetainLocalCustodyLoader(
2416
+ NomosLocalCustodyLoader loader,
2417
+ ) {
2418
+ _eventPlane._localCustodyLoader = loader;
2419
+ }
2420
+
2379
2421
  /// Reserve a KERNEL-MINTED typed id (`<TypeTag>_<uuidv7>`) via the holon's front-door mint — for app-side
2380
2422
  /// references (routing keys, optimistic UI). `.creates` payloads still carry NO id: the LAW mints those
2381
2423
  /// (see [offerCreates], which returns them).
@@ -2383,6 +2425,29 @@ class NomosBridge {
2383
2425
  (_asMap(await _call('mintId', {'typeTag': typeTag}))['id'] ?? '')
2384
2426
  .toString();
2385
2427
 
2428
+ /// Refresh client-held credentials on this already-open workspace without
2429
+ /// replacing its resident holon or refolding custody. This grants no
2430
+ /// authority: every offer is still judged by the kernel's author gate.
2431
+ Future<void> refreshCredentials(
2432
+ {String? authToken, String? authorSecret}) async {
2433
+ if (authToken == null && authorSecret == null) return;
2434
+ await _call('refreshCredentials', {
2435
+ if (authToken != null) 'authToken': authToken,
2436
+ if (authorSecret != null) 'authorSecret': authorSecret,
2437
+ });
2438
+ // The resident holon and the plane's future-child template advance
2439
+ // together. Otherwise home signs correctly after first-device enrolment
2440
+ // while a later catalogue/estate opens with the old empty default key.
2441
+ final session = _sessionName;
2442
+ if (session != null && authorSecret != null) {
2443
+ if (authorSecret.isEmpty) {
2444
+ _eventPlane._sessionAuthorSecrets.remove(session);
2445
+ } else {
2446
+ _eventPlane._sessionAuthorSecrets[session] = authorSecret;
2447
+ }
2448
+ }
2449
+ }
2450
+
2386
2451
  /// @internal The immutable genesis of a sibling custody chain. This is observational metadata used to
2387
2452
  /// compose an ordinary source-enrolment offer; the kernel still reopens and proves every foreign read.
2388
2453
  Future<String> nomosWorkspaceGenesis(String workspace,
package/dart/pubspec.yaml CHANGED
@@ -7,7 +7,7 @@ repository: https://github.com/Captain-App/nomos2
7
7
  description: >-
8
8
  Nomos 2 Dart client — generated domain values, intent payloads and application
9
9
  lifecycle types over the typed Nomos kernel protocol and USDA custody model.
10
- version: 0.64.8
10
+ version: 0.64.10
11
11
 
12
12
  environment:
13
13
  sdk: ^3.5.0
@@ -167,6 +167,54 @@ void main() {
167
167
  await bridge.dispose();
168
168
  });
169
169
 
170
+ test(
171
+ 'an absent generated child restores opaque local custody before cloud convergence',
172
+ () async {
173
+ final runner = FakeRunner();
174
+ final bridge = NomosBridge(runner);
175
+ await bridge.ready;
176
+ var loads = 0;
177
+ bridge.nomosInternalRetainLocalCustodyLoader((workspace) async {
178
+ loads++;
179
+ expect(workspace, 'catalogue');
180
+ return 'opaque-kernel-snapshot';
181
+ });
182
+
183
+ final child = await bridge.acquireSession(
184
+ 'catalogue',
185
+ ifAbsentCredentials: () async => const NomosSessionCredentials(
186
+ cloud: 'https://cloud.example',
187
+ authToken: 'token',
188
+ ),
189
+ );
190
+
191
+ expect(child.workspace, 'catalogue');
192
+ expect(loads, 1);
193
+ expect(runner.connectCount, 1);
194
+ expect(runner.connectArgs(0)['restoreFrom'], 'opaque-kernel-snapshot');
195
+ expect(runner.connectArgs(0)['cloud'], 'https://cloud.example');
196
+ await bridge.dispose();
197
+ });
198
+
199
+ test('opaque local custody can open without inventing cloud authority',
200
+ () async {
201
+ final runner = FakeRunner();
202
+ final bridge = NomosBridge(runner);
203
+ await bridge.ready;
204
+ bridge.nomosInternalRetainLocalCustodyLoader(
205
+ (_) async => 'opaque-kernel-snapshot',
206
+ );
207
+
208
+ final child = await bridge.acquireSession('offline-child');
209
+
210
+ expect(child.workspace, 'offline-child');
211
+ expect(runner.connectCount, 1);
212
+ final args = runner.connectArgs(0);
213
+ expect(args['restoreFrom'], 'opaque-kernel-snapshot');
214
+ expect(args.containsKey('cloud'), isFalse);
215
+ await bridge.dispose();
216
+ });
217
+
170
218
  test(
171
219
  'a NomosSession delegates acquireSession to the parent plane (one registry)',
172
220
  () async {
@@ -199,6 +247,31 @@ void main() {
199
247
  await bridge.dispose();
200
248
  });
201
249
 
250
+ test('an in-place signing-key refresh is inherited by later sibling opens',
251
+ () async {
252
+ final runner = FakeRunner(resident: ['catalogue', 'estate']);
253
+ final bridge = NomosBridge(runner);
254
+ await bridge.ready;
255
+ await bridge.connect(workspace: 'home', session: 'home');
256
+
257
+ await bridge
258
+ .session('home')
259
+ .refreshCredentials(authorSecret: 'newly-enrolled-device-key');
260
+ await bridge.session('home').acquireSession('catalogue');
261
+
262
+ expect(runner.connectCount, 2);
263
+ expect(runner.connectArgs(1)['authorSecret'], 'newly-enrolled-device-key',
264
+ reason:
265
+ 'refreshing the resident holon must also advance the plane credential inherited by siblings');
266
+
267
+ await bridge.session('home').refreshCredentials(authorSecret: '');
268
+ await bridge.session('home').acquireSession('estate');
269
+ expect(runner.connectArgs(2).containsKey('authorSecret'), isFalse,
270
+ reason:
271
+ 'clearing a resident signing key must not leak it into later sibling opens');
272
+ await bridge.dispose();
273
+ });
274
+
202
275
  test(
203
276
  'generated child inherits typed model decisions and stages opaque USDZ privately',
204
277
  () async {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@githolon/dsl",
3
- "version": "0.103.9",
3
+ "version": "0.103.10",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "description": "Nomos 2 domain-authoring DSL: aggregates + directives in TS, executed and encoded to the Rust kernel's wire shapes.",
@@ -5870,7 +5870,7 @@ function providerOperation(mode, rawFields, workBytes) {
5870
5870
  else throw new Error(`no typed protobuf operation for provider call '${mode}'`);
5871
5871
  return { case: "custody", value: create(CustodyRequestSchema, { operation: custody }) };
5872
5872
  }
5873
- function nmsInternalReportProviderTransport(host, encoded, phases, responseBytes) {
5873
+ function nmsInternalReportProviderTransport(host, encoded, phases, responseBytes, context = {}) {
5874
5874
  const rounded = Object.fromEntries(Object.entries({ encode: encoded.encodeMs, ...phases }).map(([key, value]) => [key, Math.round(value * 1e3) / 1e3]));
5875
5875
  const totalMs = Object.values(rounded).reduce((sum, value) => sum + value, 0);
5876
5876
  const debug2 = globalThis.__NOMOS_PROFILE_TRANSPORT__ === true || globalThis.process?.env?.NOMOS_PROFILE_TRANSPORT === "1";
@@ -5878,10 +5878,13 @@ function nmsInternalReportProviderTransport(host, encoded, phases, responseBytes
5878
5878
  console.warn(`[nomos-transport-perf] ${JSON.stringify({
5879
5879
  host,
5880
5880
  mode: encoded.mode,
5881
+ detail: encoded.detail,
5882
+ requestId: encoded.requestId,
5881
5883
  totalMs: Math.round(totalMs * 1e3) / 1e3,
5882
5884
  phases: rounded,
5883
5885
  requestBytes: encoded.bytes.length,
5884
- responseBytes
5886
+ responseBytes,
5887
+ ...context
5885
5888
  })}`);
5886
5889
  }
5887
5890
  function nmsInternalEncodeProviderCall(mode, fields, workBytes, requestPrefix = "browser") {
@@ -5898,7 +5901,9 @@ function nmsInternalEncodeTypedProviderCall(operation, requestPrefix = "browser"
5898
5901
  requestId,
5899
5902
  operation
5900
5903
  }));
5901
- return { requestId, mode: operation.case || "empty", bytes, encodeMs: monotonicMs() - started };
5904
+ const query = operation.case === "query" ? operation.value.query : void 0;
5905
+ const detail = query?.case === "named" ? `query:named:${String(query.value.operation)}` : query?.case ? `query:${query.case}` : operation.case || "empty";
5906
+ return { requestId, mode: operation.case || "empty", detail, bytes, encodeMs: monotonicMs() - started };
5902
5907
  }
5903
5908
  function nmsInternalDecodeProviderResponse(bytes, requestId, stderr = []) {
5904
5909
  const response = fromBinary(CallResponseSchema, bytes);
@@ -5959,7 +5964,8 @@ function nmsInternalDecodeProviderResponse(bytes, requestId, stderr = []) {
5959
5964
  verdictDecodeUs: Number(result.value.spans.verdictDecodeUs),
5960
5965
  promoteAndCleanupRefsUs: Number(result.value.spans.promoteAndCleanupRefsUs),
5961
5966
  frontierRebuildUs: Number(result.value.spans.frontierRebuildUs),
5962
- frontierStoreUs: Number(result.value.spans.frontierStoreUs)
5967
+ frontierStoreUs: Number(result.value.spans.frontierStoreUs),
5968
+ verification: result.value.spans.verification ? jsVerifyChainDiagnostics(result.value.spans.verification) : void 0
5963
5969
  } : void 0
5964
5970
  });
5965
5971
  case "repoStats":
@@ -6028,7 +6034,15 @@ function jsVerifyChainDiagnostics(diagnostics) {
6028
6034
  typedInstallVerifierUs: Number(step.phases.typedInstallVerifierUs),
6029
6035
  admissionUs: Number(step.phases.admissionUs),
6030
6036
  foldUs: Number(step.phases.foldUs)
6031
- } : void 0
6037
+ } : void 0,
6038
+ engineTimings: step.engineTimings.map((timing) => ({
6039
+ phase: timing.phase,
6040
+ totalUs: Number(timing.totalUs)
6041
+ }))
6042
+ })),
6043
+ engineTimings: diagnostics.engineTimings.map((timing) => ({
6044
+ phase: timing.phase,
6045
+ totalUs: Number(timing.totalUs)
6032
6046
  }))
6033
6047
  };
6034
6048
  }
@@ -6076,7 +6090,7 @@ function nmsInternalParseSnapshot(bytes) {
6076
6090
  return { treeBytes: bytes, ckpt: null, frontier: null, cursor: null, stateRoot: null, syncedBase: null };
6077
6091
  }
6078
6092
  function nmsInternalBuildSnapshot(treeBytes, ckpt, syncedBase) {
6079
- const hasCheckpoint = !!(ckpt && (ckpt.blob || ckpt.frontier || ckpt.cursor && ckpt.stateRoot));
6093
+ const hasCheckpoint = !!(ckpt && (ckpt.blob || ckpt.frontier || ckpt.cursor));
6080
6094
  if (!hasCheckpoint && !syncedBase) return treeBytes;
6081
6095
  return enc2.encode(JSON.stringify({
6082
6096
  v: 2,
@@ -6222,7 +6236,7 @@ function createWasmEnginePlane({ span } = {}) {
6222
6236
  const view = {
6223
6237
  /** The parsed restore checkpoint (so index.mjs can drive checkpoint_import after boot, exactly as before). */
6224
6238
  get restoreCheckpoint() {
6225
- return _ckptBlobStr || _ckptFrontierStr || _ckptCursor && _ckptStateRoot ? { blob: _ckptBlobStr, frontier: _ckptFrontierStr, cursor: _ckptCursor, stateRoot: _ckptStateRoot } : null;
6239
+ return _ckptBlobStr || _ckptFrontierStr || _ckptCursor ? { blob: _ckptBlobStr, frontier: _ckptFrontierStr, cursor: _ckptCursor, stateRoot: _ckptStateRoot } : null;
6226
6240
  },
6227
6241
  /** The converged fork point persisted in the restoreFrom snapshot (null for old/tree-only snapshots). */
6228
6242
  get restoreSyncedBase() {
@@ -6396,7 +6410,7 @@ function createWasmEnginePlane({ span } = {}) {
6396
6410
  const treeBytes = serializeTree(wsDirNode);
6397
6411
  return nmsInternalBuildSnapshot(
6398
6412
  treeBytes,
6399
- ckpt && (ckpt.blob || ckpt.frontier || ckpt.cursor && ckpt.stateRoot) ? ckpt : null,
6413
+ ckpt && (ckpt.blob || ckpt.frontier || ckpt.cursor) ? ckpt : null,
6400
6414
  opts.syncedBase || null
6401
6415
  );
6402
6416
  }
@@ -7664,7 +7678,7 @@ async function connectSingle({ cloud, workspace, clientId, authToken, restoreFro
7664
7678
  if (salvageOnly) allowUnborn = true;
7665
7679
  if (!cloud || !workspace) throw new Error("connect({ cloud, workspace }) required");
7666
7680
  const _fetch = typeof fetchImpl === "function" ? fetchImpl : globalThis.fetch;
7667
- const deviceSecret = authorSecret || "";
7681
+ let deviceSecret = authorSecret || "";
7668
7682
  const base = cloud.replace(/\/+$/, "");
7669
7683
  const localOnly = /^local:\/\//i.test(base);
7670
7684
  const historicSnapshotConfig = historicSnapshots === false ? null : historicSnapshots && typeof historicSnapshots === "object" ? historicSnapshots : {};
@@ -7908,9 +7922,11 @@ ${String(commit).toLowerCase()}`;
7908
7922
  const watchStops = /* @__PURE__ */ new Set();
7909
7923
  let installedLawRowsCache;
7910
7924
  let installedLawCurrentCache;
7911
- const invalidateInstalledLawRows = () => {
7925
+ let installedInterfaceCache;
7926
+ const invalidateInstalledLawMetadata = () => {
7912
7927
  installedLawRowsCache = void 0;
7913
7928
  installedLawCurrentCache = void 0;
7929
+ installedInterfaceCache = void 0;
7914
7930
  };
7915
7931
  let _disposed = false;
7916
7932
  const nudgeWatches = () => {
@@ -8255,10 +8271,13 @@ ${String(commit).toLowerCase()}`;
8255
8271
  const compatGuardWrite = (directiveId, force) => assertWriteShippable(compatState, directiveId, { force, workspace });
8256
8272
  let _lastInterfaceReadError = null;
8257
8273
  const installedInterfaceInner = () => {
8274
+ if (installedInterfaceCache !== void 0) return installedInterfaceCache;
8258
8275
  try {
8259
8276
  const compact = JSON.parse(call("query", { queryBytes: qBytes({ op: "interfaceOffer" }) }));
8260
8277
  _lastInterfaceReadError = null;
8261
- return compact && typeof compact === "object" && !Array.isArray(compact) && Object.keys(compact).length ? compact : null;
8278
+ const installedInterface = compact && typeof compact === "object" && !Array.isArray(compact) && Object.keys(compact).length ? compact : null;
8279
+ installedInterfaceCache = installedInterface;
8280
+ return installedInterface;
8262
8281
  } catch (error) {
8263
8282
  _lastInterfaceReadError = error instanceof Error ? error : new Error(String(error));
8264
8283
  return null;
@@ -8398,7 +8417,7 @@ ${String(commit).toLowerCase()}`;
8398
8417
  }
8399
8418
  }
8400
8419
  }
8401
- invalidateInstalledLawRows();
8420
+ invalidateInstalledLawMetadata();
8402
8421
  nudgeWatches();
8403
8422
  return {
8404
8423
  upToDate: false,
@@ -8540,22 +8559,35 @@ ${String(commit).toLowerCase()}`;
8540
8559
  };
8541
8560
  return err;
8542
8561
  };
8543
- if (ckptBlobStr || ckptFrontierStr || ckptStagedFrontierFile || ckptCursor && ckptStateRoot) {
8562
+ if (ckptBlobStr || ckptFrontierStr || ckptStagedFrontierFile || ckptCursor) {
8544
8563
  const _ckptSpan = span("receive", restoreFrom ? "boot: restore folded state (snapshot)" : "boot: restore checkpoint", "boot");
8564
+ let checkpointResult = null;
8545
8565
  try {
8546
- call("checkpoint_import", {
8566
+ checkpointResult = JSON.parse(call("checkpoint_import", {
8547
8567
  ...ckptBlobStr ? { blob: ckptBlobStr } : {},
8548
8568
  ...ckptFrontierStr ? { frontier: ckptFrontierStr } : {},
8549
8569
  ...ckptStagedFrontierFile ? { stagedFrontierFile: ckptStagedFrontierFile } : {},
8550
8570
  ...ckptCursor ? { cursor: ckptCursor } : {},
8551
- ...ckptStateRoot ? { stateRoot: ckptStateRoot } : {}
8552
- });
8571
+ ...ckptStateRoot ? { stateRoot: ckptStateRoot } : {},
8572
+ // Cold-open latency is a public runtime property. Ask the kernel for
8573
+ // its bounded phase table so tenant tooling can distinguish custody,
8574
+ // schema, SQLite hydration and policy-cache work without profiling the
8575
+ // opaque host bridge or weakening the kernel boundary.
8576
+ spans: true
8577
+ }));
8553
8578
  } catch (error) {
8554
8579
  if (typeof process !== "undefined" && process.env?.NOMOS_DEBUG_RAW) {
8555
8580
  console.error("[nomos] checkpoint restore refused", error);
8556
8581
  }
8557
8582
  }
8558
- _ckptSpan.end();
8583
+ _ckptSpan.end(checkpointResult ? {
8584
+ restored: checkpointResult.restored,
8585
+ reason: checkpointResult.reason,
8586
+ aggregates: checkpointResult.aggregates,
8587
+ readOnly: checkpointResult.readOnly,
8588
+ lazyReadIndex: checkpointResult.lazyReadIndex,
8589
+ kernelSpans: checkpointResult.kernelSpans
8590
+ } : {});
8559
8591
  }
8560
8592
  const remoteUnavailableAtConnect = (cause) => {
8561
8593
  const msg = String(cause?.message || cause);
@@ -9031,7 +9063,7 @@ ${String(commit).toLowerCase()}`;
9031
9063
  affected = Array.isArray(res.affected) ? res.affected : [];
9032
9064
  }
9033
9065
  if ((domain === "nomos" || domain === "bootstrap") && ["installDomain", "stageDomain", "promoteDomain", "rollbackDomain"].includes(directiveId)) {
9034
- invalidateInstalledLawRows();
9066
+ invalidateInstalledLawMetadata();
9035
9067
  }
9036
9068
  scheduleMaintenanceSoon();
9037
9069
  nudgeWatchesSoon();
@@ -11676,6 +11708,29 @@ ${String(commit).toLowerCase()}`;
11676
11708
  authHeaders = packAuthHeaders({ authToken: activeAuthToken, principal: connectionPrincipal });
11677
11709
  return { refreshed: true };
11678
11710
  },
11711
+ /** Refresh the client-held identity proof and/or default signing key without disposing, remounting or
11712
+ * refolding this resident holon. The kernel remains the authority: changing the client key grants
11713
+ * nothing; the next offer still has to prove that key is enrolled under the workspace law. */
11714
+ refreshCredentials: ({ authToken: token, authorSecret: secret } = {}) => {
11715
+ if (token !== void 0) {
11716
+ const next = typeof token === "string" ? token.trim() : "";
11717
+ if (next) {
11718
+ const subjectClaim = jwtClaim(next, "sub");
11719
+ const nextSubject = canonicalPrincipal(
11720
+ typeof subjectClaim === "string" ? subjectClaim : ""
11721
+ );
11722
+ if (!nextSubject || nextSubject !== connectionPrincipal) {
11723
+ throw new Error("credential refresh changed the signed-in identity; reopen the application explicitly");
11724
+ }
11725
+ }
11726
+ activeAuthToken = next;
11727
+ authHeaders = packAuthHeaders({ authToken: activeAuthToken, principal: connectionPrincipal });
11728
+ }
11729
+ if (secret !== void 0) {
11730
+ deviceSecret = typeof secret === "string" ? secret.trim() : "";
11731
+ }
11732
+ return { refreshed: true };
11733
+ },
11679
11734
  /**
11680
11735
  * THE ONE ENCODER as the public offer entrypoint. A generated client (TS or Dart-via-bridge) calls THIS
11681
11736
  * with the planned payload + the verified `actor` — it NEVER re-encodes the v2 envelope itself. The bytes
@@ -1650,8 +1650,8 @@ const NOMOS_TYPES_DEP = "^0.8.4";
1650
1650
  // 0.48.x: session-bound clients (XClient.bind/NomosClientInterface/DomainClientSessionMismatch/
1651
1651
  // DomainNotInstalledForSession, engine.follow, pendingConflicts lanes) — the generated client
1652
1652
  // REQUIRES this surface. 0.48.1 fixes NomosSession.watchPendingConflicts delegation.
1653
- const NOMOS_CLIENT_DEP = "^0.64.8";
1654
- const NOMOS_FLUTTER_DEP = "^0.63.11";
1653
+ const NOMOS_CLIENT_DEP = "^0.64.10";
1654
+ const NOMOS_FLUTTER_DEP = "^0.63.13";
1655
1655
  // DRIFT TRIPWIRE: pubspec_pins.test.ts asserts these equal the CURRENT versions in dsl/dart/pubspec.yaml
1656
1656
  // and dsl/dart_types/pubspec.yaml — a Dart release without this bump fails the suite, so tenants never
1657
1657
  // land back in dependency_overrides (the exact co2 report this closes, third occurrence).