@githolon/dsl 0.108.7 → 0.110.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 (308) hide show
  1. package/assets/operation-contract.wasm +0 -0
  2. package/check_package.mjs +12 -15
  3. package/compile_package.mjs +17 -18
  4. package/compile_proof.mjs +16 -1
  5. package/dart/CHANGELOG.md +80 -1
  6. package/dart/README.md +25 -2
  7. package/dart/lib/src/admission_decision.dart +41 -0
  8. package/dart/lib/src/application_framework_calls.dart +52 -2
  9. package/dart/lib/src/application_model_adoption.dart +187 -0
  10. package/dart/lib/src/application_status.dart +73 -0
  11. package/dart/lib/src/console_enrolment.dart +271 -0
  12. package/dart/lib/src/console_http_io.dart +26 -0
  13. package/dart/lib/src/console_http_stub.dart +7 -0
  14. package/dart/lib/src/dev_cloud.dart +69 -22
  15. package/dart/lib/src/generated_call.dart +83 -23
  16. package/dart/lib/src/kernel_primitives.dart +119 -0
  17. package/dart/lib/src/nms_conformance_runtime.dart +1 -1
  18. package/dart/lib/src/nms_generated_runtime.dart +32 -10
  19. package/dart/lib/src/nms_test_environment.dart +1 -1
  20. package/dart/lib/src/node_runner_transport.dart +41 -46
  21. package/dart/lib/src/observed_session_directory.dart +70 -0
  22. package/dart/lib/src/operation_receipts.dart +112 -0
  23. package/dart/lib/src/peer_application_streams.dart +103 -0
  24. package/dart/lib/src/reception/dart_reception.dart +4280 -0
  25. package/dart/lib/src/reception/event_desk.dart +214 -0
  26. package/dart/lib/src/reception/extremum_read.dart +46 -0
  27. package/dart/lib/src/reception/local_copies.dart +371 -0
  28. package/dart/lib/src/reception/peer_office_connection.dart +11 -0
  29. package/dart/lib/src/reception/progress_desk.dart +268 -0
  30. package/dart/lib/src/reception/reception_contract.dart +11 -0
  31. package/dart/lib/src/reception/reception_session.dart +284 -0
  32. package/dart/lib/src/reception/sync_diagnostics.dart +26 -0
  33. package/dart/lib/src/reception/workspace_preparation_report.dart +126 -0
  34. package/dart/lib/src/replica_readiness.dart +123 -0
  35. package/dart/lib/src/runner/node-entry.mjs +23950 -15776
  36. package/dart/lib/src/runtime_v2_gateway.dart +56 -3
  37. package/dart/lib/src/runtime_v2_transport.dart +544 -3
  38. package/dart/lib/src/session_bound.dart +200 -311
  39. package/dart/lib/src/signing_identity_kernel.dart +84 -0
  40. package/dart/lib/src/sync_status_projection.dart +550 -0
  41. package/dart/lib/src/sync_status_reducer.dart +170 -0
  42. package/dart/lib/src/test_harness.dart +809 -1153
  43. package/dart/lib/src/testing/test_custody.dart +66 -0
  44. package/dart/lib/src/testing/test_peer.dart +328 -0
  45. package/dart/lib/src/typed_watch_registry.dart +169 -0
  46. package/dart/lib/src/workspace_open_progress.dart +27 -0
  47. package/dart/pubspec.lock +24 -1
  48. package/dart/pubspec.yaml +7 -2
  49. package/dart/pubspec_overrides.yaml +2 -0
  50. package/dart/test/admission_decision_test.dart +48 -0
  51. package/dart/test/background_model_adoption_test.dart +228 -0
  52. package/dart/test/bundle_version_pairing_test.dart +4 -4
  53. package/dart/test/child_authentication_repair_test.dart +359 -0
  54. package/dart/test/cloud_bound_local_shell_test.dart +119 -0
  55. package/dart/test/console_enrolment_refusal_test.dart +52 -0
  56. package/dart/test/console_enrolment_test.dart +227 -0
  57. package/dart/test/errors_test.dart +5 -5
  58. package/dart/test/event_plane_seam_test.dart +50 -164
  59. package/dart/test/extremum_read_test.dart +58 -0
  60. package/dart/test/fixtures/wedge/wedge-entry.mjs +3 -21
  61. package/dart/test/generated_query_test.dart +32 -0
  62. package/dart/test/harness_phase_timeout_test.dart +18 -23
  63. package/dart/test/kernel_author_after_read_test.dart +242 -0
  64. package/dart/test/kernel_fence_test.dart +137 -0
  65. package/dart/test/local_copies_test.dart +222 -0
  66. package/dart/test/model_adoption_test.dart +198 -0
  67. package/dart/test/node_peer_local_custody_test.dart +153 -0
  68. package/dart/test/offer_authentication_proof_test.dart +352 -52
  69. package/dart/test/operation_compatibility_test.dart +151 -0
  70. package/dart/test/platform_credential_effect_test.dart +386 -0
  71. package/dart/test/receiving_group_open_test.dart +213 -0
  72. package/dart/test/reception/workspace_preparation_report_test.dart +103 -0
  73. package/dart/test/reception_event_desk_close_test.dart +16 -0
  74. package/dart/test/reception_span_trace_test.dart +23 -0
  75. package/dart/test/replica_readiness_test.dart +156 -0
  76. package/dart/test/runtime_projections_test.dart +92 -0
  77. package/dart/test/runtime_v2_gateway_test.dart +131 -0
  78. package/dart/test/signing_identity_kernel_test.dart +75 -0
  79. package/dart/test/sync_status_preparation_report_test.dart +29 -0
  80. package/dart/test/sync_status_reducer_test.dart +419 -0
  81. package/dart/test/test_harness_test.dart +71 -95
  82. package/dart/test/typed_query_watch_test.dart +170 -0
  83. package/dart/test/typed_watch_registry_test.dart +249 -0
  84. package/dart_lints/README.md +18 -0
  85. package/dart_lints/lib/nomos_lints.dart +70 -0
  86. package/dart_lints/pubspec.lock +580 -0
  87. package/dart_lints/pubspec.yaml +12 -0
  88. package/dart_lints/test/reference_identity_test.dart +75 -0
  89. package/dart_types/CHANGELOG.md +18 -0
  90. package/dart_types/lib/nomos_kernel_protocol.dart +21 -1
  91. package/dart_types/lib/nomos_types.dart +9 -1
  92. package/dart_types/lib/src/admission_decision.dart +37 -0
  93. package/dart_types/lib/src/aggregate_meta.dart +1 -1
  94. package/dart_types/lib/src/approved_model.dart +65 -0
  95. package/dart_types/lib/src/custody.dart +10 -18
  96. package/dart_types/lib/src/error_info.dart +4 -4
  97. package/dart_types/lib/src/errors.dart +29 -29
  98. package/dart_types/lib/src/foreign_ref.dart +62 -33
  99. package/dart_types/lib/src/local_work_rejected.dart +3 -3
  100. package/dart_types/lib/src/nomos_ref.dart +3 -1
  101. package/dart_types/lib/src/principal.dart +2 -2
  102. package/dart_types/lib/src/proto/google/protobuf/any.pb.dart +163 -0
  103. package/dart_types/lib/src/proto/google/protobuf/any.pbenum.dart +11 -0
  104. package/dart_types/lib/src/proto/nomos/discovery/v1/workspace_placement.pb.dart +137 -0
  105. package/dart_types/lib/src/proto/nomos/discovery/v1/workspace_placement.pbenum.dart +11 -0
  106. package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pb.dart +20721 -10433
  107. package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pbenum.dart +555 -27
  108. package/dart_types/lib/src/proto/nomos/runtime/v2/application_desk.pb.dart +387 -0
  109. package/dart_types/lib/src/proto/nomos/runtime/v2/application_desk.pbenum.dart +46 -0
  110. package/dart_types/lib/src/proto/nomos/runtime/v2/application_readiness_desk.pb.dart +295 -0
  111. package/dart_types/lib/src/proto/nomos/runtime/v2/application_readiness_desk.pbenum.dart +139 -0
  112. package/dart_types/lib/src/proto/nomos/runtime/v2/authentication_desk.pb.dart +269 -0
  113. package/dart_types/lib/src/proto/nomos/runtime/v2/authentication_desk.pbenum.dart +103 -0
  114. package/dart_types/lib/src/proto/nomos/runtime/v2/compatibility_desk.pb.dart +417 -0
  115. package/dart_types/lib/src/proto/nomos/runtime/v2/compatibility_desk.pbenum.dart +62 -0
  116. package/dart_types/lib/src/proto/nomos/runtime/v2/correspondence_desk.pb.dart +9968 -0
  117. package/dart_types/lib/src/proto/nomos/runtime/v2/correspondence_desk.pbenum.dart +133 -0
  118. package/dart_types/lib/src/proto/nomos/runtime/v2/credentials_desk.pb.dart +204 -0
  119. package/dart_types/lib/src/proto/nomos/runtime/v2/credentials_desk.pbenum.dart +54 -0
  120. package/dart_types/lib/src/proto/nomos/runtime/v2/custody_desk.pb.dart +1550 -0
  121. package/dart_types/lib/src/proto/nomos/runtime/v2/custody_desk.pbenum.dart +11 -0
  122. package/dart_types/lib/src/proto/nomos/runtime/v2/framework.pb.dart +710 -0
  123. package/dart_types/lib/src/proto/nomos/runtime/v2/framework.pbenum.dart +11 -0
  124. package/dart_types/lib/src/proto/nomos/runtime/v2/identity_desk.pb.dart +845 -0
  125. package/dart_types/lib/src/proto/nomos/runtime/v2/identity_desk.pbenum.dart +11 -0
  126. package/dart_types/lib/src/proto/nomos/runtime/v2/interaction_desk.pb.dart +198 -0
  127. package/dart_types/lib/src/proto/nomos/runtime/v2/interaction_desk.pbenum.dart +11 -0
  128. package/dart_types/lib/src/proto/nomos/runtime/v2/law_desk.pb.dart +369 -0
  129. package/dart_types/lib/src/proto/nomos/runtime/v2/law_desk.pbenum.dart +11 -0
  130. package/dart_types/lib/src/proto/nomos/runtime/v2/maintenance_desk.pb.dart +609 -0
  131. package/dart_types/lib/src/proto/nomos/runtime/v2/maintenance_desk.pbenum.dart +65 -0
  132. package/dart_types/lib/src/proto/nomos/runtime/v2/model_adoption_desk.pb.dart +358 -0
  133. package/dart_types/lib/src/proto/nomos/runtime/v2/model_adoption_desk.pbenum.dart +100 -0
  134. package/dart_types/lib/src/proto/nomos/runtime/v2/observability_desk.pb.dart +2231 -0
  135. package/dart_types/lib/src/proto/nomos/runtime/v2/observability_desk.pbenum.dart +271 -0
  136. package/dart_types/lib/src/proto/nomos/runtime/v2/placement_desk.pb.dart +1286 -0
  137. package/dart_types/lib/src/proto/nomos/runtime/v2/placement_desk.pbenum.dart +11 -0
  138. package/dart_types/lib/src/proto/nomos/runtime/v2/receiving_group_desk.pb.dart +636 -0
  139. package/dart_types/lib/src/proto/nomos/runtime/v2/receiving_group_desk.pbenum.dart +116 -0
  140. package/dart_types/lib/src/proto/nomos/runtime/v2/records_desk.pb.dart +1637 -0
  141. package/dart_types/lib/src/proto/nomos/runtime/v2/records_desk.pbenum.dart +175 -0
  142. package/dart_types/lib/src/proto/nomos/runtime/v2/recovery_desk.pb.dart +1269 -0
  143. package/dart_types/lib/src/proto/nomos/runtime/v2/recovery_desk.pbenum.dart +129 -0
  144. package/dart_types/lib/src/proto/nomos/runtime/v2/residency_desk.pb.dart +2782 -0
  145. package/dart_types/lib/src/proto/nomos/runtime/v2/residency_desk.pbenum.dart +97 -0
  146. package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pb.dart +2232 -8627
  147. package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pbenum.dart +0 -358
  148. package/dart_types/lib/src/proto/nomos/runtime/v2/sealing_desk.pb.dart +1639 -0
  149. package/dart_types/lib/src/proto/nomos/runtime/v2/sealing_desk.pbenum.dart +46 -0
  150. package/dart_types/lib/src/runtime_outcome.dart +133 -0
  151. package/dart_types/lib/src/subscriptions.dart +116 -23
  152. package/dart_types/pubspec.yaml +1 -1
  153. package/dart_types/test/extremum_subscriptions_test.dart +40 -0
  154. package/dart_types/test/foreign_ref_resolution_test.dart +75 -0
  155. package/dart_types/test/nomos_ref_address_test.dart +25 -0
  156. package/dart_types/test/ordered_subscriptions_test.dart +34 -0
  157. package/operation_contract_check.mjs +24 -0
  158. package/package.json +11 -6
  159. package/src/aggregate.ts +70 -10
  160. package/src/application_topology.ts +18 -11
  161. package/src/attested.ts +3 -0
  162. package/src/attested_core.ts +46 -3
  163. package/src/birth_meter_ensure.ts +19 -7
  164. package/src/births.ts +29 -4
  165. package/src/build_package.ts +140 -13
  166. package/src/business_birth.ts +181 -4
  167. package/src/codegen_call_proto.ts +1276 -0
  168. package/src/codegen_call_usda.ts +49 -6
  169. package/src/codegen_dart.ts +83 -44
  170. package/src/codegen_dart_client.ts +458 -800
  171. package/src/{codegen_dart_application.ts → codegen_dart_facade.ts} +331 -582
  172. package/src/codegen_dart_framework_calls.ts +320 -37
  173. package/src/codegen_dart_indexed_variant.ts +159 -0
  174. package/src/codegen_dart_scenario.ts +42 -13
  175. package/src/codegen_proof.ts +3 -3
  176. package/src/codegen_provider_dart.ts +5 -0
  177. package/src/codegen_query_proto.ts +158 -0
  178. package/src/codegen_refusal.ts +189 -0
  179. package/src/codegen_result_proto.ts +931 -0
  180. package/src/codegen_result_usda.ts +4 -0
  181. package/src/codegen_ts.ts +464 -616
  182. package/src/codegen_workspace_access.ts +105 -0
  183. package/src/compatibility_graph.ts +759 -0
  184. package/src/compatibility_usda.ts +264 -0
  185. package/src/compile_package_main.ts +2017 -1195
  186. package/src/custody_placement.ts +156 -0
  187. package/src/custody_placement_usda.ts +91 -0
  188. package/src/decl_shapes.ts +21 -2
  189. package/src/describe_model.ts +1 -0
  190. package/src/directive.ts +59 -2
  191. package/src/drivers.ts +51 -0
  192. package/src/engine_entry.ts +52 -8
  193. package/src/evolve_preview.ts +11 -4
  194. package/src/exists.ts +2 -0
  195. package/src/fields.ts +75 -11
  196. package/src/flow_gate.ts +2 -1
  197. package/src/framework/application_home.ts +170 -18
  198. package/src/framework/attested_receipts.ts +8 -3
  199. package/src/framework/auth_provider_law.ts +169 -9
  200. package/src/framework/birth_certificate_law.ts +4 -0
  201. package/src/framework/capability.ts +34 -3
  202. package/src/framework/child_authentication.ts +346 -0
  203. package/src/framework/console_governance.ts +295 -0
  204. package/src/framework/delegated_roles.ts +301 -0
  205. package/src/framework/domain_lifecycle.ts +26 -13
  206. package/src/framework/founding_genesis.ts +193 -0
  207. package/src/framework/framework_aggregates.ts +1 -1
  208. package/src/framework/genesis.ts +6 -1
  209. package/src/framework/governance_relations.ts +19 -0
  210. package/src/framework/home.ts +5 -734
  211. package/src/framework/legacy/child_auth_provider_epoch.ts +73 -0
  212. package/src/framework/model_authority_repair.ts +116 -0
  213. package/src/framework/model_authority_seed.ts +185 -0
  214. package/src/framework/model_transition.ts +211 -0
  215. package/src/framework/owned_custody.ts +1 -1
  216. package/src/framework/principal_enrollment.ts +302 -0
  217. package/src/framework/receiving_group.ts +857 -0
  218. package/src/framework/receiving_group_recovery.ts +314 -0
  219. package/src/framework/relations.ts +4 -8
  220. package/src/framework/signing_identity.ts +242 -95
  221. package/src/framework/source_roster.ts +11 -5
  222. package/src/framework/workspace_access.ts +149 -0
  223. package/src/framework/workspace_invariant.ts +73 -52
  224. package/src/framework/workspaces.ts +407 -40
  225. package/src/framework_call_definitions.ts +32 -3
  226. package/src/generated_client_bundle_boundary.ts +97 -0
  227. package/src/generated_client_names.ts +1 -0
  228. package/src/identity_usda.ts +27 -0
  229. package/src/index.ts +183 -12
  230. package/src/indexed_variant.ts +83 -0
  231. package/src/intent.ts +173 -45
  232. package/src/law_check.ts +8 -5
  233. package/src/law_dependency_index.ts +231 -0
  234. package/src/law_graph.ts +508 -71
  235. package/src/law_graph_usda.ts +170 -24
  236. package/src/law_identity.ts +119 -81
  237. package/src/law_source_map.ts +4 -1
  238. package/src/law_units.ts +498 -0
  239. package/src/law_value_type.ts +7 -3
  240. package/src/member_authentication.ts +302 -0
  241. package/src/null_meta.ts +1 -1
  242. package/src/openusd_compiled_layer.ts +132 -0
  243. package/src/operation_contract_check.ts +31 -0
  244. package/src/ordered_read.ts +2 -1
  245. package/src/package_config.ts +33 -12
  246. package/src/package_dependencies.ts +1 -0
  247. package/src/plan_source_slice.ts +30 -1
  248. package/src/protobuf_field_number.ts +36 -0
  249. package/src/provenance_wire.ts +6 -0
  250. package/src/query.ts +2 -1
  251. package/src/read.ts +50 -0
  252. package/src/relation.ts +4 -1
  253. package/src/relation_schema.ts +15 -2
  254. package/src/report.ts +2 -2
  255. package/src/sqlite_computation_bundle.ts +78 -0
  256. package/src/sqlite_computed.ts +102 -0
  257. package/src/sqlite_counts.ts +154 -0
  258. package/src/sqlite_layout.ts +823 -0
  259. package/src/sqlite_reads.ts +275 -0
  260. package/src/sqlite_samples.ts +185 -0
  261. package/src/stable_id_identity_bridge.ts +1 -1
  262. package/src/stable_ids_for_module.ts +16 -4
  263. package/src/test_call_usda.ts +6 -6
  264. package/src/usda_relationship_integrity.ts +20 -3
  265. package/src/usda_text.ts +21 -1
  266. package/src/value_object.ts +81 -11
  267. package/src/wire.ts +22 -0
  268. package/src/wire_encode.ts +227 -20
  269. package/src/workspace_sharding.ts +15 -6
  270. package/src/workspace_sharing.ts +51 -49
  271. package/src/zod_introspection.ts +2 -0
  272. package/compat_package.mjs +0 -46
  273. package/dart/lib/src/home.dart +0 -15
  274. package/dart/lib/src/runner/offline-install.mjs +0 -15367
  275. package/dart/lib/src/source_trust.dart +0 -51
  276. package/dart/lib/src/webview_bridge.dart +0 -6540
  277. package/dart/lib/src/workspace_name.dart +0 -30
  278. package/dart/test/acquire_session_credentials_test.dart +0 -150
  279. package/dart/test/acquire_session_test.dart +0 -534
  280. package/dart/test/adv_realm_interference_test.dart +0 -600
  281. package/dart/test/cloud_bound_topology_test.dart +0 -168
  282. package/dart/test/cluster_births_test.dart +0 -202
  283. package/dart/test/cluster_device_keyed_acceptance_test.dart +0 -105
  284. package/dart/test/cluster_local_autosync_test.dart +0 -123
  285. package/dart/test/cluster_scale_test.dart +0 -122
  286. package/dart/test/compat_test.dart +0 -61
  287. package/dart/test/dlq_session_surface_test.dart +0 -222
  288. package/dart/test/first_app_gauntlet_test.dart +0 -386
  289. package/dart/test/fixtures/wedge/fake-install.mjs +0 -11
  290. package/dart/test/four_layer_nested_topology_test.dart +0 -290
  291. package/dart/test/home_parity_test.dart +0 -13
  292. package/dart/test/local_sync_inert_test.dart +0 -107
  293. package/dart/test/node_runner_transport_test.dart +0 -78
  294. package/dart/test/parent_signer_recovery_test.dart +0 -155
  295. package/dart/test/residency_refusal_test.dart +0 -49
  296. package/dart/test/sealing_client_test.dart +0 -181
  297. package/dart/test/session_bound_test.dart +0 -285
  298. package/dart/test/stale_bundle_test.dart +0 -80
  299. package/dart/test/vo_read_typing_test.dart +0 -131
  300. package/dart/test/watch_after_offer_stall_test.dart +0 -100
  301. package/dart/test/webview_bridge_test.dart +0 -1930
  302. package/dart/test/workspace_name_test.dart +0 -24
  303. package/runtime/generated-application-host.js +0 -22860
  304. package/src/codegen_query_usda.ts +0 -214
  305. package/src/compat_manifest.ts +0 -26
  306. package/src/compat_package_main.ts +0 -224
  307. package/src/shape_compat.ts +0 -352
  308. package/src/usd_state.ts +0 -505
