@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
@@ -1,49 +0,0 @@
1
- // THE KERNEL NAMES WHAT IT NEEDS; EVERY HOST MUST SATISFY IT.
2
- //
3
- // The colocated-read residency rule is enforced by the KERNEL, so it fires identically in the cloud
4
- // container and on a phone — the whole point of one artifact everywhere. It shipped with only the
5
- // cloud taught to satisfy it, so an estate whose history reads a catalogue could not open on a
6
- // device at all. These tests pin the client's half: the exact refusal the kernel emits must be
7
- // recognised, and nothing else must be mistaken for it.
8
- import 'package:test/test.dart';
9
- import 'package:nomos_client/src/webview_bridge.dart'
10
- show nomosInternalResidencyRequiredWorkspace;
11
-
12
- void main() {
13
- test('recognises the kernel refusal and names the workspace to mount', () {
14
- // Verbatim from a device, 2026-08-07 (build 1182, opening an estate).
15
- const refusal =
16
- 'NomosBridgeError: NMS-KERNEL-CALL: restore_main: imported custody was refused: '
17
- '{"atCommit":"2059537e7c7d1dcaa9b4f6f4ac2ded2ae59b53a5","atIndex":20,'
18
- '"check":"colocated-read","error":"foreign-read-not-ready: source workspace '
19
- "'catalogue-531e3764f974ff741be62b119a28f0a9dbf396d7' is not resident in this kernel\","
20
- '"mode":"verify_chain","ok":true,"valid":false,"walk":"full"}';
21
- expect(
22
- nomosInternalResidencyRequiredWorkspace(refusal),
23
- 'catalogue-531e3764f974ff741be62b119a28f0a9dbf396d7',
24
- );
25
- });
26
-
27
- test('does not mistake other failures for a residency miss', () {
28
- // If any of these were read as "mount something and retry", a real error would retry forever.
29
- for (final other in <String>[
30
- 'NomosBridgeError: NMS-KERNEL-CALL: restore_main: verification failed: bad signature',
31
- 'NomosSeatingPendingFailure: signer enrollment is not yet provably durable',
32
- 'StateError: the workspace is not on this device\'s plane',
33
- '',
34
- ]) {
35
- expect(nomosInternalResidencyRequiredWorkspace(other), isNull,
36
- reason: 'must not treat "$other" as a residency requirement');
37
- }
38
- });
39
-
40
- test('the sibling refusal that names no workspace is not actionable', () {
41
- // The kernel has a second foreign-read-not-ready shape for an unsafe path. There is nothing to
42
- // mount, so it must fall through to the caller rather than being retried.
43
- expect(
44
- nomosInternalResidencyRequiredWorkspace(
45
- "foreign-read-not-ready: source workspace '../escape' is not a safe internal custody path"),
46
- isNull,
47
- );
48
- });
49
- }
@@ -1,181 +0,0 @@
1
- // E2E SEALING FROM DART (task #86 gap 3): the operator-blind encryption handshake driven end-to-end
2
- // through the Dart sealing-client surface (NomosEncryption — the owner ceremony; WrappedKeyStore —
3
- // the reader's key custody; the kernel crypto ops over the bridge) against the REAL encrypted-notes
4
- // law on a local holon. Mirrors bench/scale/e2e_encryption.smoke.mjs leg for leg:
5
- // reader device key → grantAndWrap (grant + epoch fan-out in ONE ceremony call) → author-seal →
6
- // write the envelope → the reader unwraps its scope key from the on-chain WrappedKey and reads
7
- // DECRYPTED → without the key the body stays the opaque envelope → a non-member read is refused.
8
- @TestOn('vm')
9
- library;
10
-
11
- import 'dart:async';
12
- import 'dart:convert';
13
- import 'dart:io';
14
-
15
- import 'package:nomos_client/src/nms_conformance_runtime.dart';
16
- import 'package:test/test.dart';
17
-
18
- String get _root => '${Directory.current.path}/../..';
19
- String get _repoEntry => '$_root/cloud/web-client/runner/node-entry.ts';
20
- String get _fixture => '$_root/cloud/web-client/test/fixtures/encrypted-notes';
21
- String get _deploy => '$_fixture/build/encrypted-notes.law.usdz';
22
- String get _lockfile => '$_fixture/nomos.identity.usda';
23
- String get _runtimeDir =>
24
- Platform.environment['NOMOS_DART_RUNTIME'] ??
25
- Platform.environment['NOMOS_OFFLINE_RUNTIME'] ??
26
- '${Platform.environment['HOME'] ?? ''}/.holon/runtime';
27
-
28
- const _domain = 'encrypted_notes';
29
- const _scope = 'readNote';
30
- const _reader = 'reader-ada';
31
- const _plaintext = 'the secret body';
32
-
33
- String? _missingPrereq() {
34
- if (!File(_repoEntry).existsSync()) return 'in-repo runner not found at $_repoEntry';
35
- if (!File(_deploy).existsSync() || !File(_lockfile).existsSync()) {
36
- return 'missing encrypted-notes fixture — compile it: (cd cloud/web-client/test/fixtures/encrypted-notes && node ../../../../../dsl/compile_package.mjs)';
37
- }
38
- if (!File('$_runtimeDir/holon-testmint.wasm').existsSync() ||
39
- !File('$_runtimeDir/bootstrap.law.usdz').existsSync() ||
40
- !File('$_runtimeDir/nomos.law.usdz').existsSync()) {
41
- return 'warm ~/.holon/runtime first (run any `githolon` command once)';
42
- }
43
- return null;
44
- }
45
-
46
- Future<T> _leg<T>(String name, Future<T> Function() body) async {
47
- final sw = Stopwatch()..start();
48
- // ignore: avoid_print
49
- print('▶ SEAL $name …');
50
- try {
51
- final r = await body();
52
- // ignore: avoid_print
53
- print('✔ SEAL $name (${sw.elapsedMilliseconds}ms)');
54
- return r;
55
- } catch (e, st) {
56
- throw TestFailure('SEAL $name FAILED after ${sw.elapsedMilliseconds}ms:\n$e\n$st');
57
- }
58
- }
59
-
60
- void main() {
61
- test('E2E sealing via the Dart harness: keygen → grantAndWrap → seal → write → decrypted read',
62
- () async {
63
- final missing = _missingPrereq();
64
- if (missing != null) {
65
- markTestSkipped(missing);
66
- return;
67
- }
68
- final harness = await NomosTestHarness.ephemeral(
69
- lawUsdzPaths: [_deploy],
70
- workspace: 'sealed-notes',
71
- nodeEntry: _repoEntry,
72
- runtimeDir: _runtimeDir,
73
- phaseTimeout: const Duration(seconds: 120),
74
- );
75
- try {
76
- final s = harness.bridge;
77
- final lawHash = harness.lawHashes('sealed-notes').first;
78
-
79
- // The #58 stable sids for the (Note, body) slot — from the committed lockfile, exactly as the
80
- // generated sealing client bakes them.
81
- final lock = (jsonDecode(File(_lockfile).readAsStringSync()) as Map);
82
- final noteAgg = ((((lock['domains'] as Map)[_domain] as Map)['stableIds'] as Map)['aggregates']
83
- as Map)['Note'] as Map;
84
- final aggSid = noteAgg['sid'].toString();
85
- final fieldSid = ((noteAgg['fields'] as Map)['body'] as Map)['sid'].toString();
86
-
87
- // ── LEG 1: the reader's X25519 device key (secret stays client-side). ──
88
- final reader = await _leg('leg 1: reader device keygen (X25519, in-kernel)', () async {
89
- final kp = await s.cryptoKeygen();
90
- expect((kp['secret'] ?? '').toString(), isNotEmpty);
91
- expect((kp['public'] ?? '').toString(), isNotEmpty);
92
- return kp;
93
- });
94
-
95
- // ── LEG 2: THE OWNER CEREMONY in ONE call — grant the cap + open epoch 0 wrapping the scope
96
- // key to the resolved roster (the Dart NomosEncryption surface, gap 3's real target). ──
97
- final scopeKey = base64Encode(
98
- base64Decode((await s.cryptoKeygen())['secret'].toString()).sublist(0, 32));
99
- final ceremony = NomosEncryption(
100
- bridge: s, domain: _domain, domainHash: lawHash, scopes: const [_scope]);
101
- final epoch0 = await _leg('leg 2: grantAndWrap (grant + epoch fan-out, one ceremony call)',
102
- () async {
103
- final r = await ceremony.grantAndWrap(
104
- principal: _reader,
105
- publicKey: reader['public'].toString(),
106
- grantDirective: 'grantReader',
107
- grantPayload: {
108
- 'principal': _reader,
109
- 'grantedBy': 'owner',
110
- 'grantedAt': DateTime.now().toUtc().toIso8601String(),
111
- },
112
- scopeKey: scopeKey,
113
- );
114
- expect(r.epoch, 0, reason: 'the first ceremony opens epoch 0');
115
- expect(r.roster, [_reader], reason: 'the fan-out roster is exactly the granted member');
116
- expect(r.head, isNotEmpty);
117
- return r;
118
- });
119
-
120
- // ── LEG 3: author-seal the body (the wasm seal, sid-bound) and WRITE the envelope. ──
121
- final envelope = await _leg('leg 3: seal the body → write the envelope', () async {
122
- final env = await s.cryptoSealField(
123
- scopeKey: scopeKey,
124
- scope: _scope,
125
- epoch: epoch0.epoch,
126
- aggSid: aggSid,
127
- fieldSid: fieldSid,
128
- plaintext: _plaintext,
129
- );
130
- expect(env, contains(fieldSid), reason: 'the envelope binds the stable field sid');
131
- expect(env, contains(_scope));
132
- await s.offerOutcome(
133
- domain: _domain,
134
- directiveId: 'writeNote',
135
- payload: {'owner': _reader, 'body': env},
136
- domainHash: lawHash,
137
- );
138
- return env;
139
- });
140
-
141
- // ── LEG 4: the reader's WrappedKeyStore unwraps its scope key from the on-chain WrappedKey
142
- // with its device secret — the shipped key-custody default. ──
143
- final keys = await _leg('leg 4: WrappedKeyStore unwraps the on-chain wrapped key', () async {
144
- final store = WrappedKeyStore(
145
- bridge: s, principal: _reader, deviceSecret: reader['secret'].toString());
146
- final current = await store.scopeKey(_scope);
147
- expect(current, isNotNull, reason: 'the reader holds a wrap for its scope');
148
- expect(current!.epoch, 0);
149
- expect(current.key, scopeKey,
150
- reason: 'the unwrapped scope key IS the ceremony key (the real handoff)');
151
- return store.readKeys(const [_scope]);
152
- });
153
-
154
- // ── LEG 5: read WITH the key → DECRYPTED; read WITHOUT → the opaque envelope. ──
155
- await _leg('leg 5: keyed read decrypts; keyless read stays opaque', () async {
156
- final withKey = await s.query('notesByOwner', {'owner': _reader}, keys, _reader);
157
- expect(withKey, hasLength(1));
158
- expect((withKey.single['data'] as Map)['body'], _plaintext,
159
- reason: 'the key-holder reads plaintext');
160
- final noKey = await s.query('notesByOwner', {'owner': _reader}, null, _reader);
161
- final opaque = (noKey.single['data'] as Map)['body'];
162
- expect(opaque, isNot(_plaintext), reason: 'the operator view never decrypts');
163
- expect(opaque.toString(), contains(_scope),
164
- reason: 'the value is the scope-bound ciphertext envelope, sizes/scope visible only');
165
- expect(opaque.toString(), envelope, reason: 'byte-for-byte the on-chain envelope');
166
- });
167
-
168
- // ── LEG 6: a NON-MEMBER is refused by the read gate itself (before decryption matters). ──
169
- await _leg('leg 6: non-member read refused by the read gate', () async {
170
- await expectLater(
171
- s.query('notesByOwner', {'owner': _reader},
172
- [NomosScopeKey(scope: _scope, epoch: 0, key: scopeKey)], 'intruder-mallory'),
173
- throwsA(predicate((e) => e.toString().contains('read-forbidden'),
174
- 'a read-forbidden refusal')));
175
- });
176
- } finally {
177
- await harness.dispose().timeout(const Duration(seconds: 30),
178
- onTimeout: () => throw StateError('harness disposal hung'));
179
- }
180
- }, timeout: const Timeout(Duration(minutes: 5)));
181
- }
@@ -1,285 +0,0 @@
1
- // SESSION-BOUND APPLICATIONS — framework acceptance against the REAL wasm on a local plane.
2
- // Generated clients are private implementation parts. These tests bind the generated application
3
- // surface and use raw session calls only where they deliberately exercise nomos_client internals:
4
- //
5
- // engine → mount → generated application bind (preflight) → an internal fixture birth landing in
6
- // the session workspace → engine.follow(ref) → a second application → a business record operation.
7
- //
8
- // Plus the typed failure modes: application bind on a deliberately WRONG session throws
9
- // DomainClientSessionMismatch with every spec field; a dispatch naming an uninstalled domain
10
- // surfaces as DomainNotInstalledForSession (the context-rich replacement of the kernel's generic
11
- // "no active installed law declares domain 'x'"). Raw calls here are framework-test setup only;
12
- // they are not a supported tenant lane and are not exported by nomos_client.
13
- @TestOn('vm')
14
- library;
15
-
16
- import 'dart:io';
17
-
18
- // ignore: deprecated_member_use
19
- import 'package:nomos_client/src/nms_conformance_runtime.dart';
20
- import 'package:test/test.dart';
21
-
22
- import '../../../bench/scale/fixtures/estate-birth/build/dart/src/generated/home.application.dart';
23
- import '../../../bench/scale/fixtures/estate-birth/build/dart/src/generated/estate.application.dart';
24
-
25
- String get _root => '${Directory.current.path}/../..';
26
- String get _repoEntry => '$_root/cloud/web-client/runner/node-entry.ts';
27
- String get _deployJson =>
28
- '$_root/bench/scale/fixtures/estate-birth/build/estate-birth.law.usdz';
29
- String get _otherLawUsdz =>
30
- '$_root/bench/scale/fixtures/surfaced/build/surfaced.law.usdz';
31
- String get _runtimeDir =>
32
- Platform.environment['NOMOS_DART_RUNTIME'] ??
33
- Platform.environment['NOMOS_OFFLINE_RUNTIME'] ??
34
- '${Platform.environment['HOME'] ?? ''}/.holon/runtime';
35
-
36
- const _workspace = 'estate-birth';
37
- const _owner = 'user:session-bound-owner';
38
-
39
- String? _missingPrereq() {
40
- if (!File(_repoEntry).existsSync())
41
- return 'in-repo runner not found at $_repoEntry';
42
- if (!File(_deployJson).existsSync() || !File(_otherLawUsdz).existsSync()) {
43
- return 'compile the fixtures: (cd bench/scale/fixtures/estate-birth && node ../../../../dsl/compile_package.mjs); '
44
- '(cd bench/scale/fixtures/surfaced && node ../../../../dsl/compile_package.mjs)';
45
- }
46
- if (!File('$_runtimeDir/holon-testmint.wasm').existsSync() ||
47
- !File('$_runtimeDir/bootstrap.law.usdz').existsSync() ||
48
- !File('$_runtimeDir/nomos.law.usdz').existsSync()) {
49
- return 'warm ~/.holon/runtime first (run any `githolon` command once)';
50
- }
51
- return null;
52
- }
53
-
54
- Future<NomosTestHarness> _harness() => NomosTestHarness.ephemeral(
55
- lawUsdzPaths: [_deployJson],
56
- nodeEntry: _repoEntry,
57
- runtimeDir: _runtimeDir,
58
- workspace: _workspace,
59
- );
60
-
61
- Future<NomosOfferOutcome> _birthEstate(
62
- HomeApplication application,
63
- NomosTestHarness harness, {
64
- String owner = _owner,
65
- }) {
66
- final facts = BirthEstateWorkspacePayload(
67
- owner: owner,
68
- frameworkHash: harness.frameworkHash!,
69
- lawHash: harness.lawHashes(harness.workspace).first,
70
- bornAt: DateTime.now().toUtc().toIso8601String(),
71
- );
72
- return nomosInternalHomeBirthEstateWorkspace(application, facts);
73
- }
74
-
75
- void main() {
76
- test('an installed domain missing a required member is a newer-client shape',
77
- () {
78
- expect(
79
- nmsInternalClientExpectsNewerInterface(
80
- domain: 'home',
81
- activeDomainKeys: const ['home', 'nomos'],
82
- missing: const ['CatalogueAccessIndexEntry.catalogueWorkspace'],
83
- incompatible: const [],
84
- ),
85
- isTrue,
86
- reason:
87
- 'the generated candidate must enter exact-history adoption instead of deployment diagnostics',
88
- );
89
- expect(
90
- nmsInternalClientExpectsNewerInterface(
91
- domain: 'home',
92
- activeDomainKeys: const ['catalogue', 'nomos'],
93
- missing: const ['home'],
94
- incompatible: const [],
95
- ),
96
- isFalse,
97
- reason: 'a genuinely absent domain keeps the not-deployed diagnosis',
98
- );
99
- });
100
-
101
- test(
102
- 'generated applications: mount → bind (preflight) → fixture birth → follow(ref) → '
103
- 'second application → typed record operation', () async {
104
- final skip = _missingPrereq();
105
- if (skip != null) {
106
- markTestSkipped(skip);
107
- return;
108
- }
109
- final harness = await _harness();
110
- try {
111
- // ENGINE + SESSION: the harness bridge IS the session handle pinned to the fixture workspace.
112
- final home = harness.session(harness.workspace);
113
-
114
- // BIND (ask 2/5): the async preflight — reachable, domain installed, shape-compatible.
115
- final homeApplication =
116
- await nomosInternalBindHomeApplication(home, _owner);
117
- expect(homeApplication.activity, isA<HomeActivity>());
118
-
119
- // This fixture predates businessBirth and intentionally keeps its kernel birth
120
- // primitive out of the generated tenant application. The raw offer is framework
121
- // setup; the generated application remains the only public business surface.
122
- final birth = await _birthEstate(homeApplication, harness);
123
- expect(birth.workspace, harness.workspace,
124
- reason:
125
- 'the birth offer landed in the SESSION workspace, no loose parent');
126
- expect(birth.gatewayVerdict, isNull,
127
- reason: 'the local offer lane, not the legacy relay');
128
- expect(birth.born, hasLength(1));
129
- expect(birth.birthOutcomes.first.status,
130
- NomosBirthOutcomeStatus.BIRTH_OUTCOME_STATUS_BORN);
131
-
132
- // FOLLOW THE REF (ask 8): NomosRef in, mounted session out — never a string pair.
133
- final estate = await harness.bridge.follow(birth.bornRefs.single,
134
- authorSecret: harness.deviceSecret(harness.workspace));
135
- expect(estate.workspace, birth.born.single);
136
-
137
- // SECOND CLIENT + a typed read AND a directive on it.
138
- final estateApplication =
139
- await nomosInternalBindEstateApplication(estate, _owner);
140
- final rows =
141
- await estateApplication.estateOwners.estatesByOwner(owner: _owner);
142
- expect(rows, hasLength(1),
143
- reason: 'the child genesis seed reads back typed');
144
- final seeded = rows.single;
145
- // A directive on the second client: re-ensure the singleton with the SAME seeded values
146
- // (`.ensures` — idempotent; the squat invariant re-accepts its own binding).
147
- await estateApplication.estateOwners
148
- .seedEstateWorkspace(SeedEstateWorkspacePayload(
149
- owner: seeded.owner!,
150
- estateName: seeded.estateName!,
151
- bornAt: seeded.bornAt!,
152
- ));
153
- final afterReseed =
154
- await estateApplication.estateOwners.estatesByOwner(owner: _owner);
155
- expect(afterReseed, hasLength(1));
156
-
157
- // ask 9: the harness diagnostic names the installed domains.
158
- await harness.assertDomainInstalled(
159
- workspace: estate.workspace, domain: 'estate');
160
- } finally {
161
- await harness.dispose();
162
- }
163
- }, timeout: const Timeout(Duration(minutes: 4)));
164
-
165
- test(
166
- 'session.watchPendingConflicts() EMITS (the 0.48.0 regression: the session-level stream '
167
- 'registered on an object with no message loop and never emitted)',
168
- () async {
169
- final skip = _missingPrereq();
170
- if (skip != null) {
171
- markTestSkipped(skip);
172
- return;
173
- }
174
- final harness = await _harness();
175
- try {
176
- final session = harness.session(harness.workspace);
177
- // Subscribe FIRST on the SESSION (the co2 shape: a session-bound generated client's
178
- // conflict stream), then author any write so a watch tick fires. The broken delegation
179
- // registered the sub on the session's own dead controller registry — the stream NEVER
180
- // emitted, regardless of ticks. The fix delegates to the parent plane like every other
181
- // reactive read; the first tick must deliver a snapshot (empty — no Surfaced law here).
182
- final first = session.watchPendingConflicts().first;
183
- final application =
184
- await nomosInternalBindHomeApplication(session, _owner);
185
- await _birthEstate(application, harness);
186
- final rows = await first.timeout(const Duration(seconds: 30));
187
- expect(rows, isEmpty,
188
- reason:
189
- 'no Surfaced law in this fixture — the point is the stream EMITS at all');
190
- } finally {
191
- await harness.dispose();
192
- }
193
- }, timeout: const Timeout(Duration(minutes: 4)));
194
-
195
- test(
196
- 'bind on a deliberately WRONG session throws DomainClientSessionMismatch with every field',
197
- () async {
198
- final skip = _missingPrereq();
199
- if (skip != null) {
200
- markTestSkipped(skip);
201
- return;
202
- }
203
- // TWO workspaces, TWO different laws, ONE plane — binding HomeApplication to the docs
204
- // workspace is the deliberate wrong-session case (wrong-package-mounted).
205
- final harness = await NomosTestHarness.cluster(
206
- nodeEntry: _repoEntry,
207
- runtimeDir: _runtimeDir,
208
- workspaces: {
209
- _workspace: [_deployJson],
210
- 'docs-ws': [_otherLawUsdz],
211
- },
212
- );
213
- try {
214
- final wrong = harness.session('docs-ws');
215
- Object? thrown;
216
- try {
217
- await nomosInternalBindHomeApplication(wrong, null);
218
- } catch (e) {
219
- thrown = e;
220
- }
221
- expect(thrown, isA<DomainClientSessionMismatch>(),
222
- reason:
223
- 'the mismatch fires at CONSTRUCTION, not two clicks into the app');
224
- final m = thrown! as DomainClientSessionMismatch;
225
- expect(m.sessionId, 'docs-ws');
226
- expect(m.sessionWorkspace, 'docs-ws');
227
- expect(m.expectedDomainKey, 'home');
228
- expect(m.expectedDomainHash, isNotEmpty);
229
- expect(m.expectedInterfaceHash, isNotEmpty);
230
- expect(m.activeDomainKeys, isNot(contains(m.expectedDomainKey)));
231
- expect(m.cause, SessionMismatchCause.wrongPackageMounted,
232
- reason: 'the docs workspace RUNS law — just not this domain');
233
- expect(m.hint, isNotEmpty);
234
- expect(m.toString(), contains(m.expectedDomainKey));
235
-
236
- // The RIGHT session still binds (the plane is unharmed).
237
- await nomosInternalBindHomeApplication(
238
- harness.session(harness.workspace), null);
239
-
240
- // The other generated application gets the same typed refusal without exposing
241
- // its private interface descriptor.
242
- await expectLater(nomosInternalBindEstateApplication(wrong, null),
243
- throwsA(isA<DomainClientSessionMismatch>()));
244
- } finally {
245
- await harness.dispose();
246
- }
247
- }, timeout: const Timeout(Duration(minutes: 4)));
248
-
249
- test(
250
- 'a framework-test dispatch naming an UNINSTALLED domain surfaces as '
251
- 'DomainNotInstalledForSession with context', () async {
252
- final skip = _missingPrereq();
253
- if (skip != null) {
254
- markTestSkipped(skip);
255
- return;
256
- }
257
- final harness = await _harness();
258
- try {
259
- final session = harness.session(harness.workspace);
260
- Object? thrown;
261
- try {
262
- await session.offerOutcome(
263
- domain: 'not_installed_domain',
264
- directiveId: 'doIt',
265
- payload: const {});
266
- } catch (e) {
267
- thrown = e;
268
- }
269
- expect(thrown, isA<DomainNotInstalledForSession>());
270
- final err = thrown! as DomainNotInstalledForSession;
271
- expect(err.expectedDomainKey, 'not_installed_domain');
272
- expect(err.sessionWorkspace, harness.workspace);
273
- expect(err.requestedWorkspace, harness.workspace);
274
- expect(err.activeDomainKeys, contains('home'),
275
- reason: 'the error NAMES what the workspace actually runs');
276
- expect(err.possibleCauses,
277
- DomainNotInstalledForSession.defaultPossibleCauses);
278
- expect(err.underlying.toString(),
279
- contains('no active installed law declares domain'));
280
- expect(err.toString(), contains('Possible causes'));
281
- } finally {
282
- await harness.dispose();
283
- }
284
- }, timeout: const Timeout(Duration(minutes: 4)));
285
- }
@@ -1,80 +0,0 @@
1
- // THE STALE-BAKED-BUNDLE CHECK (the countermeasure to the co2 incidents where Flutter's build
2
- // cache silently kept an old nomos-runner.js across a correct pub upgrade). ready carries the
3
- // bundle's self-stamped version; the bridge refuses stale/pre-stamp bundles LOUDLY at boot.
4
- import 'dart:async';
5
-
6
- import 'package:nomos_client/src/nms_conformance_runtime.dart';
7
- import 'package:nomos_types/nomos_kernel_protocol.dart' as protocol;
8
- import 'package:test/test.dart';
9
-
10
- class _StampedRunner implements BridgeTransport {
11
- _StampedRunner(this.stamp) {
12
- scheduleMicrotask(() => _incoming.add({
13
- 'v': kWebviewBridgeVersion,
14
- 'event': 'ready',
15
- if (stamp != null) 'bundleVersion': stamp,
16
- }));
17
- }
18
- final String? stamp;
19
- final _incoming = StreamController<Map<String, Object?>>.broadcast();
20
- @override
21
- Stream<Map<String, Object?>> get messages => _incoming.stream;
22
- @override
23
- Future<protocol.RuntimeResponse> invokeRuntime(
24
- protocol.RuntimeRequest request,
25
- ) async =>
26
- protocol.RuntimeResponse(
27
- protocolVersion: 2,
28
- requestId: request.requestId,
29
- realmClosed: protocol.RealmClosed(),
30
- );
31
- @override
32
- void send(Map<String, Object?> message) {}
33
- }
34
-
35
- void main() {
36
- test(
37
- 'a PRE-STAMP bundle (no bundleVersion) fails ready with StaleRunnerBundle',
38
- () async {
39
- final b = NomosBridge(_StampedRunner(null));
40
- await expectLater(b.ready, throwsA(isA<StaleRunnerBundle>()));
41
- });
42
-
43
- test(
44
- 'an OLDER stamp fails ready, and the error names found/expected + the remedy',
45
- () async {
46
- final b = NomosBridge(_StampedRunner('0.53.1'));
47
- Object? err;
48
- try {
49
- await b.ready;
50
- } catch (e) {
51
- err = e;
52
- }
53
- expect(err, isA<StaleRunnerBundle>());
54
- final s = err.toString();
55
- expect(s, contains('0.53.1'));
56
- expect(s, contains(kExpectedRunnerBundleVersion));
57
- expect(s, contains('flutter clean'));
58
- });
59
-
60
- test('the CURRENT stamp passes', () async {
61
- final b = NomosBridge(_StampedRunner(kExpectedRunnerBundleVersion));
62
- await b.ready; // completes
63
- });
64
-
65
- test('a NEWER stamp passes (forward-compatible)', () async {
66
- final b = NomosBridge(_StampedRunner('99.0.0'));
67
- await b.ready;
68
- });
69
-
70
- test('unbundled-dev (the in-repo source lane) always passes', () async {
71
- final b = NomosBridge(_StampedRunner('unbundled-dev'));
72
- await b.ready;
73
- });
74
-
75
- test('allowStaleRunnerBundle is the deliberate escape hatch', () async {
76
- final b =
77
- NomosBridge(_StampedRunner('0.1.0'), allowStaleRunnerBundle: true);
78
- await b.ready;
79
- });
80
- }