@githolon/dsl 0.108.7 → 0.110.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (308) hide show
  1. package/assets/operation-contract.wasm +0 -0
  2. package/check_package.mjs +12 -15
  3. package/compile_package.mjs +17 -18
  4. package/compile_proof.mjs +16 -1
  5. package/dart/CHANGELOG.md +80 -1
  6. package/dart/README.md +25 -2
  7. package/dart/lib/src/admission_decision.dart +41 -0
  8. package/dart/lib/src/application_framework_calls.dart +52 -2
  9. package/dart/lib/src/application_model_adoption.dart +187 -0
  10. package/dart/lib/src/application_status.dart +73 -0
  11. package/dart/lib/src/console_enrolment.dart +271 -0
  12. package/dart/lib/src/console_http_io.dart +26 -0
  13. package/dart/lib/src/console_http_stub.dart +7 -0
  14. package/dart/lib/src/dev_cloud.dart +69 -22
  15. package/dart/lib/src/generated_call.dart +83 -23
  16. package/dart/lib/src/kernel_primitives.dart +119 -0
  17. package/dart/lib/src/nms_conformance_runtime.dart +1 -1
  18. package/dart/lib/src/nms_generated_runtime.dart +32 -10
  19. package/dart/lib/src/nms_test_environment.dart +1 -1
  20. package/dart/lib/src/node_runner_transport.dart +41 -46
  21. package/dart/lib/src/observed_session_directory.dart +70 -0
  22. package/dart/lib/src/operation_receipts.dart +112 -0
  23. package/dart/lib/src/peer_application_streams.dart +103 -0
  24. package/dart/lib/src/reception/dart_reception.dart +4280 -0
  25. package/dart/lib/src/reception/event_desk.dart +214 -0
  26. package/dart/lib/src/reception/extremum_read.dart +46 -0
  27. package/dart/lib/src/reception/local_copies.dart +371 -0
  28. package/dart/lib/src/reception/peer_office_connection.dart +11 -0
  29. package/dart/lib/src/reception/progress_desk.dart +268 -0
  30. package/dart/lib/src/reception/reception_contract.dart +11 -0
  31. package/dart/lib/src/reception/reception_session.dart +284 -0
  32. package/dart/lib/src/reception/sync_diagnostics.dart +26 -0
  33. package/dart/lib/src/reception/workspace_preparation_report.dart +126 -0
  34. package/dart/lib/src/replica_readiness.dart +123 -0
  35. package/dart/lib/src/runner/node-entry.mjs +23950 -15776
  36. package/dart/lib/src/runtime_v2_gateway.dart +56 -3
  37. package/dart/lib/src/runtime_v2_transport.dart +544 -3
  38. package/dart/lib/src/session_bound.dart +200 -311
  39. package/dart/lib/src/signing_identity_kernel.dart +84 -0
  40. package/dart/lib/src/sync_status_projection.dart +550 -0
  41. package/dart/lib/src/sync_status_reducer.dart +170 -0
  42. package/dart/lib/src/test_harness.dart +809 -1153
  43. package/dart/lib/src/testing/test_custody.dart +66 -0
  44. package/dart/lib/src/testing/test_peer.dart +328 -0
  45. package/dart/lib/src/typed_watch_registry.dart +169 -0
  46. package/dart/lib/src/workspace_open_progress.dart +27 -0
  47. package/dart/pubspec.lock +24 -1
  48. package/dart/pubspec.yaml +7 -2
  49. package/dart/pubspec_overrides.yaml +2 -0
  50. package/dart/test/admission_decision_test.dart +48 -0
  51. package/dart/test/background_model_adoption_test.dart +228 -0
  52. package/dart/test/bundle_version_pairing_test.dart +4 -4
  53. package/dart/test/child_authentication_repair_test.dart +359 -0
  54. package/dart/test/cloud_bound_local_shell_test.dart +119 -0
  55. package/dart/test/console_enrolment_refusal_test.dart +52 -0
  56. package/dart/test/console_enrolment_test.dart +227 -0
  57. package/dart/test/errors_test.dart +5 -5
  58. package/dart/test/event_plane_seam_test.dart +50 -164
  59. package/dart/test/extremum_read_test.dart +58 -0
  60. package/dart/test/fixtures/wedge/wedge-entry.mjs +3 -21
  61. package/dart/test/generated_query_test.dart +32 -0
  62. package/dart/test/harness_phase_timeout_test.dart +18 -23
  63. package/dart/test/kernel_author_after_read_test.dart +242 -0
  64. package/dart/test/kernel_fence_test.dart +137 -0
  65. package/dart/test/local_copies_test.dart +222 -0
  66. package/dart/test/model_adoption_test.dart +198 -0
  67. package/dart/test/node_peer_local_custody_test.dart +153 -0
  68. package/dart/test/offer_authentication_proof_test.dart +352 -52
  69. package/dart/test/operation_compatibility_test.dart +151 -0
  70. package/dart/test/platform_credential_effect_test.dart +386 -0
  71. package/dart/test/receiving_group_open_test.dart +213 -0
  72. package/dart/test/reception/workspace_preparation_report_test.dart +103 -0
  73. package/dart/test/reception_event_desk_close_test.dart +16 -0
  74. package/dart/test/reception_span_trace_test.dart +23 -0
  75. package/dart/test/replica_readiness_test.dart +156 -0
  76. package/dart/test/runtime_projections_test.dart +92 -0
  77. package/dart/test/runtime_v2_gateway_test.dart +131 -0
  78. package/dart/test/signing_identity_kernel_test.dart +75 -0
  79. package/dart/test/sync_status_preparation_report_test.dart +29 -0
  80. package/dart/test/sync_status_reducer_test.dart +419 -0
  81. package/dart/test/test_harness_test.dart +71 -95
  82. package/dart/test/typed_query_watch_test.dart +170 -0
  83. package/dart/test/typed_watch_registry_test.dart +249 -0
  84. package/dart_lints/README.md +18 -0
  85. package/dart_lints/lib/nomos_lints.dart +70 -0
  86. package/dart_lints/pubspec.lock +580 -0
  87. package/dart_lints/pubspec.yaml +12 -0
  88. package/dart_lints/test/reference_identity_test.dart +75 -0
  89. package/dart_types/CHANGELOG.md +18 -0
  90. package/dart_types/lib/nomos_kernel_protocol.dart +21 -1
  91. package/dart_types/lib/nomos_types.dart +9 -1
  92. package/dart_types/lib/src/admission_decision.dart +37 -0
  93. package/dart_types/lib/src/aggregate_meta.dart +1 -1
  94. package/dart_types/lib/src/approved_model.dart +65 -0
  95. package/dart_types/lib/src/custody.dart +10 -18
  96. package/dart_types/lib/src/error_info.dart +4 -4
  97. package/dart_types/lib/src/errors.dart +29 -29
  98. package/dart_types/lib/src/foreign_ref.dart +62 -33
  99. package/dart_types/lib/src/local_work_rejected.dart +3 -3
  100. package/dart_types/lib/src/nomos_ref.dart +3 -1
  101. package/dart_types/lib/src/principal.dart +2 -2
  102. package/dart_types/lib/src/proto/google/protobuf/any.pb.dart +163 -0
  103. package/dart_types/lib/src/proto/google/protobuf/any.pbenum.dart +11 -0
  104. package/dart_types/lib/src/proto/nomos/discovery/v1/workspace_placement.pb.dart +137 -0
  105. package/dart_types/lib/src/proto/nomos/discovery/v1/workspace_placement.pbenum.dart +11 -0
  106. package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pb.dart +20721 -10433
  107. package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pbenum.dart +555 -27
  108. package/dart_types/lib/src/proto/nomos/runtime/v2/application_desk.pb.dart +387 -0
  109. package/dart_types/lib/src/proto/nomos/runtime/v2/application_desk.pbenum.dart +46 -0
  110. package/dart_types/lib/src/proto/nomos/runtime/v2/application_readiness_desk.pb.dart +295 -0
  111. package/dart_types/lib/src/proto/nomos/runtime/v2/application_readiness_desk.pbenum.dart +139 -0
  112. package/dart_types/lib/src/proto/nomos/runtime/v2/authentication_desk.pb.dart +269 -0
  113. package/dart_types/lib/src/proto/nomos/runtime/v2/authentication_desk.pbenum.dart +103 -0
  114. package/dart_types/lib/src/proto/nomos/runtime/v2/compatibility_desk.pb.dart +417 -0
  115. package/dart_types/lib/src/proto/nomos/runtime/v2/compatibility_desk.pbenum.dart +62 -0
  116. package/dart_types/lib/src/proto/nomos/runtime/v2/correspondence_desk.pb.dart +9968 -0
  117. package/dart_types/lib/src/proto/nomos/runtime/v2/correspondence_desk.pbenum.dart +133 -0
  118. package/dart_types/lib/src/proto/nomos/runtime/v2/credentials_desk.pb.dart +204 -0
  119. package/dart_types/lib/src/proto/nomos/runtime/v2/credentials_desk.pbenum.dart +54 -0
  120. package/dart_types/lib/src/proto/nomos/runtime/v2/custody_desk.pb.dart +1550 -0
  121. package/dart_types/lib/src/proto/nomos/runtime/v2/custody_desk.pbenum.dart +11 -0
  122. package/dart_types/lib/src/proto/nomos/runtime/v2/framework.pb.dart +710 -0
  123. package/dart_types/lib/src/proto/nomos/runtime/v2/framework.pbenum.dart +11 -0
  124. package/dart_types/lib/src/proto/nomos/runtime/v2/identity_desk.pb.dart +845 -0
  125. package/dart_types/lib/src/proto/nomos/runtime/v2/identity_desk.pbenum.dart +11 -0
  126. package/dart_types/lib/src/proto/nomos/runtime/v2/interaction_desk.pb.dart +198 -0
  127. package/dart_types/lib/src/proto/nomos/runtime/v2/interaction_desk.pbenum.dart +11 -0
  128. package/dart_types/lib/src/proto/nomos/runtime/v2/law_desk.pb.dart +369 -0
  129. package/dart_types/lib/src/proto/nomos/runtime/v2/law_desk.pbenum.dart +11 -0
  130. package/dart_types/lib/src/proto/nomos/runtime/v2/maintenance_desk.pb.dart +609 -0
  131. package/dart_types/lib/src/proto/nomos/runtime/v2/maintenance_desk.pbenum.dart +65 -0
  132. package/dart_types/lib/src/proto/nomos/runtime/v2/model_adoption_desk.pb.dart +358 -0
  133. package/dart_types/lib/src/proto/nomos/runtime/v2/model_adoption_desk.pbenum.dart +100 -0
  134. package/dart_types/lib/src/proto/nomos/runtime/v2/observability_desk.pb.dart +2231 -0
  135. package/dart_types/lib/src/proto/nomos/runtime/v2/observability_desk.pbenum.dart +271 -0
  136. package/dart_types/lib/src/proto/nomos/runtime/v2/placement_desk.pb.dart +1286 -0
  137. package/dart_types/lib/src/proto/nomos/runtime/v2/placement_desk.pbenum.dart +11 -0
  138. package/dart_types/lib/src/proto/nomos/runtime/v2/receiving_group_desk.pb.dart +636 -0
  139. package/dart_types/lib/src/proto/nomos/runtime/v2/receiving_group_desk.pbenum.dart +116 -0
  140. package/dart_types/lib/src/proto/nomos/runtime/v2/records_desk.pb.dart +1637 -0
  141. package/dart_types/lib/src/proto/nomos/runtime/v2/records_desk.pbenum.dart +175 -0
  142. package/dart_types/lib/src/proto/nomos/runtime/v2/recovery_desk.pb.dart +1269 -0
  143. package/dart_types/lib/src/proto/nomos/runtime/v2/recovery_desk.pbenum.dart +129 -0
  144. package/dart_types/lib/src/proto/nomos/runtime/v2/residency_desk.pb.dart +2782 -0
  145. package/dart_types/lib/src/proto/nomos/runtime/v2/residency_desk.pbenum.dart +97 -0
  146. package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pb.dart +2232 -8627
  147. package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pbenum.dart +0 -358
  148. package/dart_types/lib/src/proto/nomos/runtime/v2/sealing_desk.pb.dart +1639 -0
  149. package/dart_types/lib/src/proto/nomos/runtime/v2/sealing_desk.pbenum.dart +46 -0
  150. package/dart_types/lib/src/runtime_outcome.dart +133 -0
  151. package/dart_types/lib/src/subscriptions.dart +116 -23
  152. package/dart_types/pubspec.yaml +1 -1
  153. package/dart_types/test/extremum_subscriptions_test.dart +40 -0
  154. package/dart_types/test/foreign_ref_resolution_test.dart +75 -0
  155. package/dart_types/test/nomos_ref_address_test.dart +25 -0
  156. package/dart_types/test/ordered_subscriptions_test.dart +34 -0
  157. package/operation_contract_check.mjs +24 -0
  158. package/package.json +11 -6
  159. package/src/aggregate.ts +70 -10
  160. package/src/application_topology.ts +18 -11
  161. package/src/attested.ts +3 -0
  162. package/src/attested_core.ts +46 -3
  163. package/src/birth_meter_ensure.ts +19 -7
  164. package/src/births.ts +29 -4
  165. package/src/build_package.ts +140 -13
  166. package/src/business_birth.ts +181 -4
  167. package/src/codegen_call_proto.ts +1276 -0
  168. package/src/codegen_call_usda.ts +49 -6
  169. package/src/codegen_dart.ts +83 -44
  170. package/src/codegen_dart_client.ts +458 -800
  171. package/src/{codegen_dart_application.ts → codegen_dart_facade.ts} +331 -582
  172. package/src/codegen_dart_framework_calls.ts +320 -37
  173. package/src/codegen_dart_indexed_variant.ts +159 -0
  174. package/src/codegen_dart_scenario.ts +42 -13
  175. package/src/codegen_proof.ts +3 -3
  176. package/src/codegen_provider_dart.ts +5 -0
  177. package/src/codegen_query_proto.ts +158 -0
  178. package/src/codegen_refusal.ts +189 -0
  179. package/src/codegen_result_proto.ts +931 -0
  180. package/src/codegen_result_usda.ts +4 -0
  181. package/src/codegen_ts.ts +464 -616
  182. package/src/codegen_workspace_access.ts +105 -0
  183. package/src/compatibility_graph.ts +759 -0
  184. package/src/compatibility_usda.ts +264 -0
  185. package/src/compile_package_main.ts +2017 -1195
  186. package/src/custody_placement.ts +156 -0
  187. package/src/custody_placement_usda.ts +91 -0
  188. package/src/decl_shapes.ts +21 -2
  189. package/src/describe_model.ts +1 -0
  190. package/src/directive.ts +59 -2
  191. package/src/drivers.ts +51 -0
  192. package/src/engine_entry.ts +52 -8
  193. package/src/evolve_preview.ts +11 -4
  194. package/src/exists.ts +2 -0
  195. package/src/fields.ts +75 -11
  196. package/src/flow_gate.ts +2 -1
  197. package/src/framework/application_home.ts +170 -18
  198. package/src/framework/attested_receipts.ts +8 -3
  199. package/src/framework/auth_provider_law.ts +169 -9
  200. package/src/framework/birth_certificate_law.ts +4 -0
  201. package/src/framework/capability.ts +34 -3
  202. package/src/framework/child_authentication.ts +346 -0
  203. package/src/framework/console_governance.ts +295 -0
  204. package/src/framework/delegated_roles.ts +301 -0
  205. package/src/framework/domain_lifecycle.ts +26 -13
  206. package/src/framework/founding_genesis.ts +193 -0
  207. package/src/framework/framework_aggregates.ts +1 -1
  208. package/src/framework/genesis.ts +6 -1
  209. package/src/framework/governance_relations.ts +19 -0
  210. package/src/framework/home.ts +5 -734
  211. package/src/framework/legacy/child_auth_provider_epoch.ts +73 -0
  212. package/src/framework/model_authority_repair.ts +116 -0
  213. package/src/framework/model_authority_seed.ts +185 -0
  214. package/src/framework/model_transition.ts +211 -0
  215. package/src/framework/owned_custody.ts +1 -1
  216. package/src/framework/principal_enrollment.ts +302 -0
  217. package/src/framework/receiving_group.ts +857 -0
  218. package/src/framework/receiving_group_recovery.ts +314 -0
  219. package/src/framework/relations.ts +4 -8
  220. package/src/framework/signing_identity.ts +242 -95
  221. package/src/framework/source_roster.ts +11 -5
  222. package/src/framework/workspace_access.ts +149 -0
  223. package/src/framework/workspace_invariant.ts +73 -52
  224. package/src/framework/workspaces.ts +407 -40
  225. package/src/framework_call_definitions.ts +32 -3
  226. package/src/generated_client_bundle_boundary.ts +97 -0
  227. package/src/generated_client_names.ts +1 -0
  228. package/src/identity_usda.ts +27 -0
  229. package/src/index.ts +183 -12
  230. package/src/indexed_variant.ts +83 -0
  231. package/src/intent.ts +173 -45
  232. package/src/law_check.ts +8 -5
  233. package/src/law_dependency_index.ts +231 -0
  234. package/src/law_graph.ts +508 -71
  235. package/src/law_graph_usda.ts +170 -24
  236. package/src/law_identity.ts +119 -81
  237. package/src/law_source_map.ts +4 -1
  238. package/src/law_units.ts +498 -0
  239. package/src/law_value_type.ts +7 -3
  240. package/src/member_authentication.ts +302 -0
  241. package/src/null_meta.ts +1 -1
  242. package/src/openusd_compiled_layer.ts +132 -0
  243. package/src/operation_contract_check.ts +31 -0
  244. package/src/ordered_read.ts +2 -1
  245. package/src/package_config.ts +33 -12
  246. package/src/package_dependencies.ts +1 -0
  247. package/src/plan_source_slice.ts +30 -1
  248. package/src/protobuf_field_number.ts +36 -0
  249. package/src/provenance_wire.ts +6 -0
  250. package/src/query.ts +2 -1
  251. package/src/read.ts +50 -0
  252. package/src/relation.ts +4 -1
  253. package/src/relation_schema.ts +15 -2
  254. package/src/report.ts +2 -2
  255. package/src/sqlite_computation_bundle.ts +78 -0
  256. package/src/sqlite_computed.ts +102 -0
  257. package/src/sqlite_counts.ts +154 -0
  258. package/src/sqlite_layout.ts +823 -0
  259. package/src/sqlite_reads.ts +275 -0
  260. package/src/sqlite_samples.ts +185 -0
  261. package/src/stable_id_identity_bridge.ts +1 -1
  262. package/src/stable_ids_for_module.ts +16 -4
  263. package/src/test_call_usda.ts +6 -6
  264. package/src/usda_relationship_integrity.ts +20 -3
  265. package/src/usda_text.ts +21 -1
  266. package/src/value_object.ts +81 -11
  267. package/src/wire.ts +22 -0
  268. package/src/wire_encode.ts +227 -20
  269. package/src/workspace_sharding.ts +15 -6
  270. package/src/workspace_sharing.ts +51 -49
  271. package/src/zod_introspection.ts +2 -0
  272. package/compat_package.mjs +0 -46
  273. package/dart/lib/src/home.dart +0 -15
  274. package/dart/lib/src/runner/offline-install.mjs +0 -15367
  275. package/dart/lib/src/source_trust.dart +0 -51
  276. package/dart/lib/src/webview_bridge.dart +0 -6540
  277. package/dart/lib/src/workspace_name.dart +0 -30
  278. package/dart/test/acquire_session_credentials_test.dart +0 -150
  279. package/dart/test/acquire_session_test.dart +0 -534
  280. package/dart/test/adv_realm_interference_test.dart +0 -600
  281. package/dart/test/cloud_bound_topology_test.dart +0 -168
  282. package/dart/test/cluster_births_test.dart +0 -202
  283. package/dart/test/cluster_device_keyed_acceptance_test.dart +0 -105
  284. package/dart/test/cluster_local_autosync_test.dart +0 -123
  285. package/dart/test/cluster_scale_test.dart +0 -122
  286. package/dart/test/compat_test.dart +0 -61
  287. package/dart/test/dlq_session_surface_test.dart +0 -222
  288. package/dart/test/first_app_gauntlet_test.dart +0 -386
  289. package/dart/test/fixtures/wedge/fake-install.mjs +0 -11
  290. package/dart/test/four_layer_nested_topology_test.dart +0 -290
  291. package/dart/test/home_parity_test.dart +0 -13
  292. package/dart/test/local_sync_inert_test.dart +0 -107
  293. package/dart/test/node_runner_transport_test.dart +0 -78
  294. package/dart/test/parent_signer_recovery_test.dart +0 -155
  295. package/dart/test/residency_refusal_test.dart +0 -49
  296. package/dart/test/sealing_client_test.dart +0 -181
  297. package/dart/test/session_bound_test.dart +0 -285
  298. package/dart/test/stale_bundle_test.dart +0 -80
  299. package/dart/test/vo_read_typing_test.dart +0 -131
  300. package/dart/test/watch_after_offer_stall_test.dart +0 -100
  301. package/dart/test/webview_bridge_test.dart +0 -1930
  302. package/dart/test/workspace_name_test.dart +0 -24
  303. package/runtime/generated-application-host.js +0 -22860
  304. package/src/codegen_query_usda.ts +0 -214
  305. package/src/compat_manifest.ts +0 -26
  306. package/src/compat_package_main.ts +0 -224
  307. package/src/shape_compat.ts +0 -352
  308. package/src/usd_state.ts +0 -505
