@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
@@ -1,352 +0,0 @@
1
- // NOMOS — Nomos Sovereign: participants act · verify · remember LOCALLY; hosted
2
- // remotes are replaceable custody/transport, not truth. ⇒ ONE Nomos GitHolon
3
- // wasm32-wasip1 artifact. If a file isn't this / hosting this / authoring for this
4
- // / proving this — it's gone.
5
- //
6
- // SHAPE COMPATIBILITY (#72) — the structural contract a client and a workspace
7
- // negotiate by, INSTEAD of the package hash. See architecture/shape_compatibility.md.
8
- //
9
- // A client fits a workspace iff the workspace's installed interface SUBTYPES what the
10
- // client depends on:
11
- // • WRITES are CONTRAVARIANT — for every directive the client calls, the workspace
12
- // has that directive id and its CURRENT payload schema ACCEPTS the client's
13
- // payload: every field the workspace REQUIRES the client always sends, and every
14
- // shared field's kind matches. (Extra client fields are ignored — non-strict zod.)
15
- // • READS are COVARIANT by STABLE ID (#58) — for every aggregate the client reads,
16
- // the workspace has that aggregate SID and every field the client CONSUMES (by
17
- // field sid) is present with a compatible kind. The workspace may serve MORE.
18
- //
19
- // Identity is by stable id, not name or hash — that is what makes the relation
20
- // decidable across renames (a renamed aggregate field keeps its sid, so an old client
21
- // stays read-compatible). Directive/payload identity is the dispatched id + field
22
- // names (directives are not sid-tracked yet — a payload rename IS a write break, and
23
- // is reported precisely).
24
-
25
- import { z } from "zod";
26
- import type { DomainModule } from "./codegen_dart.js";
27
- import { lowerLawValueType, type LawValueType } from "./law_value_type.js";
28
- import type { StableIds } from "./stable_ids_types.js";
29
- import type { Field } from "./fields.js";
30
- import { isBusinessIntent } from "./intent.js";
31
-
32
- /** One payload field's normalized shape: its kind + whether the schema makes it optional. */
33
- export interface PayloadFieldShape {
34
- readonly kind: string;
35
- readonly optional: boolean;
36
- }
37
- /** A directive's payload contract — the field set + types the gate validates against. */
38
- export interface DirectivePayloadShape {
39
- readonly fields: Record<string, PayloadFieldShape>;
40
- }
41
- /** An aggregate's read contract — fields keyed by STABLE ID (rename-safe), each carrying
42
- * its current label (for human-readable verdicts) + its read kind. */
43
- export interface AggregateReadShape {
44
- readonly sid: string;
45
- readonly label: string;
46
- /** keyed by FIELD SID. */
47
- readonly fields: Record<string, { kind: string; label: string }>;
48
- }
49
- /** A domain's full structural interface — the offer (a workspace's installed law) AND
50
- * the requirement (the law a client was generated from) are the SAME vocabulary. */
51
- export interface DomainInterface {
52
- readonly v: 1;
53
- readonly domain: string;
54
- readonly domainSid?: string;
55
- /** keyed by DIRECTIVE ID (the dispatched name). */
56
- readonly directives: Record<string, DirectivePayloadShape>;
57
- /** keyed by AGGREGATE SID. */
58
- readonly aggregates: Record<string, AggregateReadShape>;
59
- /** ATTESTED READS (slice B + dynamic policies): directive id → its declared foreign-read edges —
60
- * a STATIC `{queryId, from}` edge or a dynamic `{queryId, policy, fromPayload}` edge — the
61
- * cross-workspace dependencies this law consumes on its write path. OMITTED when none (era rule). */
62
- readonly foreignReads?: Record<
63
- string,
64
- { queryId: string; from?: string; policy?: string; fromPayload?: string }[]
65
- >;
66
- }
67
-
68
- /** Remove framework-managed aggregate fields from the client-facing structural interface. Stable ids for
69
- * those fields remain in the law/lockfile; clients negotiate only the business shape they can see. */
70
- export function publicClientInterface(
71
- modules: readonly DomainModule[],
72
- offered: Readonly<Record<string, DomainInterface>>,
73
- ): Record<string, DomainInterface> {
74
- const hidden = new Map<string, Map<string, Set<string>>>();
75
- for (const mod of modules) {
76
- const domain = mod.domain ?? mod.name;
77
- const byAggregate = hidden.get(domain) ?? new Map<string, Set<string>>();
78
- hidden.set(domain, byAggregate);
79
- for (const aggregate of mod.aggregates ?? []) {
80
- const fields = (aggregate as { internalFields?: readonly string[] }).internalFields ?? [];
81
- if (fields.length > 0) byAggregate.set(aggregate.id, new Set(fields));
82
- }
83
- }
84
- const result: Record<string, DomainInterface> = {};
85
- for (const [domain, value] of Object.entries(offered)) {
86
- const byAggregate = hidden.get(domain);
87
- if (byAggregate === undefined || byAggregate.size === 0) {
88
- result[domain] = value;
89
- continue;
90
- }
91
- const aggregates: Record<string, AggregateReadShape> = {};
92
- for (const [sid, aggregate] of Object.entries(value.aggregates)) {
93
- const fields = byAggregate.get(aggregate.label);
94
- aggregates[sid] = fields === undefined
95
- ? aggregate
96
- : {
97
- ...aggregate,
98
- fields: Object.fromEntries(
99
- Object.entries(aggregate.fields).filter(([, field]) => !fields.has(field.label)),
100
- ),
101
- };
102
- }
103
- result[domain] = { ...value, aggregates };
104
- }
105
- return result;
106
- }
107
-
108
- /** The verdict: compatible iff nothing is missing and nothing is type-incompatible.
109
- * `missing` = a depended-on directive/aggregate/field the workspace doesn't expose;
110
- * `incompatible` = present but type-divergent (a payload field kind, a retyped read field). */
111
- export interface CompatVerdict {
112
- readonly ok: boolean;
113
- readonly missing: string[];
114
- readonly incompatible: string[];
115
- }
116
-
117
- /** Normalize the canonical language-neutral DSL value graph to the compatibility
118
- * vocabulary. Language generators are projections of this graph, never authorities
119
- * for it. */
120
- function payloadFieldKind(value: LawValueType): string {
121
- switch (value.kind) {
122
- case "enum":
123
- return "enum";
124
- case "string":
125
- return "string";
126
- case "integer":
127
- return "int";
128
- case "number":
129
- return "double";
130
- case "boolean":
131
- return "bool";
132
- case "literal":
133
- return typeof value.value === "boolean"
134
- ? "bool"
135
- : typeof value.value === "number"
136
- ? Number.isInteger(value.value) ? "int" : "double"
137
- : typeof value.value === "string" ? "string" : "json";
138
- case "list":
139
- return value.element.kind === "string" ? "set" : "json";
140
- case "nullable":
141
- case "default":
142
- case "recursive":
143
- return payloadFieldKind(value.value);
144
- case "map":
145
- case "record":
146
- case "sum":
147
- case "null":
148
- case "unknown":
149
- case "recursive-ref":
150
- return "json";
151
- }
152
- }
153
-
154
- /** The aggregate read kind when no stable-id kind is recorded (pre-#58 fallback): the
155
- * field's own declared kind, with the read-collapsed CRDTs normalized to their scalar. */
156
- function aggFieldReadKind(f: Field): string {
157
- switch (f.kind) {
158
- case "counter":
159
- return "int";
160
- case "position":
161
- return "string";
162
- default:
163
- return f.kind;
164
- }
165
- }
166
-
167
- /** Extract a domain's structural interface from its loaded module + (optionally) its
168
- * stable-id surface. Without stable ids (pre-#58) aggregate fields key by NAME and the
169
- * kind comes from the field declaration — a graceful, rename-unaware fallback. */
170
- export function domainInterface(mod: DomainModule, stableIds?: StableIds): DomainInterface {
171
- const isInternal = (value: unknown): boolean =>
172
- !!value &&
173
- typeof value === "object" &&
174
- (value as { businessBirthInternal?: unknown }).businessBirthInternal === true;
175
- const enumTypes = new Map<string, string>();
176
- // DETERMINISTIC KEY ORDER — directive ids, aggregate sids, and field keys are SORTED, so the
177
- // emitted interface is byte-stable and the layered-USD fold (which merges + sorts) reproduces it
178
- // byte-identically (the `nomosStableIds`/`nomosReadGate` convention). architecture/shape_compatibility.md.
179
- const sortedRec = <T>(entries: Array<[string, T]>): Record<string, T> => {
180
- const out: Record<string, T> = {};
181
- for (const [k, v] of entries.sort((a, b) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0))) out[k] = v;
182
- return out;
183
- };
184
- const directives: Record<string, DirectivePayloadShape> = {};
185
- const dirEntries: Array<[string, DirectivePayloadShape]> = [];
186
- for (const d of (mod.directives ?? []) as Array<{
187
- id?: unknown;
188
- payloadSchema?: unknown;
189
- businessBirth?: { publicPayloadSchema?: unknown };
190
- }>) {
191
- if (!d || typeof d.id !== "string") continue;
192
- if (isInternal(d)) continue;
193
- const fieldEntries: Array<[string, PayloadFieldShape]> = [];
194
- const schema = d.businessBirth?.publicPayloadSchema ?? d.payloadSchema;
195
- if (schema && typeof schema === "object") {
196
- const payload = lowerLawValueType(schema as z.ZodTypeAny);
197
- if (payload.kind !== "record") {
198
- throw new Error(`directive '${d.id}' payload must lower to a typed record`);
199
- }
200
- for (const field of payload.fields) {
201
- fieldEntries.push([field.name, { kind: payloadFieldKind(field.value), optional: !field.required }]);
202
- }
203
- }
204
- dirEntries.push([
205
- d.businessBirth === undefined || isBusinessIntent(d) ? d.id : "birth",
206
- { fields: sortedRec(fieldEntries) },
207
- ]);
208
- }
209
- Object.assign(directives, sortedRec(dirEntries));
210
- const aggregates: Record<string, AggregateReadShape> = {};
211
- const aggEntries: Array<[string, AggregateReadShape]> = [];
212
- for (const agg of (mod.aggregates ?? []) as Array<{
213
- id: string;
214
- fields: Record<string, Field>;
215
- }>) {
216
- if (isInternal(agg)) continue;
217
- const label = agg.id;
218
- const sa = stableIds?.aggregates?.[label];
219
- const aggSid = sa?.sid ?? label;
220
- const fieldEntries: Array<[string, { kind: string; label: string }]> = [];
221
- for (const [fname, f] of Object.entries(agg.fields ?? {})) {
222
- // This is the workspace's complete structural offer and the input to law-evolution
223
- // checking, so framework-managed stored fields belong here too. Only the generated
224
- // client's view hides them, in publicClientInterface below. Filtering them at both
225
- // seams makes an unchanged private field look deleted when the current offer is
226
- // compared with the committed identity ledger.
227
- if (!f || f.kind === "hasMany") continue;
228
- const fsid = sa?.fields?.[fname]?.sid ?? fname;
229
- const kind = sa?.fields?.[fname]?.kind ?? aggFieldReadKind(f);
230
- fieldEntries.push([fsid, { kind, label: fname }]);
231
- }
232
- aggEntries.push([aggSid, { sid: aggSid, label, fields: sortedRec(fieldEntries) }]);
233
- }
234
- Object.assign(aggregates, sortedRec(aggEntries));
235
- // ATTESTED READS (slice B): the declared trust edges — so shape-compat + client codegen can
236
- // SEE the cross-workspace dependency (typed clients don't call it; it's write-path-internal).
237
- type ForeignEdge = { queryId: string; from?: string; policy?: string; fromPayload?: string };
238
- const foreignReadEntries: Array<[string, ForeignEdge[]]> = [];
239
- for (const d of (mod.directives ?? []) as Array<{ id?: unknown; declaredForeignReads?: ForeignEdge[] }>) {
240
- if (!d || typeof d.id !== "string") continue;
241
- if (isInternal(d)) continue;
242
- if (d.declaredForeignReads !== undefined && d.declaredForeignReads.length > 0) {
243
- foreignReadEntries.push([d.id, d.declaredForeignReads.map((e) => ({ ...e }))]);
244
- }
245
- }
246
- const foreignReads = sortedRec(foreignReadEntries);
247
- return {
248
- v: 1,
249
- domain: (mod as { domain?: string; name?: string }).domain ?? (mod as { name?: string }).name ?? "",
250
- ...(stableIds?.domain !== undefined ? { domainSid: stableIds.domain } : {}),
251
- directives,
252
- aggregates,
253
- ...(foreignReadEntries.length > 0 ? { foreignReads } : {}),
254
- };
255
- }
256
-
257
- /** One member's structural verdict — `ok`, plus the exact break `reason` when not. */
258
- export interface MemberVerdict {
259
- readonly ok: boolean;
260
- readonly reason?: string;
261
- }
262
-
263
- /** PER-MEMBER structural verdict (#72b, the compat superpower): the SAME subtype relation as
264
- * {@link compatible}, decomposed to ONE verdict per callable MEMBER — keyed by directive id
265
- * (writes) AND by aggregate label (reads). A generated client method (or the CLI gate) consults
266
- * its own member so a KNOWN-incompatible call refuses CLIENT-SIDE, never as a server 422. */
267
- export function memberVerdicts(client: DomainInterface, workspace: DomainInterface): Record<string, MemberVerdict> {
268
- const out: Record<string, MemberVerdict> = {};
269
-
270
- // WRITES — contravariant, one verdict per directive the client calls.
271
- for (const [did, cShape] of Object.entries(client.directives)) {
272
- const wShape = workspace.directives[did];
273
- if (!wShape) { out[did] = { ok: false, reason: `directive '${did}' is not installed on the workspace` }; continue; }
274
- const reasons: string[] = [];
275
- for (const [f, wf] of Object.entries(wShape.fields)) {
276
- if (wf.optional) continue;
277
- const cf = cShape.fields[f];
278
- if (!cf || cf.optional) reasons.push(`workspace requires field '${f}' the client does not always send`);
279
- }
280
- for (const [f, cf] of Object.entries(cShape.fields)) {
281
- const wf = wShape.fields[f];
282
- if (wf && wf.kind !== cf.kind) reasons.push(`field '${f}' kind ${cf.kind} ≠ workspace ${wf.kind}`);
283
- }
284
- out[did] = reasons.length ? { ok: false, reason: reasons.join("; ") } : { ok: true };
285
- }
286
-
287
- // READS — covariant by stable id, one verdict per aggregate the client reads (keyed by LABEL).
288
- for (const [sid, cAgg] of Object.entries(client.aggregates)) {
289
- const wAgg = workspace.aggregates[sid];
290
- if (!wAgg) { out[cAgg.label] = { ok: false, reason: `aggregate '${cAgg.label}' is not served by the workspace` }; continue; }
291
- const reasons: string[] = [];
292
- for (const [fsid, cf] of Object.entries(cAgg.fields)) {
293
- const wf = wAgg.fields[fsid];
294
- if (!wf) reasons.push(`field '${cAgg.label}.${cf.label}' is not served`);
295
- else if (wf.kind !== cf.kind) reasons.push(`field '${cAgg.label}.${cf.label}' read kind ${cf.kind} ≠ workspace ${wf.kind}`);
296
- }
297
- out[cAgg.label] = reasons.length ? { ok: false, reason: reasons.join("; ") } : { ok: true };
298
- }
299
-
300
- return out;
301
- }
302
-
303
- /** Decide whether a CLIENT interface is satisfied by a WORKSPACE interface (the offer).
304
- * Pure + deterministic — the SAME relation runs at connect() and (mirrored) at the
305
- * editor/CI. Names the exact directive / aggregate / field at fault, never a hash. */
306
- export function compatible(client: DomainInterface, workspace: DomainInterface): CompatVerdict {
307
- const missing: string[] = [];
308
- const incompatible: string[] = [];
309
-
310
- // WRITES — contravariant. The workspace must accept every payload the client sends.
311
- for (const [did, cShape] of Object.entries(client.directives)) {
312
- const wShape = workspace.directives[did];
313
- if (!wShape) {
314
- missing.push(`directive '${did}'`);
315
- continue;
316
- }
317
- // Every field the WORKSPACE requires, the client must ALWAYS send (present + required).
318
- for (const [f, wf] of Object.entries(wShape.fields)) {
319
- if (wf.optional) continue;
320
- const cf = cShape.fields[f];
321
- if (!cf || cf.optional) {
322
- incompatible.push(`directive '${did}': workspace requires field '${f}' the client does not always send`);
323
- }
324
- }
325
- // Every field both sides know must agree on kind (a payload retype is a write break).
326
- for (const [f, cf] of Object.entries(cShape.fields)) {
327
- const wf = wShape.fields[f];
328
- if (wf && wf.kind !== cf.kind) {
329
- incompatible.push(`directive '${did}': field '${f}' kind ${cf.kind} ≠ workspace ${wf.kind}`);
330
- }
331
- }
332
- }
333
-
334
- // READS — covariant by stable id. Every field the client consumes must be served compatibly.
335
- for (const [sid, cAgg] of Object.entries(client.aggregates)) {
336
- const wAgg = workspace.aggregates[sid];
337
- if (!wAgg) {
338
- missing.push(`aggregate '${cAgg.label}'`);
339
- continue;
340
- }
341
- for (const [fsid, cf] of Object.entries(cAgg.fields)) {
342
- const wf = wAgg.fields[fsid];
343
- if (!wf) {
344
- missing.push(`field '${cAgg.label}.${cf.label}'`);
345
- } else if (wf.kind !== cf.kind) {
346
- incompatible.push(`field '${cAgg.label}.${cf.label}': read kind ${cf.kind} ≠ workspace ${wf.kind}`);
347
- }
348
- }
349
- }
350
-
351
- return { ok: missing.length === 0 && incompatible.length === 0, missing, incompatible };
352
- }