@githolon/dsl 0.108.6 → 0.110.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (307) 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 +76 -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 +211 -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 +267 -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 +23905 -15774
  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 +548 -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_span_trace_test.dart +23 -0
  74. package/dart/test/replica_readiness_test.dart +156 -0
  75. package/dart/test/runtime_projections_test.dart +92 -0
  76. package/dart/test/runtime_v2_gateway_test.dart +131 -0
  77. package/dart/test/signing_identity_kernel_test.dart +75 -0
  78. package/dart/test/sync_status_preparation_report_test.dart +29 -0
  79. package/dart/test/sync_status_reducer_test.dart +419 -0
  80. package/dart/test/test_harness_test.dart +71 -95
  81. package/dart/test/typed_query_watch_test.dart +170 -0
  82. package/dart/test/typed_watch_registry_test.dart +249 -0
  83. package/dart_lints/README.md +18 -0
  84. package/dart_lints/lib/nomos_lints.dart +70 -0
  85. package/dart_lints/pubspec.lock +580 -0
  86. package/dart_lints/pubspec.yaml +12 -0
  87. package/dart_lints/test/reference_identity_test.dart +75 -0
  88. package/dart_types/CHANGELOG.md +18 -0
  89. package/dart_types/lib/nomos_kernel_protocol.dart +21 -1
  90. package/dart_types/lib/nomos_types.dart +9 -1
  91. package/dart_types/lib/src/admission_decision.dart +37 -0
  92. package/dart_types/lib/src/aggregate_meta.dart +1 -1
  93. package/dart_types/lib/src/approved_model.dart +65 -0
  94. package/dart_types/lib/src/custody.dart +10 -18
  95. package/dart_types/lib/src/error_info.dart +4 -4
  96. package/dart_types/lib/src/errors.dart +29 -29
  97. package/dart_types/lib/src/foreign_ref.dart +62 -33
  98. package/dart_types/lib/src/local_work_rejected.dart +3 -3
  99. package/dart_types/lib/src/nomos_ref.dart +3 -1
  100. package/dart_types/lib/src/principal.dart +2 -2
  101. package/dart_types/lib/src/proto/google/protobuf/any.pb.dart +163 -0
  102. package/dart_types/lib/src/proto/google/protobuf/any.pbenum.dart +11 -0
  103. package/dart_types/lib/src/proto/nomos/discovery/v1/workspace_placement.pb.dart +137 -0
  104. package/dart_types/lib/src/proto/nomos/discovery/v1/workspace_placement.pbenum.dart +11 -0
  105. package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pb.dart +20721 -10433
  106. package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pbenum.dart +555 -27
  107. package/dart_types/lib/src/proto/nomos/runtime/v2/application_desk.pb.dart +387 -0
  108. package/dart_types/lib/src/proto/nomos/runtime/v2/application_desk.pbenum.dart +46 -0
  109. package/dart_types/lib/src/proto/nomos/runtime/v2/application_readiness_desk.pb.dart +295 -0
  110. package/dart_types/lib/src/proto/nomos/runtime/v2/application_readiness_desk.pbenum.dart +139 -0
  111. package/dart_types/lib/src/proto/nomos/runtime/v2/authentication_desk.pb.dart +269 -0
  112. package/dart_types/lib/src/proto/nomos/runtime/v2/authentication_desk.pbenum.dart +103 -0
  113. package/dart_types/lib/src/proto/nomos/runtime/v2/compatibility_desk.pb.dart +417 -0
  114. package/dart_types/lib/src/proto/nomos/runtime/v2/compatibility_desk.pbenum.dart +62 -0
  115. package/dart_types/lib/src/proto/nomos/runtime/v2/correspondence_desk.pb.dart +9968 -0
  116. package/dart_types/lib/src/proto/nomos/runtime/v2/correspondence_desk.pbenum.dart +133 -0
  117. package/dart_types/lib/src/proto/nomos/runtime/v2/credentials_desk.pb.dart +204 -0
  118. package/dart_types/lib/src/proto/nomos/runtime/v2/credentials_desk.pbenum.dart +54 -0
  119. package/dart_types/lib/src/proto/nomos/runtime/v2/custody_desk.pb.dart +1550 -0
  120. package/dart_types/lib/src/proto/nomos/runtime/v2/custody_desk.pbenum.dart +11 -0
  121. package/dart_types/lib/src/proto/nomos/runtime/v2/framework.pb.dart +710 -0
  122. package/dart_types/lib/src/proto/nomos/runtime/v2/framework.pbenum.dart +11 -0
  123. package/dart_types/lib/src/proto/nomos/runtime/v2/identity_desk.pb.dart +845 -0
  124. package/dart_types/lib/src/proto/nomos/runtime/v2/identity_desk.pbenum.dart +11 -0
  125. package/dart_types/lib/src/proto/nomos/runtime/v2/interaction_desk.pb.dart +198 -0
  126. package/dart_types/lib/src/proto/nomos/runtime/v2/interaction_desk.pbenum.dart +11 -0
  127. package/dart_types/lib/src/proto/nomos/runtime/v2/law_desk.pb.dart +369 -0
  128. package/dart_types/lib/src/proto/nomos/runtime/v2/law_desk.pbenum.dart +11 -0
  129. package/dart_types/lib/src/proto/nomos/runtime/v2/maintenance_desk.pb.dart +609 -0
  130. package/dart_types/lib/src/proto/nomos/runtime/v2/maintenance_desk.pbenum.dart +65 -0
  131. package/dart_types/lib/src/proto/nomos/runtime/v2/model_adoption_desk.pb.dart +358 -0
  132. package/dart_types/lib/src/proto/nomos/runtime/v2/model_adoption_desk.pbenum.dart +100 -0
  133. package/dart_types/lib/src/proto/nomos/runtime/v2/observability_desk.pb.dart +2231 -0
  134. package/dart_types/lib/src/proto/nomos/runtime/v2/observability_desk.pbenum.dart +271 -0
  135. package/dart_types/lib/src/proto/nomos/runtime/v2/placement_desk.pb.dart +1286 -0
  136. package/dart_types/lib/src/proto/nomos/runtime/v2/placement_desk.pbenum.dart +11 -0
  137. package/dart_types/lib/src/proto/nomos/runtime/v2/receiving_group_desk.pb.dart +636 -0
  138. package/dart_types/lib/src/proto/nomos/runtime/v2/receiving_group_desk.pbenum.dart +116 -0
  139. package/dart_types/lib/src/proto/nomos/runtime/v2/records_desk.pb.dart +1637 -0
  140. package/dart_types/lib/src/proto/nomos/runtime/v2/records_desk.pbenum.dart +175 -0
  141. package/dart_types/lib/src/proto/nomos/runtime/v2/recovery_desk.pb.dart +1269 -0
  142. package/dart_types/lib/src/proto/nomos/runtime/v2/recovery_desk.pbenum.dart +129 -0
  143. package/dart_types/lib/src/proto/nomos/runtime/v2/residency_desk.pb.dart +2782 -0
  144. package/dart_types/lib/src/proto/nomos/runtime/v2/residency_desk.pbenum.dart +97 -0
  145. package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pb.dart +2232 -8627
  146. package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pbenum.dart +0 -358
  147. package/dart_types/lib/src/proto/nomos/runtime/v2/sealing_desk.pb.dart +1639 -0
  148. package/dart_types/lib/src/proto/nomos/runtime/v2/sealing_desk.pbenum.dart +46 -0
  149. package/dart_types/lib/src/runtime_outcome.dart +133 -0
  150. package/dart_types/lib/src/subscriptions.dart +116 -23
  151. package/dart_types/pubspec.yaml +1 -1
  152. package/dart_types/test/extremum_subscriptions_test.dart +40 -0
  153. package/dart_types/test/foreign_ref_resolution_test.dart +75 -0
  154. package/dart_types/test/nomos_ref_address_test.dart +25 -0
  155. package/dart_types/test/ordered_subscriptions_test.dart +34 -0
  156. package/operation_contract_check.mjs +24 -0
  157. package/package.json +11 -6
  158. package/src/aggregate.ts +70 -10
  159. package/src/application_topology.ts +18 -11
  160. package/src/attested.ts +3 -0
  161. package/src/attested_core.ts +46 -3
  162. package/src/birth_meter_ensure.ts +19 -7
  163. package/src/births.ts +29 -4
  164. package/src/build_package.ts +140 -13
  165. package/src/business_birth.ts +181 -4
  166. package/src/codegen_call_proto.ts +1274 -0
  167. package/src/codegen_call_usda.ts +49 -6
  168. package/src/codegen_dart.ts +79 -44
  169. package/src/codegen_dart_client.ts +458 -800
  170. package/src/{codegen_dart_application.ts → codegen_dart_facade.ts} +331 -582
  171. package/src/codegen_dart_framework_calls.ts +320 -37
  172. package/src/codegen_dart_indexed_variant.ts +159 -0
  173. package/src/codegen_dart_scenario.ts +42 -13
  174. package/src/codegen_proof.ts +3 -3
  175. package/src/codegen_provider_dart.ts +5 -0
  176. package/src/codegen_query_proto.ts +158 -0
  177. package/src/codegen_refusal.ts +189 -0
  178. package/src/codegen_result_proto.ts +931 -0
  179. package/src/codegen_result_usda.ts +4 -0
  180. package/src/codegen_ts.ts +464 -616
  181. package/src/codegen_workspace_access.ts +105 -0
  182. package/src/compatibility_graph.ts +759 -0
  183. package/src/compatibility_usda.ts +264 -0
  184. package/src/compile_package_main.ts +2083 -1248
  185. package/src/custody_placement.ts +156 -0
  186. package/src/custody_placement_usda.ts +91 -0
  187. package/src/decl_shapes.ts +21 -2
  188. package/src/describe_model.ts +1 -0
  189. package/src/directive.ts +59 -2
  190. package/src/drivers.ts +51 -0
  191. package/src/engine_entry.ts +52 -8
  192. package/src/evolve_preview.ts +11 -4
  193. package/src/exists.ts +2 -0
  194. package/src/fields.ts +75 -11
  195. package/src/flow_gate.ts +2 -1
  196. package/src/framework/application_home.ts +170 -18
  197. package/src/framework/attested_receipts.ts +8 -3
  198. package/src/framework/auth_provider_law.ts +169 -9
  199. package/src/framework/birth_certificate_law.ts +4 -0
  200. package/src/framework/capability.ts +34 -3
  201. package/src/framework/child_authentication.ts +346 -0
  202. package/src/framework/console_governance.ts +295 -0
  203. package/src/framework/delegated_roles.ts +301 -0
  204. package/src/framework/domain_lifecycle.ts +26 -13
  205. package/src/framework/founding_genesis.ts +193 -0
  206. package/src/framework/framework_aggregates.ts +1 -1
  207. package/src/framework/genesis.ts +6 -1
  208. package/src/framework/governance_relations.ts +19 -0
  209. package/src/framework/home.ts +5 -734
  210. package/src/framework/legacy/child_auth_provider_epoch.ts +73 -0
  211. package/src/framework/model_authority_repair.ts +116 -0
  212. package/src/framework/model_authority_seed.ts +185 -0
  213. package/src/framework/model_transition.ts +211 -0
  214. package/src/framework/owned_custody.ts +1 -1
  215. package/src/framework/principal_enrollment.ts +302 -0
  216. package/src/framework/receiving_group.ts +857 -0
  217. package/src/framework/receiving_group_recovery.ts +314 -0
  218. package/src/framework/relations.ts +4 -8
  219. package/src/framework/signing_identity.ts +242 -95
  220. package/src/framework/source_roster.ts +11 -5
  221. package/src/framework/workspace_access.ts +149 -0
  222. package/src/framework/workspace_invariant.ts +73 -52
  223. package/src/framework/workspaces.ts +407 -40
  224. package/src/framework_call_definitions.ts +32 -3
  225. package/src/generated_client_bundle_boundary.ts +97 -0
  226. package/src/generated_client_names.ts +1 -0
  227. package/src/identity_usda.ts +27 -0
  228. package/src/index.ts +183 -12
  229. package/src/indexed_variant.ts +83 -0
  230. package/src/intent.ts +173 -45
  231. package/src/law_check.ts +8 -5
  232. package/src/law_dependency_index.ts +231 -0
  233. package/src/law_graph.ts +508 -71
  234. package/src/law_graph_usda.ts +170 -24
  235. package/src/law_identity.ts +119 -81
  236. package/src/law_source_map.ts +4 -1
  237. package/src/law_units.ts +498 -0
  238. package/src/law_value_type.ts +7 -3
  239. package/src/member_authentication.ts +302 -0
  240. package/src/null_meta.ts +1 -1
  241. package/src/openusd_compiled_layer.ts +132 -0
  242. package/src/operation_contract_check.ts +31 -0
  243. package/src/ordered_read.ts +2 -1
  244. package/src/package_config.ts +33 -12
  245. package/src/package_dependencies.ts +1 -0
  246. package/src/plan_source_slice.ts +30 -1
  247. package/src/protobuf_field_number.ts +36 -0
  248. package/src/provenance_wire.ts +6 -0
  249. package/src/query.ts +2 -1
  250. package/src/read.ts +50 -0
  251. package/src/relation.ts +4 -1
  252. package/src/relation_schema.ts +15 -2
  253. package/src/report.ts +2 -2
  254. package/src/sqlite_computation_bundle.ts +78 -0
  255. package/src/sqlite_computed.ts +102 -0
  256. package/src/sqlite_counts.ts +154 -0
  257. package/src/sqlite_layout.ts +823 -0
  258. package/src/sqlite_reads.ts +275 -0
  259. package/src/sqlite_samples.ts +185 -0
  260. package/src/stable_id_identity_bridge.ts +1 -1
  261. package/src/stable_ids_for_module.ts +16 -4
  262. package/src/test_call_usda.ts +6 -6
  263. package/src/usda_relationship_integrity.ts +20 -3
  264. package/src/usda_text.ts +21 -1
  265. package/src/value_object.ts +81 -11
  266. package/src/wire.ts +22 -0
  267. package/src/wire_encode.ts +227 -20
  268. package/src/workspace_sharding.ts +15 -6
  269. package/src/workspace_sharing.ts +51 -49
  270. package/src/zod_introspection.ts +2 -0
  271. package/compat_package.mjs +0 -46
  272. package/dart/lib/src/home.dart +0 -15
  273. package/dart/lib/src/runner/offline-install.mjs +0 -15367
  274. package/dart/lib/src/source_trust.dart +0 -51
  275. package/dart/lib/src/webview_bridge.dart +0 -6540
  276. package/dart/lib/src/workspace_name.dart +0 -30
  277. package/dart/test/acquire_session_credentials_test.dart +0 -150
  278. package/dart/test/acquire_session_test.dart +0 -534
  279. package/dart/test/adv_realm_interference_test.dart +0 -600
  280. package/dart/test/cloud_bound_topology_test.dart +0 -168
  281. package/dart/test/cluster_births_test.dart +0 -202
  282. package/dart/test/cluster_device_keyed_acceptance_test.dart +0 -105
  283. package/dart/test/cluster_local_autosync_test.dart +0 -123
  284. package/dart/test/cluster_scale_test.dart +0 -122
  285. package/dart/test/compat_test.dart +0 -61
  286. package/dart/test/dlq_session_surface_test.dart +0 -222
  287. package/dart/test/first_app_gauntlet_test.dart +0 -386
  288. package/dart/test/fixtures/wedge/fake-install.mjs +0 -11
  289. package/dart/test/four_layer_nested_topology_test.dart +0 -290
  290. package/dart/test/home_parity_test.dart +0 -13
  291. package/dart/test/local_sync_inert_test.dart +0 -107
  292. package/dart/test/node_runner_transport_test.dart +0 -78
  293. package/dart/test/parent_signer_recovery_test.dart +0 -155
  294. package/dart/test/residency_refusal_test.dart +0 -49
  295. package/dart/test/sealing_client_test.dart +0 -181
  296. package/dart/test/session_bound_test.dart +0 -285
  297. package/dart/test/stale_bundle_test.dart +0 -80
  298. package/dart/test/vo_read_typing_test.dart +0 -131
  299. package/dart/test/watch_after_offer_stall_test.dart +0 -100
  300. package/dart/test/webview_bridge_test.dart +0 -1930
  301. package/dart/test/workspace_name_test.dart +0 -24
  302. package/runtime/generated-application-host.js +0 -22860
  303. package/src/codegen_query_usda.ts +0 -214
  304. package/src/compat_manifest.ts +0 -26
  305. package/src/compat_package_main.ts +0 -224
  306. package/src/shape_compat.ts +0 -352
  307. package/src/usd_state.ts +0 -505
