@githolon/dsl 0.107.4 → 0.108.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/dart/CHANGELOG.md +24 -0
  2. package/dart/lib/src/application_framework_calls.dart +299 -0
  3. package/dart/lib/src/generated_call.dart +96 -0
  4. package/dart/lib/src/nms_generated_runtime.dart +29 -0
  5. package/dart/lib/src/node_runner_transport.dart +77 -1
  6. package/dart/lib/src/result_usda.dart +487 -0
  7. package/dart/lib/src/runner/node-entry.mjs +10634 -6122
  8. package/dart/lib/src/runner/offline-install.mjs +4187 -2716
  9. package/dart/lib/src/runtime_v2_gateway.dart +54 -0
  10. package/dart/lib/src/runtime_v2_transport.dart +117 -0
  11. package/dart/lib/src/session_bound.dart +7 -2
  12. package/dart/lib/src/test_harness.dart +373 -282
  13. package/dart/lib/src/webview_bridge.dart +2146 -725
  14. package/dart/pubspec.lock +17 -1
  15. package/dart/pubspec.yaml +3 -2
  16. package/dart/test/acquire_session_credentials_test.dart +1 -1
  17. package/dart/test/acquire_session_test.dart +68 -14
  18. package/dart/test/adv_realm_interference_test.dart +6 -4
  19. package/dart/test/cluster_births_test.dart +11 -8
  20. package/dart/test/cluster_local_autosync_test.dart +1 -1
  21. package/dart/test/cluster_scale_test.dart +3 -2
  22. package/dart/test/dlq_session_surface_test.dart +52 -35
  23. package/dart/test/first_app_gauntlet_test.dart +1 -1
  24. package/dart/test/local_sync_inert_test.dart +23 -26
  25. package/dart/test/offer_authentication_proof_test.dart +193 -0
  26. package/dart/test/result_usda_test.dart +49 -0
  27. package/dart/test/session_bound_test.dart +8 -11
  28. package/dart/test/stale_bundle_test.dart +18 -3
  29. package/dart/test/test_harness_test.dart +14 -27
  30. package/dart/test/webview_bridge_test.dart +504 -83
  31. package/dart_types/CHANGELOG.md +17 -0
  32. package/dart_types/lib/nomos_kernel_protocol.dart +11 -0
  33. package/dart_types/lib/src/custody.dart +64 -19
  34. package/dart_types/lib/src/local_work_rejected.dart +30 -45
  35. package/dart_types/lib/src/proto/nomos/custody/v1/snapshot.pb.dart +169 -0
  36. package/dart_types/lib/src/proto/nomos/custody/v1/snapshot.pbenum.dart +11 -0
  37. package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pb.dart +17945 -0
  38. package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pbenum.dart +933 -0
  39. package/dart_types/lib/src/proto/nomos/kernel/v1/progress.pb.dart +245 -0
  40. package/dart_types/lib/src/proto/nomos/kernel/v1/progress.pbenum.dart +160 -0
  41. package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pb.dart +8664 -0
  42. package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pbenum.dart +369 -0
  43. package/dart_types/lib/src/surfaced.dart +30 -25
  44. package/dart_types/pubspec.lock +16 -0
  45. package/dart_types/pubspec.yaml +3 -1
  46. package/dart_types/test/surfaced_test.dart +2 -1
  47. package/package.json +1 -1
  48. package/runtime/generated-application-host.js +5760 -1879
  49. package/src/authoring.ts +3 -2
  50. package/src/birth_meter_ensure.ts +2 -0
  51. package/src/births.ts +21 -0
  52. package/src/build_package.ts +30 -0
  53. package/src/business_birth.ts +41 -35
  54. package/src/codegen_call_usda.ts +1111 -0
  55. package/src/codegen_dart.ts +207 -282
  56. package/src/codegen_dart_application.ts +195 -252
  57. package/src/codegen_dart_client.ts +1978 -593
  58. package/src/codegen_dart_framework_calls.ts +291 -0
  59. package/src/codegen_dart_scenario.ts +7 -0
  60. package/src/codegen_proof.ts +3 -4
  61. package/src/codegen_provider_dart.ts +21 -7
  62. package/src/codegen_query_usda.ts +214 -0
  63. package/src/codegen_result_usda.ts +685 -0
  64. package/src/codegen_ts.ts +3945 -1111
  65. package/src/compile_package_main.ts +392 -46
  66. package/src/directive.ts +19 -4
  67. package/src/engine_entry.ts +45 -4
  68. package/src/framework/application_home.ts +4 -0
  69. package/src/framework/auth_provider_law.ts +296 -20
  70. package/src/framework/birth_certificate_law.ts +24 -0
  71. package/src/framework/home.ts +83 -40
  72. package/src/framework/owned_custody.ts +25 -12
  73. package/src/framework/owned_custody_value.ts +51 -0
  74. package/src/framework/relations.ts +47 -21
  75. package/src/framework/signing_identity.ts +100 -17
  76. package/src/framework/workspaces.ts +39 -10
  77. package/src/framework_call_definitions.ts +53 -0
  78. package/src/framework_read_definitions.ts +45 -0
  79. package/src/identity_frontier.ts +58 -0
  80. package/src/index.ts +22 -1
  81. package/src/intent.ts +216 -16
  82. package/src/law_check.ts +19 -1
  83. package/src/law_graph.ts +57 -8
  84. package/src/law_graph_usda.ts +73 -5
  85. package/src/law_value_type.ts +106 -19
  86. package/src/read.ts +47 -0
  87. package/src/read_projection_namespace.ts +7 -0
  88. package/src/shape_compat.ts +44 -42
  89. package/src/stable_ids.ts +37 -2
  90. package/src/test_call_usda.ts +83 -0
  91. package/src/wire.ts +36 -2
  92. package/src/wire_encode.ts +45 -1
  93. package/src/workspace_sharing.ts +27 -10
@@ -66,7 +66,9 @@ import type { ContractHandle } from "./contract.js";
66
66
  import { bindEnumTypeExports } from "./enum_type.js";
67
67
  import { discoverEvolutionModulePaths, isEvolutionModulePath } from "./evolution_files.js";
68
68
  import { assertEvolutionModuleExports } from "./evolution.js";
69
+ import { readHistoricalIdentityFrontier } from "./identity_frontier.js";
69
70
  import { generateDartBridgeClient } from "./codegen_dart_client.js";
