@githolon/dsl 0.108.7 → 0.110.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (307) hide show
  1. package/assets/operation-contract.wasm +0 -0
  2. package/check_package.mjs +12 -15
  3. package/compile_package.mjs +17 -18
  4. package/compile_proof.mjs +16 -1
  5. package/dart/CHANGELOG.md +76 -1
  6. package/dart/README.md +25 -2
  7. package/dart/lib/src/admission_decision.dart +41 -0
  8. package/dart/lib/src/application_framework_calls.dart +52 -2
  9. package/dart/lib/src/application_model_adoption.dart +187 -0
  10. package/dart/lib/src/application_status.dart +73 -0
  11. package/dart/lib/src/console_enrolment.dart +271 -0
  12. package/dart/lib/src/console_http_io.dart +26 -0
  13. package/dart/lib/src/console_http_stub.dart +7 -0
  14. package/dart/lib/src/dev_cloud.dart +69 -22
  15. package/dart/lib/src/generated_call.dart +83 -23
  16. package/dart/lib/src/kernel_primitives.dart +119 -0
  17. package/dart/lib/src/nms_conformance_runtime.dart +1 -1
  18. package/dart/lib/src/nms_generated_runtime.dart +32 -10
  19. package/dart/lib/src/nms_test_environment.dart +1 -1
  20. package/dart/lib/src/node_runner_transport.dart +41 -46
  21. package/dart/lib/src/observed_session_directory.dart +70 -0
  22. package/dart/lib/src/operation_receipts.dart +112 -0
  23. package/dart/lib/src/peer_application_streams.dart +103 -0
  24. package/dart/lib/src/reception/dart_reception.dart +4280 -0
  25. package/dart/lib/src/reception/event_desk.dart +211 -0
  26. package/dart/lib/src/reception/extremum_read.dart +46 -0
  27. package/dart/lib/src/reception/local_copies.dart +371 -0
  28. package/dart/lib/src/reception/peer_office_connection.dart +11 -0
  29. package/dart/lib/src/reception/progress_desk.dart +267 -0
  30. package/dart/lib/src/reception/reception_contract.dart +11 -0
  31. package/dart/lib/src/reception/reception_session.dart +284 -0
  32. package/dart/lib/src/reception/sync_diagnostics.dart +26 -0
  33. package/dart/lib/src/reception/workspace_preparation_report.dart +126 -0
  34. package/dart/lib/src/replica_readiness.dart +123 -0
  35. package/dart/lib/src/runner/node-entry.mjs +23905 -15774
  36. package/dart/lib/src/runtime_v2_gateway.dart +56 -3
  37. package/dart/lib/src/runtime_v2_transport.dart +544 -3
  38. package/dart/lib/src/session_bound.dart +200 -311
  39. package/dart/lib/src/signing_identity_kernel.dart +84 -0
  40. package/dart/lib/src/sync_status_projection.dart +548 -0
  41. package/dart/lib/src/sync_status_reducer.dart +170 -0
  42. package/dart/lib/src/test_harness.dart +809 -1153
  43. package/dart/lib/src/testing/test_custody.dart +66 -0
  44. package/dart/lib/src/testing/test_peer.dart +328 -0
  45. package/dart/lib/src/typed_watch_registry.dart +169 -0
  46. package/dart/lib/src/workspace_open_progress.dart +27 -0
  47. package/dart/pubspec.lock +24 -1
  48. package/dart/pubspec.yaml +7 -2
  49. package/dart/pubspec_overrides.yaml +2 -0
  50. package/dart/test/admission_decision_test.dart +48 -0
  51. package/dart/test/background_model_adoption_test.dart +228 -0
  52. package/dart/test/bundle_version_pairing_test.dart +4 -4
  53. package/dart/test/child_authentication_repair_test.dart +359 -0
  54. package/dart/test/cloud_bound_local_shell_test.dart +119 -0
  55. package/dart/test/console_enrolment_refusal_test.dart +52 -0
  56. package/dart/test/console_enrolment_test.dart +227 -0
  57. package/dart/test/errors_test.dart +5 -5
  58. package/dart/test/event_plane_seam_test.dart +50 -164
  59. package/dart/test/extremum_read_test.dart +58 -0
  60. package/dart/test/fixtures/wedge/wedge-entry.mjs +3 -21
  61. package/dart/test/generated_query_test.dart +32 -0
  62. package/dart/test/harness_phase_timeout_test.dart +18 -23
  63. package/dart/test/kernel_author_after_read_test.dart +242 -0
  64. package/dart/test/kernel_fence_test.dart +137 -0
  65. package/dart/test/local_copies_test.dart +222 -0
  66. package/dart/test/model_adoption_test.dart +198 -0
  67. package/dart/test/node_peer_local_custody_test.dart +153 -0
  68. package/dart/test/offer_authentication_proof_test.dart +352 -52
  69. package/dart/test/operation_compatibility_test.dart +151 -0
  70. package/dart/test/platform_credential_effect_test.dart +386 -0
  71. package/dart/test/receiving_group_open_test.dart +213 -0
  72. package/dart/test/reception/workspace_preparation_report_test.dart +103 -0
  73. package/dart/test/reception_span_trace_test.dart +23 -0
  74. package/dart/test/replica_readiness_test.dart +156 -0
  75. package/dart/test/runtime_projections_test.dart +92 -0
  76. package/dart/test/runtime_v2_gateway_test.dart +131 -0
  77. package/dart/test/signing_identity_kernel_test.dart +75 -0
  78. package/dart/test/sync_status_preparation_report_test.dart +29 -0
  79. package/dart/test/sync_status_reducer_test.dart +419 -0
  80. package/dart/test/test_harness_test.dart +71 -95
  81. package/dart/test/typed_query_watch_test.dart +170 -0
  82. package/dart/test/typed_watch_registry_test.dart +249 -0
  83. package/dart_lints/README.md +18 -0
  84. package/dart_lints/lib/nomos_lints.dart +70 -0
  85. package/dart_lints/pubspec.lock +580 -0
  86. package/dart_lints/pubspec.yaml +12 -0
  87. package/dart_lints/test/reference_identity_test.dart +75 -0
  88. package/dart_types/CHANGELOG.md +18 -0
  89. package/dart_types/lib/nomos_kernel_protocol.dart +21 -1
  90. package/dart_types/lib/nomos_types.dart +9 -1
  91. package/dart_types/lib/src/admission_decision.dart +37 -0
  92. package/dart_types/lib/src/aggregate_meta.dart +1 -1
  93. package/dart_types/lib/src/approved_model.dart +65 -0
  94. package/dart_types/lib/src/custody.dart +10 -18
  95. package/dart_types/lib/src/error_info.dart +4 -4
  96. package/dart_types/lib/src/errors.dart +29 -29
  97. package/dart_types/lib/src/foreign_ref.dart +62 -33
  98. package/dart_types/lib/src/local_work_rejected.dart +3 -3
  99. package/dart_types/lib/src/nomos_ref.dart +3 -1
  100. package/dart_types/lib/src/principal.dart +2 -2
  101. package/dart_types/lib/src/proto/google/protobuf/any.pb.dart +163 -0
  102. package/dart_types/lib/src/proto/google/protobuf/any.pbenum.dart +11 -0
  103. package/dart_types/lib/src/proto/nomos/discovery/v1/workspace_placement.pb.dart +137 -0
  104. package/dart_types/lib/src/proto/nomos/discovery/v1/workspace_placement.pbenum.dart +11 -0
  105. package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pb.dart +20721 -10433
  106. package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pbenum.dart +555 -27
  107. package/dart_types/lib/src/proto/nomos/runtime/v2/application_desk.pb.dart +387 -0
  108. package/dart_types/lib/src/proto/nomos/runtime/v2/application_desk.pbenum.dart +46 -0
  109. package/dart_types/lib/src/proto/nomos/runtime/v2/application_readiness_desk.pb.dart +295 -0
  110. package/dart_types/lib/src/proto/nomos/runtime/v2/application_readiness_desk.pbenum.dart +139 -0
  111. package/dart_types/lib/src/proto/nomos/runtime/v2/authentication_desk.pb.dart +269 -0
  112. package/dart_types/lib/src/proto/nomos/runtime/v2/authentication_desk.pbenum.dart +103 -0
  113. package/dart_types/lib/src/proto/nomos/runtime/v2/compatibility_desk.pb.dart +417 -0
  114. package/dart_types/lib/src/proto/nomos/runtime/v2/compatibility_desk.pbenum.dart +62 -0
  115. package/dart_types/lib/src/proto/nomos/runtime/v2/correspondence_desk.pb.dart +9968 -0
  116. package/dart_types/lib/src/proto/nomos/runtime/v2/correspondence_desk.pbenum.dart +133 -0
  117. package/dart_types/lib/src/proto/nomos/runtime/v2/credentials_desk.pb.dart +204 -0
  118. package/dart_types/lib/src/proto/nomos/runtime/v2/credentials_desk.pbenum.dart +54 -0
  119. package/dart_types/lib/src/proto/nomos/runtime/v2/custody_desk.pb.dart +1550 -0
  120. package/dart_types/lib/src/proto/nomos/runtime/v2/custody_desk.pbenum.dart +11 -0
  121. package/dart_types/lib/src/proto/nomos/runtime/v2/framework.pb.dart +710 -0
  122. package/dart_types/lib/src/proto/nomos/runtime/v2/framework.pbenum.dart +11 -0
  123. package/dart_types/lib/src/proto/nomos/runtime/v2/identity_desk.pb.dart +845 -0
  124. package/dart_types/lib/src/proto/nomos/runtime/v2/identity_desk.pbenum.dart +11 -0
  125. package/dart_types/lib/src/proto/nomos/runtime/v2/interaction_desk.pb.dart +198 -0
  126. package/dart_types/lib/src/proto/nomos/runtime/v2/interaction_desk.pbenum.dart +11 -0
  127. package/dart_types/lib/src/proto/nomos/runtime/v2/law_desk.pb.dart +369 -0
  128. package/dart_types/lib/src/proto/nomos/runtime/v2/law_desk.pbenum.dart +11 -0
  129. package/dart_types/lib/src/proto/nomos/runtime/v2/maintenance_desk.pb.dart +609 -0
  130. package/dart_types/lib/src/proto/nomos/runtime/v2/maintenance_desk.pbenum.dart +65 -0
  131. package/dart_types/lib/src/proto/nomos/runtime/v2/model_adoption_desk.pb.dart +358 -0
  132. package/dart_types/lib/src/proto/nomos/runtime/v2/model_adoption_desk.pbenum.dart +100 -0
  133. package/dart_types/lib/src/proto/nomos/runtime/v2/observability_desk.pb.dart +2231 -0
  134. package/dart_types/lib/src/proto/nomos/runtime/v2/observability_desk.pbenum.dart +271 -0
  135. package/dart_types/lib/src/proto/nomos/runtime/v2/placement_desk.pb.dart +1286 -0
  136. package/dart_types/lib/src/proto/nomos/runtime/v2/placement_desk.pbenum.dart +11 -0
  137. package/dart_types/lib/src/proto/nomos/runtime/v2/receiving_group_desk.pb.dart +636 -0
  138. package/dart_types/lib/src/proto/nomos/runtime/v2/receiving_group_desk.pbenum.dart +116 -0
  139. package/dart_types/lib/src/proto/nomos/runtime/v2/records_desk.pb.dart +1637 -0
  140. package/dart_types/lib/src/proto/nomos/runtime/v2/records_desk.pbenum.dart +175 -0
  141. package/dart_types/lib/src/proto/nomos/runtime/v2/recovery_desk.pb.dart +1269 -0
  142. package/dart_types/lib/src/proto/nomos/runtime/v2/recovery_desk.pbenum.dart +129 -0
  143. package/dart_types/lib/src/proto/nomos/runtime/v2/residency_desk.pb.dart +2782 -0
  144. package/dart_types/lib/src/proto/nomos/runtime/v2/residency_desk.pbenum.dart +97 -0
  145. package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pb.dart +2232 -8627
  146. package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pbenum.dart +0 -358
  147. package/dart_types/lib/src/proto/nomos/runtime/v2/sealing_desk.pb.dart +1639 -0
  148. package/dart_types/lib/src/proto/nomos/runtime/v2/sealing_desk.pbenum.dart +46 -0
  149. package/dart_types/lib/src/runtime_outcome.dart +133 -0
  150. package/dart_types/lib/src/subscriptions.dart +116 -23
  151. package/dart_types/pubspec.yaml +1 -1
  152. package/dart_types/test/extremum_subscriptions_test.dart +40 -0
  153. package/dart_types/test/foreign_ref_resolution_test.dart +75 -0
  154. package/dart_types/test/nomos_ref_address_test.dart +25 -0
  155. package/dart_types/test/ordered_subscriptions_test.dart +34 -0
  156. package/operation_contract_check.mjs +24 -0
  157. package/package.json +11 -6
  158. package/src/aggregate.ts +70 -10
  159. package/src/application_topology.ts +18 -11
  160. package/src/attested.ts +3 -0
  161. package/src/attested_core.ts +46 -3
  162. package/src/birth_meter_ensure.ts +19 -7
  163. package/src/births.ts +29 -4
  164. package/src/build_package.ts +140 -13
  165. package/src/business_birth.ts +181 -4
  166. package/src/codegen_call_proto.ts +1274 -0
  167. package/src/codegen_call_usda.ts +49 -6
  168. package/src/codegen_dart.ts +79 -44
  169. package/src/codegen_dart_client.ts +458 -800
  170. package/src/{codegen_dart_application.ts → codegen_dart_facade.ts} +331 -582
  171. package/src/codegen_dart_framework_calls.ts +320 -37
  172. package/src/codegen_dart_indexed_variant.ts +159 -0
  173. package/src/codegen_dart_scenario.ts +42 -13
  174. package/src/codegen_proof.ts +3 -3
  175. package/src/codegen_provider_dart.ts +5 -0
  176. package/src/codegen_query_proto.ts +158 -0
  177. package/src/codegen_refusal.ts +189 -0
  178. package/src/codegen_result_proto.ts +931 -0
  179. package/src/codegen_result_usda.ts +4 -0
  180. package/src/codegen_ts.ts +464 -616
  181. package/src/codegen_workspace_access.ts +105 -0
  182. package/src/compatibility_graph.ts +759 -0
  183. package/src/compatibility_usda.ts +264 -0
  184. package/src/compile_package_main.ts +1994 -1189
  185. package/src/custody_placement.ts +156 -0
  186. package/src/custody_placement_usda.ts +91 -0
  187. package/src/decl_shapes.ts +21 -2
  188. package/src/describe_model.ts +1 -0
  189. package/src/directive.ts +59 -2
  190. package/src/drivers.ts +51 -0
  191. package/src/engine_entry.ts +52 -8
  192. package/src/evolve_preview.ts +11 -4
  193. package/src/exists.ts +2 -0
  194. package/src/fields.ts +75 -11
  195. package/src/flow_gate.ts +2 -1
  196. package/src/framework/application_home.ts +170 -18
  197. package/src/framework/attested_receipts.ts +8 -3
  198. package/src/framework/auth_provider_law.ts +169 -9
  199. package/src/framework/birth_certificate_law.ts +4 -0
  200. package/src/framework/capability.ts +34 -3
  201. package/src/framework/child_authentication.ts +346 -0
  202. package/src/framework/console_governance.ts +295 -0
  203. package/src/framework/delegated_roles.ts +301 -0
  204. package/src/framework/domain_lifecycle.ts +26 -13
  205. package/src/framework/founding_genesis.ts +193 -0
  206. package/src/framework/framework_aggregates.ts +1 -1
  207. package/src/framework/genesis.ts +6 -1
  208. package/src/framework/governance_relations.ts +19 -0
  209. package/src/framework/home.ts +5 -734
  210. package/src/framework/legacy/child_auth_provider_epoch.ts +73 -0
  211. package/src/framework/model_authority_repair.ts +116 -0
  212. package/src/framework/model_authority_seed.ts +185 -0
  213. package/src/framework/model_transition.ts +211 -0
  214. package/src/framework/owned_custody.ts +1 -1
  215. package/src/framework/principal_enrollment.ts +302 -0
  216. package/src/framework/receiving_group.ts +857 -0
  217. package/src/framework/receiving_group_recovery.ts +314 -0
  218. package/src/framework/relations.ts +4 -8
  219. package/src/framework/signing_identity.ts +242 -95
  220. package/src/framework/source_roster.ts +11 -5
  221. package/src/framework/workspace_access.ts +149 -0
  222. package/src/framework/workspace_invariant.ts +73 -52
  223. package/src/framework/workspaces.ts +407 -40
  224. package/src/framework_call_definitions.ts +32 -3
  225. package/src/generated_client_bundle_boundary.ts +97 -0
  226. package/src/generated_client_names.ts +1 -0
  227. package/src/identity_usda.ts +27 -0
  228. package/src/index.ts +183 -12
  229. package/src/indexed_variant.ts +83 -0
  230. package/src/intent.ts +173 -45
  231. package/src/law_check.ts +8 -5
  232. package/src/law_dependency_index.ts +231 -0
  233. package/src/law_graph.ts +508 -71
  234. package/src/law_graph_usda.ts +170 -24
  235. package/src/law_identity.ts +119 -81
  236. package/src/law_source_map.ts +4 -1
  237. package/src/law_units.ts +498 -0
  238. package/src/law_value_type.ts +7 -3
  239. package/src/member_authentication.ts +302 -0
  240. package/src/null_meta.ts +1 -1
  241. package/src/openusd_compiled_layer.ts +132 -0
  242. package/src/operation_contract_check.ts +31 -0
  243. package/src/ordered_read.ts +2 -1
  244. package/src/package_config.ts +33 -12
  245. package/src/package_dependencies.ts +1 -0
  246. package/src/plan_source_slice.ts +30 -1
  247. package/src/protobuf_field_number.ts +36 -0
  248. package/src/provenance_wire.ts +6 -0
  249. package/src/query.ts +2 -1
  250. package/src/read.ts +50 -0
  251. package/src/relation.ts +4 -1
  252. package/src/relation_schema.ts +15 -2
  253. package/src/report.ts +2 -2
  254. package/src/sqlite_computation_bundle.ts +78 -0
  255. package/src/sqlite_computed.ts +102 -0
  256. package/src/sqlite_counts.ts +154 -0
  257. package/src/sqlite_layout.ts +823 -0
  258. package/src/sqlite_reads.ts +275 -0
  259. package/src/sqlite_samples.ts +185 -0
  260. package/src/stable_id_identity_bridge.ts +1 -1
  261. package/src/stable_ids_for_module.ts +16 -4
  262. package/src/test_call_usda.ts +6 -6
  263. package/src/usda_relationship_integrity.ts +20 -3
  264. package/src/usda_text.ts +21 -1
  265. package/src/value_object.ts +81 -11
  266. package/src/wire.ts +22 -0
  267. package/src/wire_encode.ts +227 -20
  268. package/src/workspace_sharding.ts +15 -6
  269. package/src/workspace_sharing.ts +51 -49
  270. package/src/zod_introspection.ts +2 -0
  271. package/compat_package.mjs +0 -46
  272. package/dart/lib/src/home.dart +0 -15
  273. package/dart/lib/src/runner/offline-install.mjs +0 -15367
  274. package/dart/lib/src/source_trust.dart +0 -51
  275. package/dart/lib/src/webview_bridge.dart +0 -6540
  276. package/dart/lib/src/workspace_name.dart +0 -30
  277. package/dart/test/acquire_session_credentials_test.dart +0 -150
  278. package/dart/test/acquire_session_test.dart +0 -534
  279. package/dart/test/adv_realm_interference_test.dart +0 -600
  280. package/dart/test/cloud_bound_topology_test.dart +0 -168
  281. package/dart/test/cluster_births_test.dart +0 -202
  282. package/dart/test/cluster_device_keyed_acceptance_test.dart +0 -105
  283. package/dart/test/cluster_local_autosync_test.dart +0 -123
  284. package/dart/test/cluster_scale_test.dart +0 -122
  285. package/dart/test/compat_test.dart +0 -61
  286. package/dart/test/dlq_session_surface_test.dart +0 -222
  287. package/dart/test/first_app_gauntlet_test.dart +0 -386
  288. package/dart/test/fixtures/wedge/fake-install.mjs +0 -11
  289. package/dart/test/four_layer_nested_topology_test.dart +0 -290
  290. package/dart/test/home_parity_test.dart +0 -13
  291. package/dart/test/local_sync_inert_test.dart +0 -107
  292. package/dart/test/node_runner_transport_test.dart +0 -78
  293. package/dart/test/parent_signer_recovery_test.dart +0 -155
  294. package/dart/test/residency_refusal_test.dart +0 -49
  295. package/dart/test/sealing_client_test.dart +0 -181
  296. package/dart/test/session_bound_test.dart +0 -285
  297. package/dart/test/stale_bundle_test.dart +0 -80
  298. package/dart/test/vo_read_typing_test.dart +0 -131
  299. package/dart/test/watch_after_offer_stall_test.dart +0 -100
  300. package/dart/test/webview_bridge_test.dart +0 -1930
  301. package/dart/test/workspace_name_test.dart +0 -24
  302. package/runtime/generated-application-host.js +0 -22860
  303. package/src/codegen_query_usda.ts +0 -214
  304. package/src/compat_manifest.ts +0 -26
  305. package/src/compat_package_main.ts +0 -224
  306. package/src/shape_compat.ts +0 -352
  307. package/src/usd_state.ts +0 -505