@@ -1,6 +1,6 @@
1
1
  import type { DomainModule } from "./codegen_dart.js";
2
2
  import { cap } from "./codegen_dart.js";
3
- import { dartApplicationClassName } from "./codegen_dart_application.js";
3
+ import { dartApplicationClassName } from "./codegen_dart_facade.js";
4
4
  import { synthesizePayload } from "./codegen_proof.js";
5
5
  import { isBusinessIntent } from "./intent.js";
6
6
 
@@ -103,7 +103,7 @@ export function generateDartScenario(
103
103
  const usesJsonFacts = permissions.some(
104
104
  (permission) => Object.keys(permission.sampleFacts).length > 0,
105
105
  );
106
- const bind = `nomosInternalBind${application}`;
106
+ const receive = `receive${application}`;
107
107
  const applicationFile = options.applicationFile ?? `${mod.name}.application`;
108
108
  return [
109
109
  `// AUTO-GENERATED by nomos-compile — business application test environment.`,
@@ -116,13 +116,28 @@ export function generateDartScenario(
116
116
  `import 'package:flutter/services.dart' show rootBundle;`,
117
117
  `import 'package:flutter/widgets.dart' show WidgetsFlutterBinding;`,
118
118
  `import 'package:${clientPackage}/${clientPackage}.dart' show ${application};`,
119
- `import 'package:${clientPackage}/src/generated/${applicationFile}.dart' show ${bind};`,
119
+ `import 'package:${clientPackage}/src/generated/${applicationFile}.dart' show ${receive};`,
120
120
  ...(options.applicationFrameworkCallsFile === undefined
121
121
  ? []
122
122
  : [`import 'package:${clientPackage}/src/generated/${options.applicationFrameworkCallsFile}.dart' show nomosInternalApplicationFrameworkCalls;`]),
123
- `import 'package:nomos_flutter/src/generated_application_host.dart' show NmsInternalApplicationUserBinding;`,
124
- `import 'package:nomos_client/src/home.dart' show nmsInternalReceivingGroupNameOf;`,
125
- `import 'package:nomos_client/src/nms_test_environment.dart' show NomosTestCloud, NomosTestHarness;`,
123
+ `import 'package:nomos_client/src/reception/reception_session.dart' show NmsReceptionUser, NmsReceptionSessionView;`,
124
+ `import 'package:nomos_client/src/nms_generated_runtime.dart' show NomosSession;`,
125
+ `import 'package:nomos_client/src/nms_test_environment.dart' show NomosTestCloud, NomosTestHarness, NomosTestFrontier;`,
126
+ ``,
127
+ `// The office names the framework's identity anchor; a scenario never re-derives it.`,
128
+ `Future<NmsReceptionSessionView> _nmsTestReception(`,
129
+ ` NomosSession session, String principal,`,
130
+ `) async {`,
131
+ ` final identityId = await session.nmsReceivingGroupWorkspace(principal);`,
132
+ ` return NmsReceptionSessionView(`,
133
+ ` desk: session,`,
134
+ ` user: NmsReceptionUser(`,
135
+ ` actor: principal,`,
136
+ ` identityId: identityId,`,
137
+ ` identityAddress: 'nomos-identity:\${Uri.encodeComponent(identityId)}',`,
138
+ ` ),`,
139
+ ` );`,
140
+ `}`,
126
141
  ``,
127
142
  `final class ${testPerson} {`,
128
143
  ` static final RegExp _idPattern = RegExp(r'^[A-Za-z0-9][A-Za-z0-9._-]*$');`,
@@ -207,14 +222,13 @@ export function generateDartScenario(
207
222
  ? []
208
223
  : [` applicationMaxChildWorkspacesPerUser: ${options.applicationMaxChildWorkspacesPerUser},`]),
209
224
  ` ownerSubject: person._principal,`,
210
- ` workspace: nmsInternalReceivingGroupNameOf(person._principal),`,
211
225
  ` nodeEntry: Platform.environment['NOMOS_NODE_ENTRY'],`,
212
226
  ` phaseTimeout: const Duration(minutes: 2),`,
213
227
  ` onDiagnostic: Platform.environment['NOMOS_TEST_DIAGNOSTICS'] == '1' ? stderr.writeln : null,`,
214
228
  ` );`,
215
- ` final application = await ${bind}(`,
216
- ` environment.session(environment.workspace), NmsInternalApplicationUserBinding.fromActor(person._principal),`,
217
- ` );`,
229
+ ` final application = await ${receive}(await _nmsTestReception(`,
230
+ ` environment.session(environment.workspace), person._principal,`,
231
+ ` ));`,
218
232
  ` final scenario = ${scenario}._(environment, person._principal, packageFiles.last, application);`,
219
233
  ` registerTearDown?.call(scenario.close);`,
220
234
  ` return scenario;`,
@@ -243,6 +257,9 @@ export function generateDartScenario(
243
257
  ` late final NomosTestHarness environment;`,
244
258
  ` try {`,
245
259
  ` environment = await NomosTestHarness.cloudBound(`,
260
+ ...(options.applicationFrameworkCallsFile === undefined
261
+ ? []
262
+ : [` applicationFrameworkCalls: nomosInternalApplicationFrameworkCalls,`]),
246
263
  ` cloud: cloud, lawUsdzPaths: packageFiles.map((file) => file.path).toList(growable: false),`,
247
264
  ` platformWorkspace: applicationName, subject: person._principal,`,
248
265
  ` nodeEntry: Platform.environment['NOMOS_NODE_ENTRY'],`,
@@ -253,12 +270,24 @@ export function generateDartScenario(
253
270
  ` await cloud.stop();`,
254
271
  ` rethrow;`,
255
272
  ` }`,
256
- ` final application = await ${bind}(environment.homeSession, NmsInternalApplicationUserBinding.fromActor(person._principal));`,
273
+ ` final application = await ${receive}(await _nmsTestReception(environment.homeSession, person._principal));`,
257
274
  ` final scenario = ${scenario}._(environment, person._principal, packageFiles.last, application);`,
258
275
  ` registerTearDown?.call(scenario.close);`,
259
276
  ` return scenario;`,
260
277
  ` }`,
261
278
  ``,
279
+ ` /// Capture an authenticated point in this isolated local test peer.`,
280
+ ` Future<NomosTestFrontier> captureLocalFrontier(String workspace, {NomosTestFrontier? after}) => _environment.captureLocalFrontier(workspace, after: after);`,
281
+ ``,
282
+ ` /// Arrange retained-upgrade test custody, with canonical verification.`,
283
+ ` Future<void> arrangeRetainedFrontier(NomosTestFrontier frontier) async {`,
284
+ ` await _environment.arrangeRetainedFrontier(frontier);`,
285
+ ` _application = await ${receive}(await _nmsTestReception(_environment.homeSession, _principal));`,
286
+ ` }`,
287
+ ``,
288
+ ` /// Deliver held Git history through ordinary admission and watch invalidation.`,
289
+ ` Future<String> admitRetainedAdvance(NomosTestFrontier frontier) => _environment.admitRetainedAdvance(frontier);`,
290
+ ``,
262
291
  ` /// Simulate losing connectivity. Local business actions remain available.`,
263
292
  ` void disconnect() => _environment.testCloud?.setOnline(false);`,
264
293
  ``,
@@ -273,14 +302,14 @@ export function generateDartScenario(
273
302
  ` /// Kill and reopen the application from durable local state, then return the same business API.`,
274
303
  ` Future<${application}> restart() async {`,
275
304
  ` await _environment.restart();`,
276
- ` _application = await ${bind}(_environment.homeSession, NmsInternalApplicationUserBinding.fromActor(_principal));`,
305
+ ` _application = await ${receive}(await _nmsTestReception(_environment.homeSession, _principal));`,
277
306
  ` return _application;`,
278
307
  ` }`,
279
308
  ``,
280
309
  ` /// Remove local custody and reinstall entirely from remote history.`,
281
310
  ` Future<${application}> reinstall() async {`,
282
311
  ` await _environment.reinstall();`,
283
- ` _application = await ${bind}(_environment.homeSession, NmsInternalApplicationUserBinding.fromActor(_principal));`,
312
+ ` _application = await ${receive}(await _nmsTestReception(_environment.homeSession, _principal));`,
284
313
  ` return _application;`,
285
314
  ` }`,
286
315
  ``,
@@ -44,7 +44,7 @@ import type { RelationTypeDecl, Rewrite } from "./relation_schema.js";
44
44
  import type { WorkspaceInvariantDecl } from "./framework/workspace_invariant.js";
45
45
  import { finishCount } from "./count.js";
46
46
  import { clearDirectiveId } from "./clear_directive.js";
47
- import type { DomainInterface } from "./shape_compat.js";
47
+ import type { DomainInterface } from "./compatibility_graph.js";
48
48
  import { idOfMetaOf, idOfTargetKindOf, versionedRefOfMetaOf, voMetaOf, voSample } from "./value_object.js";
49
49
  import { mintedCreateField } from "./workspace_routing.js";
50
50
  import { deterministicPorts } from "./ctx.js";
@@ -2249,7 +2249,7 @@ export function discoverChildBirthLegOrReason(
2249
2249
  return { reason: `${who}: the plan THREW at the compile probe (${(e as Error)?.message ?? e}) — the probe runs it on a synthesized payload to read the birth recipe` };
2250
2250
  }
2251
2251
  if (recipe === undefined) {
2252
- return { reason: `${who}: the plan declared .births() but recorded NO birth — its plan must call birth({ workspace, genesisChain }) (see dsl/src/framework/home.ts birthHome, or bench/scale/fixtures/estate-birth)` };
2252
+ return { reason: `${who}: the plan declared .births() but recorded NO birth — its plan must call birth({ workspace, genesisChain }) (see dsl/src/framework/receiving_group.ts birthReceivingGroup, or bench/scale/fixtures/estate-birth)` };
2253
2253
  }
2254
2254
  if (!Array.isArray(recipe.genesisChain)) {
2255
2255
  return { reason: `${who}: birth() was called without a genesisChain ARRAY — the recipe is { workspace, genesisChain: [ ...steps ] }` };
@@ -3352,7 +3352,7 @@ function generateSealedApplicationProof(
3352
3352
  `// Regenerated from the business law; do not edit or maintain a second client example.`,
3353
3353
  `// The local proof runner executes every deep framework leg without exposing it here.`,
3354
3354
  `// @nomos-proof-legs ${marker}`,
3355
- `import { ${opener}, sameRecord${optionalReferenceImport}${typeImports} } from "./${opts.packageName}.client.mjs";`,
3355
+ `import { ${opener}, sameRecord${optionalReferenceImport}${typeImports} } from "./${opts.packageName}.reception.mjs";`,
3356
3356
  ``,
3357
3357
  `const fail: (message: string) => never = (message) => { throw new Error(message); };`,
3358
3358
  `const ok = (message: string) => console.log("✓ " + message);`,
@@ -72,6 +72,11 @@ export interface ImpureCapabilityDecl {
72
72
  readonly name?: string;
73
73
  /** HTTPS offer endpoint; absent means obligations remain locally requested. */
74
74
  readonly endpoint?: string;
75
+ /** Resolved execution policy authored with an addressed capability. */
76
+ readonly execution?: {
77
+ readonly placement: "custodian";
78
+ readonly cardinality: "singleton";
79
+ };
75
80
  /** Maintained requested-task read used by the executor scan lane. */
76
81
  readonly tasks?: { readonly id: string };
77
82
  /** The task aggregate handle; `.id` is the wire type (e.g. `TranscribeVoiceNoteAggregate`). */
@@ -0,0 +1,158 @@
1
+ import type { LawGraph, LawRowReadNode } from "./law_graph.js";
2
+ import {
3
+ composedWireIdentity,
4
+ operationMessageIdentity,
5
+ protoFieldName,
6
+ protoMessageName,
7
+ } from "./codegen_call_proto.js";
8
+
9
+ export type QueryScalarKind = "string" | "reference" | "token" | "integer" | "boolean";
10
+
11
+ export interface DartQueryProtoParameter {
12
+ readonly authoredPath: string;
13
+ readonly name: string;
14
+ readonly type: "String" | "int" | "bool";
15
+ readonly value: string;
16
+ readonly kind: QueryScalarKind;
17
+ }
18
+
19
+ export interface TsQueryProtoParameter {
20
+ readonly authoredPath: string;
21
+ readonly name: string;
22
+ readonly type: "string" | "number" | "boolean";
23
+ readonly value: string;
24
+ readonly kind: QueryScalarKind;
25
+ }
26
+
27
+ export interface QueryProtoEncoder {
28
+ readonly functionName: string;
29
+ readonly call: string;
30
+ readonly typeUrl: string;
31
+ readonly source: readonly string[];
32
+ }
33
+
34
+ const symbol = (value: string): string =>
35
+ value.replace(/[^A-Za-z0-9_$]+/g, "_").replace(/^[^A-Za-z_$]/, "_$&");
36
+
37
+ function querySpec(
38
+ graph: LawGraph,
39
+ paths: ReadonlyMap<string, string>,
40
+ domain: string,
41
+ queryId: string,
42
+ ) {
43
+ const query = graph.nodes.find(
44
+ (node): node is LawRowReadNode =>
45
+ node.kind === "read" && (node.readKind === "query" || node.readKind === "ordered") && node.entity.label === queryId,
46
+ );
47
+ if (query === undefined) {
48
+ throw new Error(`query Protobuf codegen: domain '${domain}' has no law query '${queryId}'`);
49
+ }
50
+ const nodes = new Map(graph.nodes.map((node) => [node.entity.id, node]));
51
+ const keys = (query.readKind === "query" ? query.key : []).map((key) => {
52
+ const field = nodes.get(key.field.id);
53
+ if (field?.kind !== "field") {
54
+ throw new Error(`query Protobuf codegen: '${domain}/${queryId}' references non-field '${key.field.id}'`);
55
+ }
56
+ const terminalRef = key.path.at(-1);
57
+ const terminal = terminalRef === undefined
58
+ ? field
59
+ : nodes.get(terminalRef.id);
60
+ if (
61
+ terminal?.kind !== "field" &&
62
+ !(
63
+ terminal?.kind === "structural" &&
64
+ (terminal.structuralKind === "value-field" || terminal.structuralKind === "value-variant")
65
+ )
66
+ ) {
67
+ throw new Error(
68
+ `query Protobuf codegen: '${domain}/${queryId}' key '${field.entity.label}' has non-field terminal '${terminalRef?.id ?? key.field.id}'`,
69
+ );
70
+ }
71
+ return { key, field, sid: composedWireIdentity(paths, terminal.entity) };
72
+ });
73
+ const messageName = protoMessageName(
74
+ "Query",
75
+ operationMessageIdentity(graph, query.entity.sid),
76
+ );
77
+ return {
78
+ query,
79
+ keys,
80
+ messageName,
81
+ typeUrl: `type.nomos.dev/nomos.operation.v1.Query_${query.entity.sid}`,
82
+ };
83
+ }
84
+
85
+ export function emitTsQueryProtoEncoder(
86
+ graph: LawGraph,
87
+ paths: ReadonlyMap<string, string>,
88
+ domain: string,
89
+ queryId: string,
90
+ parameters: readonly TsQueryProtoParameter[],
91
+ ): QueryProtoEncoder {
92
+ const spec = querySpec(graph, paths, domain, queryId);
93
+ if (spec.keys.length !== parameters.length) {
94
+ throw new Error(`query Protobuf codegen: '${domain}/${queryId}' key/parameter length differs`);
95
+ }
96
+ const properties = spec.keys.map(({ key, sid }, index) => {
97
+ const parameter = parameters[index]!;
98
+ if (key.authoredPath !== parameter.authoredPath) {
99
+ throw new Error(`query Protobuf codegen: '${domain}/${queryId}' key ${index} identity differs`);
100
+ }
101
+ const value = parameter.kind === "integer" ? `BigInt(${parameter.name})` : parameter.name;
102
+ return `${protoFieldName(sid)}: ${value}`;
103
+ });
104
+ const functionName = `_nmsQueryProto_${symbol(domain)}_${symbol(queryId)}`;
105
+ return {
106
+ functionName,
107
+ call: `${functionName}(${parameters.map((parameter) => parameter.value).join(", ")})`,
108
+ typeUrl: spec.typeUrl,
109
+ source: [
110
+ `function ${functionName}(${parameters.map((parameter) => `${parameter.name}: ${parameter.type}`).join(", ")}): NmsGeneratedQuery<${JSON.stringify(domain)}, ${JSON.stringify(queryId)}> {`,
111
+ ` const message = create(_nmsop.${spec.messageName}Schema, { ${properties.join(", ")} });`,
112
+ ` return _nmsGeneratedQuery(${JSON.stringify(domain)}, ${JSON.stringify(queryId)}, ${JSON.stringify(spec.typeUrl)}, toBinary(_nmsop.${spec.messageName}Schema, message));`,
113
+ `}`,
114
+ ``,
115
+ ],
116
+ };
117
+ }
118
+
119
+ export function emitDartQueryProtoEncoder(
120
+ graph: LawGraph,
121
+ paths: ReadonlyMap<string, string>,
122
+ domain: string,
123
+ queryId: string,
124
+ parameters: readonly DartQueryProtoParameter[],
125
+ ): QueryProtoEncoder {
126
+ const spec = querySpec(graph, paths, domain, queryId);
127
+ if (spec.keys.length !== parameters.length) {
128
+ throw new Error(`query Protobuf codegen: '${domain}/${queryId}' key/parameter length differs`);
129
+ }
130
+ const setters = spec.keys.map(({ key, sid }, index) => {
131
+ const parameter = parameters[index]!;
132
+ if (key.authoredPath !== parameter.authoredPath) {
133
+ throw new Error(`query Protobuf codegen: '${domain}/${queryId}' key ${index} identity differs`);
134
+ }
135
+ const value = parameter.kind === "integer" ? `_nmsProtoInt(${parameter.name})` : parameter.name;
136
+ return ` ..${protoFieldName(sid)} = ${value}`;
137
+ });
138
+ const functionName = `_nmsQueryProto_${symbol(domain)}_${symbol(queryId)}`;
139
+ return {
140
+ functionName,
141
+ call: `${functionName}(${parameters.map((parameter) => parameter.value).join(", ")})`,
142
+ typeUrl: spec.typeUrl,
143
+ source: [
144
+ `NmsGeneratedQuery ${functionName}(${parameters.map((parameter) => `${parameter.type} ${parameter.name}`).join(", ")}) {`,
145
+ ` final message = _nmsop.${spec.messageName}()`,
146
+ ...setters,
147
+ ` ;`,
148
+ ` return NmsInternalGeneratedQueries.create(`,
149
+ ` domain: ${JSON.stringify(domain)},`,
150
+ ` query: ${JSON.stringify(queryId)},`,
151
+ ` protobufType: ${JSON.stringify(spec.typeUrl)},`,
152
+ ` protobufPayload: Uint8List.fromList(message.writeToBuffer()),`,
153
+ ` );`,
154
+ `}`,
155
+ ``,
156
+ ],
157
+ };
158
+ }
@@ -0,0 +1,189 @@
1
+ import type { DomainModule } from "./codegen_dart.js";
2
+ import type { ValueObject } from "./value_object.js";
3
+ import { isBusinessIntent } from "./intent.js";
4
+ import type { LawGraph } from "./law_graph.js";
5
+
6
+ const cap = (s: string) => s[0]!.toUpperCase() + s.slice(1);
7
+ export function refusalContracts(mod: DomainModule, command: string): ValueObject<unknown>[] {
8
+ const collect = (id: string, active = new Set<string>()): ValueObject<unknown>[] => {
9
+ if (active.has(id)) throw new Error(`cyclic refusal contract composition at '${id}'`);
10
+ const direct = (mod.workspaceInvariants ?? []).flatMap(rule => rule.on === id && rule.refusal ? [rule.refusal] : []);
11
+ const declaration = mod.directives.find(d => d.id === id);
12
+ return [...direct, ...(isBusinessIntent(declaration)
13
+ ? declaration.steps.flatMap(step => collect(step.directive.id, new Set([...active, id]))) : [])];
14
+ };
15
+ return [...new Map(collect(command).map(value => [value.name, value])).values()].sort((a, b) => a.name.localeCompare(b.name));
16
+ }
17
+ export const refusalType = (command: string, contracts: readonly ValueObject<unknown>[]): string =>
18
+ contracts.length === 1 ? contracts[0]!.name : `${cap(command)}Refusal`;
19
+ export const refusalDecoder = (command: string): string => `nmsDecode${cap(command)}Refusal`;
20
+
21
+ export function dartRefusalUnions(mod: DomainModule): string[] {
22
+ return (mod.applicationIntents ?? mod.directives).flatMap(command => {
23
+ const contracts = refusalContracts(mod, command.id);
24
+ if (contracts.length < 2) return [];
25
+ const name = refusalType(command.id, contracts);
26
+ return [`sealed class ${name} { const ${name}(); }`, ...contracts.map(contract =>
27
+ `final class ${name}${contract.name} extends ${name} { final ${contract.name} value; const ${name}${contract.name}(this.value); }`)];
28
+ });
29
+ }
30
+
31
+ /** Expand the authenticated nominal graph into codecs. No schema lookup or law
32
+ * evaluation is delegated to Reception or UI code. */
33
+ export function dartRefusalDecoders(mod: DomainModule, graph: LawGraph, paths: ReadonlyMap<string, string>): string[] {
34
+ const nodes = new Map<string, LawGraph["nodes"][number]>(graph.nodes.map(node => [node.entity.id, node]));
35
+ const functions = new Map<string, string[]>();
36
+ const path = (id: string) => {
37
+ const value = paths.get(id);
38
+ if (!value) throw new Error(`refusal codegen has no law path for ${id}`);
39
+ return JSON.stringify(value);
40
+ };
41
+ const emit = (id: string): string => {
42
+ const name = `_nmsRefusal_${id.replace(/[^a-zA-Z0-9_]/g, "_")}`;
43
+ if (functions.has(id)) return name;
44
+ functions.set(id, []);
45
+ const node = nodes.get(id);
46
+ if (!node) throw new Error(`refusal codegen has no type ${id}`);
47
+ const expression = node.kind === "type"
48
+ ? node.form === "sum" ? { kind: "sum" as const, variants: node.variants }
49
+ : { kind: "record" as const, fields: node.fields }
50
+ : node.kind === "structural" && node.structuralKind === "value-type" ? node.expression : undefined;
51
+ if (!expression) throw new Error(`refusal codegen expected nominal type at ${id}`);
52
+ const lines = [`Object? ${name}(NmsUsdaPrim value) {`,
53
+ ` if (value.relationship('nomos:type') != ${path(id)}) throw const NmsUnsupportedNominalRefusal();`];
54
+ switch (expression.kind) {
55
+ case "record": {
56
+ const fields = expression.fields.map(ref => {
57
+ const field = nodes.get(ref.id);
58
+ if (!field || (field.kind !== "field" && !(field.kind === "structural" && field.structuralKind === "value-field")))
59
+ throw new Error(`refusal codegen expected field ${ref.id}`);
60
+ return { label: field.kind === "field" ? field.entity.label : field.name,
61
+ id: ref.id, value: field.value.id, required: field.required };
62
+ });
63
+ lines.push(` if (value.typeName != 'NomosRecordValue') throw const FormatException('Expected nominal record');`,
64
+ ` for (final field in value.children) { if (!<String>{${fields.map(field => path(field.id)).join(", ")}}.contains(field.relationship('nomos:field'))) throw const NmsUnsupportedNominalRefusal(); }`,
65
+ ` return <String, dynamic>{`,
66
+ ...fields.map(field => `${field.required ? "" : ` if (value.field(${path(field.id)}) != null) `}${JSON.stringify(field.label)}: ${emit(field.value)}(value.requiredField(${path(field.id)})),`), ` };`);
67
+ break;
68
+ }
69
+ case "sum":
70
+ lines.push(` if (value.typeName != 'NomosSumValue') throw const FormatException('Expected nominal sum');`,
71
+ ` return switch (value.relationship('nomos:variant')) {`, ...expression.variants.map(ref => {
72
+ const variant = nodes.get(ref.id);
73
+ if (variant?.kind !== "structural" || variant.structuralKind !== "value-variant") throw new Error(`missing refusal variant ${ref.id}`);
74
+ const body = `${emit(variant.value.id)}(value.requiredChild('Value'))`;
75
+ return ` ${path(ref.id)} => ${node.kind === "type"
76
+ ? `<String, dynamic>{'type': ${JSON.stringify(variant.label)}, ${nodes.get(variant.value.id)?.kind === "type" ? `'value': ${body}` : `...(${body} as Map<String, dynamic>)`}}`
77
+ : body},`;
78
+ }), ` _ => throw const NmsUnsupportedNominalRefusal(),`, ` };`);
79
+ break;
80
+ case "string": lines.push(` return value.stringValue();`); break;
81
+ case "enum": lines.push(` final text = value.stringValue();`, ` if (!<String>{${expression.values.map(v => JSON.stringify(v)).join(", ")}}.contains(text)) throw const NmsUnsupportedNominalRefusal();`, ` return text;`); break;
82
+ case "integer": lines.push(` return value.intValue();`); break;
83
+ case "number": lines.push(` return value.numberValue();`); break;
84
+ case "boolean": lines.push(` return value.boolValue();`); break;
85
+ case "literal":
86
+ lines.push(` final literal = value.property('nomos:value');`, ` if (literal != ${JSON.stringify(expression.value)}) throw const NmsUnsupportedNominalRefusal();`, ` return literal;`); break;
87
+ case "list": lines.push(` if (value.typeName != 'NomosListValue') throw const FormatException('Expected nominal list');`, ` return value.children.map((child) => ${emit(expression.element.id)}(child)).toList();`); break;
88
+ case "map": lines.push(` if (value.typeName != 'NomosMapValue') throw const FormatException('Expected nominal map');`, ` final result = <String, dynamic>{};`, ` for (final entry in value.children) {`, ` final key = entry.requiredStringProperty('nomos:key');`, ` if (result.containsKey(key)) throw const FormatException('Duplicate nominal map key');`, ` result[key] = ${emit(expression.value.id)}(entry.requiredChild('Value'));`, ` }`, ` return result;`); break;
89
+ case "nullable": lines.push(` return value.typeName == 'NomosNullValue' ? null : ${emit(expression.value.id)}(value);`); break;
90
+ case "default": case "recursive": lines.splice(1, 1); lines.push(` return ${emit(expression.value.id)}(value);`); break;
91
+ case "null": lines.push(` if (value.typeName != 'NomosNullValue') throw const FormatException('Expected nominal null');`, ` return null;`); break;
92
+ default: throw new Error(`refusal codec does not support ${expression.kind}`);
93
+ }
94
+ lines.push(`}`);
95
+ functions.set(id, lines);
96
+ return name;
97
+ };
98
+ const decoders = mod.directives.flatMap(command => {
99
+ const contracts = refusalContracts(mod, command.id);
100
+ if (!contracts.length) return [];
101
+ const result = refusalType(command.id, contracts);
102
+ return [`${result}? ${refusalDecoder(command.id)}(NomosDomainRefusalEvidence refusal) {`,
103
+ ` final value = NmsUsdaLayer.parse(refusal.valueUsda);`,
104
+ ` return switch (refusal.typeIdentity) {`, ...contracts.map(contract => {
105
+ const node = graph.nodes.find(node => node.kind === "type" && node.entity.label === contract.name);
106
+ if (!node) throw new Error(`missing refusal type ${contract.name}`);
107
+ const decoded = `${contract.name}.fromProjected(${emit(node.entity.id)}(value) as Map<String, dynamic>)`;
108
+ return ` ${path(node.entity.id)} => ${contracts.length === 1 ? decoded : `${result}${contract.name}(${decoded})`},`;
109
+ }), ` _ => null,`, ` };`, `}`];
110
+ });
111
+ return [...functions.values()].flat().concat(decoders);
112
+ }
113
+
114
+ export const tsRefusalDecoder = (mod: DomainModule, command: string): string =>
115
+ `_nmsRefusal_${(mod.domain ?? mod.name).replace(/\W/g, '_')}_${command}`;
116
+
117
+ export function tsRefusalDecoders(mod: DomainModule, graph: LawGraph, paths: ReadonlyMap<string, string>): string[] {
118
+ const nodes = new Map<string, LawGraph['nodes'][number]>(graph.nodes.map(node => [node.entity.id, node]));
119
+ const functions = new Map<string, string[]>();
120
+ const path = (id: string): string => {
121
+ const value = paths.get(id);
122
+ if (!value) throw new Error(`refusal codegen has no law path for ${id}`);
123
+ return JSON.stringify(value);
124
+ };
125
+ const emit = (id: string): string => {
126
+ const name = `_nmsRefusalValue_${id.replace(/\W/g, '_')}`;
127
+ if (functions.has(id)) return name;
128
+ functions.set(id, []);
129
+ const node = nodes.get(id);
130
+ const expression = node?.kind === 'type' ? node.form === 'sum'
131
+ ? { kind: 'sum' as const, variants: node.variants } : { kind: 'record' as const, fields: node.fields }
132
+ : node?.kind === 'structural' && node.structuralKind === 'value-type' ? node.expression : undefined;
133
+ if (!expression) throw new Error(`refusal codegen expected nominal type ${id}`);
134
+ const lines = [`function ${name}(value: _NominalValue): unknown {`,
135
+ ` if (value.relationship('nomos:type') !== ${path(id)}) throw new _UnsupportedNominalRefusal();`];
136
+ switch (expression.kind) {
137
+ case 'record': {
138
+ const fields = expression.fields.map(ref => {
139
+ const field = nodes.get(ref.id);
140
+ if (!field || (field.kind !== 'field' && !(field.kind === 'structural' && field.structuralKind === 'value-field'))) throw new Error(`missing field ${ref.id}`);
141
+ return { label: field.kind === 'field' ? field.entity.label : field.name, id: ref.id, value: field.value.id, required: field.required };
142
+ });
143
+ lines.push(` if (value.typeName !== 'NomosRecordValue') throw new TypeError('Expected nominal record');`,
144
+ ` for (const child of value.children) if (!([${fields.map(field => path(field.id)).join(', ')}] as readonly string[]).includes(child.relationship('nomos:field') ?? '')) throw new _UnsupportedNominalRefusal();`,
145
+ ` return {`, ...fields.map(field => field.required
146
+ ? ` ${JSON.stringify(field.label)}: ${emit(field.value)}(value.requiredField(${path(field.id)})),`
147
+ : ` ...(value.field(${path(field.id)}) === undefined ? {} : { ${JSON.stringify(field.label)}: ${emit(field.value)}(value.requiredField(${path(field.id)})) }),`), ` };`);
148
+ break;
149
+ }
150
+ case 'sum':
151
+ lines.push(` if (value.typeName !== 'NomosSumValue') throw new TypeError('Expected nominal sum');`,
152
+ ` switch (value.relationship('nomos:variant')) {`, ...expression.variants.map(ref => {
153
+ const variant = nodes.get(ref.id);
154
+ if (variant?.kind !== 'structural' || variant.structuralKind !== 'value-variant') throw new Error(`missing variant ${ref.id}`);
155
+ const body = `${emit(variant.value.id)}(value.child('Value'))`;
156
+ return ` case ${path(ref.id)}: return ${node?.kind === "type"
157
+ ? `{ type: ${JSON.stringify(variant.label)}, ${nodes.get(variant.value.id)?.kind === "type" ? `value: ${body}` : `...(${body} as Record<string, unknown>)`} }`
158
+ : body};`;
159
+ }), ` default: throw new _UnsupportedNominalRefusal();`, ` }`); break;
160
+ case 'string': lines.push(` return value.stringValue();`); break;
161
+ case 'enum': lines.push(` const text = value.stringValue();`, ` if (!${JSON.stringify(expression.values)}.includes(text)) throw new _UnsupportedNominalRefusal();`, ` return text;`); break;
162
+ case 'integer': lines.push(` return value.numberValue(true);`); break;
163
+ case 'number': lines.push(` return value.numberValue();`); break;
164
+ case 'boolean': lines.push(` return value.boolValue();`); break;
165
+ case 'literal': lines.push(` const literal = value.property('nomos:value');`, ` if (literal !== ${JSON.stringify(expression.value)}) throw new _UnsupportedNominalRefusal();`, ` return literal;`); break;
166
+ case 'list': lines.push(` if (value.typeName !== 'NomosListValue') throw new TypeError('Expected nominal list');`, ` return value.children.map(child => ${emit(expression.element.id)}(child));`); break;
167
+ case 'map': lines.push(` if (value.typeName !== 'NomosMapValue') throw new TypeError('Expected nominal map');`, ` const result = new Map<string, unknown>();`, ` for (const entry of value.children) {`, ` const key = entry.property('nomos:key');`, ` if (typeof key !== 'string') throw new TypeError('Expected nominal key');`, ` if (result.has(key)) throw new TypeError('Duplicate nominal map key');`, ` result.set(key, ${emit(expression.value.id)}(entry.child('Value')));`, ` }`, ` return Object.fromEntries(result);`); break;
168
+ case 'nullable': lines.push(` return value.typeName === 'NomosNullValue' ? null : ${emit(expression.value.id)}(value);`); break;
169
+ case 'default': case 'recursive': lines.splice(1, 1); lines.push(` return ${emit(expression.value.id)}(value);`); break;
170
+ case 'null': lines.push(` if (value.typeName !== 'NomosNullValue') throw new TypeError('Expected nominal null');`, ` return null;`); break;
171
+ default: throw new Error(`refusal codec does not support ${expression.kind}`);
172
+ }
173
+ lines.push('}'); functions.set(id, lines); return name;
174
+ };
175
+ const decoders = mod.directives.flatMap(command => {
176
+ const contracts = refusalContracts(mod, command.id);
177
+ if (!contracts.length) return [];
178
+ const result = contracts.length === 1 ? contracts[0]!.name : `${cap(mod.domain ?? mod.name)}${cap(command.id)}Refusal`;
179
+ const declarations = contracts.length < 2 ? [] : [`export type ${result} = ${contracts.map(contract => `{ readonly family: ${JSON.stringify(contract.name)}; readonly value: ${contract.name} }`).join(' | ')};`];
180
+ return [...declarations, `function ${tsRefusalDecoder(mod, command.id)}(refusal: _DomainRefusalEvidence): ${result} | undefined {`,
181
+ ` switch (refusal.typeIdentity) {`, ...contracts.map(contract => {
182
+ const type = graph.nodes.find(node => node.kind === 'type' && node.entity.label === contract.name);
183
+ if (!type) throw new Error(`missing refusal type ${contract.name}`);
184
+ const body = `${emit(type.entity.id)}(_parseNominalValue(refusal.valueUsda)) as ${contract.name}`;
185
+ return ` case ${path(type.entity.id)}: return ${contracts.length === 1 ? body : `{ family: ${JSON.stringify(contract.name)}, value: ${body} }`};`;
186
+ }), ` default: return undefined;`, ` }`, `}`];
187
+ });
188
+ return [...functions.values()].flat().concat(decoders);
189
+ }