71
+ import { generateDartApplicationFrameworkCalls } from "./codegen_dart_framework_calls.js";
70
72
  import {
71
73
  dartApplicationClassName,
72
74
  dartApplicationPublicClassNames,
@@ -88,7 +90,10 @@ import {
88
90
  } from "./framework/framework_aggregates.js";
89
91
  import { RelationTuple, relationTuplesByObject } from "./framework/relations.js";
90
92
  import { isNamespacedAggregate } from "./read_projection_namespace.js";
91
- import { collectPayloadValueObjectDescriptors } from "./value_object.js";
93
+ import {
94
+ collectPayloadValueObjectDescriptors,
95
+ collectValueObjectDescriptors,
96
+ } from "./value_object.js";
92
97
  import { finishCount, type AnyCount } from "./count.js";
93
98
  import type { QueryDecl } from "./query.js";
94
99
  import type { SpatialDecl } from "./spatial.js";
@@ -112,6 +117,7 @@ import {
112
117
  expandBusinessBirthExports,
113
118
  } from "./business_birth.js";
114
119
  import { withOwnedCustodyExports } from "./framework/owned_custody.js";
120
+ import { OwnedCustodyValue, OwnedDeviceRequestValue } from "./framework/owned_custody_value.js";
115
121
  import { expandRoleExports, rolesOf } from "./role.js";
116
122
  import { collectEngineRouting } from "./engine_entry.js";
117
123
  import {
@@ -158,9 +164,9 @@ import {
158
164
  import { reconcileStableIdsWithIdentity } from "./stable_id_identity_bridge.js";
159
165
  import { LAW_FRAMEWORK_PARENT } from "./law_identity.js";
160
166
  import { discoverLawGraph, type LawGraph } from "./law_graph.js";
161
- import { emitFrameworkLawUsda, emitSparseLawGraphUsda } from "./law_graph_usda.js";
167
+ import { compileSparseLawGraphUsda, emitFrameworkLawUsda } from "./law_graph_usda.js";
162
168
  import { assertNoDartBarrelCollisions, type BarrelExportedFile } from "./dart_barrel_guard.js";
163
- import { generateTsClient, tsApplicationName, tsClientFactoryName, recursiveLazyTypes } from "./codegen_ts.js";
169
+ import { generateTsClient, generateTsLifecycleOperator, tsApplicationName, tsClientFactoryName, recursiveLazyTypes } from "./codegen_ts.js";
164
170
  import { generateOpenApiFragment, mergeOpenApiFragments } from "./codegen_openapi.js";
165
171
  import { domainInterface, type DomainInterface } from "./shape_compat.js";
166
172
  import { generateTsProof, proofLegsIndex } from "./codegen_proof.js";
@@ -174,6 +180,7 @@ import { applicationHomePolicyLaw } from "./framework/application_home.js";
174
180
  import { isApplicationHomeGenesis } from "./application_home_genesis.js";
175
181
  import { resolveApplicationTopology } from "./application_topology.js";
176
182
  import { isBusinessIntent } from "./intent.js";
183
+ import { emitTsCallUsdaEncoder, TS_CALL_USDA_PRELUDE } from "./codegen_call_usda.js";
177
184
  import {
178
185
  compileApplicationComposition,
179
186
  isApplicationCompositionConfig,
@@ -861,11 +868,19 @@ const DART_SUPPORT_RUNTIME_SRC = [
861
868
  "webview_bridge.dart",
862
869
  "session_bound.dart",
863
870
  "record_origin.dart",
871
+ // Canonical USDA application-call/result syntax. Generated clients refer to
872
+ // these through the support barrel; omitting them from a vendored package
873
+ // silently resurrected the old map bridge at integration time.
874
+ "generated_call.dart",
875
+ "result_usda.dart",
864
876
  ] as const;
865
877
  const DART_SUPPORT_SRC = [...DART_SUPPORT_CORE_SRC, ...DART_SUPPORT_RUNTIME_SRC] as const;
866
878
  /** The local shim replacing `package:nomos_types/nomos_types.dart` inside vendored runtime files. */
867
879
  const VENDORED_TYPES_SHIM = "nomos_types.dart";
880
+ const VENDORED_KERNEL_PROTOCOL_SHIM = "nomos_kernel_protocol.dart";
868
881
  const VENDORED_META_DEP = "^1.12.0";
882
+ const VENDORED_PROTOBUF_DEP = "^5.0.0";
883
+ const VENDORED_FIXNUM_DEP = "^1.1.1";
869
884
  const VENDORED_DART_SDK_FLOOR = "3.3.0";
870
885
 
871
886
  /**
@@ -909,21 +924,12 @@ function ensureVendoredPackageRequirements(dartOut: string): void {
909
924
  `${sdkLine[1]}\">=${VENDORED_DART_SDK_FLOOR} <4.0.0\"${sdkLine[3] ?? ""}`,
910
925
  );
911
926
  }
912
- if (/^ meta:\s*/m.test(next)) {
913
- if (next !== source) writeFileSync(pubspec, next, "utf8");
914
- return;
915
- }
916
- if (!/^dependencies:\s*$/m.test(next)) {
917
- fail("generated Dart vendored support needs a dependencies: block in " + pubspec);
918
- }
919
- writeFileSync(
920
- pubspec,
921
- next.replace(
922
- /^dependencies:\s*$/m,
923
- "dependencies:\n meta: " + VENDORED_META_DEP,
924
- ),
925
- "utf8",
926
- );
927
+ if (next !== source) writeFileSync(pubspec, next, "utf8");
928
+ reconcilePubspec(dir, "", {
929
+ meta: VENDORED_META_DEP,
930
+ protobuf: VENDORED_PROTOBUF_DEP,
931
+ fixnum: VENDORED_FIXNUM_DEP,
932
+ });
927
933
  }
928
934
 
929
935
  /** The generated-owned subdirectory, relative to `dartOut` (the pub package's `lib/`). WIPED and
@@ -1121,6 +1127,7 @@ function dartValueObjectsForModule(
1121
1127
  const byName = new Map<string, NonNullable<DomainModule["valueObjects"]>[number]>();
1122
1128
  for (const descriptor of [
1123
1129
  ...(mod.valueObjects ?? []),
1130
+ ...collectValueObjectDescriptors(mod.aggregates),
1124
1131
  ...collectPayloadValueObjectDescriptors(codegenDirectives),
1125
1132
  ]) {
1126
1133
  const prior = byName.get(descriptor.name);
@@ -1180,9 +1187,23 @@ function collectDartSharedSymbols(
1180
1187
  }
1181
1188
  }
1182
1189
  }
1190
+ const frameworkVoByName = new Map(
1191
+ collectValueObjectDescriptors(frameworkAggs).map((descriptor) => [descriptor.name, descriptor]),
1192
+ );
1193
+ for (const [name, descriptor] of frameworkVoByName) {
1194
+ const prior = voDescriptorByName.get(name);
1195
+ if (prior !== undefined && JSON.stringify(prior) !== JSON.stringify(descriptor)) {
1196
+ throw new Error(
1197
+ `value object '${name}' has DIVERGENT framework/domain shapes — one name, one shape`,
1198
+ );
1199
+ }
1200
+ voDescriptorByName.set(name, descriptor);
1201
+ }
1202
+ const frameworkVoNames = new Set(frameworkVoByName.keys());
1183
1203
  const sharedVoNames: ReadonlySet<string> = new Set([
1184
1204
  ...[...voDomainsByName.entries()].filter(([, n]) => n > 1).map(([name]) => name),
1185
1205
  ...contractVoNames,
1206
+ ...frameworkVoNames,
1186
1207
  ]);
1187
1208
  const sharedVos = [...sharedVoNames].sort().map((name) => voDescriptorByName.get(name)!);
1188
1209
  const hasFrameworkSymbols =
@@ -1323,6 +1344,8 @@ function emitDart(
1323
1344
  modules: readonly DomainModule[],
1324
1345
  dartOut: string,
1325
1346
  domainHash: string,
1347
+ lawGraphs: ReadonlyMap<string, LawGraph>,
1348
+ lawPaths: ReadonlyMap<string, ReadonlyMap<string, string>>,
1326
1349
  packageInterface: Record<string, DomainInterface> = {},
1327
1350
  supportImport: DartSupportImport = "vendored",
1328
1351
  barrelName = "nomos_domains",
@@ -1357,9 +1380,46 @@ function emitDart(
1357
1380
  .replace(
1358
1381
  /import 'package:nomos_types\/src\/(?:nomos_ref|foreign_ref|versioned_nomos_ref)\.dart'/g,
1359
1382
  `import '${VENDORED_TYPES_SHIM}'`,
1383
+ )
1384
+ .replace(
1385
+ /import 'package:nomos_types\/nomos_kernel_protocol\.dart'/g,
1386
+ `import '${VENDORED_KERNEL_PROTOCOL_SHIM}'`,
1360
1387
  );
1361
1388
  writeFileSync(path.join(genDir, "src", f), src, "utf8");
1362
1389
  }
1390
+ // Protobuf is the sole kernel/host message schema. Flat vendored packages receive a generated
1391
+ // projection of that schema, never a handwritten certificate mirror. The compiler copies only the
1392
+ // generated kernel files this runtime uses; `generate:kernel-proto-dart` remains their source.
1393
+ const generatedKernelProto = path.join(DSL_DIR, "dart_types", "lib", "src", "proto", "nomos", "kernel", "v1");
1394
+ const vendoredKernelProto = path.join(genDir, "src", "proto", "nomos", "kernel", "v1");
1395
+ mkdirSync(vendoredKernelProto, { recursive: true });
1396
+ for (const f of [
1397
+ "kernel.pb.dart",
1398
+ "kernel.pbenum.dart",
1399
+ "progress.pb.dart",
1400
+ "progress.pbenum.dart",
1401
+ ]) {
1402
+ copyFileSync(path.join(generatedKernelProto, f), path.join(vendoredKernelProto, f));
1403
+ }
1404
+ const generatedRuntimeProto = path.join(DSL_DIR, "dart_types", "lib", "src", "proto", "nomos", "runtime", "v2");
1405
+ const vendoredRuntimeProto = path.join(genDir, "src", "proto", "nomos", "runtime", "v2");
1406
+ mkdirSync(vendoredRuntimeProto, { recursive: true });
1407
+ for (const f of ["runtime.pb.dart", "runtime.pbenum.dart"]) {
1408
+ copyFileSync(path.join(generatedRuntimeProto, f), path.join(vendoredRuntimeProto, f));
1409
+ }
1410
+ writeFileSync(
1411
+ path.join(genDir, "src", VENDORED_KERNEL_PROTOCOL_SHIM),
1412
+ [
1413
+ "// GENERATED from proto/nomos/kernel/v1/kernel.proto by nomos-compile. DO NOT EDIT.",
1414
+ "library;",
1415
+ "",
1416
+ "export 'proto/nomos/kernel/v1/kernel.pb.dart';",
1417
+ "export 'proto/nomos/kernel/v1/progress.pb.dart';",
1418
+ "export 'proto/nomos/runtime/v2/runtime.pb.dart';",
1419
+ "",
1420
+ ].join("\n"),
1421
+ "utf8",
1422
+ );
1363
1423
  // The local shim the rewritten runtime imports resolve through (the vendored twin of the
1364
1424
  // nomos_types barrel — core files only).
1365
1425
  writeFileSync(
@@ -1427,10 +1487,51 @@ function emitDart(
1427
1487
  return p;
1428
1488
  };
1429
1489
 
1490
+ // Compiler-owned framework ceremonies (birth policy, signer seating, genesis, invitation
1491
+ // redemption) need the same generated USDA call types in flat/vendored output as in layered pub
1492
+ // packages. Keeping this file private to `src/generated` gives tests and generated application
1493
+ // infrastructure a typed setup lane without reintroducing raw payload maps.
1494
+ const applicationFrameworkCallsSource = generateDartApplicationFrameworkCalls(
1495
+ modules.flatMap((module) => {
1496
+ const graph = lawGraphs.get(module.name);
1497
+ const paths = lawPaths.get(module.name);
1498
+ return graph === undefined || paths === undefined ? [] : [{ module, graph, paths }];
1499
+ }),
1500
+ );
1501
+ if (applicationFrameworkCallsSource !== undefined) {
1502
+ const source = supportImport === "vendored"
1503
+ ? applicationFrameworkCallsSource
1504
+ .replace(
1505
+ "import 'package:nomos_types/nomos_kernel_protocol.dart' show BirthCertificate;",
1506
+ `import 'src/${VENDORED_KERNEL_PROTOCOL_SHIM}' show BirthCertificate;`,
1507
+ )
1508
+ .replace(
1509
+ "import 'package:nomos_types/nomos_types.dart' show NomosSlot, Sha256Digest;",
1510
+ `import 'src/${VENDORED_TYPES_SHIM}' show NomosSlot, Sha256Digest;`,
1511
+ )
1512
+ .replace(
1513
+ "import 'package:nomos_client/src/application_framework_calls.dart';",
1514
+ "import 'src/application_framework_calls.dart';",
1515
+ )
1516
+ .replace(
1517
+ "import 'package:nomos_client/src/generated_call.dart';",
1518
+ "import 'src/generated_call.dart';",
1519
+ )
1520
+ : applicationFrameworkCallsSource;
1521
+ const applicationFrameworkCallsPath = path.join(genDir, "application.framework_calls.dart");
1522
+ writeFileSync(applicationFrameworkCallsPath, source, "utf8");
1523
+ written.push(applicationFrameworkCallsPath);
1524
+ }
1525
+
1430
1526
  // 2a. the shared framework file — the framework aggregates + directives + queries, ONCE. Its own
1431
1527
  // surface is emitted in full (no skip). Imported by every domain that folds any framework symbol.
1432
1528
  if (shared.frameworkMod !== undefined) {
1433
- writeGenerated(FRAMEWORK_FILE, generateDartDomain(shared.frameworkMod));
1529
+ writeGenerated(
1530
+ FRAMEWORK_FILE,
1531
+ generateDartDomain(shared.frameworkMod, {
1532
+ additionalValueObjects: shared.frameworkMod.valueObjects ?? [],
1533
+ }),
1534
+ );
1434
1535
  }
1435
1536
  // 2a-bis. the shared DOMAIN CONTRACTS file (`contracts.dart`) — every public DTO class, ONCE. Pure
1436
1537
  // (nomos_types + VOs). A foreignRef targeting a contract imports THIS, never the concrete domain.
@@ -1523,6 +1624,10 @@ function emitDart(
1523
1624
 
1524
1625
  const clientSrc = generateDartBridgeClient(modForDart, {
1525
1626
  domainHash,
1627
+ callUsda: {
1628
+ graph: lawGraphs.get(mod.name)!,
1629
+ paths: lawPaths.get(mod.name)!,
1630
+ },
1526
1631
  interface: packageInterface[modForDart.domain ?? modForDart.name],
1527
1632
  ...(compat !== undefined ? { compat } : {}),
1528
1633
  supportImport,
@@ -1542,6 +1647,7 @@ function emitDart(
1542
1647
  applicationSrc,
1543
1648
  clientFile,
1544
1649
  applicationFile,
1650
+ new Set(dartApplicationPublicClassNames(modForDart)),
1545
1651
  );
1546
1652
  const cp = path.join(genDir, clientFile);
1547
1653
  writeFileSync(cp, encapsulated.clientPart, "utf8");
@@ -1660,12 +1766,12 @@ const dartTypesImportFor = (generatedSource: string): string => {
1660
1766
  * just the floor generated code needs — a lagging pin forces tenants into dependency_overrides. */
1661
1767
  // 0.3.0: SurfacedValue<T>/SurfacedObservation/PendingConflictRow — generated Surfaced-field typing +
1662
1768
  // the pendingConflicts read rows.
1663
- const NOMOS_TYPES_DEP = "^0.8.8";
1769
+ const NOMOS_TYPES_DEP = "^0.10.0";
1664
1770
  // 0.48.x: session-bound clients (XClient.bind/NomosClientInterface/DomainClientSessionMismatch/
1665
1771
  // DomainNotInstalledForSession, engine.follow, pendingConflicts lanes) — the generated client
1666
1772
  // REQUIRES this surface. 0.48.1 fixes NomosSession.watchPendingConflicts delegation.
1667
- const NOMOS_CLIENT_DEP = "^0.64.46";
1668
- const NOMOS_FLUTTER_DEP = "^0.63.76";
1773
+ const NOMOS_CLIENT_DEP = "^0.65.1";
1774
+ const NOMOS_FLUTTER_DEP = "^0.64.1";
1669
1775
  // DRIFT TRIPWIRE: pubspec_pins.test.ts asserts these equal the CURRENT versions in dsl/dart/pubspec.yaml
1670
1776
  // and dsl/dart_types/pubspec.yaml — a Dart release without this bump fails the suite, so tenants never
1671
1777
  // land back in dependency_overrides (the exact co2 report this closes, third occurrence).
@@ -1728,6 +1834,7 @@ function encapsulateDartClient(
1728
1834
  applicationSrc: string,
1729
1835
  clientFile: string,
1730
1836
  applicationFile: string,
1837
+ publicClientNames: ReadonlySet<string>,
1731
1838
  ): { readonly clientPart: string; readonly applicationLibrary: string } {
1732
1839
  const directive = /^(import|export)\s+'([^']+)'(?:\s+[^;]+)?;\s*$/;
1733
1840
  const clientImportUri = clientFile.replace(/\.dart$/, "");
@@ -1802,17 +1909,20 @@ function encapsulateDartClient(
1802
1909
  "// ignore_for_file: unused_element, unused_element_parameter",
1803
1910
  `part of '${applicationFile}';`,
1804
1911
  "",
1805
- privatize(client.body.join("\n")).trimStart(),
1912
+ privatize(client.body.join("\n"), publicClientNames).trimStart(),
1806
1913
  "",
1807
1914
  ].join("\n"),
1808
1915
  applicationLibrary: [
1809
1916
  "// AUTO-GENERATED by nomos-compile — the sole importable application library.",
1810
- "// ignore_for_file: unused_import, unused_field, invalid_use_of_internal_member",
1917
+ "// ignore_for_file: unused_import, unnecessary_import, unused_field, invalid_use_of_internal_member",
1811
1918
  ...imports.values(),
1812
1919
  ...exports.values(),
1813
1920
  `part '${clientFile}';`,
1814
1921
  "",
1815
- privatize(application.body.join("\n"), applicationNames).trimStart(),
1922
+ privatize(
1923
+ application.body.join("\n"),
1924
+ new Set([...applicationNames, ...publicClientNames]),
1925
+ ).trimStart(),
1816
1926
  "",
1817
1927
  ].join("\n"),
1818
1928
  };