package/src/intent.ts CHANGED
@@ -20,6 +20,11 @@ import type { PlannedOp } from "./ops.js";
20
20
  import type { Field } from "./fields.js";
21
21
  import type { AggregateHandle } from "./aggregate.js";
22
22
  import type { QueryDecl } from "./query.js";
23
+ import {
24
+ enrolledDeviceAuthentication,
25
+ MemberAuthenticationKind,
26
+ type MemberAuthentication,
27
+ } from "./member_authentication.js";
23
28
  import type {
24
29
  InvariantReadBinding,
25
30
  InvariantReadId,
@@ -53,12 +58,47 @@ export interface IntentStep<I = unknown, P = unknown> {
53
58
  * the target workspace address; the nominal target directive and payload type remain sealed by the
54
59
  * compiled source graph and its generated USDA encoder. */
55
60
  export interface WorkspaceEffectStep<I = unknown, P = unknown> {
61
+ /** A source-local name for an effect that later consequences depend on. */
62
+ readonly key?: string;
63
+ /** Named predecessors from this same atomic consequence set, in declaration order. */
64
+ readonly after?: readonly string[];
56
65
  readonly target: Directive<P>;
57
66
  readonly destination:
58
- | { readonly kind: "workspace"; readonly address: (facts: I) => string }
67
+ | { readonly kind: "workspace"; readonly address: (facts: I, ctx: Ports) => string }
59
68
  | { readonly kind: "verifiedParent" }
60
69
  | { readonly kind: "verifiedSource" };
61
- readonly payload: (facts: I) => P;
70
+ readonly payload: (facts: I, ctx: Ports) => P;
71
+ /** Conditional correspondence is still captured source law, not host routing. */
72
+ readonly when?: (facts: I, ctx: Ports) => boolean;
73
+ }
74
+
75
+ /** Validate the source-local dependency graph independently of payloads and host state. */
76
+ export function validateWorkspaceEffectDependencies(
77
+ effects: readonly Pick<WorkspaceEffectStep, "key" | "after">[],
78
+ ): void {
79
+ const preceding = new Set<string>();
80
+ for (const effect of effects) {
81
+ if (effect.after !== undefined && !Array.isArray(effect.after)) {
82
+ throw new Error("Workspace effect dependencies must be an array of earlier effect names");
83
+ }
84
+ if (effect.key !== undefined && (
85
+ typeof effect.key !== "string" || effect.key.trim().length === 0 ||
86
+ effect.key !== effect.key.trim() || preceding.has(effect.key)
87
+ )) {
88
+ throw new Error("Workspace effect keys must be non-empty, unique names without surrounding whitespace");
89
+ }
90
+ const seen = new Set<string>();
91
+ for (const key of effect.after ?? []) {
92
+ if (!preceding.has(key)) {
93
+ throw new Error(`Workspace effect dependency '${key}' must name an earlier effect in the same atomic intent`);
94
+ }
95
+ if (seen.has(key)) {
96
+ throw new Error(`Workspace effect dependency '${key}' is repeated`);
97
+ }
98
+ seen.add(key);
99
+ }
100
+ if (effect.key !== undefined) preceding.add(effect.key);
101
+ }
62
102
  }
63
103
 
64
104
  const PAYLOAD_TRACE_PATH = Symbol("nomos.intent.payload-trace-path");
@@ -210,9 +250,6 @@ export interface BusinessIntent<I = unknown> extends Directive<I> {
210
250
  ) => void;
211
251
  readonly steps: readonly IntentStep<I, any>[];
212
252
  readonly workspaceEffects: readonly WorkspaceEffectStep<I, any>[];
213
- /** Law-selected proof for this exact public offer. Omitted means the ordinary session proof
214
- * posture. Tenant callers never choose this at invocation time. */
215
- readonly offerAuthenticationProof?: "enrolledDevice";
216
253
  /** Compiler-visible application lifecycle declaration. When opening a child of this aggregate
217
254
  * type proves that its verifier/signer posture is stale, the generated parent application may
218
255
  * invoke this exact nominal action on the already-authenticated parent. The action itself remains
@@ -234,7 +271,7 @@ export function authenticatesWithEnrolledDevice<I>(
234
271
  ): BusinessIntent<I> {
235
272
  return Object.freeze({
236
273
  ...action,
237
- offerAuthenticationProof: "enrolledDevice" as const,
274
+ authentication: enrolledDeviceAuthentication(),
238
275
  });
239
276
  }
240
277
 
@@ -248,14 +285,30 @@ export function repairsChildAuthenticationFor<I>(
248
285
  child: AggregateHandle,
249
286
  action: BusinessIntent<I>
250
287
  ): BusinessIntent<I> {
251
- if (action.offerAuthenticationProof !== "enrolledDevice") {
288
+ assertRepairsChildAuthentication(action, `repairsChildAuthenticationFor(${child.id})`);
289
+ return Object.freeze({
290
+ ...action,
291
+ [CHILD_AUTHENTICATION_RECOVERY]: child.id,
292
+ });
293
+ }
294
+
295
+ /** THE CHILD-AUTHENTICATION REPAIR GATE — the shape every repair must have, whether a tenant marks its
296
+ * own action per child kind ({@link repairsChildAuthenticationFor}) or the framework composes the one
297
+ * workspace-parameterised repair (`framework/child_authentication.ts`): the parent's enrolled device
298
+ * proves the author, the action writes nothing locally, and every effect addresses the exact child
299
+ * workspace named by its typed input. */
300
+ export function assertRepairsChildAuthentication<I>(
301
+ action: BusinessIntent<I>,
302
+ gate: string
303
+ ): void {
304
+ if (action.authentication?.kind !== MemberAuthenticationKind.EnrolledDevice) {
252
305
  throw new Error(
253
- `repairsChildAuthenticationFor(${child.id}): '${action.id}' must authenticate with the parent's enrolled device`
306
+ `${gate}: '${action.id}' must authenticate with the parent's enrolled device`
254
307
  );
255
308
  }
256
309
  if (action.steps.length !== 0 || action.workspaceEffects.length === 0) {
257
310
  throw new Error(
258
- `repairsChildAuthenticationFor(${child.id}): '${action.id}' must emit at least one child effect and make no parent-local write`
311
+ `${gate}: '${action.id}' must emit at least one child effect and make no parent-local write`
259
312
  );
260
313
  }
261
314
  if (
@@ -264,13 +317,9 @@ export function repairsChildAuthenticationFor<I>(
264
317
  )
265
318
  ) {
266
319
  throw new Error(
267
- `repairsChildAuthenticationFor(${child.id}): '${action.id}' must address the exact child workspace from its typed input`
320
+ `${gate}: '${action.id}' must address the exact child workspace from its typed input`
268
321
  );
269
322
  }
270
- return Object.freeze({
271
- ...action,
272
- [CHILD_AUTHENTICATION_RECOVERY]: child.id,
273
- });
274
323
  }
275
324
 
276
325
  /** Internal compiler projection of {@link repairsChildAuthenticationFor}. */
@@ -339,6 +388,47 @@ function oneStaticRelationGate<I>(
339
388
  return gates[0];
340
389
  }
341
390
 
391
+ const authenticationIdentity = (authentication: MemberAuthentication): string =>
392
+ authentication.kind === MemberAuthenticationKind.SelectedProvider
393
+ ? stable({
394
+ kind: authentication.kind,
395
+ providerKind: authentication.provider.kind,
396
+ scope: authentication.provider.scope,
397
+ identitySha256:
398
+ authentication.provider.kind === "legacySelected"
399
+ ? authentication.provider.identitySha256
400
+ : undefined,
401
+ })
402
+ : stable({ kind: authentication.kind });
403
+
404
+ /** The one authentication a business intent carries: its own, or the single one its steps declare. */
405
+ function oneAuthentication<I>(
406
+ id: string,
407
+ own: MemberAuthentication | undefined,
408
+ steps: readonly IntentStep<I, any>[]
409
+ ): MemberAuthentication | undefined {
410
+ // Only a provider selection (D7/D22) is inherited. An enrolled-device proof stays an explicit
411
+ // intent-level choice (`authenticatesWithEnrolledDevice`), exactly as before, so no existing law's
412
+ // published members change.
413
+ const declared = steps
414
+ .map((step) => (step.directive as { authentication?: MemberAuthentication }).authentication)
415
+ .filter((authentication): authentication is MemberAuthentication =>
416
+ authentication?.kind === MemberAuthenticationKind.SelectedProvider);
417
+ const identities = new Set(declared.map(authenticationIdentity));
418
+ if (identities.size > 1) {
419
+ throw new Error(
420
+ `intent('${id}') composes directives that authenticate with different providers — one member has one provider`
421
+ );
422
+ }
423
+ if (own !== undefined && declared.length > 0 && !identities.has(authenticationIdentity(own))) {
424
+ // e.g. an enrolled-device intent over a provider-selected directive: two different proofs.
425
+ throw new Error(
426
+ `intent('${id}') declares an authentication that differs from its directives'`
427
+ );
428
+ }
429
+ return own ?? declared[0];
430
+ }
431
+
342
432
  function unsupportedKernelGate(directive: Directive<any>): string | undefined {
343
433
  if (directive.attestationAuthorizedGate !== undefined)
344
434
  return "attestation authorization";
@@ -428,7 +518,10 @@ function composePrimaryConsequenceOp(
428
518
  ...(directive.marker === "ensures" && op.aggregateType === undefined
429
519
  ? { aggregateType: directive.aggregateId }
430
520
  : {}),
431
- marker: directive.marker,
521
+ // An op the plan marked explicitly (`withMarker`) keeps its marker: a `.creates` directive that also
522
+ // supersedes an existing row of its own type (declared `.alsoMutates`) must lower that row as a Mutate,
523
+ // or the referential gate refuses it as a create of an id that already exists.
524
+ marker: op.marker ?? directive.marker,
432
525
  };
433
526
  }
434
527
 
@@ -446,7 +539,7 @@ class IntentBuilder<I> {
446
539
  private readonly intentRelationGate?: NonNullable<
447
540
  Directive["requiresRelationGate"]
448
541
  >,
449
- private readonly offerAuthenticationProof?: "enrolledDevice",
542
+ private readonly authentication?: MemberAuthentication,
450
543
  private readonly acceptsVerifiedBirthParentRecovery = false
451
544
  ) {}
452
545
 
@@ -473,7 +566,7 @@ class IntentBuilder<I> {
473
566
  this.intentReads,
474
567
  this.acceptsWorkspaceEffects,
475
568
  this.intentRelationGate,
476
- this.offerAuthenticationProof,
569
+ this.authentication,
477
570
  this.acceptsVerifiedBirthParentRecovery
478
571
  );
479
572
  }
@@ -484,10 +577,13 @@ class IntentBuilder<I> {
484
577
  directsWorkspace<P>(
485
578
  target: Directive<P>,
486
579
  effect: {
580
+ readonly key?: string;
581
+ readonly after?: readonly string[];
487
582
  readonly workspace: (facts: I) => string;
488
583
  readonly payload: (facts: I) => P;
489
584
  }
490
585
  ): IntentBuilder<I> {
586
+ validateWorkspaceEffectDependencies([...this.workspaceEffects, effect]);
491
587
  if (
492
588
  isBusinessIntent(target) &&
493
589
  target.acceptsWorkspaceEffectGate !== true
@@ -506,12 +602,14 @@ class IntentBuilder<I> {
506
602
  target,
507
603
  destination: { kind: "workspace", address: effect.workspace },
508
604
  payload: effect.payload,
605
+ ...(effect.key !== undefined ? { key: effect.key } : {}),
606
+ ...(effect.after !== undefined ? { after: [...effect.after] } : {}),
509
607
  },
510
608
  ],
511
609
  this.intentReads,
512
610
  this.acceptsWorkspaceEffects,
513
611
  this.intentRelationGate,
514
- this.offerAuthenticationProof,
612
+ this.authentication,
515
613
  this.acceptsVerifiedBirthParentRecovery
516
614
  );
517
615
  }
@@ -546,7 +644,7 @@ class IntentBuilder<I> {
546
644
  this.intentReads,
547
645
  this.acceptsWorkspaceEffects,
548
646
  this.intentRelationGate,
549
- this.offerAuthenticationProof,
647
+ this.authentication,
550
648
  this.acceptsVerifiedBirthParentRecovery
551
649
  );
552
650
  }