@@ -0,0 +1,46 @@
1
+ // This is a generated file - do not edit.
2
+ //
3
+ // Generated from nomos/runtime/v2/sealing_desk.proto.
4
+
5
+ // @dart = 3.3
6
+
7
+ // ignore_for_file: annotate_overrides, camel_case_types, comment_references
8
+ // ignore_for_file: constant_identifier_names
9
+ // ignore_for_file: curly_braces_in_flow_control_structures
10
+ // ignore_for_file: deprecated_member_use_from_same_package, library_prefixes
11
+ // ignore_for_file: non_constant_identifier_names
12
+
13
+ import 'dart:core' as $core;
14
+
15
+ import 'package:protobuf/protobuf.dart' as $pb;
16
+
17
+ class OwnedRecordAction extends $pb.ProtobufEnum {
18
+ static const OwnedRecordAction OWNED_RECORD_ACTION_UNSPECIFIED =
19
+ OwnedRecordAction._(
20
+ 0, _omitEnumNames ? '' : 'OWNED_RECORD_ACTION_UNSPECIFIED');
21
+ static const OwnedRecordAction OWNED_RECORD_ACTION_SHARE =
22
+ OwnedRecordAction._(1, _omitEnumNames ? '' : 'OWNED_RECORD_ACTION_SHARE');
23
+ static const OwnedRecordAction OWNED_RECORD_ACTION_UNSHARE =
24
+ OwnedRecordAction._(
25
+ 2, _omitEnumNames ? '' : 'OWNED_RECORD_ACTION_UNSHARE');
26
+ static const OwnedRecordAction OWNED_RECORD_ACTION_TRANSFER =
27
+ OwnedRecordAction._(
28
+ 3, _omitEnumNames ? '' : 'OWNED_RECORD_ACTION_TRANSFER');
29
+
30
+ static const $core.List<OwnedRecordAction> values = <OwnedRecordAction>[
31
+ OWNED_RECORD_ACTION_UNSPECIFIED,
32
+ OWNED_RECORD_ACTION_SHARE,
33
+ OWNED_RECORD_ACTION_UNSHARE,
34
+ OWNED_RECORD_ACTION_TRANSFER,
35
+ ];
36
+
37
+ static final $core.List<OwnedRecordAction?> _byValue =
38
+ $pb.ProtobufEnum.$_initByValueList(values, 3);
39
+ static OwnedRecordAction? valueOf($core.int value) =>
40
+ value < 0 || value >= _byValue.length ? null : _byValue[value];
41
+
42
+ const OwnedRecordAction._(super.value, super.name);
43
+ }
44
+
45
+ const $core.bool _omitEnumNames =
46
+ $core.bool.fromEnvironment('protobuf.omit_enum_names');
@@ -0,0 +1,133 @@
1
+ /// Closed, presentation-safe terminal outcomes from the Peer Runtime.
2
+ ///
3
+ /// These are facts, not repair procedures. A frontend can exhaustively project
4
+ /// them into its own state vocabulary without parsing diagnostics or taking
5
+ /// ownership of workspace, custody, replica-follow or retry lifecycles.
6
+ library;
7
+
8
+ import 'proto/nomos/runtime/v2/observability_desk.pb.dart'
9
+ show RuntimeUnavailable;
10
+ import 'proto/nomos/runtime/v2/observability_desk.pbenum.dart'
11
+ show RuntimeUnavailableReason;
12
+
13
+ enum NomosUnavailableReason {
14
+ remoteOnlyOffline,
15
+ remoteUnreachable,
16
+ remoteTimeout,
17
+ localReplicaNotReady,
18
+ credentialUnavailable,
19
+ workspaceOpening,
20
+ unknown,
21
+ }
22
+
23
+ final class NomosUnavailable implements Exception {
24
+ const NomosUnavailable({
25
+ required this.reason,
26
+ required this.workspace,
27
+ required this.retryable,
28
+ this.retryAfter,
29
+ this.detail = '',
30
+ });
31
+
32
+ final NomosUnavailableReason reason;
33
+ final String workspace;
34
+ final bool retryable;
35
+ final Duration? retryAfter;
36
+
37
+ /// Diagnostic prose for logs/support. Application control flow uses
38
+ /// [reason], [retryable] and [retryAfter], never this value.
39
+ final String detail;
40
+
41
+ /// The one translation of the generated `unavailable` arm, for every transport.
42
+ factory NomosUnavailable.fromRuntime(RuntimeUnavailable unavailable) =>
43
+ NomosUnavailable(
44
+ reason: switch (unavailable.reason) {
45
+ RuntimeUnavailableReason
46
+ .RUNTIME_UNAVAILABLE_REASON_REMOTE_ONLY_OFFLINE =>
47
+ NomosUnavailableReason.remoteOnlyOffline,
48
+ RuntimeUnavailableReason
49
+ .RUNTIME_UNAVAILABLE_REASON_REMOTE_UNREACHABLE =>
50
+ NomosUnavailableReason.remoteUnreachable,
51
+ RuntimeUnavailableReason.RUNTIME_UNAVAILABLE_REASON_REMOTE_TIMEOUT =>
52
+ NomosUnavailableReason.remoteTimeout,
53
+ RuntimeUnavailableReason
54
+ .RUNTIME_UNAVAILABLE_REASON_LOCAL_REPLICA_NOT_READY =>
55
+ NomosUnavailableReason.localReplicaNotReady,
56
+ RuntimeUnavailableReason
57
+ .RUNTIME_UNAVAILABLE_REASON_CREDENTIAL_UNAVAILABLE =>
58
+ NomosUnavailableReason.credentialUnavailable,
59
+ RuntimeUnavailableReason
60
+ .RUNTIME_UNAVAILABLE_REASON_WORKSPACE_OPENING =>
61
+ NomosUnavailableReason.workspaceOpening,
62
+ _ => NomosUnavailableReason.unknown,
63
+ },
64
+ workspace: unavailable.workspace,
65
+ retryable: unavailable.retryable,
66
+ retryAfter: unavailable.hasRetryAfterMillis()
67
+ ? Duration(milliseconds: unavailable.retryAfterMillis)
68
+ : null,
69
+ detail: unavailable.detail,
70
+ );
71
+
72
+ @override
73
+ String toString() =>
74
+ 'NomosUnavailable(${reason.name}, workspace: $workspace, retryable: $retryable'
75
+ '${detail.isEmpty ? '' : ', detail: $detail'})';
76
+ }
77
+
78
+ enum NomosRefusalReason {
79
+ invalidCredential,
80
+ accessDenied,
81
+ placementPolicy,
82
+ sessionUnbound,
83
+ unknown,
84
+ }
85
+
86
+ final class NomosRefused implements Exception {
87
+ const NomosRefused({
88
+ required this.reason,
89
+ required this.workspace,
90
+ required this.retryable,
91
+ this.detail = '',
92
+ });
93
+
94
+ final NomosRefusalReason reason;
95
+ final String workspace;
96
+ final bool retryable;
97
+
98
+ /// Diagnostic prose only; [reason] is the exhaustive control value.
99
+ final String detail;
100
+
101
+ @override
102
+ String toString() =>
103
+ 'NomosRefused(${reason.name}, workspace: $workspace, retryable: $retryable)';
104
+ }
105
+
106
+ enum NomosRuntimeFailureKind {
107
+ internal,
108
+ protocol,
109
+ integrity,
110
+ unsupported,
111
+ unknown,
112
+ }
113
+
114
+ final class NomosRuntimeFailure implements Exception {
115
+ const NomosRuntimeFailure({
116
+ required this.kind,
117
+ required this.code,
118
+ required this.message,
119
+ required this.component,
120
+ this.workspace,
121
+ });
122
+
123
+ final NomosRuntimeFailureKind kind;
124
+ final String code;
125
+ final String message;
126
+ final String component;
127
+ final String? workspace;
128
+
129
+ @override
130
+ String toString() =>
131
+ 'NomosRuntimeFailure(${kind.name}, $code, component: $component'
132
+ '${message.isEmpty ? '' : ', message: $message'})';
133
+ }
@@ -95,15 +95,23 @@ class NomosReads {
95
95
 
96
96
  /// The maintained-count seam (`client.count`). Reads ONE maintained counter
97
97
  /// by `(countId, groupKey)` — O(1) PK lookup, never a scan. Threads in from the
98
- /// app's host client (Slice 1). When null, `readCount`/`watchCount` return 0
99
- /// (no count seam provided — useful in tests that don't exercise counts).
98
+ /// app's host client. A missing callback is unsupported, not an empty group.
100
99
  final Counter? counter;
101
100
 
102
101
  /// The maintained-sum seam (`client.sum`). Reads ONE maintained sum by
103
102
  /// `(sumId, groupKey)` — O(1) PK lookup, never a scan. Threads in from the
104
- /// app's host client (Slice 1). When null, `readSum`/`watchSum` return 0.
103
+ /// app's host client. A missing callback is unsupported, not a zero sum.
105
104
  final Summer? summer;
106
105
 
106
+ /// Snapshot read callbacks for declared extrema. Missing support refuses; it
107
+ /// must not masquerade as an empty group. Live clients use async Reception.
108
+ final int? Function(String id, String groupKey)? minimum;
109
+ final int? Function(String id, String groupKey)? maximum;
110
+
111
+ /// Ordered snapshot rows, already selected under installed law and authority.
112
+ /// No caller-supplied limit/order goes to this callback. Live clients use Reception.
113
+ final String Function(String id)? ordered;
114
+
107
115
  /// The "projection changed" tick. When null, every accessor is a ONE-SHOT read
108
116
  /// (a single current value, no further updates) — used in tests / pure snapshots.
109
117
  final ReadTick? tick;
@@ -113,6 +121,9 @@ class NomosReads {
113
121
  required this.queryById,
114
122
  this.counter,
115
123
  this.summer,
124
+ this.minimum,
125
+ this.maximum,
126
+ this.ordered,
116
127
  this.tick,
117
128
  });