@@ -1844,6 +1954,7 @@ function generatedPackageApplication(
1844
1954
  }[],
1845
1955
  homeDomain: string,
1846
1956
  rootDomains: readonly string[],
1957
+ hasApplicationFrameworkCalls: boolean,
1847
1958
  ): string {
1848
1959
  const application = dartApplicationClassName(packageName);
1849
1960
  const root = domains.find(({ domain }) => domain === homeDomain);
@@ -1903,6 +2014,9 @@ function generatedPackageApplication(
1903
2014
  `import 'package:nomos_flutter/src/application_status.dart' show ApplicationSignIn, ApplicationStatus;`,
1904
2015
  `import 'package:nomos_client/src/nms_generated_runtime.dart' show NmsInternalUsers, NomosSession, User${hasInvitations ? ", Invitation, Recipient" : ""};`,
1905
2016
  `import 'package:nomos_flutter/src/generated_application_host.dart' show ApplicationModelChange, NomosApplicationStartupState, NmsInternalApplicationHost, NmsInternalApplicationUserBinding${hasInvitations ? ", NmsInternalInvitationPolicy" : ""};`,
2017
+ ...(hasApplicationFrameworkCalls
2018
+ ? [`import 'application.framework_calls.dart' show nomosInternalApplicationFrameworkCalls;`]
2019
+ : []),
1906
2020
  ...members.map(({ file, prefix }) =>
1907
2021
  `import '${file}.application.dart' as ${prefix};`),
1908
2022
  ``,
@@ -1967,6 +2081,7 @@ function generatedPackageApplication(
1967
2081
  ` /// Redeem a transported invitation as [currentUser].`,
1968
2082
  ` Future<void> redeemInvitation(String link) => NmsInternalApplicationHost.redeemInvitation<User>(`,
1969
2083
  ` _nmsSession,`,
2084
+ ` frameworkCalls: nomosInternalApplicationFrameworkCalls,`,
1970
2085
  ` link: link,`,
1971
2086
  ` identity: _nmsUser.nmsInternalActor,`,
1972
2087
  ` policies: [`,
@@ -2005,6 +2120,9 @@ function generatedPackageApplication(
2005
2120
  ` Duration startupTimeout = const Duration(minutes: 3),`,
2006
2121
  ` }) => NmsInternalApplicationHost.home<${application}>(`,
2007
2122
  ` key: key, cloud: cloud, application: application, signIn: signIn,`,
2123
+ ...(hasApplicationFrameworkCalls
2124
+ ? [` frameworkCalls: nomosInternalApplicationFrameworkCalls,`]
2125
+ : []),
2008
2126
  ` bind: nomosInternalBind${application}, builder: builder,`,
2009
2127
  ` loadingBuilder: loadingBuilder, errorBuilder: errorBuilder,`,
2010
2128
  ` onModelChange: onModelChange,`,
@@ -2194,6 +2312,8 @@ function emitDartPackages(
2194
2312
  modules: readonly DomainModule[],
2195
2313
  dartOut: string,
2196
2314
  domainHash: string,
2315
+ lawGraphs: ReadonlyMap<string, LawGraph>,
2316
+ lawPaths: ReadonlyMap<string, ReadonlyMap<string, string>>,
2197
2317
  packageInterface: Record<string, DomainInterface>,
2198
2318
  packages: { readonly types: string; readonly client: string; readonly test?: string; readonly compat?: string; readonly barrelExports?: "all" | "explicit" },
2199
2319
  names: Readonly<Record<string, string>> | undefined,
@@ -2201,6 +2321,7 @@ function emitDartPackages(
2201
2321
  describePackageName = packages.client,
2202
2322
  lawUsdzPath?: string,
2203
2323
  applicationMaxChildWorkspacesPerUser?: number,
2324
+ frameworkModules: readonly DomainModule[] = modules,
2204
2325
  ): { written: string[]; cursed: string[] } {
2205
2326
  for (const [role, name] of Object.entries(packages)) {
2206
2327
  if (typeof name !== "string" || !isPubPackageName(name)) {
@@ -2273,7 +2394,14 @@ function emitDartPackages(
2273
2394
  written.push(p);
2274
2395
  };
2275
2396
 
2276
- if (shared.frameworkMod !== undefined) writeTypes(FRAMEWORK_FILE, generateDartDomain(shared.frameworkMod));
2397
+ if (shared.frameworkMod !== undefined) {
2398
+ writeTypes(
2399
+ FRAMEWORK_FILE,
2400
+ generateDartDomain(shared.frameworkMod, {
2401
+ additionalValueObjects: shared.frameworkMod.valueObjects ?? [],
2402
+ }),
2403
+ );
2404
+ }
2277
2405
  // DOMAIN CONTRACTS (layered): the shared `contracts.dart` DTO file in the TYPES package (pure —
2278
2406
  // nomos_types + VOs). A contract-target foreignRef imports THIS sibling, never the concrete domain.
2279
2407
  const contractsImportUri = packageContracts.length > 0 ? `${CONTRACTS_FILE}.dart` : undefined;
@@ -2474,6 +2602,22 @@ function emitDartPackages(
2474
2602
 
2475
2603
  // ── the CLIENT package — effectful runtime, depends on types + nomos_client ──
2476
2604
  const clientGen = freshGenDir(packages.client);
2605
+ const applicationFrameworkCallsFile = "application.framework_calls";
2606
+ const applicationFrameworkCallsSource = generateDartApplicationFrameworkCalls(
2607
+ frameworkModules.flatMap((module) => {
2608
+ const graph = lawGraphs.get(module.name);
2609
+ const paths = lawPaths.get(module.name);
2610
+ return graph === undefined || paths === undefined ? [] : [{ module, graph, paths }];
2611
+ }),
2612
+ );
2613
+ if (applicationFrameworkCallsSource !== undefined) {
2614
+ const applicationFrameworkCallsPath = path.join(
2615
+ clientGen,
2616
+ `${applicationFrameworkCallsFile}.dart`,
2617
+ );
2618
+ writeFileSync(applicationFrameworkCallsPath, applicationFrameworkCallsSource, "utf8");
2619
+ written.push(applicationFrameworkCallsPath);
2620
+ }
2477
2621
  const embeddedLawName = `${describePackageName}.law.usdz`;
2478
2622
  const applicationLawPath = lawUsdzPath === undefined
2479
2623
  ? undefined
@@ -2494,10 +2638,18 @@ function emitDartPackages(
2494
2638
  : undefined;
2495
2639
  const frameworkTypeNames = frameworkImplementationImport === undefined
2496
2640
  ? []
2497
- : [...declaredDartTypeNames(typesSources.get(FRAMEWORK_FILE) ?? "")];
2641
+ : [...declaredDartTypeNames(typesSources.get(FRAMEWORK_FILE) ?? "")]
2642
+ // These private framework values are supplied by nomos_client itself. A
2643
+ // tenant implementation mentioning them must not manufacture an import of
2644
+ // the package-local framework file's duplicate private projection helper.
2645
+ .filter((name) => name !== OwnedCustodyValue.name && name !== OwnedDeviceRequestValue.name);
2498
2646
  for (const { mod, dd } of perDomain) {
2499
2647
  const makeClient = (imports: readonly string[]) => generateDartBridgeClient(dd.modForDart, {
2500
2648
  domainHash,
2649
+ callUsda: {
2650
+ graph: lawGraphs.get(mod.name)!,
2651
+ paths: lawPaths.get(mod.name)!,
2652
+ },
2501
2653
  ...(applicationLawAssetKey !== undefined
2502
2654
  ? { lawAssetKey: applicationLawAssetKey }
2503
2655
  : {}),
@@ -2522,6 +2674,9 @@ function emitDartPackages(
2522
2674
  packageAggregateDomains: buildPackageAggregateDomains(modules),
2523
2675
  flutterHost: true,
2524
2676
  tenantRoot: perDomain.length === 1,
2677
+ ...(applicationFrameworkCallsSource === undefined
2678
+ ? {}
2679
+ : { applicationFrameworkCallsImportUri: `${applicationFrameworkCallsFile}.dart` }),
2525
2680
  ...(imports.length > 0
2526
2681
  ? { explicitTypeImports: imports }
2527
2682
  : {}),
@@ -2547,6 +2702,7 @@ function emitDartPackages(
2547
2702
  applicationSrc,
2548
2703
  clientFile,
2549
2704
  applicationFile,
2705
+ new Set(dartApplicationPublicClassNames(dd.modForDart)),
2550
2706
  );
2551
2707
  const cp = path.join(clientGen, clientFile);
2552
2708
  writeFileSync(cp, encapsulated.clientPart, "utf8");
@@ -2577,6 +2733,7 @@ function emitDartPackages(
2577
2733
  })),
2578
2734
  topology.homeDomain,
2579
2735
  topology.rootDomains,
2736
+ applicationFrameworkCallsSource !== undefined,
2580
2737
  ),
2581
2738
  "utf8",
2582
2739
  );
@@ -2708,6 +2865,9 @@ function emitDartPackages(
2708
2865
  surfaceName,
2709
2866
  applicationFile,
2710
2867
  applicationModules: perDomain.map(({ dd: candidate }) => candidate.modForDart),
2868
+ ...(applicationFrameworkCallsSource === undefined
2869
+ ? {}
2870
+ : { applicationFrameworkCallsFile }),
2711
2871
  ...(applicationMaxChildWorkspacesPerUser === undefined
2712
2872
  ? {}
2713
2873
  : { applicationMaxChildWorkspacesPerUser }),
@@ -3074,6 +3234,13 @@ async function main(): Promise<void> {
3074
3234
  const nativeWorkspaceInvariantReadIds = new Set<string>();
3075
3235
  const routingInput: Record<string, Mod[]> = {};
3076
3236
  const domainModules: DomainModule[] = [];
3237
+ const directiveExportSources: Array<{
3238
+ readonly directive: object;
3239
+ readonly domainKey: string;
3240
+ readonly graphName: string;
3241
+ readonly modulePath: string;
3242
+ readonly exportName: string;
3243
+ }> = [];
3077
3244
  // THE SELF-DESCRIBE DECLS (G1): per domain key, the FINISHED plain read/maintenance decls the
3078
3245
  // lump's `globalThis.describe` needs that it cannot rediscover by shape alone (mins/maxes are
3079
3246
  // config-named; sharding sums are framework-appended). Plain JSON (finishCount/Sum/Extremum
@@ -3171,6 +3338,13 @@ async function main(): Promise<void> {
3171
3338
  typeof (value as { plan?: unknown }).plan === "function" &&
3172
3339
  typeof (value as { aggregateId?: unknown }).aggregateId === "string"
3173
3340
  ) {
3341
+ directiveExportSources.push({
3342
+ directive: value,
3343
+ domainKey: d.key,
3344
+ graphName: d.name ?? d.key,
3345
+ modulePath: abs,
3346
+ exportName,
3347
+ });
3174
3348
  directOfferExports.set((value as { id: string }).id, {
3175
3349
  modulePath: abs,
3176
3350
  exportName,
@@ -3776,6 +3950,10 @@ async function main(): Promise<void> {
3776
3950
  const priorLock: CompilerIdentityModel | undefined = existsSync(lockPath)
3777
3951
  ? parseIdentityUsda(readFileSync(lockPath, "utf8"))
3778
3952
  : undefined;
3953
+ const historicalFrontier = readHistoricalIdentityFrontier(lockPath);
3954
+ const historicalLock: CompilerIdentityModel | undefined = historicalFrontier === undefined
3955
+ ? undefined
3956
+ : parseIdentityUsda(historicalFrontier.source);
3779
3957
  const inferredRenames: { domain: string; renames: InferredRename[] }[] = [];
3780
3958
  let nextIdentity = identityRegistryFromModel(priorLock);
3781
3959
  const typedLawGraphs = new Map<string, LawGraph>();
@@ -3831,6 +4009,7 @@ async function main(): Promise<void> {
3831
4009
  currentAggs,
3832
4010
  prior,
3833
4011
  priorSchemas,
4012
+ mod.retirements,
3834
4013
  );
3835
4014
  const reconciled = reconcileStableIdsWithIdentity(
3836
4015
  nextIdentity,
@@ -3924,9 +4103,9 @@ async function main(): Promise<void> {
3924
4103
  // The identity file is project-wide while a package may own only some of its domains. Scope the
3925
4104
  // prior side to the modules in this compile so compiling one sibling never reads another sibling's
3926
4105
  // absence as a domain retirement.
3927
- if (priorLock !== undefined) {
4106
+ if (historicalLock !== undefined) {
3928
4107
  const priorDomainsForPackage: CompilerIdentityModel["domains"] = {};
3929
- const priorIdentity = identityRegistryFromModel(priorLock);
4108
+ const priorIdentity = identityRegistryFromModel(historicalLock);
3930
4109
  const frameworkAggregateSids = new Set(
3931
4110
  Object.values(priorIdentity.entities)
3932
4111
  .filter((entity) => entity.kind === "aggregate" && entity.parent === LAW_FRAMEWORK_PARENT)
@@ -3934,7 +4113,7 @@ async function main(): Promise<void> {
3934
4113
  );
3935
4114
  for (const mod of domainModules) {
3936
4115
  const domainKey = mod.domain ?? mod.name;
3937
- const locked = priorLock.domains[mod.name] ?? priorLock.domains[domainKey];
4116
+ const locked = historicalLock.domains[mod.name] ?? historicalLock.domains[domainKey];
3938
4117
  if (locked !== undefined) {
3939
4118
  const currentImplementationDetailAggregateIds = new Set(
3940
4119
  mod.aggregates
@@ -3972,7 +4151,7 @@ async function main(): Promise<void> {
3972
4151
  const priorLaw = evolveLawFromLockfile({
3973
4152
  v: 1,
3974
4153
  domains: priorDomainsForPackage,
3975
- ...(priorLock.identity === undefined ? {} : { identity: priorLock.identity }),
4154
+ ...(historicalLock.identity === undefined ? {} : { identity: historicalLock.identity }),
3976
4155
  });
3977
4156
  const candidateLaw = currentEvolveLaw(domainModules, nextLock);
3978
4157
  const evolutionFindings = evolveDiff(priorLaw, candidateLaw).findings;
@@ -4062,10 +4241,12 @@ async function main(): Promise<void> {
4062
4241
  const v3Closure = [...typedLawGraphs.values()];
4063
4242
  const v3DomainAssets: EmittedLawClosureAsset[] = [];
4064
4243
  const typedDomainIdentityByName = new Map<string, string>();
4244
+ const typedLawPathsByName = new Map<string, ReadonlyMap<string, string>>();
4065
4245
  for (const [domain, graph] of typedLawGraphs) {
4066
4246
  const safeDomain = domain.replace(/[^A-Za-z0-9._-]/g, "_");
4067
4247
  const logicalPath = `domains/${safeDomain}.usda`;
4068
- const layerText = emitSparseLawGraphUsda(graph, logicalPath, v3Closure);
4248
+ const compiledLayer = compileSparseLawGraphUsda(graph, logicalPath, v3Closure);
4249
+ const layerText = compiledLayer.text;
4069
4250
  const sha256 = sha256HexUtf8(layerText);
4070
4251
  v3DomainAssets.push({
4071
4252
  logicalPath,
@@ -4073,6 +4254,66 @@ async function main(): Promise<void> {
4073
4254
  utf8: layerText,
4074
4255
  });
4075
4256
  typedDomainIdentityByName.set(domain, sha256);
4257
+ typedLawPathsByName.set(domain, compiledLayer.paths);
4258
+ }
4259
+
4260
+ // Cross-workspace effects retain the exact target Directive object in the typed application
4261
+ // language. Resolve that object back to its configured export once, then generate its nominal
4262
+ // USDA encoder from the target's own canonical graph. Runtime law receives no schema descriptor,
4263
+ // operation string or host mapping: only one generated function per exact target declaration.
4264
+ const workspaceEffectRuntimeBindings: Array<{
4265
+ readonly sourceDomain: string;
4266
+ readonly sourceModulePath: string;
4267
+ readonly sourceExportName: string;
4268
+ readonly targetModulePath: string;
4269
+ readonly targetExportName: string;
4270
+ readonly encoderName: string;
4271
+ readonly encoderSource: readonly string[];
4272
+ }> = [];
4273
+ for (const module of domainModules) {
4274
+ const sourceDomain = module.domain ?? module.name;
4275
+ for (const directive of module.directives ?? []) {
4276
+ if (!isBusinessIntent(directive)) continue;
4277
+ for (const effect of directive.workspaceEffects) {
4278
+ const sourceMatches = directiveExportSources.filter((candidate) => candidate.directive === directive);
4279
+ if (sourceMatches.length !== 1) {
4280
+ fail(
4281
+ `workspace effect source '${sourceDomain}/${directive.id}' is exported by ` +
4282
+ `${sourceMatches.length} configured law modules; export it once`,
4283
+ );
4284
+ }
4285
+ const source = sourceMatches[0]!;
4286
+ const matches = directiveExportSources.filter((candidate) => candidate.directive === effect.target);
4287
+ if (matches.length !== 1) {
4288
+ fail(
4289
+ `workspace effect '${sourceDomain}/${directive.id}' targets '${effect.target.id}', but that exact ` +
4290
+ `Directive object is exported by ${matches.length} configured law modules; export it once`,
4291
+ );
4292
+ }
4293
+ const target = matches[0]!;
4294
+ const graph = typedLawGraphs.get(target.graphName);
4295
+ const paths = typedLawPathsByName.get(target.graphName);
4296
+ if (graph === undefined || paths === undefined) {
4297
+ fail(`workspace effect target '${target.graphName}/${effect.target.id}' has no canonical law graph`);
4298
+ }
4299
+ const generated = emitTsCallUsdaEncoder(
4300
+ graph,
4301
+ paths,
4302
+ target.domainKey,
4303
+ effect.target.id,
4304
+ "any",
4305
+ );
4306
+ workspaceEffectRuntimeBindings.push({
4307
+ sourceDomain,
4308
+ sourceModulePath: source.modulePath,
4309
+ sourceExportName: source.exportName,
4310
+ targetModulePath: target.modulePath,
4311
+ targetExportName: target.exportName,
4312
+ encoderName: generated.functionName,
4313
+ encoderSource: generated.source,
4314
+ });
4315
+ }
4316
+ }
4076
4317
  }
4077
4318
 
4078
4319
  // ── reports ──
@@ -4152,11 +4393,13 @@ async function main(): Promise<void> {
4152
4393
  }
4153
4394
  }
4154
4395
 
4155
- // Resolve esbuild through Node's resolver (caller's copy first, else the DSL's
4156
- // own dependency) — NOT node_modules/.bin paths, which hoisted/workspace
4157
- // installs relocate. The pinned dependency keeps the engine-lump bytes (and so
4158
- // the content-addressed domainHash) reproducible across machines.
4159
- const esbuildPkgJson = [cfgDir, DSL_DIR]
4396
+ // Resolve the compiler's pinned esbuild before any application-local copy.
4397
+ // Application dependencies are authoring inputs, not part of the compiler
4398
+ // toolchain: allowing a stray nested node_modules to win makes identical law
4399
+ // source emit a different content-addressed runtime than a clean checkout.
4400
+ // Node's resolver still handles hoisted/workspace installs without relying on
4401
+ // node_modules/.bin paths.
4402
+ const esbuildPkgJson = [DSL_DIR, cfgDir]
4160
4403
  .map((dir) => {
4161
4404
  try {
4162
4405
  return createRequire(pathToFileURL(path.join(dir, "noop.js"))).resolve("esbuild/package.json");
@@ -4168,7 +4411,9 @@ async function main(): Promise<void> {
4168
4411
  if (!esbuildPkgJson) fail(`esbuild not found — reinstall @githolon/dsl (esbuild is one of its dependencies)`);
4169
4412
  const esbuildMod = (await import(pathToFileURL(path.join(path.dirname(esbuildPkgJson), "lib", "main.js")).href)) as typeof import("esbuild");
4170
4413
 
4171
- const compact = compactFlag || cfg.compact === true;
4414
+ const compact = process.env.NOMOS_READABLE === "1"
4415
+ ? false
4416
+ : compactFlag || cfg.compact === true;
4172
4417
  const runtimeZodPath = path.join(DSL_DIR, "src", "runtime_zod.ts");
4173
4418
  const runtimeZodPackage = createRequire(import.meta.url).resolve("zod/package.json");
4174
4419
  const runtimeZodV4Path = path.join(path.dirname(runtimeZodPackage), "v4", "index.js");
@@ -4255,6 +4500,41 @@ async function main(): Promise<void> {
4255
4500
  ),
4256
4501
  };
4257
4502
  };
4503
+ const workspaceEffectRuntimeFor = (
4504
+ domainKeys: readonly string[],
4505
+ sourceSlice?: readonly PlanSourceSliceTarget[],
4506
+ ) => {
4507
+ const wanted = new Set(domainKeys);
4508
+ const slicedSources = sourceSlice === undefined
4509
+ ? undefined
4510
+ : new Set(sourceSlice.map((target) => `${target.modulePath}\0${target.exportName}`));
4511
+ const selected = workspaceEffectRuntimeBindings.filter((binding) =>
4512
+ wanted.has(binding.sourceDomain) &&
4513
+ (slicedSources === undefined ||
4514
+ slicedSources.has(`${binding.sourceModulePath}\0${binding.sourceExportName}`))
4515
+ );
4516
+ const unique = [...new Map(selected.map((binding) => [
4517
+ `${binding.targetModulePath}\0${binding.targetExportName}`,
4518
+ binding,
4519
+ ])).values()];
4520
+ return {
4521
+ selected: unique,
4522
+ declarations: unique.length === 0
4523
+ ? []
4524
+ : [...TS_CALL_USDA_PRELUDE, ...unique.flatMap((binding) => binding.encoderSource), ""],
4525
+ config: unique.length === 0
4526
+ ? []
4527
+ : [
4528
+ ` workspaceEffectTargets: [`,
4529
+ ...unique.map((binding) =>
4530
+ ` { target: require(${JSON.stringify(binding.targetModulePath)})` +
4531
+ `[${JSON.stringify(binding.targetExportName)}] as any, encode: (payload: unknown, workspace: string) => ` +
4532
+ `${binding.encoderName}(payload as any, workspace).canonicalUsda },`
4533
+ ),
4534
+ ` ],`,
4535
+ ],
4536
+ };
4537
+ };
4258
4538
  const planEntrySource = (
4259
4539
  domainKeys: readonly string[],
4260
4540
  includeReports: boolean,
@@ -4265,13 +4545,16 @@ async function main(): Promise<void> {
4265
4545
  routedDomainFallback?: string,
4266
4546
  includeMintInstalls = true,
4267
4547
  sharedRuntime = false,
4548
+ sourceSlice?: readonly PlanSourceSliceTarget[],
4268
4549
  ): string => {
4550
+ const workspaceEffects = workspaceEffectRuntimeFor(domainKeys, sourceSlice);
4269
4551
  return [
4270
4552
  `// AUTO-GENERATED Nomos plan asset from ${path.basename(configPath)} — do not edit.`,
4271
4553
  `declare function require(id: string): Record<string, unknown>;`,
4272
4554
  ...(sharedRuntime ? [] : zodSeedImports),
4273
4555
  `import { registerEngine } from "@githolon/dsl/engine-entry";`,
4274
4556
  ``,
4557
+ ...workspaceEffects.declarations,
4275
4558
  `registerEngine({`,
4276
4559
  ` domains: {`,
4277
4560
  ...domainKeys.map((key) => {
@@ -4295,6 +4578,7 @@ async function main(): Promise<void> {
4295
4578
  ...(!sharedRuntime && zodSeedNames.length > 0 ? [` seeds: [${zodSeedNames.join(", ")}],`] : []),
4296
4579
  ...(includeDescribe ? [` openapiDocument: ${JSON.stringify(runtimeOpenApiDocument)},`] : []),
4297
4580
  ...(includeDescribe ? [` packageTitle: ${JSON.stringify(`${cfg.name} (nomos package)`)},`] : []),
4581
+ ...workspaceEffects.config,
4298
4582
  `});`,
4299
4583
  ...(includeMintInstalls
4300
4584
  ? domainKeys.flatMap((key) => {
@@ -4426,11 +4710,21 @@ async function main(): Promise<void> {
4426
4710
  } = {},
4427
4711
  ): Promise<UsdPlanAsset> => {
4428
4712
  const ordered = orderedDomainKeys.filter((key) => domainKeys.includes(key));
4713
+ const selectedWorkspaceEffects = workspaceEffectRuntimeFor(ordered, options.sliceTargets);
4714
+ const effectiveSliceTargets = options.sliceTargets === undefined
4715
+ ? undefined
4716
+ : [...new Map([
4717
+ ...options.sliceTargets,
4718
+ ...selectedWorkspaceEffects.selected.map((binding) => ({
4719
+ modulePath: binding.targetModulePath,
4720
+ exportName: binding.targetExportName,
4721
+ })),
4722
+ ].map((target) => [`${target.modulePath}\0${target.exportName}`, target] as const)).values()];
4429
4723
  const signature = JSON.stringify({
4430
4724
  domains: ordered,
4431
4725
  reports: includeReports,
4432
4726
  describe: includeDescribe,
4433
- slice: options.sliceTargets?.map((target) => [target.modulePath, target.exportName]) ?? null,
4727
+ slice: effectiveSliceTargets?.map((target) => [target.modulePath, target.exportName]) ?? null,
4434
4728
  cacheKey: options.cacheKey ?? null,
4435
4729
  });
4436
4730
  const hit = planBySignature.get(signature);
@@ -4446,6 +4740,7 @@ async function main(): Promise<void> {
4446
4740
  options.routedDomainFallback,
4447
4741
  options.includeMintInstalls ?? true,
4448
4742
  true,
4743
+ options.sliceTargets,
4449
4744
  ));
4450
4745
  let planProfile: readonly { readonly module: string; readonly bytesInOutput: number }[] | undefined;
4451
4746
  const profilePlan = process.env.NOMOS_PROFILE_PLANS === "1";
@@ -4486,9 +4781,9 @@ async function main(): Promise<void> {
4486
4781
  external: [...sharedRuntimeModuleIds],
4487
4782
  metafile: true,
4488
4783
  logLevel: "silent",
4489
- ...(options.sliceTargets === undefined
4784
+ ...(effectiveSliceTargets === undefined
4490
4785
  ? {}
4491
- : { plugins: [planSourceSlicer.plugin(options.sliceTargets)] }),
4786
+ : { plugins: [planSourceSlicer.plugin(effectiveSliceTargets)] }),
4492
4787
  });
4493
4788
  rmSync(sourcePath, { force: true });
4494
4789
  const output = result.outputFiles?.[0];
@@ -4940,7 +5235,7 @@ async function main(): Promise<void> {
4940
5235
  ` for (const [domain, directiveId] of workerData.checks) {`,
4941
5236
  ` let found;`,
4942
5237
  ` try { found = globalThis.__nomosHasDirective(domain, directiveId); }`,
4943
- ` catch (e) { parentPort.postMessage({ domain, error: String((e && e.message) || e) }); return; }`,
5238
+ ` catch (e) { parentPort.postMessage({ domain, error: String((e && (e.stack || e.message)) || e) }); return; }`,
4944
5239
  ` if (directiveId !== "" && found !== true) {`,
4945
5240
  ` parentPort.postMessage({ domain, error: "routed offer '" + directiveId + "' is absent from its selected plan registry" });`,
4946
5241
  ` return;`,
@@ -4948,7 +5243,7 @@ async function main(): Promise<void> {
4948
5243
  ` }`,
4949
5244
  ` parentPort.postMessage({ ok: true });`,
4950
5245
  ` } catch (e) {`,
4951
- ` parentPort.postMessage({ domain: workerData.checks[0]?.[0] || "?", error: String((e && e.message) || e) });`,
5246
+ ` parentPort.postMessage({ domain: workerData.checks[0]?.[0] || "?", error: String((e && (e.stack || e.message)) || e) });`,
4952
5247
  ` }`,
4953
5248
  `} else {`,
4954
5249
  ` const jobs = JSON.parse(fs.readFileSync(process.argv[2], "utf8"));`,
@@ -5349,6 +5644,8 @@ async function main(): Promise<void> {
5349
5644
  const clientDeclarationPath = path.join(outDir, `${cfg.name}.client.d.mts`);
5350
5645
  const headlessClientPath = path.join(outDir, `${cfg.name}.headless.mjs`);
5351
5646
  const headlessClientDeclarationPath = path.join(outDir, `${cfg.name}.headless.d.mts`);
5647
+ const operatorPath = path.join(outDir, `${cfg.name}.operator.mjs`);
5648
+ const operatorDeclarationPath = path.join(outDir, `${cfg.name}.operator.d.mts`);
5352
5649
  const clientOptions = {
5353
5650
  packageName: cfg.name,
5354
5651
  domainHash,
@@ -5356,12 +5653,18 @@ async function main(): Promise<void> {
5356
5653
  interface: packageInterface,
5357
5654
  compat: nomosCompat,
5358
5655
  homeDomain: resolveApplicationTopology(presentationDomainModules).homeDomain,
5656
+ callUsda: [...typedLawGraphs].map(([name, graph]) => {
5657
+ const paths = typedLawPathsByName.get(name);
5658
+ if (paths === undefined) throw new Error(`domain '${name}' has no rendered USDA path index`);
5659
+ return { graph, paths };
5660
+ }),
5359
5661
  } as const;
5360
5662
  const clientSource = generateTsClient(presentationDomainModules, clientOptions);
5361
5663
  const headlessClientSource = generateTsClient(presentationDomainModules, {
5362
5664
  ...clientOptions,
5363
5665
  exportHolonFactory: true,
5364
5666
  });
5667
+ const operatorSource = generateTsLifecycleOperator(clientOptions.callUsda);
5365
5668
  const runtimePath = path.join(DSL_DIR, "runtime", "generated-application-host.js");
5366
5669
  if (!existsSync(runtimePath)) {
5367
5670
  fail("the compiler-private generated application runtime is missing — reinstall @githolon/dsl");
@@ -5378,7 +5681,7 @@ async function main(): Promise<void> {
5378
5681
  const temporaryHeadlessDeclarationPath = temporaryHeadlessClientPath.replace(/\.ts$/, ".d.ts");
5379
5682
  const runtimeTypesSource = [
5380
5683
  `export declare function nomosInternalOpenGeneratedApplication<T extends object>(`,
5381
- ` options: { cloud: string; application: string; signIn: (request?: { readonly deviceChallenge?: string }) => Promise<string>; onPerformance?: (sample: { readonly operation: "open" | "offer" | "birth" | "read" | "sync" | "maintenance"; readonly name: string; readonly durationMs: number; readonly domain?: string; readonly directive?: string }) => void; approveModel?: (decision: { readonly summary: string; readonly review: { checkedActions: number; candidateActions: number; sameOutcome: boolean | null; differences: { kind: "rules" | "outcome" | "evidence"; area?: string; action?: string; summary: string }[] } }) => Promise<{ readonly because: string }>; lawHash: string; readyCommands?: readonly { readonly domain: string; readonly packageHash: string; readonly directiveId: string }[] },`,
5684
+ ` options: { cloud: string; application: string; signIn: (request?: { readonly deviceChallenge?: string }) => Promise<string>; onPerformance?: (sample: { readonly operation: "open" | "offer" | "birth" | "read" | "sync" | "maintenance"; readonly name: string; readonly durationMs: number; readonly domain?: string; readonly directive?: string }) => void; approveModel?: (decision: { readonly summary: string; readonly review: { checkedActions: number; candidateActions: number; sameOutcome: boolean | null; differences: { kind: "rules" | "outcome" | "evidence"; area?: string; action?: string; summary: string }[] } }) => Promise<{ readonly because: string }>; lawHash: string; readyCommands?: readonly { readonly domain: string; readonly packageHash: string; readonly directiveId: string }[]; frameworkCalls: unknown },`,
5382
5685
  ` bind: (holon: unknown, user: { readonly identityId: string; readonly identityAddress: string }) => T,`,
5383
5686
  `): Promise<T & {`,
5384
5687
  ` currentStatus(): Promise<any>;`,
@@ -5396,6 +5699,7 @@ async function main(): Promise<void> {
5396
5699
  ` holon: unknown,`,
5397
5700
  ` link: string,`,
5398
5701
  ` policies: readonly { readonly domain: string; readonly domainHash: string; readonly query: string; readonly redeem: string; readonly personField: string; readonly roleField: string; readonly scopeField: string }[],`,
5702
+ ` frameworkCalls: unknown,`,
5399
5703
  `): Promise<void>;`,
5400
5704
  ``,
5401
5705
  ].join("\n");
@@ -5705,6 +6009,47 @@ async function main(): Promise<void> {
5705
6009
  if (!new RegExp(`export\\s*\\{[^}]*${tsClientFactoryName(resolveApplicationTopology(presentationDomainModules).homeDomain)}`, "s").test(headlessBundled)) {
5706
6010
  fail("generated headless application omitted its structural holon factory");
5707
6011
  }
6012
+ if (operatorSource !== undefined) {
6013
+ const operatorDeclaration = ts.transpileDeclaration(operatorSource, {
6014
+ fileName: `${cfg.name}.operator.ts`,
6015
+ compilerOptions: {
6016
+ target: ts.ScriptTarget.ES2022,
6017
+ module: ts.ModuleKind.ESNext,
6018
+ strict: true,
6019
+ },
6020
+ reportDiagnostics: true,
6021
+ });
6022
+ const operatorErrors = (operatorDeclaration.diagnostics ?? []).filter(
6023
+ (diagnostic) => diagnostic.category === ts.DiagnosticCategory.Error,
6024
+ );
6025
+ if (operatorErrors.length > 0) {
6026
+ fail(`generated TypeScript lifecycle operator declarations are invalid — this is a Nomos codegen bug:\n${operatorErrors.map((diagnostic) => ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n")).join("\n")}`);
6027
+ }
6028
+ writeFileSync(operatorDeclarationPath, operatorDeclaration.outputText, "utf8");
6029
+ await esbuildMod.build({
6030
+ stdin: {
6031
+ contents: operatorSource,
6032
+ loader: "ts",
6033
+ resolveDir: outDir,
6034
+ sourcefile: `${cfg.name}.operator.ts`,
6035
+ },
6036
+ outfile: operatorPath,
6037
+ bundle: true,
6038
+ platform: "neutral",
6039
+ format: "esm",
6040
+ target: "es2022",
6041
+ legalComments: "none",
6042
+ logLevel: "silent",
6043
+ });
6044
+ writeFileSync(
6045
+ operatorPath,
6046
+ canonicalizeGeneratedClientJavascript(readFileSync(operatorPath, "utf8")),
6047
+ "utf8",
6048
+ );
6049
+ } else {
6050
+ rmSync(operatorPath, { force: true });
6051
+ rmSync(operatorDeclarationPath, { force: true });
6052
+ }
5708
6053
  } catch (e) {
5709
6054
  fail(`generated TypeScript application could not be sealed — this is a Nomos codegen bug: ${(e as Error).message}`);
5710
6055
  } finally {
@@ -5761,8 +6106,9 @@ async function main(): Promise<void> {
5761
6106
  // restores the prior good packages instead of leaving them wiped/partial. Finalized at process exit.
5762
6107
  if (dartPackages !== undefined) {
5763
6108
  const r = emitDartPackages(
5764
- presentationDomainModules, dartOut, domainHash, packageInterface, dartPackages,
6109
+ presentationDomainModules, dartOut, domainHash, typedLawGraphs, typedLawPathsByName, packageInterface, dartPackages,
5765
6110
  dartNames, nomosCompat, cfg.name, lawUsdzPath, cfg.application?.maxChildWorkspacesPerUser,
6111
+ closedDomainModules,
5766
6112
  );
5767
6113
  dartFiles = r.written;
5768
6114
  dartCursedHints = r.cursed;
@@ -5776,7 +6122,7 @@ async function main(): Promise<void> {
5776
6122
  .replace(/^(?=[0-9])/, "n");
5777
6123
  const dartBarrel =
5778
6124
  typeof dartCfg === "object" && dartCfg.barrel !== undefined ? dartCfg.barrel : defaultBarrel;
5779
- dartFiles = emitDart(presentationDomainModules, dartOut, domainHash, packageInterface, dartSupportImport, dartBarrel, nomosCompat, dartNames, cfg.name);
6125
+ dartFiles = emitDart(presentationDomainModules, dartOut, domainHash, typedLawGraphs, typedLawPathsByName, packageInterface, dartSupportImport, dartBarrel, nomosCompat, dartNames, cfg.name);
5780
6126
  }
5781
6127
  // COMPILE-VALID MUST MEAN COMPILABLE (co2): `githolon compile` reported success while the generated Dart
5782
6128
  // had hard compiler errors (a duplicate id symbol, missing contract-id defs). Run `dart analyze` over the