@@ -582,7 +680,7 @@ class IntentBuilder<I> {
582
680
  this.intentReads,
583
681
  this.acceptsWorkspaceEffects,
584
682
  this.intentRelationGate,
585
- this.offerAuthenticationProof,
683
+ this.authentication,
586
684
  this.acceptsVerifiedBirthParentRecovery
587
685
  );
588
686
  }
@@ -598,7 +696,7 @@ class IntentBuilder<I> {
598
696
  this.intentReads,
599
697
  true,
600
698
  this.intentRelationGate,
601
- this.offerAuthenticationProof,
699
+ this.authentication,
602
700
  this.acceptsVerifiedBirthParentRecovery
603
701
  );
604
702
  }
@@ -615,7 +713,7 @@ class IntentBuilder<I> {
615
713
  this.intentReads,
616
714
  true,
617
715
  this.intentRelationGate,
618
- this.offerAuthenticationProof,
716
+ this.authentication,
619
717
  true
620
718
  );
621
719
  }
@@ -632,7 +730,7 @@ class IntentBuilder<I> {
632
730
  this.intentReads,
633
731
  this.acceptsWorkspaceEffects,
634
732
  this.intentRelationGate,
635
- "enrolledDevice",
733
+ enrolledDeviceAuthentication(),
636
734
  this.acceptsVerifiedBirthParentRecovery
637
735
  );