118
129
 
@@ -131,7 +142,8 @@ class NomosReads {
131
142
  ) {
132
143
  final decoded = jsonDecode(rowsJson);
133
144
  if (decoded is! List) {
134
- throw FormatException('read rows must be a JSON array, got ${decoded.runtimeType}');
145
+ throw FormatException(
146
+ 'read rows must be a JSON array, got ${decoded.runtimeType}');
135
147
  }
136
148
  final out = <T>[];
137
149
  for (final row in decoded) {
@@ -192,27 +204,97 @@ class NomosReads {
192
204
 
193
205
  // ---- maintained count/sum seams (Slice 1) ----
194
206
 
207
+ T? readFirst<T>(
208
+ String id, T Function(Map<String, dynamic>, String) fromJson) {
209
+ final rows = readTake(id, 1, fromJson);
210
+ return rows.isEmpty ? null : rows.single;
211
+ }
212
+
213
+ /// [limit] validates the generated result contract; it never selects rows locally.
214
+ List<T> readTake<T>(
215
+ String id, int limit, T Function(Map<String, dynamic>, String) fromJson) {
216
+ final read = ordered;
217
+ if (read == null)
218
+ throw UnsupportedError('Declared ordered reads are not bound');
219
+ if (limit < 1) throw ArgumentError.value(limit, 'limit');
220
+ final rows = jsonDecode(read(id));
221
+ if (rows is! List || rows.length > limit)
222
+ throw const FormatException(
223
+ 'Ordered result violates its declared cardinality');
224
+ return rows.map((row) {
225
+ if (row is! Map<String, dynamic> ||
226
+ row['data'] is! Map<String, dynamic> ||
227
+ row['id'] is! String)
228
+ throw const FormatException('Ordered result contains a malformed row');
229
+ return fromJson(row['data'] as Map<String, dynamic>, row['id'] as String);
230
+ }).toList(growable: false);
231
+ }
232
+
233
+ Stream<T?> watchFirst<T>(
234
+ String id, T Function(Map<String, dynamic>, String) fromJson) =>
235
+ _reactive(() => readFirst(id, fromJson));
236
+
237
+ Stream<List<T>> watchTake<T>(String id, int limit,
238
+ T Function(Map<String, dynamic>, String) fromJson) =>
239
+ _reactive(() => readTake(id, limit, fromJson));
240
+
195
241
  /// Read the current maintained counter for [countId] + [groupKey] NOW. Returns 0
196
242
  /// when no entry exists (either truly zero, or no group for this key). O(1) PK
197
- /// lookup in the `counts` table — never a scan. Returns 0 when [counter] is null
198
- /// (no count seam provided — useful in tests).
199
- int readCount(String countId, String groupKey) => counter?.call(countId, groupKey) ?? 0;
243
+ /// lookup in the `counts` table — never a scan. Missing support refuses.
244
+ int readCount(String countId, String groupKey) {
245
+ final read = counter;
246
+ if (read == null)
247
+ throw UnsupportedError('Declared count reads are not bound');
248
+ final count = read(countId, groupKey);
249
+ if (count < 0) throw StateError('Negative membership count');
250
+ return count;
251
+ }
252
+
253
+ /// Existence uses the same maintained count; a zero-valued member still exists.
254
+ bool readExists(String id, String groupKey) => readCount(id, groupKey) > 0;
255
+
256
+ Stream<bool> watchExists(String id, String groupKey) =>
257
+ _reactive(() => readExists(id, groupKey));
200
258
 
201
259
  /// Subscribe to the maintained counter for [countId] + [groupKey] as a
202
260
  /// `Stream<int>`. Emits the current count immediately, then re-emits on every
203
- /// [tick]. Returns 0 when [counter] is null.
261
+ /// [tick]. Missing support refuses.
204
262
  Stream<int> watchCount(String countId, String groupKey) =>
205
263
  _reactive(() => readCount(countId, groupKey));
206
264
 
207
265
  /// Read the current maintained sum for [sumId] + [groupKey] NOW. Returns 0 when
208
266
  /// no entry exists (a group pruned at 0 is indistinguishable from absent —
209
267
  /// documented Slice-1 caveat). O(1) PK lookup in the `sums` table — never a scan.
210
- /// Returns 0 when [summer] is null.
211
- int readSum(String sumId, String groupKey) => summer?.call(sumId, groupKey) ?? 0;
268
+ /// Missing support refuses.
269
+ int readSum(String sumId, String groupKey) {
270
+ final read = summer;
271
+ if (read == null)
272
+ throw UnsupportedError('Declared sum reads are not bound');
273
+ return read(sumId, groupKey);
274
+ }
275
+
276
+ int? readMin(String id, String groupKey) {
277
+ final read = minimum;
278
+ if (read == null)
279
+ throw UnsupportedError('Declared min reads are not bound');
280
+ return read(id, groupKey);
281
+ }
282
+
283
+ int? readMax(String id, String groupKey) {
284
+ final read = maximum;
285
+ if (read == null)
286
+ throw UnsupportedError('Declared max reads are not bound');
287
+ return read(id, groupKey);
288
+ }
289
+
290
+ Stream<int?> watchMin(String id, String groupKey) =>
291
+ _reactive(() => readMin(id, groupKey));
292
+
293
+ Stream<int?> watchMax(String id, String groupKey) =>
294
+ _reactive(() => readMax(id, groupKey));
212
295
 
213
296
  /// Subscribe to the maintained sum for [sumId] + [groupKey] as a `Stream<int>`.
214
- /// Emits the current total immediately, then re-emits on every [tick]. Returns 0
215
- /// when [summer] is null.
297
+ /// Emits the current total immediately, then re-emits on every [tick].
216
298
  Stream<int> watchSum(String sumId, String groupKey) =>
217
299
  _reactive(() => readSum(sumId, groupKey));
218
300
 
@@ -281,21 +363,24 @@ int readInt(Map<String, dynamic> data, String aggregate, String field) {
281
363
  final n = int.tryParse(v);
282
364
  if (n != null) return n;
283
365
  }
284
- throw FormatException('$aggregate.$field: expected int, got ${v.runtimeType}');
366
+ throw FormatException(
367
+ '$aggregate.$field: expected int, got ${v.runtimeType}');
285
368
  }
286
369
 
287
370
  /// Read a `set`-kind field as a `Set<String>` (the projection emits a JSON array).
288
371
  Set<String> readSet(Map<String, dynamic> data, String aggregate, String field) {
289
372
  final v = _required(data, aggregate, field);
290
373
  if (v is List) return v.map((e) => e.toString()).toSet();
291
- throw FormatException('$aggregate.$field: expected a set/array, got ${v.runtimeType}');
374
+ throw FormatException(
375
+ '$aggregate.$field: expected a set/array, got ${v.runtimeType}');
292
376
  }
293
377
 
294
378
  /// Read a `map`-kind field as a `Map<String, String>`. The projection may emit it
295
379
  /// as a flat `{k:v}` object (the loss-less author path) OR — if it folded through a
296
380
  /// kernel `Value::Map` — as the structural `{"Map":{k:{value:{Str:v},…}}}` serde
297
381
  /// form; both are reduced to `{k:v}` so the aggregate's typed map is stable.
298
- Map<String, String> readStrMap(Map<String, dynamic> data, String aggregate, String field) {
382
+ Map<String, String> readStrMap(
383
+ Map<String, dynamic> data, String aggregate, String field) {
299
384
  final v = _required(data, aggregate, field);
300
385
  if (v is Map) {
301
386
  // Structural kernel `Value::Map` form: `{"Map": {k: {value:{Str:..},stamp:..}}}`.
@@ -308,7 +393,8 @@ Map<String, String> readStrMap(Map<String, dynamic> data, String aggregate, Stri
308
393
  return out;
309
394
  }
310
395
  }
311
- throw FormatException('$aggregate.$field: expected a map/object, got ${v.runtimeType}');
396
+ throw FormatException(
397
+ '$aggregate.$field: expected a map/object, got ${v.runtimeType}');
312
398
  }
313
399
 
314
400
  /// Reduce one map entry value to a String, peeling the kernel `{value:{Str:..}}`
@@ -317,8 +403,10 @@ String _flattenMapValue(Object? val) {
317
403
  if (val is String) return val;
318
404
  if (val is Map) {
319
405
  final value = val['value'];
320
- if (value is Map && value.containsKey('Str')) return value['Str'].toString();
321
- if (value is Map && value.containsKey('Int')) return value['Int'].toString();
406
+ if (value is Map && value.containsKey('Str'))
407
+ return value['Str'].toString();
408
+ if (value is Map && value.containsKey('Int'))
409
+ return value['Int'].toString();
322
410
  }
323
411
  return val.toString();
324
412
  }
@@ -446,7 +534,8 @@ int? readIntOrNull(Map<String, dynamic> data, String aggregate, String field) {
446
534
  final n = int.tryParse(v);
447
535
  if (n != null) return n;
448
536
  }
449
- throw FormatException('$aggregate.$field: expected int, got ${v.runtimeType}');
537
+ throw FormatException(
538
+ '$aggregate.$field: expected int, got ${v.runtimeType}');
450
539
  }
451
540
 
452
541
  /// Read an OPTIONAL enum-kind field's wire string, or `null` when absent (a present
@@ -473,17 +562,20 @@ String? readJsonStrOrNull(Map<String, dynamic> data, String field) {
473
562
  /// Read a `set`-kind field as a `Set<String>`, defaulting to EMPTY when the flat
474
563
  /// `data` lacks it (a freshly-created aggregate need not have folded the set). A
475
564
  /// PRESENT-but-non-array value still throws (parity with [readSet]).
476
- Set<String> readSetOrEmpty(Map<String, dynamic> data, String aggregate, String field) {
565
+ Set<String> readSetOrEmpty(
566
+ Map<String, dynamic> data, String aggregate, String field) {
477
567
  final v = data[field];
478
568
  if (v == null) return <String>{};
479
569
  if (v is List) return v.map((e) => e.toString()).toSet();
480
- throw FormatException('$aggregate.$field: expected a set/array, got ${v.runtimeType}');
570
+ throw FormatException(
571
+ '$aggregate.$field: expected a set/array, got ${v.runtimeType}');
481
572
  }
482
573
 
483
574
  /// Read a `map`-kind field as a `Map<String, String>`, defaulting to EMPTY when
484
575
  /// absent. A PRESENT value is reduced exactly as [readStrMap] (handling both the flat
485
576
  /// `{k:v}` form and the structural kernel `Value::Map` form).
486
- Map<String, String> readStrMapOrEmpty(Map<String, dynamic> data, String aggregate, String field) {
577
+ Map<String, String> readStrMapOrEmpty(
578
+ Map<String, dynamic> data, String aggregate, String field) {
487
579
  final v = data[field];
488
580
  if (v == null) return <String, String>{};
489
581
  return readStrMap(data, aggregate, field);
@@ -515,7 +607,8 @@ Map<String, Object?> readJsonMapOrEmpty(
515
607
  return out;
516
608
  }
517
609
  }
518
- throw FormatException('$aggregate.$field: expected a map/object, got ${v.runtimeType}');
610
+ throw FormatException(
611
+ '$aggregate.$field: expected a map/object, got ${v.runtimeType}');
519
612
  }
520
613
 
521
614
  /// Decode one JSON-valued map entry to its object: peel the kernel
@@ -9,7 +9,7 @@ description: >-
9
9
  Pure kernel wire/data types for Nomos Dart frontends — no transport, no bridge,
10
10
  no runtime. Typed protobuf and USDA boundary values plus the offer codec,
11
11
  reactive read engine, schema validation, and data-only error/trace types.
12
- version: 0.10.1
12
+ version: 0.11.2
13
13
 
14
14
  environment:
15
15
  sdk: ^3.5.0
@@ -0,0 +1,40 @@
1
+ import 'package:nomos_types/src/subscriptions.dart';
2
+ import 'package:test/test.dart';
3
+
4
+ void main() {
5
+ test('snapshot membership is a count, not a sum or missing callback',
6
+ () async {
7
+ final reads = NomosReads(
8
+ query: (_, __) => '[]',
9
+ queryById: (_) => '[]',
10
+ counter: (_, group) => group == 'empty' ? 0 : 2,
11
+ summer: (_, __) => 0);
12
+ expect(reads.readExists('hasMembers', 'empty'), false);
13
+ expect(await reads.watchExists('hasMembers', 'filled').first, true);
14
+ expect(reads.readSum('total', 'filled'), 0);
15
+ final unbound = NomosReads(query: (_, __) => '[]', queryById: (_) => '[]');
16
+ expect(() => unbound.readExists('hasMembers', ''), throwsUnsupportedError);
17
+ expect(() => unbound.readCount('count', ''), throwsUnsupportedError);
18
+ expect(() => unbound.readSum('total', ''), throwsUnsupportedError);
19
+ final invalid = NomosReads(
20
+ query: (_, __) => '[]', queryById: (_) => '[]', counter: (_, __) => -1);
21
+ expect(() => invalid.readExists('hasMembers', ''), throwsStateError);
22
+ });
23
+ test(
24
+ 'snapshot extrema preserve null and zero without inventing missing support',
25
+ () async {
26
+ final reads = NomosReads(
27
+ query: (_, __) => '[]',
28
+ queryById: (_) => '[]',
29
+ minimum: (_, group) => group == 'empty' ? null : 0,
30
+ maximum: (_, group) => group == 'empty' ? null : 7);
31
+ expect(reads.readMin('minimum', 'empty'), isNull);
32
+ expect(reads.readMin('minimum', 'filled'), 0);
33
+ expect(await reads.watchMin('minimum', 'filled').first, 0);
34
+ expect(await reads.watchMax('maximum', 'empty').first, isNull);
35
+ expect(reads.readMax('maximum', 'filled'), 7);
36
+ final unbound = NomosReads(query: (_, __) => '[]', queryById: (_) => '[]');
37
+ expect(() => unbound.readMin('minimum', ''), throwsUnsupportedError);
38
+ expect(() => unbound.readMax('maximum', ''), throwsUnsupportedError);
39
+ });
40
+ }
@@ -0,0 +1,75 @@
1
+ import 'dart:typed_data';
2
+ import 'package:nomos_types/src/foreign_ref.dart';
3
+ import 'package:test/test.dart';
4
+
5
+ class Reader implements NomosForeignReader {
6
+ Reader(this.read);
7
+ final Future<Uint8List> Function() read;
8
+ @override
9
+ NomosForeignWorkspaceReader foreignWorkspace(String workspace) =>
10
+ WorkspaceReader(read);
11
+ }
12
+
13
+ class WorkspaceReader extends NomosForeignWorkspaceReader {
14
+ WorkspaceReader(this.read);
15
+ final Future<Uint8List> Function() read;
16
+ @override
17
+ Future<Uint8List> queryById(String aggregateType, String id) => read();
18
+ }
19
+
20
+ void main() {
21
+ final ref = NmsInternalForeignRefs.create<String>(
22
+ id: 'definition-1',
23
+ workspace: 'field-library',
24
+ type: 'FieldDefinition',
25
+ fromUsda: (bytes, _, __) => bytes.isEmpty ? null : 'found');
26
+ test('only a successful absent result resolves to null', () async {
27
+ expect(
28
+ await NmsInternalForeignRefs.resolve(
29
+ ref, Reader(() async => Uint8List(0))),
30
+ isNull);
31
+ expect(
32
+ await NmsInternalForeignRefs.resolve(
33
+ ref, Reader(() async => Uint8List(1))),
34
+ 'found');
35
+ });
36
+ test(
37
+ 'denial and offline transport remain failures with payload-free provenance',
38
+ () async {
39
+ for (final example in [
40
+ (
41
+ StateError('UNAUTHORIZED sensitive-value'),
42
+ ForeignReadFailureKind.denied
43
+ ),
44
+ (
45
+ StateError('offline sensitive-value'),
46
+ ForeignReadFailureKind.unreachable
47
+ ),
48
+ ]) {
49
+ try {
50
+ await NmsInternalForeignRefs.resolve(
51
+ ref, Reader(() async => throw example.$1));
52
+ fail('a failed read must not become a missing record');
53
+ } on ForeignReadFailure catch (failure) {
54
+ expect(failure.kind, example.$2);
55
+ expect(failure.workspace, 'field-library');
56
+ expect(failure.id, 'definition-1');
57
+ expect(failure.toString(), isNot(contains('sensitive-value')));
58
+ }
59
+ }
60
+ });
61
+ test('a missing generated nominal codec is a failure, never missing data',
62
+ () async {
63
+ final locator = NmsInternalForeignRefs.create<String>(
64
+ id: 'definition-1',
65
+ workspace: 'field-library',
66
+ type: 'FieldDefinition');
67
+ expect(
68
+ () => NmsInternalForeignRefs.resolve(
69
+ locator, Reader(() async => Uint8List(1))),
70
+ throwsA(isA<ForeignReadFailure>().having(
71
+ (failure) => failure.sourceErrorType,
72
+ 'source type',
73
+ 'StateError')));
74
+ });
75
+ }
@@ -0,0 +1,25 @@
1
+ import 'package:nomos_types/src/nomos_ref.dart';
2
+ import 'package:test/test.dart';
3
+
4
+ class Drawing {}
5
+
6
+ void main() {
7
+ test(
8
+ 'address round trip preserves identity, including literal percent escapes',
9
+ () {
10
+ for (final id in [
11
+ 'plain',
12
+ 'floor/one',
13
+ '50% complete',
14
+ '%2F',
15
+ 'a?#b',
16
+ 'Étage 1'
17
+ ]) {
18
+ final ref = NmsInternalNomosRefs.create<Drawing>(
19
+ workspace: 'estate-test', type: 'estate.SiteDrawing', id: id);
20
+ final restored = NmsInternalNomosRefs.fromUri<Drawing>(ref.address);
21
+ expect(restored, ref, reason: id);
22
+ expect(restored.id, id);
23
+ }
24
+ });
25
+ }
@@ -0,0 +1,34 @@
1
+ import 'dart:convert';
2
+ import 'package:nomos_types/src/subscriptions.dart';
3
+ import 'package:test/test.dart';
4
+
5
+ void main() {
6
+ String decode(Map<String, dynamic> data, String id) => id;
7
+ test(
8
+ 'ordered snapshots preserve selection order and reject invalid cardinality',
9
+ () async {
10
+ final rows = <Object>[];
11
+ final calls = <String>[];
12
+ final reads = NomosReads(
13
+ query: (_, __) => throw StateError('not a keyed query'),
14
+ queryById: (_) => throw StateError('not a primary-key query'),
15
+ ordered: (id) {
16
+ calls.add(id);
17
+ return jsonEncode(rows);
18
+ });
19
+ expect(reads.readFirst('first', decode), isNull);
20
+ expect(await reads.watchTake('top', 2, decode).first, isEmpty);
21
+ rows.add({'id': 'z', 'data': {}});
22
+ expect(await reads.watchFirst('first', decode).first, 'z');
23
+ rows.add({'id': 'a', 'data': {}});
24
+ expect(reads.readTake('top', 2, decode), ['z', 'a']);
25
+ expect(() => reads.readFirst('first', decode), throwsFormatException);
26
+ rows
27
+ ..clear()
28
+ ..add({'id': 123, 'data': {}});
29
+ expect(() => reads.readTake('top', 2, decode), throwsFormatException);
30
+ expect(calls, everyElement(anyOf('first', 'top')));
31
+ final missing = NomosReads(query: (_, __) => '[]', queryById: (_) => '[]');
32
+ expect(() => missing.readFirst('first', decode), throwsUnsupportedError);
33
+ });
34
+ }
@@ -0,0 +1,24 @@
1
+ // Compiler-only, read-only invocation of the kernel's contract checker.
2
+ // No peer, workspace, credentials, offers or second execution lifecycle.
3
+ import { WASI } from 'node:wasi';
4
+ import { readFileSync } from 'node:fs';
5
+ import path from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+
8
+ const input = process.argv[2];
9
+ const descriptors = process.argv[3];
10
+ if (!input) throw new Error('operation contract checker needs a compiled law package');
11
+ const artifact = new URL('./assets/operation-contract.wasm', import.meta.url);
12
+ const wasi = new WASI({
13
+ version: 'preview1',
14
+ args: ['operation-contract', 'validate-operation-contracts', `/input/${path.basename(input)}`,
15
+ ...(descriptors === undefined ? [] : [`/descriptors/${path.basename(descriptors)}`])],
16
+ env: {}, preopens: { '/input': path.dirname(path.resolve(input)),
17
+ ...(descriptors === undefined ? {} : { '/descriptors': path.dirname(path.resolve(descriptors)) }) }, returnOnExit: true,
18
+ });
19
+ let bytes;
20
+ try { bytes = readFileSync(artifact); }
21
+ catch { throw new Error(`compiler package is incomplete: missing ${fileURLToPath(artifact)}; reinstall @githolon/dsl`); }
22
+ const module = await WebAssembly.compile(bytes);
23
+ const instance = await WebAssembly.instantiate(module, { wasi_snapshot_preview1: wasi.wasiImport });
24
+ process.exitCode = wasi.start(instance);