@githolon/dsl 0.108.0 → 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 (94) hide show
  1. package/dart/CHANGELOG.md +5 -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 +6401 -2102
  8. package/dart/lib/src/runner/offline-install.mjs +1538 -163
  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 +193 -112
  13. package/dart/lib/src/webview_bridge.dart +2120 -569
  14. package/dart/pubspec.yaml +2 -2
  15. package/dart/test/acquire_session_credentials_test.dart +1 -1
  16. package/dart/test/acquire_session_test.dart +68 -14
  17. package/dart/test/adv_realm_interference_test.dart +6 -4
  18. package/dart/test/cluster_births_test.dart +11 -8
  19. package/dart/test/cluster_local_autosync_test.dart +1 -1
  20. package/dart/test/cluster_scale_test.dart +3 -2
  21. package/dart/test/dlq_session_surface_test.dart +52 -35
  22. package/dart/test/first_app_gauntlet_test.dart +1 -1
  23. package/dart/test/local_sync_inert_test.dart +23 -26
  24. package/dart/test/offer_authentication_proof_test.dart +193 -0
  25. package/dart/test/result_usda_test.dart +49 -0
  26. package/dart/test/session_bound_test.dart +8 -11
  27. package/dart/test/stale_bundle_test.dart +18 -3
  28. package/dart/test/test_harness_test.dart +14 -27
  29. package/dart/test/webview_bridge_test.dart +504 -83
  30. package/dart_types/CHANGELOG.md +7 -0
  31. package/dart_types/lib/nomos_kernel_protocol.dart +3 -2
  32. package/dart_types/lib/src/custody.dart +64 -19
  33. package/dart_types/lib/src/local_work_rejected.dart +30 -45
  34. package/dart_types/lib/src/proto/nomos/custody/v1/snapshot.pb.dart +169 -0
  35. package/dart_types/lib/src/proto/nomos/custody/v1/snapshot.pbenum.dart +11 -0
  36. package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pb.dart +2021 -234
  37. package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pbenum.dart +175 -8
  38. package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pb.dart +8664 -0
  39. package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pbenum.dart +369 -0
  40. package/dart_types/lib/src/surfaced.dart +30 -25
  41. package/dart_types/pubspec.yaml +1 -1
  42. package/dart_types/test/surfaced_test.dart +2 -1
  43. package/package.json +1 -1
  44. package/runtime/generated-application-host.js +5736 -2047
  45. package/src/authoring.ts +3 -2
  46. package/src/births.ts +21 -0
  47. package/src/build_package.ts +30 -0
  48. package/src/business_birth.ts +39 -35
  49. package/src/codegen_call_usda.ts +1111 -0
  50. package/src/codegen_dart.ts +207 -282
  51. package/src/codegen_dart_application.ts +195 -252
  52. package/src/codegen_dart_client.ts +1978 -593
  53. package/src/codegen_dart_framework_calls.ts +291 -0
  54. package/src/codegen_dart_scenario.ts +7 -0
  55. package/src/codegen_proof.ts +3 -4
  56. package/src/codegen_provider_dart.ts +21 -7
  57. package/src/codegen_query_usda.ts +214 -0
  58. package/src/codegen_result_usda.ts +685 -0
  59. package/src/codegen_ts.ts +3945 -1111
  60. package/src/compile_package_main.ts +360 -32
  61. package/src/directive.ts +19 -4
  62. package/src/engine_entry.ts +45 -4
  63. package/src/framework/application_home.ts +2 -0
  64. package/src/framework/auth_provider_law.ts +262 -20
  65. package/src/framework/home.ts +32 -28
  66. package/src/framework/owned_custody.ts +19 -11
  67. package/src/framework/owned_custody_value.ts +51 -0
  68. package/src/framework/relations.ts +47 -21
  69. package/src/framework/signing_identity.ts +34 -0
  70. package/src/framework/workspaces.ts +31 -9
  71. package/src/framework_call_definitions.ts +53 -0
  72. package/src/framework_read_definitions.ts +45 -0
  73. package/src/identity_frontier.ts +58 -0
  74. package/src/index.ts +20 -1
  75. package/src/intent.ts +216 -16
  76. package/src/law_check.ts +19 -1
  77. package/src/law_graph.ts +57 -8
  78. package/src/law_graph_usda.ts +73 -5
  79. package/src/law_value_type.ts +106 -19
  80. package/src/read.ts +47 -0
  81. package/src/read_projection_namespace.ts +7 -0
  82. package/src/shape_compat.ts +38 -39
  83. package/src/stable_ids.ts +37 -2
  84. package/src/test_call_usda.ts +83 -0
  85. package/src/wire.ts +36 -2
  86. package/src/wire_encode.ts +45 -1
  87. package/src/workspace_sharing.ts +27 -10
  88. package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pbjson.dart +0 -6096
  89. package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pbserver.dart +0 -50
  90. package/dart_types/lib/src/proto/nomos/kernel/v1/progress.pbjson.dart +0 -178
  91. package/dart_types/lib/src/proto/nomos/runtime/v1/runtime.pb.dart +0 -828
  92. package/dart_types/lib/src/proto/nomos/runtime/v1/runtime.pbenum.dart +0 -465
  93. package/dart_types/lib/src/proto/nomos/runtime/v1/runtime.pbjson.dart +0 -573
  94. package/dart_types/lib/src/proto/nomos/runtime/v1/runtime.pbserver.dart +0 -50