638
736
  }
@@ -664,7 +762,7 @@ class IntentBuilder<I> {
664
762
  this.intentReads,
665
763
  this.acceptsWorkspaceEffects,
666
764
  gate,
667
- this.offerAuthenticationProof,
765
+ this.authentication,
668
766
  this.acceptsVerifiedBirthParentRecovery
669
767
  );
670
768
  }
@@ -688,7 +786,7 @@ class IntentBuilder<I> {
688
786
  [...byKey.values()],
689
787
  this.acceptsWorkspaceEffects,
690
788
  this.intentRelationGate,
691
- this.offerAuthenticationProof,
789
+ this.authentication,
692
790
  this.acceptsVerifiedBirthParentRecovery
693
791
  );
694
792
  }
@@ -707,13 +805,14 @@ class IntentBuilder<I> {
707
805
  this.intentReads,
708
806
  this.acceptsWorkspaceEffects,
709
807
  this.intentRelationGate,
710
- this.offerAuthenticationProof,
808
+ this.authentication,
711
809
  this.acceptsVerifiedBirthParentRecovery
712
810
  );
713
811
  }
714
812
 
715
813
  /** Finish the intent and lower its directive graph to one atomic offer. */
716
814
  atomically(): BusinessIntent<I> {
815
+ validateWorkspaceEffectDependencies(this.workspaceEffects);
717
816
  if (this.steps.length === 0 && this.workspaceEffects.length === 0) {
718
817
  throw new Error(
719
818
  `intent('${this.id}') needs at least one directed consequence`
@@ -897,6 +996,18 @@ class IntentBuilder<I> {
897
996
  }
898
997
  }
899
998
  const inheritedRelationGate = oneStaticRelationGate(this.steps);
999
+ // D7/D22 — authentication is declared per directive; the business intent that publishes a
1000
+ // directive IS the routable member the kernel judges, so it carries its steps' one provider (and
1001
+ // a sovereign self-certification marker) rather than silently dropping them.
1002
+ const authentication = oneAuthentication(this.id, this.authentication, this.steps);
1003
+ const selfCertifying = this.steps.some(
1004
+ (step) => step.directive.selfCertifyingPrincipalGate === true
1005
+ );
1006
+ if (selfCertifying && (this.steps.length !== 1 || this.workspaceEffects.length > 0)) {
1007
+ throw new Error(
1008
+ `intent('${this.id}') composes a sovereign self-certification; it must be the intent's only effect`
1009
+ );
1010
+ }
900
1011
  if (
901
1012
  this.intentRelationGate !== undefined &&
902
1013
  inheritedRelationGate !== undefined &&
@@ -968,10 +1079,10 @@ class IntentBuilder<I> {
968
1079
  },
969
1080
  marker: primary.marker as ReferentialMarker,
970
1081
  aggregateId: primary.aggregateId,
971
- // Keep the typed local target on the lowered public intent. A narrow
972
- // runtime plan may retain only this intent export; without the handle the
973
- // engine cannot rebuild its aggregate registry entry and silently drops
974
- // compound intents that also birth a child.
1082
+ // Keep the typed target on the executable intent. A narrow runtime plan
1083
+ // may retain only this intent export and needs the handle to register the
1084
+ // route. Package composition separately excludes a pure workspace
1085
+ // effect's remote target from the source domain's generated record types.
975
1086
  ...(primary.aggregate === undefined
976
1087
  ? {}
977
1088
  : { aggregate: primary.aggregate }),
@@ -986,9 +1097,8 @@ class IntentBuilder<I> {
986
1097
  plan,
987
1098
  steps,
988
1099
  workspaceEffects: this.workspaceEffects,
989
- ...(this.offerAuthenticationProof === undefined
990
- ? {}
991
- : { offerAuthenticationProof: this.offerAuthenticationProof }),
1100
+ ...(authentication === undefined ? {} : { authentication }),
1101
+ ...(selfCertifying ? { selfCertifyingPrincipalGate: true as const } : {}),
992
1102
  ...(this.acceptsWorkspaceEffects
993
1103
  ? { acceptsWorkspaceEffectGate: true as const }
994
1104
  : {}),
@@ -1044,7 +1154,10 @@ class IntentBuilder<I> {
1044
1154
  }
1045
1155
 
1046
1156
  class IntentContractStep {
1047
- constructor(private readonly id: string) {}
1157
+ private readonly id: string;
1158
+ constructor(id: string) {
1159
+ this.id = id;
1160
+ }
1048
1161
 
1049
1162
  /**
1050
1163
  * Publish one existing effect as a business intent without repeating its
@@ -1254,7 +1367,7 @@ export function executableDirectivesForLanguage(
1254
1367
  `domain '${domain}' intent '${candidate.id}' collides with a different directive — rename one of them`
1255
1368
  );
1256
1369
  }
1257
- if (isBusinessIntent(candidate) && published === undefined) {
1370
+ if (isBusinessIntent(candidate) && published === undefined && candidate.businessBirthInternal !== true) {
1258
1371
  throw new Error(
1259
1372
  `domain '${domain}' exports intent '${candidate.id}' outside its declared language — add it to language('${domain}', [...]) or remove it`
1260
1373
  );
@@ -1262,11 +1375,34 @@ export function executableDirectivesForLanguage(
1262
1375
  }
1263
1376
 
1264
1377
  const remaining = discovered.filter(
1265
- (candidate) => !privateIds.has(candidate.id) && !isBusinessIntent(candidate)
1378
+ (candidate) => !privateIds.has(candidate.id) && !publicById.has(candidate.id)
1379
+ && (!isBusinessIntent(candidate) || candidate.businessBirthInternal === true)
1266
1380
  );
1267
1381
  return [...remaining, ...language.intents];
1268
1382
  }
1269
1383
 
1384
+ /**
1385
+ * The command name admitted at the public offer boundary.
1386
+ *
1387
+ * Most executable declarations keep their authored id. A bare `birth(A)` is
1388
+ * lowered to a private, aggregate-specific directive so replay can retain the
1389
+ * exact implementation, while every generated application exposes the single
1390
+ * stable verb `birth`. A wider authored business intent keeps its own name even
1391
+ * when one of its private consequences is a birth.
1392
+ *
1393
+ * Law description, generated clients and the executable registry must all call
1394
+ * this function. Re-deriving the rule at those boundaries creates a route that
1395
+ * type-checks but cannot dispatch.
1396
+ */
1397
+ export function publicOfferRoute(directive: Directive<any>): string {
1398
+ const businessBirth = (
1399
+ directive as Directive<any> & { readonly businessBirth?: unknown }
1400
+ ).businessBirth;
1401
+ return businessBirth === undefined || isBusinessIntent(directive)
1402
+ ? directive.id
1403
+ : "birth";
1404
+ }
1405
+
1270
1406
  /**
1271
1407
  * Refuse a half-migrated source module. Once a domain declares its language,
1272
1408
  * every authored directive export must either be a published intent or one of
@@ -1284,20 +1420,12 @@ export function assertApplicationLanguageCoversAuthoredDirectives(
1284
1420
  candidate.steps.map((step) => step.directive.id)
1285
1421
  )
1286
1422
  );
1287
- const sharingReceiptIds = new Set(
1288
- language.workspaceSharing.flatMap((policy) =>
1289
- [...policy.delivered, ...policy.refused].map(
1290
- (receipt) => receipt.records.id
1291
- )
1292
- )
1293
- );
1294
1423
  const uncovered = authored
1295
1424
  .filter(
1296
1425
  (directive) =>
1297
1426
  directive.businessBirthInternal !== true &&
1298
1427
  !publicIds.has(directive.id) &&
1299
- !privateIds.has(directive.id) &&
1300
- !sharingReceiptIds.has(directive.id)
1428
+ !privateIds.has(directive.id)
1301
1429
  )
1302
1430
  .map((directive) => directive.id)
1303
1431
  .sort();
package/src/law_check.ts CHANGED
@@ -142,7 +142,7 @@ function probeDirective(dir: Directive<unknown>, where: string): ProbeResult | u
142
142
  returned = dir.plan(tracked as never, deterministicPorts({ physical: 1, replica: 1, principal: "principal:probe" }));
143
143
  const drained: PlannedOp[] = [...__drainAuthoring(), ...(Array.isArray(returned) ? returned : [])];
144
144
  ops = drained.filter((o): o is FieldOp => (o as { kind?: string }).kind !== "strike");
145
- if (isBusinessIntent(dir)) {
145
+ if (dir.workspaceEffects) {
146
146
  for (const effect of dir.workspaceEffects) {
147
147
  // These two mappers are source law just as surely as the local plan. Run them against
148
148
  // the same tracking payload so route/payload fields are not falsely diagnosed as dead.
@@ -150,10 +150,11 @@ function probeDirective(dir: Directive<unknown>, where: string): ProbeResult | u
150
150
  // turn a successful local plan into a plan-return warning, but reads reached before the
151
151
  // refusal are still drained and checked below.
152
152
  try {
153
- if (effect.destination.kind === "workspace") {
154
- effect.destination.address(tracked as never);
153
+ const ports = deterministicPorts({ physical: 1, replica: 1, principal: "principal:probe" });
154
+ if (effect.when?.(tracked as never, ports) ?? true) {
155
+ if (effect.destination.kind === "workspace") effect.destination.address(tracked as never, ports);
156
+ effect.payload(tracked as never, ports);
155
157
  }
156
- effect.payload(tracked as never);
157
158
  } catch {
158
159
  // Inconclusive mapper branch on the synthesized fixture; runtime/generator proof remains.
159
160
  }
@@ -1029,7 +1030,7 @@ function invariantFindings(mod: DomainModule, aggById: ReadonlyMap<string, Aggre
1029
1030
  const snap = synthesizeSnapshot(agg, `${domain}/${agg.id}#invariant`);
1030
1031
  if (snap === undefined) continue; // unsynthesizable — proven by hand, not by check
1031
1032
  try {
1032
- withBirthProbeGlobals(() => agg.invariant!(snap));
1033
+ withBirthProbeGlobals(() => agg.invariant!(snap, null));
1033
1034
  } catch (e) {
1034
1035
  out.push({
1035
1036
  domain,
@@ -1232,6 +1233,8 @@ function attestedReadFindings(mod: DomainModule): Finding[] {
1232
1233
  // (b) unpopulatable trust set — a policy allow-list no directive writes.
1233
1234
  const writtenTypes = new Set(directives.map((d) => (d as { aggregateId?: string }).aggregateId).filter(Boolean) as string[]);
1234
1235
  for (const pol of mod.trustPolicies ?? []) {
1236
+ if (pol.authorizationOnly === true) continue;
1237
+ if (pol.allowListType === undefined) continue;
1235
1238
  if (!writtenTypes.has(pol.allowListType)) {
1236
1239
  findings.push({
1237
1240
  domain,