@githolon/dsl 0.108.7 → 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 +1994 -1189
  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
@@ -0,0 +1,156 @@
1
+ declare const PEER_CLASS: unique symbol;
2
+
3
+ /** A stable class of peer used by custody-placement declarations. */
4
+ export type PeerClass<Name extends string = string> = Name & {
5
+ readonly [PEER_CLASS]: true;
6
+ };
7
+
8
+ /**
9
+ * Whether this peer should keep custodied workspace state open in kernel memory.
10
+ * This is independent of durable/offline Git retention.
11
+ */
12
+ export type KernelResidency = "warm" | "on-demand";
13
+
14
+ /**
15
+ * Whether this peer should retain durable Git custody independently of memory residency.
16
+ * `retain`, not `warm`, is the policy that makes existing custody survive restart/offline use.
17
+ */
18
+ export type CustodyRetention = "retain" | "cache" | "none";
19
+
20
+ /** A named reception route selected by placement policy, never part of `NomosRef<T>`. */
21
+ export interface CustodyRemote<Name extends string = string> {
22
+ readonly __isCustodyRemote: true;
23
+ readonly name: Name;
24
+ readonly url: string;
25
+ readonly peer: string;
26
+ readonly priority: number;
27
+ }
28
+
29
+ export interface CustodyPlacementRule {
30
+ readonly peerClass: PeerClass;
31
+ readonly kernelResidency: KernelResidency;
32
+ readonly custodyRetention: CustodyRetention;
33
+ readonly remotes: readonly string[];
34
+ }
35
+
36
+ /**
37
+ * A domain-shipped placement option. This is not live workspace policy.
38
+ *
39
+ * A workspace adopts one declaration on its independent placement frontier;
40
+ * evolving main law never adopts or changes it implicitly. Generated clients
41
+ * address stable workspace identities; the peer runtime resolves this policy.
42
+ * Do not copy its remotes or retention choices into domain records or Nomos refs.
43
+ */
44
+ export interface CustodyPlacementDeclaration<Id extends string = string> {
45
+ readonly __isCustodyPlacement: true;
46
+ readonly id: Id;
47
+ readonly remotes: readonly CustodyRemote[];
48
+ readonly rules: readonly CustodyPlacementRule[];
49
+ }
50
+
51
+ const identifier = (kind: string, value: string): void => {
52
+ if (!/^[A-Za-z][A-Za-z0-9._-]*$/.test(value)) {
53
+ throw new Error(`${kind} '${value}' is not a stable Nomos identifier`);
54
+ }
55
+ };
56
+
57
+ export function peerClass<const Name extends string>(name: Name): PeerClass<Name> {
58
+ identifier("peer class", name);
59
+ return name as PeerClass<Name>;
60
+ }
61
+
62
+ export function custodyRemote<const Name extends string>(
63
+ name: Name,
64
+ url: string,
65
+ options: { readonly peer: string; readonly priority?: number },
66
+ ): CustodyRemote<Name> {
67
+ identifier("custody remote", name);
68
+ if (!options.peer.trim()) throw new Error(`custody remote '${name}' requires a peer identity`);
69
+ let parsed: URL;
70
+ try {
71
+ parsed = new URL(url);
72
+ } catch {
73
+ throw new Error(`custody remote '${name}' has invalid URL '${url}'`);
74
+ }
75
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
76
+ throw new Error(`custody remote '${name}' requires an HTTP(S) URL`);
77
+ }
78
+ const priority = options.priority ?? 0;
79
+ if (!Number.isSafeInteger(priority) || priority < 0) {
80
+ throw new Error(`custody remote '${name}' priority must be a non-negative integer`);
81
+ }
82
+ return Object.freeze({
83
+ __isCustodyRemote: true,
84
+ name,
85
+ url: parsed.toString(),
86
+ peer: options.peer,
87
+ priority,
88
+ });
89
+ }
90
+
91
+ export function custodyPlacementRule(
92
+ peer: PeerClass,
93
+ policy: {
94
+ readonly kernelResidency: KernelResidency;
95
+ readonly custodyRetention: CustodyRetention;
96
+ readonly remotes?: readonly CustodyRemote[];
97
+ },
98
+ ): CustodyPlacementRule {
99
+ return Object.freeze({
100
+ peerClass: peer,
101
+ kernelResidency: policy.kernelResidency,
102
+ custodyRetention: policy.custodyRetention,
103
+ remotes: Object.freeze((policy.remotes ?? []).map((remote) => remote.name)),
104
+ });
105
+ }
106
+
107
+ export function custodyPlacement<const Id extends string>(
108
+ id: Id,
109
+ policy: {
110
+ readonly remotes?: readonly CustodyRemote[];
111
+ readonly rules: readonly CustodyPlacementRule[];
112
+ },
113
+ ): CustodyPlacementDeclaration<Id> {
114
+ identifier("custody placement", id);
115
+ const rules = policy.rules;
116
+ if (rules.length === 0) {
117
+ throw new Error(`custody placement '${id}' declares no peer rules`);
118
+ }
119
+ const remotes = [...(policy.remotes ?? [])];
120
+ const remoteNames = new Set<string>();
121
+ for (const remote of remotes) {
122
+ if (!remoteNames.add(remote.name)) {
123
+ throw new Error(`custody placement '${id}' repeats remote '${remote.name}'`);
124
+ }
125
+ }
126
+ const seen = new Set<string>();
127
+ for (const rule of rules) {
128
+ if (seen.has(rule.peerClass)) {
129
+ throw new Error(
130
+ `custody placement '${id}' repeats peer class '${rule.peerClass}'`,
131
+ );
132
+ }
133
+ seen.add(rule.peerClass);
134
+ for (const remote of rule.remotes) {
135
+ if (!remoteNames.has(remote)) {
136
+ throw new Error(
137
+ `custody placement '${id}' rule for '${rule.peerClass}' references unknown remote '${remote}'`,
138
+ );
139
+ }
140
+ }
141
+ }
142
+ return Object.freeze({
143
+ __isCustodyPlacement: true,
144
+ id,
145
+ remotes: Object.freeze(remotes),
146
+ rules: Object.freeze([...rules]),
147
+ });
148
+ }
149
+
150
+ export function isCustodyPlacementDeclaration(
151
+ value: unknown,
152
+ ): value is CustodyPlacementDeclaration {
153
+ return value !== null
154
+ && typeof value === "object"
155
+ && (value as { __isCustodyPlacement?: unknown }).__isCustodyPlacement === true;
156
+ }
@@ -0,0 +1,91 @@
1
+ import {
2
+ type CustodyPlacementDeclaration,
3
+ } from "./custody_placement.js";
4
+ import { usdaString } from "./usda_text.js";
5
+
6
+ export interface DomainCustodyPlacement {
7
+ readonly domain: string;
8
+ readonly declaration: CustodyPlacementDeclaration;
9
+ }
10
+
11
+ const primName = (value: string): string =>
12
+ value.replace(/[^A-Za-z0-9_]/g, (character) =>
13
+ `_x${character.codePointAt(0)!.toString(16).padStart(2, "0")}_`
14
+ );
15
+
16
+ /** Emit independently adoptable placement declarations, never main law. */
17
+ export function custodyPlacementDeclarationsUsda(
18
+ declarations: readonly DomainCustodyPlacement[],
19
+ ): string {
20
+ const ordered = [...declarations].sort((left, right) => {
21
+ const domain = left.domain.localeCompare(right.domain);
22
+ return domain !== 0
23
+ ? domain
24
+ : left.declaration.id.localeCompare(right.declaration.id);
25
+ });
26
+ const identities = new Set<string>();
27
+ for (const { domain, declaration } of ordered) {
28
+ const identity = `${domain}/${declaration.id}`;
29
+ if (!identities.add(identity)) {
30
+ throw new Error(`custody placement declaration '${identity}' is repeated`);
31
+ }
32
+ }
33
+
34
+ return [
35
+ "#usda 1.0",
36
+ "(",
37
+ ' defaultPrim = "NomosPlacementDeclarations"',
38
+ " customLayerData = {",
39
+ ' string "nomos:format" = "nomos.custody-placement-declarations.v1"',
40
+ " }",
41
+ ")",
42
+ "",
43
+ 'def Scope "NomosPlacementDeclarations"',
44
+ "{",
45
+ ...ordered.flatMap(({ domain, declaration }) => [
46
+ ` def Scope ${usdaString(`d_${primName(domain)}__${primName(declaration.id)}`)}`,
47
+ " {",
48
+ ` custom string nomos:domain = ${usdaString(domain)}`,
49
+ ` custom string nomos:declaration = ${usdaString(declaration.id)}`,
50
+ "",
51
+ ' def Scope "Remotes"',
52
+ " {",
53
+ ...[...declaration.remotes]
54
+ .sort((left, right) => left.name.localeCompare(right.name))
55
+ .flatMap((remote) => [
56
+ ` def NomosCustodyRemote ${usdaString(`r_${primName(remote.name)}`)}`,
57
+ " {",
58
+ ` custom string nomos:name = ${usdaString(remote.name)}`,
59
+ ` custom string nomos:url = ${usdaString(remote.url)}`,
60
+ ` custom string nomos:peer = ${usdaString(remote.peer)}`,
61
+ ` custom int nomos:priority = ${remote.priority}`,
62
+ " }",
63
+ ]),
64
+ " }",
65
+ "",
66
+ ' def Scope "Rules"',
67
+ " {",
68
+ ...[...declaration.rules]
69
+ .sort((left, right) => left.peerClass.localeCompare(right.peerClass))
70
+ .flatMap((rule, index) => [
71
+ ` def Scope "r_${String(index).padStart(4, "0")}"`,
72
+ " {",
73
+ ` custom token nomos:peerClass = ${usdaString(rule.peerClass)}`,
74
+ ` custom token nomos:kernelResidency = ${usdaString(rule.kernelResidency)}`,
75
+ ` custom token nomos:custodyRetention = ${usdaString(rule.custodyRetention)}`,
76
+ ...(rule.remotes.length === 0
77
+ ? []
78
+ : [
79
+ ` rel nomos:remotes = [${rule.remotes
80
+ .map((remote) => `</NomosPlacementDeclarations/d_${primName(domain)}__${primName(declaration.id)}/Remotes/r_${primName(remote)}>`)
81
+ .join(", ")}]`,
82
+ ]),
83
+ " }",
84
+ ]),
85
+ " }",
86
+ " }",
87
+ ]),
88
+ "}",
89
+ "",
90
+ ].join("\n");
91
+ }
@@ -20,6 +20,9 @@ import type { QueryDecl } from "./query.js";
20
20
  import type { SpatialDecl } from "./spatial.js";