@@ -0,0 +1,211 @@
1
+ import 'dart:async';
2
+
3
+ import 'package:nomos_types/nomos_kernel_protocol.dart' as nomos_protocol;
4
+ import 'package:nomos_types/nomos_types.dart'
5
+ show NomosCustodyEvent, NomosLocalWorkRejectedEvent;
6
+
7
+ import '../application_model_adoption.dart' show NomosModelAdoptionProgress;
8
+ import 'local_copies.dart' show NomosPreservedLocalCopy;
9
+ import '../sync_status_projection.dart' show NmsSyncStatusProjection;
10
+ import '../typed_watch_registry.dart' show NmsTypedWatchRegistry;
11
+ import 'progress_desk.dart' show ReceptionProgressDesk;
12
+ import 'progress_desk.dart' show KernelProgress;
13
+ import 'workspace_preparation_report.dart'
14
+ show WorkspacePreparationReport, WorkspacePreparationStep;
15
+
16
+ /// Language-native event and presentation state for one Reception lifetime.
17
+ ///
18
+ /// This desk observes typed Peer Office events. It does not decide custody,
19
+ /// admission, placement, sync policy or application law. Workspace session
20
+ /// views share this exact object; they never allocate a second event plane.
21
+ final class ReceptionEventDesk {
22
+ ReceptionEventDesk() {
23
+ _syncStatusChanges = syncStatuses.changes.listen((_) => _notifyCopies());
24
+ }
25
+
26
+ late final StreamSubscription<void> _syncStatusChanges;
27
+ final StreamController<void> _copyChanges =
28
+ StreamController<void>.broadcast();
29
+ final Map<String, WorkspacePreparationReport> _preparation = {};
30
+ final StreamController<nomos_protocol.RuntimeEvent> _sync =
31
+ StreamController<nomos_protocol.RuntimeEvent>.broadcast();
32
+ final StreamController<NomosCustodyEvent> _custody =
33
+ StreamController<NomosCustodyEvent>.broadcast();
34
+ final StreamController<NomosLocalWorkRejectedEvent> _localWorkRejected =
35
+ StreamController<NomosLocalWorkRejectedEvent>.broadcast();
36
+ final StreamController<nomos_protocol.ReceivingGroupConvergence>
37
+ _receivingGroupConvergence =
38
+ StreamController<nomos_protocol.ReceivingGroupConvergence>.broadcast();
39
+ final StreamController<NomosModelAdoptionProgress> _modelAdoption =
40
+ StreamController<NomosModelAdoptionProgress>.broadcast();
41
+ final StreamController<NomosPreservedLocalCopy> _preserved =
42
+ StreamController<NomosPreservedLocalCopy>.broadcast();
43
+ final List<NomosPreservedLocalCopy> _preservedLog = [];
44
+ final StreamController<nomos_protocol.ForeignPlacementIgnored>
45
+ _foreignPlacements =
46
+ StreamController<nomos_protocol.ForeignPlacementIgnored>.broadcast();
47
+ final Completer<void> _ready = Completer<void>();
48
+
49
+ final ReceptionProgressDesk progress = ReceptionProgressDesk();
50
+ final NmsSyncStatusProjection syncStatuses = NmsSyncStatusProjection();
51
+ late final NmsTypedWatchRegistry typedWatches =
52
+ NmsTypedWatchRegistry(synced: workspacesSynced);
53
+
54
+ Future<void> get ready => _ready.future;
55
+ Stream<nomos_protocol.RuntimeEvent> get syncEvents => _sync.stream;
56
+ Stream<void> get copyChanges => _copyChanges.stream;
57
+ WorkspacePreparationReport? preparationFor(String workspace) =>
58
+ _preparation[workspace];
59
+
60
+ void observeMaintenance(nomos_protocol.ReadMaintenanceProgress progress) {
61
+ final previous = _preparation[progress.workspace];
62
+ final next = WorkspacePreparationReport.fromMaintenance(
63
+ progress,
64
+ previous: previous,
65
+ );
66
+ _preparation[progress.workspace] = next;
67
+ if (previous?.step != next.step ||
68
+ previous?.active != next.active ||
69
+ previous?.retrying != next.retrying ||
70
+ previous?.sqliteCurrent != next.sqliteCurrent ||
71
+ previous?.gitFrontier != next.gitFrontier ||
72
+ previous?.readFrontier != next.readFrontier ||
73
+ previous?.sqliteFrontier != next.sqliteFrontier) {
74
+ _notifyCopies();
75
+ }
76
+ _updatePreparationCounts();
77
+ }
78
+
79
+ void observeRestore(String workspace, KernelProgress progress) {
80
+ final previous = _preparation[workspace];
81
+ final next = WorkspacePreparationReport.fromRestore(
82
+ progress,
83
+ );
84
+ _preparation[workspace] = next;
85
+ if (previous?.step != next.step ||
86
+ previous?.active != next.active ||
87
+ previous?.gitFrontier != next.gitFrontier ||
88
+ previous?.readFrontier != next.readFrontier ||
89
+ previous?.sqliteFrontier != next.sqliteFrontier) {
90
+ _notifyCopies();
91
+ }
92
+ _updatePreparationCounts();
93
+ }
94
+
95
+ void _updatePreparationCounts() {
96
+ final active =
97
+ _preparation.values.where((report) => report.active).toList();
98
+ syncStatuses.updatePreparationCounts(
99
+ active.length,
100
+ _preparation.values.where((report) => report.retrying).length,
101
+ activity: active.length == 1
102
+ ? switch (active.single.step) {
103
+ WorkspacePreparationStep.restoringHistory =>
104
+ 'Checking saved workspace history',
105
+ WorkspacePreparationStep.installingLaw =>
106
+ 'Installing workspace rules',
107
+ WorkspacePreparationStep.preparingReads =>
108
+ 'Getting workspace data ready',
109
+ WorkspacePreparationStep.preparingWrites =>
110
+ 'Getting workspace actions ready',
111
+ WorkspacePreparationStep.preparingCustody =>
112
+ 'Preparing saved workspace data',
113
+ _ => 'Preparing a workspace',
114
+ }
115
+ : null,
116
+ );
117
+ }
118
+
119
+ void _notifyCopies() {
120
+ if (!_copyChanges.isClosed) _copyChanges.add(null);
121
+ }
122
+
123
+ /// Each workspace whose sync round just completed: the moment a copy that
124
+ /// answered "not ready yet" may be ready to read.
125
+ Stream<String> get workspacesSynced => _sync.stream
126
+ .where((event) => event.hasSyncCompleted())
127
+ .map((event) => event.syncCompleted.result.workspace);
128
+ Stream<NomosCustodyEvent> get custodyEvents => _custody.stream;
129
+ Stream<NomosLocalWorkRejectedEvent> get localWorkRejectedEvents =>
130
+ _localWorkRejected.stream;
131
+ Stream<nomos_protocol.ReceivingGroupConvergence>
132
+ get receivingGroupConvergence => _receivingGroupConvergence.stream;
133
+
134
+ /// The model-adoption desk's observations for every workspace on this plane.
135
+ Stream<NomosModelAdoptionProgress> get modelAdoption => _modelAdoption.stream;
136
+
137
+ /// Diagnostics log: every local copy this lifetime saw replaced and kept aside.
138
+ Stream<NomosPreservedLocalCopy> get localCopiesPreserved => _preserved.stream;
139
+
140
+ /// The most recent preservations, oldest first (bounded).
141
+ List<NomosPreservedLocalCopy> get recentLocalCopiesPreserved =>
142
+ List.unmodifiable(_preservedLog);
143
+
144
+ /// Diagnostics log: a placement naming an origin outside this host's configured
145
+ /// providers was ignored (never contacted).
146
+ Stream<nomos_protocol.ForeignPlacementIgnored> get foreignPlacementsIgnored =>
147
+ _foreignPlacements.stream;
148
+
149
+ void publishForeignPlacementIgnored(
150
+ nomos_protocol.ForeignPlacementIgnored ignored) {
151
+ if (!_foreignPlacements.isClosed) _foreignPlacements.add(ignored);
152
+ }
153
+
154
+ void publishLocalCopyPreserved(NomosPreservedLocalCopy copy) {
155
+ _preservedLog.add(copy);
156
+ if (_preservedLog.length > 64) _preservedLog.removeAt(0);
157
+ if (!_preserved.isClosed) _preserved.add(copy);
158
+ }
159
+
160
+ void publishModelAdoption(NomosModelAdoptionProgress progress) {
161
+ if (!_modelAdoption.isClosed) _modelAdoption.add(progress);
162
+ }
163
+
164
+ void markReady() {
165
+ if (!_ready.isCompleted) _ready.complete();
166
+ }
167
+
168
+ void failReady(Object error, [StackTrace? stackTrace]) {
169
+ if (_ready.isCompleted) return;
170
+ stackTrace == null
171
+ ? _ready.completeError(error)
172
+ : _ready.completeError(error, stackTrace);
173
+ }
174
+
175
+ void publishSync(nomos_protocol.RuntimeEvent event) {
176
+ if (!_sync.isClosed) _sync.add(event);
177
+ }
178
+
179
+ void publishCustody(NomosCustodyEvent event) {
180
+ if (!_custody.isClosed) _custody.add(event);
181
+ }
182
+
183
+ void publishLocalWorkRejected(NomosLocalWorkRejectedEvent event) {
184
+ if (!_localWorkRejected.isClosed) _localWorkRejected.add(event);
185
+ }
186
+
187
+ void publishReceivingGroupConvergence(
188
+ nomos_protocol.ReceivingGroupConvergence event,
189
+ ) {
190
+ if (!_receivingGroupConvergence.isClosed) {
191
+ _receivingGroupConvergence.add(event);
192
+ }
193
+ }
194
+
195
+ Future<void> close() async {
196
+ await _syncStatusChanges.cancel();
197
+ if (!_copyChanges.isClosed) await _copyChanges.close();
198
+ await typedWatches.close();
199
+ if (!_sync.isClosed) await _sync.close();
200
+ if (!_custody.isClosed) await _custody.close();
201
+ if (!_localWorkRejected.isClosed) await _localWorkRejected.close();
202
+ if (!_receivingGroupConvergence.isClosed) {
203
+ await _receivingGroupConvergence.close();
204
+ }
205
+ if (!_modelAdoption.isClosed) await _modelAdoption.close();
206
+ if (!_preserved.isClosed) await _preserved.close();
207
+ if (!_foreignPlacements.isClosed) await _foreignPlacements.close();
208
+ await progress.close();
209
+ await syncStatuses.close();
210
+ }
211
+ }
@@ -0,0 +1,46 @@
1
+ import 'package:nomos_types/nomos_kernel_protocol.dart' as protocol;
2
+
3
+ /// Encode one fixed framework read; the kernel resolves law and read authority.
4
+ protocol.QueryRequest extremumQuery(String id, String kind, String? groupKey) {
5
+ if (id.isEmpty || (kind != 'min' && kind != 'max')) {
6
+ throw ArgumentError('A declared extremum needs an id and min/max kind');
7
+ }
8
+ return protocol.QueryRequest(
9
+ named: protocol.NamedQuery(
10
+ operation: protocol.QueryOperation.QUERY_OPERATION_EXTREMUM,
11
+ arguments: protocol.NomosStruct(
12
+ fields: {
13
+ 'extremumId': protocol.NomosValue(text: id),
14
+ 'kind': protocol.NomosValue(text: kind),
15
+ 'groupKey': protocol.NomosValue(text: groupKey ?? ''),
16
+ }.entries),
17
+ ));
18
+ }
19
+
20
+ /// Empty is explicit null, never a missing or refused result. Keep the same exact
21
+ /// integer range as the generated TypeScript application, including on Dart web.
22
+ int? extremumValue(protocol.QueryResponse response) {
23
+ if (!response.hasValue() || !response.value.hasObject()) {
24
+ throw StateError('Kernel extremum returned no typed value');
25
+ }
26
+ final fields = response.value.object.fields;
27
+ if (fields['ok']?.hasBoolean() != true || !fields['ok']!.boolean) {
28
+ throw StateError('Kernel extremum did not succeed');
29
+ }
30
+ final value = fields['value'];
31
+ if (value?.whichKind() == protocol.NomosValue_Kind.null_1) return null;
32
+ final integer = switch (value?.whichKind()) {
33
+ protocol.NomosValue_Kind.signedInteger => value!.signedInteger,
34
+ protocol.NomosValue_Kind.unsignedInteger => value!.unsignedInteger,
35
+ _ =>
36
+ throw StateError('Kernel extremum returned neither an integer nor null'),
37
+ };
38
+ // Check in Int64 before toInt so JavaScript targets cannot round silently.
39
+ if ((value.hasUnsignedInteger() && integer.isNegative) ||
40
+ integer < -9007199254740991 ||
41
+ integer > 9007199254740991) {
42
+ throw StateError(
43
+ 'Kernel extremum integer is outside the safe number range');
44
+ }
45
+ return integer.toInt();
46
+ }
@@ -0,0 +1,371 @@
1
+ import 'package:meta/meta.dart' show immutable;
2
+ import 'package:nomos_types/nomos_kernel_protocol.dart' as nomos_protocol;
3
+ import 'workspace_preparation_report.dart';
4
+ import '../sync_status_projection.dart' show SyncStatus;
5
+
6
+ /// The provider now serves this workspace from a different genesis than this
7
+ /// device's local copy: it was re-founded ("reborn") remotely. Sync refuses to
8
+ /// merge, rebase or offer across geneses and schedules no retry. Dropping the
9
+ /// local copy ([ReceptionLocalCopies.drop]) is the fix.
10
+ @immutable
11
+ final class NomosWorkspaceRebirth {
12
+ const NomosWorkspaceRebirth({
13
+ required this.localGenesis,
14
+ required this.remoteGenesis,
15
+ required this.localHead,
16
+ required this.remoteHead,
17
+ required this.detail,
18
+ });
19
+
20
+ factory NomosWorkspaceRebirth.fromRuntime(
21
+ nomos_protocol.WorkspaceRebirth rebirth,
22
+ ) =>
23
+ NomosWorkspaceRebirth(
24
+ localGenesis: rebirth.localGenesis,
25
+ remoteGenesis: rebirth.remoteGenesis,
26
+ localHead: rebirth.localHead,
27
+ remoteHead: rebirth.remoteHead,
28
+ detail: rebirth.detail,
29
+ );
30
+
31
+ final String localGenesis;
32
+ final String remoteGenesis;
33
+ final String localHead;
34
+ final String remoteHead;
35
+
36
+ /// A short explanation to show next to the workspace.
37
+ final String detail;
38
+
39
+ @override
40
+ bool operator ==(Object other) =>
41
+ other is NomosWorkspaceRebirth &&
42
+ other.localGenesis == localGenesis &&
43
+ other.remoteGenesis == remoteGenesis &&
44
+ other.localHead == localHead &&
45
+ other.remoteHead == remoteHead &&
46
+ other.detail == detail;
47
+
48
+ @override
49
+ int get hashCode =>
50
+ Object.hash(localGenesis, remoteGenesis, localHead, remoteHead, detail);
51
+ }
52
+
53
+ /// One workspace this device holds or follows, as its local copy stands.
54
+ @immutable
55
+ final class NomosLocalWorkspaceCopy {
56
+ const NomosLocalWorkspaceCopy({
57
+ required this.workspace,
58
+ required this.followed,
59
+ required this.loaded,
60
+ required this.rebornRemotely,
61
+ required this.dropPending,
62
+ this.unreadableReason,
63
+ this.preservedCopies = const [],
64
+ this.preparation,
65
+ this.sessionStatuses = const [],
66
+ });
67
+
68
+ factory NomosLocalWorkspaceCopy.fromRuntime(
69
+ nomos_protocol.WorkspaceSummary summary,
70
+ {WorkspacePreparationReport? preparation,
71
+ List<SyncStatus> sessionStatuses = const []}) =>
72
+ NomosLocalWorkspaceCopy(
73
+ workspace: summary.workspace,
74
+ followed: summary.followed,
75
+ loaded: summary.kernelResident,
76
+ rebornRemotely: summary.hasRebornRemotely()
77
+ ? NomosWorkspaceRebirth.fromRuntime(summary.rebornRemotely)
78
+ : null,
79
+ dropPending: summary.localCopyDropPending,
80
+ unreadableReason: summary.hasLocalCopyUnreadable()
81
+ ? summary.localCopyUnreadable
82
+ : null,
83
+ preservedCopies: List.unmodifiable([
84
+ for (final copy in summary.preservedCopies)
85
+ NomosPreservedLocalCopy.fromRuntime(copy),
86
+ ]),
87
+ preparation: preparation,
88
+ sessionStatuses: sessionStatuses,
89
+ );
90
+
91
+ final String workspace;
92
+
93
+ /// A provider exists for this workspace, so a dropped copy can be refetched.
94
+ final bool followed;
95
+
96
+ /// The workspace's kernel is resident on this device right now.
97
+ final bool loaded;
98
+
99
+ /// Non-null while the provider serves another genesis than this copy.
100
+ final NomosWorkspaceRebirth? rebornRemotely;
101
+
102
+ /// A drop was authorized and its refetch has not finished yet.
103
+ final bool dropPending;
104
+
105
+ /// Non-null when this device's kernel cannot read the copy (for example it
106
+ /// is from an older storage format). The app opens around it; dropping the
107
+ /// copy refetches it.
108
+ final String? unreadableReason;
109
+
110
+ /// Earlier copies of this workspace that a refetch replaced and kept aside
111
+ /// (preserved, not merged), each with what it held that was never synced.
112
+ final List<NomosPreservedLocalCopy> preservedCopies;
113
+
114
+ /// Last preparation observation from the peer during this Reception lifetime.
115
+ final WorkspacePreparationReport? preparation;
116
+
117
+ /// Exact sync observations for sessions bound to this workspace. An empty
118
+ /// list does not prove that a followed copy has settled.
119
+ final List<SyncStatus> sessionStatuses;
120
+ }
121
+
122
+ /// A local copy replaced by a refetch and kept aside under
123
+ /// `refs/heads/custody-preserved/`: never deleted, never merged.
124
+ @immutable
125
+ final class NomosPreservedLocalCopy {
126
+ const NomosPreservedLocalCopy({
127
+ required this.workspace,
128
+ required this.preservedHead,
129
+ required this.preservedRef,
130
+ required this.reason,
131
+ required this.unsyncedLocalChanges,
132
+ required this.changesCounted,
133
+ required this.automatic,
134
+ required this.preservedAt,
135
+ required this.syncedHead,
136
+ });
137
+
138
+ factory NomosPreservedLocalCopy.fromRuntime(
139
+ nomos_protocol.PreservedLocalCopy copy,
140
+ ) =>
141
+ NomosPreservedLocalCopy(
142
+ workspace: copy.workspace,
143
+ preservedHead: copy.preservedHead,
144
+ preservedRef: copy.preservedRef,
145
+ reason: copy.reason,
146
+ unsyncedLocalChanges: copy.unsyncedLocalChanges.toInt(),
147
+ changesCounted: copy.changesCounted,
148
+ automatic: copy.automatic,
149
+ preservedAt: copy.preservedAtUnixMillis == 0
150
+ ? null
151
+ : DateTime.fromMillisecondsSinceEpoch(
152
+ copy.preservedAtUnixMillis.toInt(),
153
+ isUtc: true,
154
+ ),
155
+ syncedHead: copy.hasSyncedHead() ? copy.syncedHead : null,
156
+ );
157
+
158
+ final String workspace;
159
+ final String preservedHead;
160
+ final String preservedRef;
161
+
162
+ /// Why it was replaced, e.g. "local copy is from an older storage format".
163
+ final String reason;
164
+
165
+ /// Commits it held above the provider's last admitted head.
166
+ final int unsyncedLocalChanges;
167
+
168
+ /// False when those could not be determined: [unsyncedLocalChanges] then
169
+ /// means "unknown", never "none".
170
+ final bool changesCounted;
171
+
172
+ /// The application's own open refetched it, not a user's drop.
173
+ final bool automatic;
174
+ final DateTime? preservedAt;
175
+ final String? syncedHead;
176
+
177
+ @override
178
+ bool operator ==(Object other) =>
179
+ other is NomosPreservedLocalCopy &&
180
+ other.workspace == workspace &&
181
+ other.preservedHead == preservedHead &&
182
+ other.reason == reason &&
183
+ other.unsyncedLocalChanges == unsyncedLocalChanges &&
184
+ other.changesCounted == changesCounted &&
185
+ other.automatic == automatic;
186
+
187
+ @override
188
+ int get hashCode => Object.hash(workspace, preservedHead, reason,
189
+ unsyncedLocalChanges, changesCounted, automatic);
190
+ }
191
+
192
+ /// What dropping a workspace's local copy would discard. Obtain it from
193
+ /// [ReceptionLocalCopies.preview]; pass it back to [ReceptionLocalCopies.drop],
194
+ /// which drops exactly the previewed copy and nothing newer.
195
+ @immutable
196
+ final class NomosLocalCopyDropPreview {
197
+ const NomosLocalCopyDropPreview({
198
+ required this.workspace,
199
+ required this.localHead,
200
+ required this.unsyncedLocalChanges,
201
+ required this.parkedLocalChanges,
202
+ required this.undeliveredLetters,
203
+ required this.lettersCounted,
204
+ required this.followed,
205
+ required this.rebornRemotely,
206
+ this.changesCounted = true,
207
+ this.unreadableReason,
208
+ });
209
+
210
+ factory NomosLocalCopyDropPreview.fromRuntime(
211
+ nomos_protocol.LocalCopyDropPreview preview,
212
+ ) =>
213
+ NomosLocalCopyDropPreview(
214
+ workspace: preview.workspace,
215
+ localHead: preview.hasLocalHead() ? preview.localHead : null,
216
+ unsyncedLocalChanges: preview.unsyncedLocalChanges.toInt(),
217
+ parkedLocalChanges: preview.parkedLocalChanges.toInt(),
218
+ undeliveredLetters: preview.undeliveredLetters.toInt(),
219
+ lettersCounted: preview.lettersCounted,
220
+ followed: preview.followed,
221
+ rebornRemotely: preview.hasRebornRemotely()
222
+ ? NomosWorkspaceRebirth.fromRuntime(preview.rebornRemotely)
223
+ : null,
224
+ changesCounted: preview.changesCounted,
225
+ unreadableReason: preview.hasLocalCopyUnreadable()
226
+ ? preview.localCopyUnreadable
227
+ : null,
228
+ );
229
+
230
+ final String workspace;
231
+
232
+ /// The exact local head a drop replaces; null when there is no local copy.
233
+ final String? localHead;
234
+
235
+ /// Local changes the provider never admitted.
236
+ final int unsyncedLocalChanges;
237
+
238
+ /// Refused local changes parked on this device.
239
+ final int parkedLocalChanges;
240
+
241
+ /// Cross-workspace letters not yet delivered.
242
+ final int undeliveredLetters;
243
+
244
+ /// False when [undeliveredLetters] is a lower bound.
245
+ final bool lettersCounted;
246
+
247
+ /// A provider exists to refetch from; [ReceptionLocalCopies.drop] refuses otherwise.
248
+ final bool followed;
249
+
250
+ final NomosWorkspaceRebirth? rebornRemotely;
251
+
252
+ /// False when Git could not determine the unsynced changes:
253
+ /// [unsyncedLocalChanges] then means "unknown", never "none".
254
+ final bool changesCounted;
255
+
256
+ /// Why this device's kernel cannot read the copy, when it cannot.
257
+ final String? unreadableReason;
258
+
259
+ /// Everything the drop would discard, summed.
260
+ int get changesLost =>
261
+ unsyncedLocalChanges + parkedLocalChanges + undeliveredLetters;
262
+
263
+ /// Whether dropping loses any work at all.
264
+ bool get losesWork => changesLost > 0 || !lettersCounted || !changesCounted;
265
+
266
+ /// Whether there is a local copy that can be dropped and refetched.
267
+ bool get canDrop => localHead != null && followed;
268
+ }
269
+
270
+ /// Fixed Reception capability over this device's local workspace copies. A
271
+ /// local copy is a droppable cache of the provider's custody: dropping one
272
+ /// replaces only that workspace's local custody, projections and indexes, then
273
+ /// refetches it from the current provider. Device keys, credentials, the
274
+ /// identity store and every other workspace are untouched.
275
+ final class ReceptionLocalCopies {
276
+ const ReceptionLocalCopies({
277
+ required Future<nomos_protocol.RuntimeResponse> Function(
278
+ nomos_protocol.RuntimeRequest)
279
+ invoke,
280
+ required this.changes,
281
+ Stream<NomosPreservedLocalCopy> preservations = const Stream.empty(),
282
+ List<NomosPreservedLocalCopy> Function() recentPreservations = _none,
283
+ WorkspacePreparationReport? Function(String) preparationFor =
284
+ _noPreparation,
285
+ List<SyncStatus> Function(List<String>) statusesFor = _noStatuses,
286
+ }) : _invoke = invoke,
287
+ _preservations = preservations,
288
+ _recentPreservations = recentPreservations,
289
+ _preparationFor = preparationFor,
290
+ _statusesFor = statusesFor;
291
+
292
+ static List<NomosPreservedLocalCopy> _none() => const [];
293
+ static WorkspacePreparationReport? _noPreparation(String _) => null;
294
+ static List<SyncStatus> _noStatuses(List<String> _) => const [];
295
+
296
+ final Future<nomos_protocol.RuntimeResponse> Function(
297
+ nomos_protocol.RuntimeRequest) _invoke;
298
+
299
+ /// Fires whenever a workspace's sync status changes; re-read [list] then.
300
+ final Stream<void> changes;
301
+
302
+ final Stream<NomosPreservedLocalCopy> _preservations;
303
+ final List<NomosPreservedLocalCopy> Function() _recentPreservations;
304
+ final WorkspacePreparationReport? Function(String) _preparationFor;
305
+ final List<SyncStatus> Function(List<String>) _statusesFor;
306
+
307
+ /// Diagnostics log: each local copy replaced and kept aside, as it happens
308
+ /// (including the unreadable Home refetched by the application's own open).
309
+ Stream<NomosPreservedLocalCopy> get preservations => _preservations;
310
+
311
+ /// The preservations this Reception has observed so far, oldest first.
312
+ List<NomosPreservedLocalCopy> get recentPreservations =>
313
+ _recentPreservations();
314
+
315
+ /// Every workspace this device holds or follows, with its reborn state.
316
+ Future<List<NomosLocalWorkspaceCopy>> list() async {
317
+ final response = await _invoke(nomos_protocol.RuntimeRequest(
318
+ listWorkspaces: nomos_protocol.ListWorkspacesRequest(),
319
+ ));
320
+ if (!response.hasWorkspaceList()) {
321
+ throw StateError(
322
+ 'Runtime v2 returned ${response.whichOutcome().name} for listWorkspaces');
323
+ }
324
+ return List.unmodifiable([
325
+ for (final summary in response.workspaceList.workspaces)
326
+ NomosLocalWorkspaceCopy.fromRuntime(
327
+ summary,
328
+ preparation: _preparationFor(summary.workspace),
329
+ sessionStatuses: _statusesFor(summary.sessions),
330
+ ),
331
+ ]);
332
+ }
333
+
334
+ /// What dropping [workspace]'s local copy would discard. Reads only.
335
+ Future<NomosLocalCopyDropPreview> preview(String workspace) async {
336
+ final response = await _invoke(nomos_protocol.RuntimeRequest(
337
+ previewLocalCopyDrop:
338
+ nomos_protocol.PreviewLocalCopyDropRequest(workspace: workspace),
339
+ ));
340
+ if (!response.hasLocalCopyDropPreview()) {
341
+ throw StateError('Runtime v2 returned ${response.whichOutcome().name} '
342
+ 'for previewLocalCopyDrop');
343
+ }
344
+ return NomosLocalCopyDropPreview.fromRuntime(response.localCopyDropPreview);
345
+ }
346
+
347
+ /// Drop exactly the previewed local copy and refetch it from the provider.
348
+ /// Refused (thrown) when the copy changed since [preview], when there is no
349
+ /// local copy, or when no provider exists. The refetch runs in the
350
+ /// background; watch [list] until the workspace is no longer [NomosLocalWorkspaceCopy.dropPending].
351
+ Future<void> drop(NomosLocalCopyDropPreview preview) async {
352
+ final head = preview.localHead;
353
+ if (head == null) {
354
+ throw StateError('${preview.workspace} has no local copy to drop');
355
+ }
356
+ if (!preview.followed) {
357
+ throw StateError(
358
+ '${preview.workspace} has no provider to refetch it from');
359
+ }
360
+ final response = await _invoke(nomos_protocol.RuntimeRequest(
361
+ dropLocalCopy: nomos_protocol.DropLocalCopyRequest(
362
+ workspace: preview.workspace,
363
+ expectedLocalHead: head,
364
+ ),
365
+ ));
366
+ if (!response.hasLocalCopyDropScheduled()) {
367
+ throw StateError(
368
+ 'Runtime v2 returned ${response.whichOutcome().name} for dropLocalCopy');
369
+ }
370
+ }
371
+ }
@@ -0,0 +1,11 @@
1
+ import '../runtime_v2_transport.dart'
2
+ show NomosRuntimeV2EventTransport, NomosRuntimeV2Transport;
3
+
4
+ /// The typed connection Reception receives from a platform shell.
5
+ ///
6
+ /// This is the entire physical boundary to Peer Office: correlated Runtime v2
7
+ /// requests plus its asynchronous event lane. A conforming connection cannot
8
+ /// silently omit subscriptions. It contains no application, custody, placement
9
+ /// or authority semantics.
10
+ abstract interface class PeerOfficeConnection
11
+ implements NomosRuntimeV2Transport, NomosRuntimeV2EventTransport {}