@@ -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,6 +868,11 @@ 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. */
@@ -1115,6 +1127,7 @@ function dartValueObjectsForModule(
1115
1127
  const byName = new Map<string, NonNullable<DomainModule["valueObjects"]>[number]>();
1116
1128
  for (const descriptor of [
1117
1129
  ...(mod.valueObjects ?? []),
1130
+ ...collectValueObjectDescriptors(mod.aggregates),
1118
1131
  ...collectPayloadValueObjectDescriptors(codegenDirectives),
1119
1132
  ]) {
1120
1133
  const prior = byName.get(descriptor.name);
@@ -1174,9 +1187,23 @@ function collectDartSharedSymbols(
1174
1187
  }
1175
1188
  }
1176
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());
1177
1203
  const sharedVoNames: ReadonlySet<string> = new Set([
1178
1204
  ...[...voDomainsByName.entries()].filter(([, n]) => n > 1).map(([name]) => name),
1179
1205
  ...contractVoNames,
1206
+ ...frameworkVoNames,
1180
1207
  ]);
1181
1208
  const sharedVos = [...sharedVoNames].sort().map((name) => voDescriptorByName.get(name)!);
1182
1209
  const hasFrameworkSymbols =
@@ -1317,6 +1344,8 @@ function emitDart(
1317
1344
  modules: readonly DomainModule[],
1318
1345
  dartOut: string,
1319
1346
  domainHash: string,
1347
+ lawGraphs: ReadonlyMap<string, LawGraph>,
1348
+ lawPaths: ReadonlyMap<string, ReadonlyMap<string, string>>,
1320
1349
  packageInterface: Record<string, DomainInterface> = {},
1321
1350
  supportImport: DartSupportImport = "vendored",
1322
1351
  barrelName = "nomos_domains",
@@ -1364,9 +1393,20 @@ function emitDart(
1364
1393
  const generatedKernelProto = path.join(DSL_DIR, "dart_types", "lib", "src", "proto", "nomos", "kernel", "v1");
1365
1394
  const vendoredKernelProto = path.join(genDir, "src", "proto", "nomos", "kernel", "v1");
1366
1395
  mkdirSync(vendoredKernelProto, { recursive: true });
1367
- for (const f of ["kernel.pb.dart", "kernel.pbenum.dart"]) {
1396
+ for (const f of [
1397
+ "kernel.pb.dart",
1398
+ "kernel.pbenum.dart",
1399
+ "progress.pb.dart",
1400
+ "progress.pbenum.dart",
1401
+ ]) {
1368
1402
  copyFileSync(path.join(generatedKernelProto, f), path.join(vendoredKernelProto, f));
1369
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
+ }
1370
1410
  writeFileSync(
1371
1411
  path.join(genDir, "src", VENDORED_KERNEL_PROTOCOL_SHIM),
1372
1412
  [
@@ -1374,6 +1414,8 @@ function emitDart(
1374
1414
  "library;",
1375
1415
  "",
1376
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';",
1377
1419
  "",
1378
1420
  ].join("\n"),
1379
1421
  "utf8",
@@ -1445,10 +1487,51 @@ function emitDart(
1445
1487
  return p;
1446
1488
  };
1447
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
+
1448
1526
  // 2a. the shared framework file — the framework aggregates + directives + queries, ONCE. Its own
1449
1527
  // surface is emitted in full (no skip). Imported by every domain that folds any framework symbol.
1450
1528
  if (shared.frameworkMod !== undefined) {
1451
- writeGenerated(FRAMEWORK_FILE, generateDartDomain(shared.frameworkMod));
1529
+ writeGenerated(
1530
+ FRAMEWORK_FILE,
1531
+ generateDartDomain(shared.frameworkMod, {
1532
+ additionalValueObjects: shared.frameworkMod.valueObjects ?? [],
1533
+ }),
1534
+ );
1452
1535
  }
1453
1536
  // 2a-bis. the shared DOMAIN CONTRACTS file (`contracts.dart`) — every public DTO class, ONCE. Pure
1454
1537
  // (nomos_types + VOs). A foreignRef targeting a contract imports THIS, never the concrete domain.
@@ -1541,6 +1624,10 @@ function emitDart(
1541
1624
 
1542
1625
  const clientSrc = generateDartBridgeClient(modForDart, {
1543
1626
  domainHash,
1627
+ callUsda: {
1628
+ graph: lawGraphs.get(mod.name)!,
1629
+ paths: lawPaths.get(mod.name)!,
1630
+ },
1544
1631
  interface: packageInterface[modForDart.domain ?? modForDart.name],
1545
1632
  ...(compat !== undefined ? { compat } : {}),
1546
1633
  supportImport,
@@ -1560,6 +1647,7 @@ function emitDart(
1560
1647
  applicationSrc,
1561
1648
  clientFile,
1562
1649
  applicationFile,
1650
+ new Set(dartApplicationPublicClassNames(modForDart)),
1563
1651
  );
1564
1652
  const cp = path.join(genDir, clientFile);
1565
1653
  writeFileSync(cp, encapsulated.clientPart, "utf8");
@@ -1678,12 +1766,12 @@ const dartTypesImportFor = (generatedSource: string): string => {
1678
1766
  * just the floor generated code needs — a lagging pin forces tenants into dependency_overrides. */
1679
1767
  // 0.3.0: SurfacedValue<T>/SurfacedObservation/PendingConflictRow — generated Surfaced-field typing +
1680
1768
  // the pendingConflicts read rows.
1681
- const NOMOS_TYPES_DEP = "^0.9.0";
1769
+ const NOMOS_TYPES_DEP = "^0.10.0";
1682
1770
  // 0.48.x: session-bound clients (XClient.bind/NomosClientInterface/DomainClientSessionMismatch/
1683
1771
  // DomainNotInstalledForSession, engine.follow, pendingConflicts lanes) — the generated client
1684
1772
  // REQUIRES this surface. 0.48.1 fixes NomosSession.watchPendingConflicts delegation.
1685
- const NOMOS_CLIENT_DEP = "^0.65.0";
1686
- const NOMOS_FLUTTER_DEP = "^0.64.0";
1773
+ const NOMOS_CLIENT_DEP = "^0.65.1";
1774
+ const NOMOS_FLUTTER_DEP = "^0.64.1";
1687
1775
  // DRIFT TRIPWIRE: pubspec_pins.test.ts asserts these equal the CURRENT versions in dsl/dart/pubspec.yaml
1688
1776
  // and dsl/dart_types/pubspec.yaml — a Dart release without this bump fails the suite, so tenants never
1689
1777
  // land back in dependency_overrides (the exact co2 report this closes, third occurrence).
@@ -1746,6 +1834,7 @@ function encapsulateDartClient(
1746
1834
  applicationSrc: string,
1747
1835
  clientFile: string,
1748
1836
  applicationFile: string,
1837
+ publicClientNames: ReadonlySet<string>,
1749
1838
  ): { readonly clientPart: string; readonly applicationLibrary: string } {
1750
1839
  const directive = /^(import|export)\s+'([^']+)'(?:\s+[^;]+)?;\s*$/;
1751
1840
  const clientImportUri = clientFile.replace(/\.dart$/, "");
@@ -1820,17 +1909,20 @@ function encapsulateDartClient(
1820
1909
  "// ignore_for_file: unused_element, unused_element_parameter",
1821
1910
  `part of '${applicationFile}';`,
1822
1911
  "",
1823
- privatize(client.body.join("\n")).trimStart(),
1912
+ privatize(client.body.join("\n"), publicClientNames).trimStart(),
1824
1913
  "",
1825
1914
  ].join("\n"),
1826
1915
  applicationLibrary: [
1827
1916
  "// AUTO-GENERATED by nomos-compile — the sole importable application library.",
1828
- "// 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",
1829
1918
  ...imports.values(),
1830
1919
  ...exports.values(),
1831
1920
  `part '${clientFile}';`,
1832
1921
  "",
1833
- privatize(application.body.join("\n"), applicationNames).trimStart(),
1922
+ privatize(
1923
+ application.body.join("\n"),
1924
+ new Set([...applicationNames, ...publicClientNames]),
1925
+ ).trimStart(),
1834
1926
  "",
1835
1927
  ].join("\n"),
1836
1928
  };
@@ -1862,6 +1954,7 @@ function generatedPackageApplication(
1862
1954
  }[],
1863
1955
  homeDomain: string,
1864
1956
  rootDomains: readonly string[],
1957
+ hasApplicationFrameworkCalls: boolean,
1865
1958
  ): string {
1866
1959
  const application = dartApplicationClassName(packageName);
1867
1960
  const root = domains.find(({ domain }) => domain === homeDomain);
@@ -1921,6 +2014,9 @@ function generatedPackageApplication(
1921
2014
  `import 'package:nomos_flutter/src/application_status.dart' show ApplicationSignIn, ApplicationStatus;`,
1922
2015
  `import 'package:nomos_client/src/nms_generated_runtime.dart' show NmsInternalUsers, NomosSession, User${hasInvitations ? ", Invitation, Recipient" : ""};`,
1923
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
+ : []),
1924
2020
  ...members.map(({ file, prefix }) =>
1925
2021
  `import '${file}.application.dart' as ${prefix};`),
1926
2022
  ``,
@@ -1985,6 +2081,7 @@ function generatedPackageApplication(
1985
2081
  ` /// Redeem a transported invitation as [currentUser].`,
1986
2082
  ` Future<void> redeemInvitation(String link) => NmsInternalApplicationHost.redeemInvitation<User>(`,
1987
2083
  ` _nmsSession,`,
2084
+ ` frameworkCalls: nomosInternalApplicationFrameworkCalls,`,
1988
2085
  ` link: link,`,
1989
2086
  ` identity: _nmsUser.nmsInternalActor,`,
1990
2087
  ` policies: [`,
@@ -2023,6 +2120,9 @@ function generatedPackageApplication(
2023
2120
  ` Duration startupTimeout = const Duration(minutes: 3),`,
2024
2121
  ` }) => NmsInternalApplicationHost.home<${application}>(`,
2025
2122
  ` key: key, cloud: cloud, application: application, signIn: signIn,`,
2123
+ ...(hasApplicationFrameworkCalls
2124
+ ? [` frameworkCalls: nomosInternalApplicationFrameworkCalls,`]
2125
+ : []),
2026
2126
  ` bind: nomosInternalBind${application}, builder: builder,`,
2027
2127
  ` loadingBuilder: loadingBuilder, errorBuilder: errorBuilder,`,
2028
2128
  ` onModelChange: onModelChange,`,
@@ -2212,6 +2312,8 @@ function emitDartPackages(
2212
2312
  modules: readonly DomainModule[],
2213
2313
  dartOut: string,
2214
2314
  domainHash: string,
2315
+ lawGraphs: ReadonlyMap<string, LawGraph>,
2316
+ lawPaths: ReadonlyMap<string, ReadonlyMap<string, string>>,
2215
2317
  packageInterface: Record<string, DomainInterface>,
2216
2318
  packages: { readonly types: string; readonly client: string; readonly test?: string; readonly compat?: string; readonly barrelExports?: "all" | "explicit" },
2217
2319
  names: Readonly<Record<string, string>> | undefined,
@@ -2219,6 +2321,7 @@ function emitDartPackages(
2219
2321
  describePackageName = packages.client,
2220
2322
  lawUsdzPath?: string,
2221
2323
  applicationMaxChildWorkspacesPerUser?: number,
2324
+ frameworkModules: readonly DomainModule[] = modules,
2222
2325
  ): { written: string[]; cursed: string[] } {
2223
2326
  for (const [role, name] of Object.entries(packages)) {
2224
2327
  if (typeof name !== "string" || !isPubPackageName(name)) {
@@ -2291,7 +2394,14 @@ function emitDartPackages(
2291
2394
  written.push(p);
2292
2395
  };
2293
2396
 
2294
- 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
+ }
2295
2405
  // DOMAIN CONTRACTS (layered): the shared `contracts.dart` DTO file in the TYPES package (pure —
2296
2406
  // nomos_types + VOs). A contract-target foreignRef imports THIS sibling, never the concrete domain.
2297
2407
  const contractsImportUri = packageContracts.length > 0 ? `${CONTRACTS_FILE}.dart` : undefined;
@@ -2492,6 +2602,22 @@ function emitDartPackages(
2492
2602
 
2493
2603
  // ── the CLIENT package — effectful runtime, depends on types + nomos_client ──
2494
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
+ }
2495
2621
  const embeddedLawName = `${describePackageName}.law.usdz`;
2496
2622
  const applicationLawPath = lawUsdzPath === undefined
2497
2623
  ? undefined
@@ -2512,10 +2638,18 @@ function emitDartPackages(
2512
2638
  : undefined;
2513
2639
  const frameworkTypeNames = frameworkImplementationImport === undefined
2514
2640
  ? []
2515
- : [...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);
2516
2646
  for (const { mod, dd } of perDomain) {
2517
2647
  const makeClient = (imports: readonly string[]) => generateDartBridgeClient(dd.modForDart, {
2518
2648
  domainHash,
2649
+ callUsda: {
2650
+ graph: lawGraphs.get(mod.name)!,
2651
+ paths: lawPaths.get(mod.name)!,
2652
+ },
2519
2653
  ...(applicationLawAssetKey !== undefined
2520
2654
  ? { lawAssetKey: applicationLawAssetKey }
2521
2655
  : {}),
@@ -2540,6 +2674,9 @@ function emitDartPackages(
2540
2674
  packageAggregateDomains: buildPackageAggregateDomains(modules),
2541
2675
  flutterHost: true,
2542
2676
  tenantRoot: perDomain.length === 1,
2677
+ ...(applicationFrameworkCallsSource === undefined
2678
+ ? {}
2679
+ : { applicationFrameworkCallsImportUri: `${applicationFrameworkCallsFile}.dart` }),
2543
2680
  ...(imports.length > 0
2544
2681
  ? { explicitTypeImports: imports }
2545
2682
  : {}),
@@ -2565,6 +2702,7 @@ function emitDartPackages(
2565
2702
  applicationSrc,
2566
2703
  clientFile,
2567
2704
  applicationFile,
2705
+ new Set(dartApplicationPublicClassNames(dd.modForDart)),
2568
2706
  );
2569
2707
  const cp = path.join(clientGen, clientFile);
2570
2708
  writeFileSync(cp, encapsulated.clientPart, "utf8");
@@ -2595,6 +2733,7 @@ function emitDartPackages(
2595
2733
  })),
2596
2734
  topology.homeDomain,
2597
2735
  topology.rootDomains,
2736
+ applicationFrameworkCallsSource !== undefined,
2598
2737
  ),
2599
2738
  "utf8",
2600
2739
  );
@@ -2726,6 +2865,9 @@ function emitDartPackages(
2726
2865
  surfaceName,
2727
2866
  applicationFile,
2728
2867
  applicationModules: perDomain.map(({ dd: candidate }) => candidate.modForDart),
2868
+ ...(applicationFrameworkCallsSource === undefined
2869
+ ? {}
2870
+ : { applicationFrameworkCallsFile }),
2729
2871
  ...(applicationMaxChildWorkspacesPerUser === undefined
2730
2872
  ? {}
2731
2873
  : { applicationMaxChildWorkspacesPerUser }),
@@ -3092,6 +3234,13 @@ async function main(): Promise<void> {
3092
3234
  const nativeWorkspaceInvariantReadIds = new Set<string>();
3093
3235
  const routingInput: Record<string, Mod[]> = {};
3094
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
+ }> = [];
3095
3244
  // THE SELF-DESCRIBE DECLS (G1): per domain key, the FINISHED plain read/maintenance decls the
3096
3245
  // lump's `globalThis.describe` needs that it cannot rediscover by shape alone (mins/maxes are
3097
3246
  // config-named; sharding sums are framework-appended). Plain JSON (finishCount/Sum/Extremum
@@ -3189,6 +3338,13 @@ async function main(): Promise<void> {
3189
3338
  typeof (value as { plan?: unknown }).plan === "function" &&
3190
3339
  typeof (value as { aggregateId?: unknown }).aggregateId === "string"
3191
3340
  ) {
3341
+ directiveExportSources.push({
3342
+ directive: value,
3343
+ domainKey: d.key,
3344
+ graphName: d.name ?? d.key,
3345
+ modulePath: abs,
3346
+ exportName,
3347
+ });
3192
3348
  directOfferExports.set((value as { id: string }).id, {
3193
3349
  modulePath: abs,
3194
3350
  exportName,
@@ -3794,6 +3950,10 @@ async function main(): Promise<void> {
3794
3950
  const priorLock: CompilerIdentityModel | undefined = existsSync(lockPath)
3795
3951
  ? parseIdentityUsda(readFileSync(lockPath, "utf8"))
3796
3952
  : undefined;
3953
+ const historicalFrontier = readHistoricalIdentityFrontier(lockPath);
3954
+ const historicalLock: CompilerIdentityModel | undefined = historicalFrontier === undefined
3955
+ ? undefined
3956
+ : parseIdentityUsda(historicalFrontier.source);
3797
3957
  const inferredRenames: { domain: string; renames: InferredRename[] }[] = [];
3798
3958
  let nextIdentity = identityRegistryFromModel(priorLock);
3799
3959
  const typedLawGraphs = new Map<string, LawGraph>();
@@ -3849,6 +4009,7 @@ async function main(): Promise<void> {
3849
4009
  currentAggs,
3850
4010
  prior,
3851
4011
  priorSchemas,
4012
+ mod.retirements,
3852
4013
  );
3853
4014
  const reconciled = reconcileStableIdsWithIdentity(
3854
4015
  nextIdentity,
@@ -3942,9 +4103,9 @@ async function main(): Promise<void> {
3942
4103
  // The identity file is project-wide while a package may own only some of its domains. Scope the
3943
4104
  // prior side to the modules in this compile so compiling one sibling never reads another sibling's
3944
4105
  // absence as a domain retirement.
3945
- if (priorLock !== undefined) {
4106
+ if (historicalLock !== undefined) {
3946
4107
  const priorDomainsForPackage: CompilerIdentityModel["domains"] = {};
3947
- const priorIdentity = identityRegistryFromModel(priorLock);
4108
+ const priorIdentity = identityRegistryFromModel(historicalLock);
3948
4109
  const frameworkAggregateSids = new Set(
3949
4110
  Object.values(priorIdentity.entities)
3950
4111
  .filter((entity) => entity.kind === "aggregate" && entity.parent === LAW_FRAMEWORK_PARENT)
@@ -3952,7 +4113,7 @@ async function main(): Promise<void> {
3952
4113
  );
3953
4114
  for (const mod of domainModules) {
3954
4115
  const domainKey = mod.domain ?? mod.name;
3955
- const locked = priorLock.domains[mod.name] ?? priorLock.domains[domainKey];
4116
+ const locked = historicalLock.domains[mod.name] ?? historicalLock.domains[domainKey];
3956
4117
  if (locked !== undefined) {
3957
4118
  const currentImplementationDetailAggregateIds = new Set(
3958
4119
  mod.aggregates
@@ -3990,7 +4151,7 @@ async function main(): Promise<void> {
3990
4151
  const priorLaw = evolveLawFromLockfile({
3991
4152
  v: 1,
3992
4153
  domains: priorDomainsForPackage,
3993
- ...(priorLock.identity === undefined ? {} : { identity: priorLock.identity }),
4154
+ ...(historicalLock.identity === undefined ? {} : { identity: historicalLock.identity }),
3994
4155
  });
3995
4156
  const candidateLaw = currentEvolveLaw(domainModules, nextLock);
3996
4157
  const evolutionFindings = evolveDiff(priorLaw, candidateLaw).findings;
@@ -4080,10 +4241,12 @@ async function main(): Promise<void> {
4080
4241
  const v3Closure = [...typedLawGraphs.values()];
4081
4242
  const v3DomainAssets: EmittedLawClosureAsset[] = [];
4082
4243
  const typedDomainIdentityByName = new Map<string, string>();
4244
+ const typedLawPathsByName = new Map<string, ReadonlyMap<string, string>>();
4083
4245
  for (const [domain, graph] of typedLawGraphs) {
4084
4246
  const safeDomain = domain.replace(/[^A-Za-z0-9._-]/g, "_");
4085
4247
  const logicalPath = `domains/${safeDomain}.usda`;
4086
- const layerText = emitSparseLawGraphUsda(graph, logicalPath, v3Closure);
4248
+ const compiledLayer = compileSparseLawGraphUsda(graph, logicalPath, v3Closure);
4249
+ const layerText = compiledLayer.text;
4087
4250
  const sha256 = sha256HexUtf8(layerText);
4088
4251
  v3DomainAssets.push({
4089
4252
  logicalPath,
@@ -4091,6 +4254,66 @@ async function main(): Promise<void> {
4091
4254
  utf8: layerText,
4092
4255
  });
4093
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
+ }
4094
4317
  }
4095
4318
 
4096
4319
  // ── reports ──
@@ -4170,11 +4393,13 @@ async function main(): Promise<void> {
4170
4393
  }
4171
4394
  }
4172
4395
 
4173
- // Resolve esbuild through Node's resolver (caller's copy first, else the DSL's
4174
- // own dependency) — NOT node_modules/.bin paths, which hoisted/workspace
4175
- // installs relocate. The pinned dependency keeps the engine-lump bytes (and so
4176
- // the content-addressed domainHash) reproducible across machines.
4177
- 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]
4178
4403
  .map((dir) => {
4179
4404
  try {
4180
4405
  return createRequire(pathToFileURL(path.join(dir, "noop.js"))).resolve("esbuild/package.json");
@@ -4186,7 +4411,9 @@ async function main(): Promise<void> {
4186
4411
  if (!esbuildPkgJson) fail(`esbuild not found — reinstall @githolon/dsl (esbuild is one of its dependencies)`);
4187
4412
  const esbuildMod = (await import(pathToFileURL(path.join(path.dirname(esbuildPkgJson), "lib", "main.js")).href)) as typeof import("esbuild");
4188
4413
 
4189
- const compact = compactFlag || cfg.compact === true;
4414
+ const compact = process.env.NOMOS_READABLE === "1"
4415
+ ? false
4416
+ : compactFlag || cfg.compact === true;
4190
4417
  const runtimeZodPath = path.join(DSL_DIR, "src", "runtime_zod.ts");
4191
4418
  const runtimeZodPackage = createRequire(import.meta.url).resolve("zod/package.json");
4192
4419
  const runtimeZodV4Path = path.join(path.dirname(runtimeZodPackage), "v4", "index.js");
@@ -4273,6 +4500,41 @@ async function main(): Promise<void> {
4273
4500
  ),
4274
4501
  };
4275
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
+ };
4276
4538
  const planEntrySource = (
4277
4539
  domainKeys: readonly string[],
4278
4540
  includeReports: boolean,
@@ -4283,13 +4545,16 @@ async function main(): Promise<void> {
4283
4545
  routedDomainFallback?: string,
4284
4546
  includeMintInstalls = true,
4285
4547
  sharedRuntime = false,
4548
+ sourceSlice?: readonly PlanSourceSliceTarget[],
4286
4549
  ): string => {
4550
+ const workspaceEffects = workspaceEffectRuntimeFor(domainKeys, sourceSlice);
4287
4551
  return [
4288
4552
  `// AUTO-GENERATED Nomos plan asset from ${path.basename(configPath)} — do not edit.`,
4289
4553
  `declare function require(id: string): Record<string, unknown>;`,
4290
4554
  ...(sharedRuntime ? [] : zodSeedImports),
4291
4555
  `import { registerEngine } from "@githolon/dsl/engine-entry";`,
4292
4556
  ``,
4557
+ ...workspaceEffects.declarations,
4293
4558
  `registerEngine({`,
4294
4559
  ` domains: {`,
4295
4560
  ...domainKeys.map((key) => {
@@ -4313,6 +4578,7 @@ async function main(): Promise<void> {
4313
4578
  ...(!sharedRuntime && zodSeedNames.length > 0 ? [` seeds: [${zodSeedNames.join(", ")}],`] : []),
4314
4579
  ...(includeDescribe ? [` openapiDocument: ${JSON.stringify(runtimeOpenApiDocument)},`] : []),
4315
4580
  ...(includeDescribe ? [` packageTitle: ${JSON.stringify(`${cfg.name} (nomos package)`)},`] : []),
4581
+ ...workspaceEffects.config,
4316
4582
  `});`,
4317
4583
  ...(includeMintInstalls
4318
4584
  ? domainKeys.flatMap((key) => {
@@ -4444,11 +4710,21 @@ async function main(): Promise<void> {
4444
4710
  } = {},
4445
4711
  ): Promise<UsdPlanAsset> => {
4446
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()];
4447
4723
  const signature = JSON.stringify({
4448
4724
  domains: ordered,
4449
4725
  reports: includeReports,
4450
4726
  describe: includeDescribe,
4451
- slice: options.sliceTargets?.map((target) => [target.modulePath, target.exportName]) ?? null,
4727
+ slice: effectiveSliceTargets?.map((target) => [target.modulePath, target.exportName]) ?? null,
4452
4728
  cacheKey: options.cacheKey ?? null,
4453
4729
  });
4454
4730
  const hit = planBySignature.get(signature);
@@ -4464,6 +4740,7 @@ async function main(): Promise<void> {
4464
4740
  options.routedDomainFallback,
4465
4741
  options.includeMintInstalls ?? true,
4466
4742
  true,
4743
+ options.sliceTargets,
4467
4744
  ));
4468
4745
  let planProfile: readonly { readonly module: string; readonly bytesInOutput: number }[] | undefined;
4469
4746
  const profilePlan = process.env.NOMOS_PROFILE_PLANS === "1";
@@ -4504,9 +4781,9 @@ async function main(): Promise<void> {
4504
4781
  external: [...sharedRuntimeModuleIds],
4505
4782
  metafile: true,
4506
4783
  logLevel: "silent",
4507
- ...(options.sliceTargets === undefined
4784
+ ...(effectiveSliceTargets === undefined
4508
4785
  ? {}
4509
- : { plugins: [planSourceSlicer.plugin(options.sliceTargets)] }),
4786
+ : { plugins: [planSourceSlicer.plugin(effectiveSliceTargets)] }),
4510
4787
  });
4511
4788
  rmSync(sourcePath, { force: true });
4512
4789
  const output = result.outputFiles?.[0];
@@ -4958,7 +5235,7 @@ async function main(): Promise<void> {
4958
5235
  ` for (const [domain, directiveId] of workerData.checks) {`,
4959
5236
  ` let found;`,
4960
5237
  ` try { found = globalThis.__nomosHasDirective(domain, directiveId); }`,
4961
- ` 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; }`,
4962
5239
  ` if (directiveId !== "" && found !== true) {`,
4963
5240
  ` parentPort.postMessage({ domain, error: "routed offer '" + directiveId + "' is absent from its selected plan registry" });`,
4964
5241
  ` return;`,
@@ -4966,7 +5243,7 @@ async function main(): Promise<void> {
4966
5243
  ` }`,
4967
5244
  ` parentPort.postMessage({ ok: true });`,
4968
5245
  ` } catch (e) {`,
4969
- ` 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) });`,
4970
5247
  ` }`,
4971
5248
  `} else {`,
4972
5249
  ` const jobs = JSON.parse(fs.readFileSync(process.argv[2], "utf8"));`,
@@ -5367,6 +5644,8 @@ async function main(): Promise<void> {
5367
5644
  const clientDeclarationPath = path.join(outDir, `${cfg.name}.client.d.mts`);
5368
5645
  const headlessClientPath = path.join(outDir, `${cfg.name}.headless.mjs`);
5369
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`);
5370
5649
  const clientOptions = {
5371
5650
  packageName: cfg.name,
5372
5651
  domainHash,
@@ -5374,12 +5653,18 @@ async function main(): Promise<void> {
5374
5653
  interface: packageInterface,
5375
5654
  compat: nomosCompat,
5376
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
+ }),
5377
5661
  } as const;
5378
5662
  const clientSource = generateTsClient(presentationDomainModules, clientOptions);
5379
5663
  const headlessClientSource = generateTsClient(presentationDomainModules, {
5380
5664
  ...clientOptions,
5381
5665
  exportHolonFactory: true,
5382
5666
  });
5667
+ const operatorSource = generateTsLifecycleOperator(clientOptions.callUsda);
5383
5668
  const runtimePath = path.join(DSL_DIR, "runtime", "generated-application-host.js");
5384
5669
  if (!existsSync(runtimePath)) {
5385
5670
  fail("the compiler-private generated application runtime is missing — reinstall @githolon/dsl");
@@ -5396,7 +5681,7 @@ async function main(): Promise<void> {
5396
5681
  const temporaryHeadlessDeclarationPath = temporaryHeadlessClientPath.replace(/\.ts$/, ".d.ts");
5397
5682
  const runtimeTypesSource = [
5398
5683
  `export declare function nomosInternalOpenGeneratedApplication<T extends object>(`,
5399
- ` 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 },`,
5400
5685
  ` bind: (holon: unknown, user: { readonly identityId: string; readonly identityAddress: string }) => T,`,
5401
5686
  `): Promise<T & {`,
5402
5687
  ` currentStatus(): Promise<any>;`,
@@ -5414,6 +5699,7 @@ async function main(): Promise<void> {
5414
5699
  ` holon: unknown,`,
5415
5700
  ` link: string,`,
5416
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,`,
5417
5703
  `): Promise<void>;`,
5418
5704
  ``,
5419
5705
  ].join("\n");
@@ -5723,6 +6009,47 @@ async function main(): Promise<void> {
5723
6009
  if (!new RegExp(`export\\s*\\{[^}]*${tsClientFactoryName(resolveApplicationTopology(presentationDomainModules).homeDomain)}`, "s").test(headlessBundled)) {
5724
6010
  fail("generated headless application omitted its structural holon factory");
5725
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
+ }
5726
6053
  } catch (e) {
5727
6054
  fail(`generated TypeScript application could not be sealed — this is a Nomos codegen bug: ${(e as Error).message}`);
5728
6055
  } finally {
@@ -5779,8 +6106,9 @@ async function main(): Promise<void> {
5779
6106
  // restores the prior good packages instead of leaving them wiped/partial. Finalized at process exit.
5780
6107
  if (dartPackages !== undefined) {
5781
6108
  const r = emitDartPackages(
5782
- presentationDomainModules, dartOut, domainHash, packageInterface, dartPackages,
6109
+ presentationDomainModules, dartOut, domainHash, typedLawGraphs, typedLawPathsByName, packageInterface, dartPackages,
5783
6110
  dartNames, nomosCompat, cfg.name, lawUsdzPath, cfg.application?.maxChildWorkspacesPerUser,
6111
+ closedDomainModules,
5784
6112
  );
5785
6113
  dartFiles = r.written;
5786
6114
  dartCursedHints = r.cursed;
@@ -5794,7 +6122,7 @@ async function main(): Promise<void> {
5794
6122
  .replace(/^(?=[0-9])/, "n");
5795
6123
  const dartBarrel =
5796
6124
  typeof dartCfg === "object" && dartCfg.barrel !== undefined ? dartCfg.barrel : defaultBarrel;
5797
- 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);
5798
6126
  }
5799
6127
  // COMPILE-VALID MUST MEAN COMPILABLE (co2): `githolon compile` reported success while the generated Dart
5800
6128
  // had hard compiler errors (a duplicate id symbol, missing contract-id defs). Run `dart analyze` over the