21
21
  import type { AnySum } from "./sum.js";
22
22
  import type { AnyCount } from "./count.js";
23
+ import type { AnyExtremum } from "./extremum.js";
24
+ import type { AnyExists } from "./exists.js";
25
+ import type { OrderedReadDecl } from "./ordered_read.js";
23
26
  import type { WorkspaceInvariantDecl } from "./framework/workspace_invariant.js";
24
27
 
25
28
  /** A merged domain-module exports bag (scanned by shape). */
@@ -79,7 +82,7 @@ export function isCountDecl(v: unknown): v is AnyCount {
79
82
  !("field" in o) && // extremum (wire-descriptor shape)
80
83
  !("valueField" in o) && // extremum (the ExtremumDecl/Extremum-builder mark — never a count)
81
84
  !("sumField" in o) && // sum (the SumDecl/Sum-builder mark — never a count)
82
- !("orderBy" in o) && // ordered read
85
+ !("orderBy" in o) && !("orderKey" in o) && // unfinished/finished ordered read
83
86
  !("_existsMarker" in o) && // exists
84
87
  typeof o.refField !== "string" && // combined
85
88
  o.__isAggregateHandle !== true && // aggregate
@@ -89,7 +92,7 @@ export function isCountDecl(v: unknown): v is AnyCount {
89
92
  }
90
93
 
91
94
  /** An extremum decl/builder — `{id, of, valueField}` with `{kind:"min"|"max"}` (the #47 read). */
92
- export function isExtremumDecl(v: unknown): boolean {
95
+ export function isExtremumDecl(v: unknown): v is AnyExtremum {
93
96
  if (!v || typeof v !== "object") return false;
94
97
  const o = v as Record<string, unknown>;
95
98
  return (
@@ -100,6 +103,22 @@ export function isExtremumDecl(v: unknown): boolean {
100
103
  );
101
104
  }
102
105
 
106
+ /** Both total and grouped membership declarations carry the same explicit brand. */
107
+ export function isExistsDecl(v: unknown): v is AnyExists {
108
+ if (!v || typeof v !== "object") return false;
109
+ const o = v as Record<string, unknown>;
110
+ return typeof o.id === "string" && typeof o.of === "string" && o._existsMarker === true;
111
+ }
112
+
113
+ /** Finished first/take declaration; an unfinished orderBy builder is not executable law. */
114
+ export function isOrderedReadDecl(v: unknown): v is OrderedReadDecl {
115
+ if (!v || typeof v !== "object") return false;
116
+ const o = v as Record<string, unknown>;
117
+ return typeof o.id === "string" && typeof o.of === "string"
118
+ && typeof o.orderKey === "string" && typeof o.orderDesc === "boolean"
119
+ && typeof o.limit === "number";
120
+ }
121
+
103
122
  /**
104
123
  * Scan merged exports for decls matching `match`: individual exports AND exported arrays, deduped
105
124
  * by a function-blind JSON key (the SAME dedup `compile_package_main.ts` `discover` uses).
@@ -81,6 +81,7 @@ const mergePolicy = (driver: unknown): string => {
81
81
  const d = driver as { kind?: unknown; inner?: unknown; principal?: unknown };
82
82
  switch (d.kind) {
83
83
  case "FirstWriterWins": return "the first concurrent change wins; a later informed edit may replace it";
84
+ case "FirstWriterCandidates": return "the first of the changes nobody had seen wins; a later informed edit settles it";
84
85
  case "Lww": return "the latest recorded change wins";
85
86
  case "LwwCausal": return "a change based on another wins; truly concurrent changes use a stable tie-break";
86
87
  case "LwwBy": return `${String(d.principal ?? "the declared authority")} is the sole writer`;
package/src/directive.ts CHANGED
@@ -23,6 +23,8 @@ import type { PlannedOp } from "./ops.js";
23
23
  import type { Ports } from "./ctx.js";
24
24
  import type { RelationDecl } from "./relation.js";
25
25
  import type { QueryDecl } from "./query.js";
26
+ import type { AuthenticatedMember } from "./member_authentication.js";
27
+ import { enrolledDeviceAuthentication } from "./member_authentication.js";
26
28
  import {
27
29
  normalizeActivity,
28
30
  type ActivityInput,
@@ -39,6 +41,7 @@ import {
39
41
  type FromPayloadRef,
40
42
  type TrustPolicyDecl,
41
43
  type ForeignReadEdge,
44
+ type AttestedReadSubjectRef,
42
45
  } from "./attested_core.js";
43
46
  import {
44
47
  buildPointGuard,
@@ -253,7 +256,9 @@ export interface BusinessSourceTrust {
253
256
  readonly satisfiedByQueryArgs?: Readonly<Record<string, string>>;
254
257
  }
255
258
 
256
- export interface Directive<P = unknown> {
259
+ export interface Directive<P = unknown> extends AuthenticatedMember {
260
+ /** Durable consequences emitted through the same offer outbox as public intentions. */
261
+ readonly workspaceEffects?: readonly import("./intent.js").WorkspaceEffectStep<P, any>[];
257
262
  readonly id: string;
258
263
  readonly marker: ReferentialMarker;
259
264
  readonly aggregateId: string;
@@ -274,6 +279,12 @@ export interface Directive<P = unknown> {
274
279
  * two generated client shapes without changing the directive's replay law.
275
280
  */
276
281
  readonly outputCardinality?: "many" | "optional";
282
+ /**
283
+ * Law-selected authentication proof for this exact directive. Omitted means
284
+ * the ordinary session posture (provider token plus enrolled device for a
285
+ * warranted human workspace). This is authentication only: the directive's
286
+ * independent `.requires(...)` authorization policy still has to pass.
287
+ */
277
288
  /**
278
289
  * MULTI-OUTPUT DIRECTIVES: additional aggregates this directive declares it writes, beyond the primary
279
290
  * marker target. Present iff the directive chained `.alsoEnsures/.alsoCreates/.alsoMutates/.alsoArchives`
@@ -360,6 +371,9 @@ export interface Directive<P = unknown> {
360
371
  readonly recordType: string;
361
372
  readonly idField: string;
362
373
  };
374
+ /** Use the workspace identity proven by this declared foreign read as the
375
+ * Zanzibar subject. Absent means the ordinary session principal. */
376
+ readonly subjectFromAttestedRead?: string;
363
377
  };
364
378
  /**
365
379
  * Admit this directive when it is the exact target call carried by a verified,
@@ -372,6 +386,16 @@ export interface Directive<P = unknown> {
372
386
  /** Recovery-only workspace-effect door. The carried source must prove it is this workspace's
373
387
  * exact K_root-rooted birth parent; no Zanzibar relation or host assertion substitutes for it. */
374
388
  readonly acceptsVerifiedBirthParentRecoveryGate?: true;
389
+ /** Accept a claim made by a cryptographically verified source workspace. This proves the
390
+ * speaker, not a role in the recipient. Receiving law must scope the claim to that speaker. */
391
+ readonly acceptsVerifiedWorkspaceClaimGate?: true;
392
+ /**
393
+ * SOVEREIGN SELF-CERTIFICATION (identity target model D22). The founding signer tuple this directive
394
+ * writes (`identity:<scope>:<h>#signer@key:<h>`) is admitted with no prior signer of the principal iff
395
+ * the signing key's sha256 is `h`, the captured principal's subject. Lowered to
396
+ * `nomos:selfCertifyingPrincipal = "true"`; framework-only (`sovereignSelfCertification`).
397
+ */
398
+ readonly selfCertifyingPrincipalGate?: true;
375
399
  /**
376
400
  * CROSS-CUSTODY ATTESTATION-AUTHORIZED (home_holons §3/§5). When `true`, this directive's authorization
377
401
  * is a carried §3 SIGNED QUOTE (the asserter's pubkey + a signature over the edge), NOT an author block —
@@ -663,10 +687,20 @@ export interface RequirableDirective<P> extends Directive<P> {
663
687
  opts?: {
664
688
  object?: string;
665
689
  objectFrom?: { recordType: string; idField: string };
690
+ subjectFrom?: AttestedReadSubjectRef;
666
691
  }
667
692
  ): RequirableDirective<P>;
668
693
  /** Declare this exact call shape as an admissible signed parent-workspace effect. */
669
694
  acceptsWorkspaceEffect(): RequirableDirective<P>;
695
+ acceptsVerifiedWorkspaceClaim(): RequirableDirective<P>;
696
+ /**
697
+ * Authenticate this exact directive with an already-enrolled active device,
698
+ * without requiring a provider token. Use for operations which repair the
699
+ * provider verifier itself; authorization remains separately law-declared.
700
+ */
701
+ authenticatesWithEnrolledDevice(): RequirableDirective<P>;
702
+ /** Framework-only: mark this directive as a sovereign principal's self-certification (D22). */
703
+ selfCertifyingPrincipal(): RequirableDirective<P>;
670
704
  /**
671
705
  * Declare this directive ATTESTATION-AUTHORIZED (home_holons §3/§5): its authorization is a carried §3
672
706
  * signed quote rather than an author block — lowered into the `nomosAttestationGate` era key so the one
@@ -834,7 +868,10 @@ export interface RequirableDirective<P> extends Directive<P> {
834
868
 
835
869
  /** Stage 1: id + a referential marker (which fixes the target aggregate). */
836
870
  class DirectiveMarkerStep<Id extends string> {
837
- constructor(private readonly id: Id) {}
871
+ private readonly id: Id;
872
+ constructor(id: Id) {
873
+ this.id = id;
874
+ }
838
875
  /**
839
876
  * `creates(Agg)` — Nomos MINTS the id (byte-identical to before this arg existed). For CREATE-ONCE at an
840
877
  * APP-SUPPLIED stable id, chain `.payload(...).withId(p => p.id)` on the plan step (typed against the
@@ -1404,6 +1441,7 @@ function makeRequirable<P>(base: Directive<P>): RequirableDirective<P> {
1404
1441
  opts?: {
1405
1442
  object?: string;
1406
1443
  objectFrom?: { recordType: string; idField: string };
1444
+ subjectFrom?: AttestedReadSubjectRef;
1407
1445
  }
1408
1446
  ): RequirableDirective<P> {
1409
1447
  // THE ONE write-authz declaration (full-native Zanzibar, no mixed systems): the captured author
@@ -1420,12 +1458,31 @@ function makeRequirable<P>(base: Directive<P>): RequirableDirective<P> {
1420
1458
  ...(opts?.objectFrom !== undefined
1421
1459
  ? { objectFrom: opts.objectFrom }
1422
1460
  : {}),
1461
+ ...(opts?.subjectFrom !== undefined
1462
+ ? { subjectFromAttestedRead: opts.subjectFrom.queryId }
1463
+ : {}),
1423
1464
  },
1424
1465
  });
1425
1466
  },
1426
1467
  acceptsWorkspaceEffect(): RequirableDirective<P> {
1427
1468
  return makeRequirable({ ...base, acceptsWorkspaceEffectGate: true });
1428
1469
  },
1470
+ acceptsVerifiedWorkspaceClaim(): RequirableDirective<P> {
1471
+ return makeRequirable({
1472
+ ...base,
1473
+ acceptsWorkspaceEffectGate: true,
1474
+ acceptsVerifiedWorkspaceClaimGate: true,
1475
+ });
1476
+ },
1477
+ authenticatesWithEnrolledDevice(): RequirableDirective<P> {
1478
+ return makeRequirable({
1479
+ ...base,
1480
+ authentication: enrolledDeviceAuthentication(),
1481
+ });
1482
+ },
1483
+ selfCertifyingPrincipal(): RequirableDirective<P> {
1484
+ return makeRequirable({ ...base, selfCertifyingPrincipalGate: true });
1485
+ },
1429
1486
  attestationAuthorized(owner: {
1430
1487
  ownerObject: string;
1431
1488
  ownerField: string;
package/src/drivers.ts CHANGED
@@ -14,6 +14,7 @@
14
14
  * PALETTE_ONLY mechanism + throw remain for any FUTURE driver added to this
15
15
  * palette ahead of its kernel merge arm — never silently emit an unsupported wire driver.
16
16
  */
17
+ import { canonicalJson } from "./canonical_json.js";
17
18
  import type { WireDriver } from "./wire.js";
18
19
 
19
20
  /**
@@ -24,6 +25,7 @@ import type { WireDriver } from "./wire.js";
24
25
  export type KernelDriverKind =
25
26
  | "Lww"
26
27
  | "FirstWriterWins"
28
+ | "FirstWriterCandidates"
27
29
  // ── EXPLICIT TIME-AUTHORITY Lww drivers (the "whose clock?" axis) ──
28
30
  // Nomos has no servers, so "do we trust the clock?" is the WRONG question — the real
29
31
  // one is WHOSE clock orders THIS field, and a dev assigns it per field. `Lww` trusts
@@ -61,6 +63,14 @@ export const Lww: Driver = { kind: "Lww" };
61
63
  /** Nomos's ordinary scalar conflict policy: an informed later edit replaces the
62
64
  * value; concurrent edits converge on the earliest writer. */
63
65
  export const FirstWriterWins: Driver = { kind: "FirstWriterWins" };
66
+ /** The same policy as `FirstWriterWins`, decided from the SET of changes rather than the
67
+ * order they happened to arrive in: changes nobody had seen compete, the earliest of them is
68
+ * the value, and a change made with knowledge of the others settles it. Because arrival order
69
+ * cannot matter, work recorded offline joins a workspace without replaying its history.
70
+ * Opt in per field with `.merge(FirstWriterCandidates)`, or for every first-writer field of an
71
+ * aggregate with `{ firstWriter: "candidates" }`. It is a law change: roll it out as one.
72
+ * (architecture/path_independent_first_writer.md) */
73
+ export const FirstWriterCandidates: Driver = { kind: "FirstWriterCandidates" };
64
74
  export const AddWins: Driver = { kind: "AddWins" };
65
75
  export const Conflict: Driver = { kind: "Conflict" };
66
76
  export const MapOf = (inner: Driver): Driver => ({ kind: "MapOf", inner });
@@ -163,11 +173,52 @@ export const Surfaced = (inner: Driver): Driver => {
163
173
  // throws for it rather than emit a wire driver the kernel can't merge.
164
174
  const PALETTE_ONLY: ReadonlySet<DriverKind> = new Set<DriverKind>([]);
165
175
 
176
+ /**
177
+ * Is this wire driver a SINGLE-VALUE driver (D20)? Mirrors the kernel's
178
+ * `is_single_value_driver`: one visible value chosen from the field's stored observation
179
+ * antichain, so the driver is a pure reduction at projection time. Counters, sets, lists,
180
+ * maps, positions and `Conflict` are not.
181
+ */
182
+ export function isSingleValueWireDriver(driver: unknown): boolean {
183
+ if (typeof driver === "string") {
184
+ return (
185
+ driver === "Lww" ||
186
+ driver === "LwwCausal" ||
187
+ driver === "FirstWriterWins" ||
188
+ driver === "FirstWriterCandidates"
189
+ );
190
+ }
191
+ if (driver === null || typeof driver !== "object") return false;
192
+ const d = driver as Record<string, unknown>;
193
+ if (typeof d.LwwBy === "string") return true;
194
+ if ("Surfaced" in d) return isSingleValueWireDriver(d.Surfaced);
195
+ if ("Attributed" in d) return isSingleValueWireDriver(d.Attributed);
196
+ return false;
197
+ }
198
+
199
+ /**
200
+ * The stored VALUE SPACE of a wire driver — the `driver` slot of the field schema identity.
201
+ * Mirrors the kernel's `field_schema_value_space` byte-for-byte: every single-value driver
202
+ * shares one value space and is written as its representative `"Lww"` (so fields already
203
+ * declared `Lww` keep the identity they always had); any other driver is its own value space.
204
+ * Switching among single-value drivers in a later law is therefore not a retype.
205
+ */
206
+ export function driverValueSpace(driver: unknown): unknown {
207
+ return isSingleValueWireDriver(driver) ? "Lww" : driver;
208
+ }
209
+
210
+ /** Do two wire drivers store the same value space (a driver switch is a plain law change)? */
211
+ export function driversShareValueSpace(a: unknown, b: unknown): boolean {
212
+ return canonicalJson(driverValueSpace(a)) === canonicalJson(driverValueSpace(b));
213
+ }
214
+
166
215
  /** Encode one Driver to its kernel wire shape, or throw if not yet in the kernel. */
167
216
  export function encodeDriver(d: Driver): WireDriver {
168
217
  switch (d.kind) {
169
218
  case "FirstWriterWins":
170
219
  return "FirstWriterWins";
220
+ case "FirstWriterCandidates":
221
+ return "FirstWriterCandidates";
171
222
  case "Lww":
172
223
  return "Lww";
173
224
  // ── EXPLICIT TIME-AUTHORITY Lww drivers (kernel `merge_field` arms) ──
@@ -55,14 +55,24 @@ import { executeDirectiveToIntent } from "./wire_encode.js";
55
55
  import { expandCapabilityExports, isCapabilityDecl } from "./capability_exports.js";
56
56
  import { RelationTuple, __setDispatchContext } from "./framework/relations.js";
57
57
  import { BIRTH_METER_AGGREGATES } from "./birth_meter.js";
58
- import { AuthProvider as FrameworkAuthProvider, setAuthProvider as frameworkSetAuthProvider } from "./framework/auth_provider_law.js";
58
+ import {
59
+ AuthProvider as FrameworkAuthProvider,
60
+ AuthProviderCertificate as FrameworkAuthProviderCertificate,
61
+ AuthProviderKey as FrameworkAuthProviderKey,
62
+ adoptIdentityProviderWitness as frameworkAdoptIdentityProviderWitness,
63
+ setAuthProvider as frameworkSetAuthProvider,
64
+ } from "./framework/auth_provider_law.js";
59
65
  import { namespacedAggregateIds, qualifyReadProjectionType, READ_PROJECTION_DELIMITER } from "./read_projection_namespace.js";
60
66
  import { discoverRelationTypeDeclarations } from "./relation_schema.js";
61
67
  import { synthesizePreconditionInvariants } from "./precondition.js";
62
68
  import { synthesizeBirthQuotaInvariants } from "./birth_meter.js";
63
69
  import { withBirthMeterExports } from "./birth_meter_ensure.js";
64
70
  import { expandRoleExports } from "./role.js";
65
- import { withAttestedReadExports } from "./attested.js";
71
+ import {
72
+ NomosSourceFrontier,
73
+ nomosSourceFrontierEnsure,
74
+ withAttestedReadExports,
75
+ } from "./attested.js";
66
76
  import type { OpenApiDoc } from "./codegen_openapi.js";
67
77
  import type { Directive } from "./directive.js";
68
78
  import type { AggregateHandle, AggregateInvariantFn, AggregateInvariantVerdict } from "./aggregate.js";
@@ -83,6 +93,7 @@ import {
83
93
  applicationLanguageOf,
84
94
  assertApplicationLanguageCoversAuthoredDirectives,
85
95
  executableDirectivesForLanguage,
96
+ publicOfferRoute,
86
97
  remapWorkspaceInvariantsForLanguage,
87
98
  } from "./intent.js";
88
99
 
@@ -400,16 +411,42 @@ function buildDomainSlice(mod: DomainModuleExports, domain: string): DomainSlice
400
411
  if (declaresBirthHere || declaresPrivateHere) {
401
412
  if (!aggs.has(FrameworkAuthProvider.id)) aggs.set(FrameworkAuthProvider.id, FrameworkAuthProvider);
402
413
  if (!dirs.has(frameworkSetAuthProvider.id)) dirs.set(frameworkSetAuthProvider.id, frameworkSetAuthProvider as unknown as Directive<unknown>);
414
+ if (declaresPrivateHere) {
415
+ for (const aggregate of [
416
+ FrameworkAuthProviderKey,
417
+ FrameworkAuthProviderCertificate,
418
+ NomosSourceFrontier,
419
+ ]) {
420
+ if (!aggs.has(aggregate.id)) aggs.set(aggregate.id, aggregate);
421
+ }
422
+ if (!dirs.has(frameworkAdoptIdentityProviderWitness.id)) {
423
+ dirs.set(
424
+ frameworkAdoptIdentityProviderWitness.id,
425
+ frameworkAdoptIdentityProviderWitness as unknown as Directive<unknown>,
426
+ );
427
+ }
428
+ if (!dirs.has(nomosSourceFrontierEnsure.id)) {
429
+ dirs.set(nomosSourceFrontierEnsure.id, nomosSourceFrontierEnsure as unknown as Directive<unknown>);
430
+ }
431
+ }
403
432
  }
404
433
  }
405
- for (const [dirId, directive] of dirs) {
434
+ for (const directive of dirs.values()) {
406
435
  const agg = aggs.get(directive.aggregateId);
407
436
  if (agg === undefined) {
408
437
  // A directive targeting an aggregate not exported by its module is an
409
438
  // authoring bug; surface it lazily (only if that directive is invoked).
410
439
  continue;
411
440
  }
412
- registry.set(dirId, { directive, agg });
441
+ const publicRoute = publicOfferRoute(directive);
442
+ const prior = registry.get(publicRoute);
443
+ if (prior !== undefined && prior.directive !== directive) {
444
+ throw new Error(
445
+ `engine bundle: public offer route '${publicRoute}' resolves to both ` +
446
+ `'${prior.directive.id}' and '${directive.id}' in domain '${domain}'`,
447
+ );
448
+ }
449
+ registry.set(publicRoute, { directive, agg });
413
450
  }
414
451
 
415
452
  // ── aggregate type → derived / combined decls (fn bodies ship HERE, never the ledger) ──
@@ -780,7 +817,7 @@ export function registerEngine(config: EngineEntryConfig): RegisteredEngine {
780
817
  }
781
818
 
782
819
  function planAggInvariant(job: {
783
- intent?: { aggregateInvariant?: { of?: string } };
820
+ intent?: { aggregateInvariant?: { of?: string; previous?: Record<string, unknown> | null } };
784
821
  priorState?: Record<string, unknown>;
785
822
  }): string {
786
823
  // WIRE SHAPE (the host oracle's contract, EXACT): `{ aggregateInvariant: { of: "<type>" } }`.
@@ -802,7 +839,7 @@ export function registerEngine(config: EngineEntryConfig): RegisteredEngine {
802
839
  return JSON.stringify({ accept: true } satisfies AggregateInvariantVerdict);
803
840
  }
804
841
  const snapshot = (job.priorState ?? {}) as Record<string, unknown>;
805
- const verdict: AggregateInvariantVerdict = body(snapshot);
842
+ const verdict: AggregateInvariantVerdict = body(snapshot, job.intent?.aggregateInvariant?.previous);
806
843
  return JSON.stringify(verdict);
807
844
  }
808
845
 
@@ -1072,8 +1109,9 @@ export function registerEngine(config: EngineEntryConfig): RegisteredEngine {
1072
1109
  // and meter `Event`s directly instead of walking a second returned object graph. This is an
1073
1110
  // execution ABI, not authority: the same values still pass the ordinary kernel gates, and old
1074
1111
  // kernels/packages retain the returned-value lane below for era replay.
1075
- const submitNativePlan = (globalThis as unknown as {
1112
+ const nativePlanKernel = (globalThis as unknown as {
1076
1113
  nomos?: {
1114
+ __workspaceEffectDependencies?: number;
1077
1115
  __submitPlan?: (
1078
1116
  events: WireEvent[],
1079
1117
  strikes: string[],
@@ -1082,10 +1120,16 @@ export function registerEngine(config: EngineEntryConfig): RegisteredEngine {
1082
1120
  workspaceEffects: {
1083
1121
  destination: { workspace: string } | { verifiedParent: true } | { verifiedSource: true };
1084
1122
  targetCallUsda: Uint8Array;
1123
+ dependsOn?: readonly number[];
1085
1124
  }[],
1086
1125
  ) => void;
1087
1126
  };
1088
- }).nomos?.__submitPlan;
1127
+ }).nomos;
1128
+ if (wire.workspaceEffects?.some(effect => effect.dependsOn?.length) &&
1129
+ nativePlanKernel?.__workspaceEffectDependencies !== 1) {
1130
+ throw new Error("workspace effect dependencies require kernel support for authenticated predecessor judgments");
1131
+ }
1132
+ const submitNativePlan = nativePlanKernel?.__submitPlan;
1089
1133
  if (typeof submitNativePlan === "function") {
1090
1134
  submitNativePlan(
1091
1135
  wire.events,