@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.
- package/assets/operation-contract.wasm +0 -0
- package/check_package.mjs +12 -15
- package/compile_package.mjs +17 -18
- package/compile_proof.mjs +16 -1
- package/dart/CHANGELOG.md +80 -1
- package/dart/README.md +25 -2
- package/dart/lib/src/admission_decision.dart +41 -0
- package/dart/lib/src/application_framework_calls.dart +52 -2
- package/dart/lib/src/application_model_adoption.dart +187 -0
- package/dart/lib/src/application_status.dart +73 -0
- package/dart/lib/src/console_enrolment.dart +271 -0
- package/dart/lib/src/console_http_io.dart +26 -0
- package/dart/lib/src/console_http_stub.dart +7 -0
- package/dart/lib/src/dev_cloud.dart +69 -22
- package/dart/lib/src/generated_call.dart +83 -23
- package/dart/lib/src/kernel_primitives.dart +119 -0
- package/dart/lib/src/nms_conformance_runtime.dart +1 -1
- package/dart/lib/src/nms_generated_runtime.dart +32 -10
- package/dart/lib/src/nms_test_environment.dart +1 -1
- package/dart/lib/src/node_runner_transport.dart +41 -46
- package/dart/lib/src/observed_session_directory.dart +70 -0
- package/dart/lib/src/operation_receipts.dart +112 -0
- package/dart/lib/src/peer_application_streams.dart +103 -0
- package/dart/lib/src/reception/dart_reception.dart +4280 -0
- package/dart/lib/src/reception/event_desk.dart +214 -0
- package/dart/lib/src/reception/extremum_read.dart +46 -0
- package/dart/lib/src/reception/local_copies.dart +371 -0
- package/dart/lib/src/reception/peer_office_connection.dart +11 -0
- package/dart/lib/src/reception/progress_desk.dart +268 -0
- package/dart/lib/src/reception/reception_contract.dart +11 -0
- package/dart/lib/src/reception/reception_session.dart +284 -0
- package/dart/lib/src/reception/sync_diagnostics.dart +26 -0
- package/dart/lib/src/reception/workspace_preparation_report.dart +126 -0
- package/dart/lib/src/replica_readiness.dart +123 -0
- package/dart/lib/src/runner/node-entry.mjs +23950 -15776
- package/dart/lib/src/runtime_v2_gateway.dart +56 -3
- package/dart/lib/src/runtime_v2_transport.dart +544 -3
- package/dart/lib/src/session_bound.dart +200 -311
- package/dart/lib/src/signing_identity_kernel.dart +84 -0
- package/dart/lib/src/sync_status_projection.dart +550 -0
- package/dart/lib/src/sync_status_reducer.dart +170 -0
- package/dart/lib/src/test_harness.dart +809 -1153
- package/dart/lib/src/testing/test_custody.dart +66 -0
- package/dart/lib/src/testing/test_peer.dart +328 -0
- package/dart/lib/src/typed_watch_registry.dart +169 -0
- package/dart/lib/src/workspace_open_progress.dart +27 -0
- package/dart/pubspec.lock +24 -1
- package/dart/pubspec.yaml +7 -2
- package/dart/pubspec_overrides.yaml +2 -0
- package/dart/test/admission_decision_test.dart +48 -0
- package/dart/test/background_model_adoption_test.dart +228 -0
- package/dart/test/bundle_version_pairing_test.dart +4 -4
- package/dart/test/child_authentication_repair_test.dart +359 -0
- package/dart/test/cloud_bound_local_shell_test.dart +119 -0
- package/dart/test/console_enrolment_refusal_test.dart +52 -0
- package/dart/test/console_enrolment_test.dart +227 -0
- package/dart/test/errors_test.dart +5 -5
- package/dart/test/event_plane_seam_test.dart +50 -164
- package/dart/test/extremum_read_test.dart +58 -0
- package/dart/test/fixtures/wedge/wedge-entry.mjs +3 -21
- package/dart/test/generated_query_test.dart +32 -0
- package/dart/test/harness_phase_timeout_test.dart +18 -23
- package/dart/test/kernel_author_after_read_test.dart +242 -0
- package/dart/test/kernel_fence_test.dart +137 -0
- package/dart/test/local_copies_test.dart +222 -0
- package/dart/test/model_adoption_test.dart +198 -0
- package/dart/test/node_peer_local_custody_test.dart +153 -0
- package/dart/test/offer_authentication_proof_test.dart +352 -52
- package/dart/test/operation_compatibility_test.dart +151 -0
- package/dart/test/platform_credential_effect_test.dart +386 -0
- package/dart/test/receiving_group_open_test.dart +213 -0
- package/dart/test/reception/workspace_preparation_report_test.dart +103 -0
- package/dart/test/reception_event_desk_close_test.dart +16 -0
- package/dart/test/reception_span_trace_test.dart +23 -0
- package/dart/test/replica_readiness_test.dart +156 -0
- package/dart/test/runtime_projections_test.dart +92 -0
- package/dart/test/runtime_v2_gateway_test.dart +131 -0
- package/dart/test/signing_identity_kernel_test.dart +75 -0
- package/dart/test/sync_status_preparation_report_test.dart +29 -0
- package/dart/test/sync_status_reducer_test.dart +419 -0
- package/dart/test/test_harness_test.dart +71 -95
- package/dart/test/typed_query_watch_test.dart +170 -0
- package/dart/test/typed_watch_registry_test.dart +249 -0
- package/dart_lints/README.md +18 -0
- package/dart_lints/lib/nomos_lints.dart +70 -0
- package/dart_lints/pubspec.lock +580 -0
- package/dart_lints/pubspec.yaml +12 -0
- package/dart_lints/test/reference_identity_test.dart +75 -0
- package/dart_types/CHANGELOG.md +18 -0
- package/dart_types/lib/nomos_kernel_protocol.dart +21 -1
- package/dart_types/lib/nomos_types.dart +9 -1
- package/dart_types/lib/src/admission_decision.dart +37 -0
- package/dart_types/lib/src/aggregate_meta.dart +1 -1
- package/dart_types/lib/src/approved_model.dart +65 -0
- package/dart_types/lib/src/custody.dart +10 -18
- package/dart_types/lib/src/error_info.dart +4 -4
- package/dart_types/lib/src/errors.dart +29 -29
- package/dart_types/lib/src/foreign_ref.dart +62 -33
- package/dart_types/lib/src/local_work_rejected.dart +3 -3
- package/dart_types/lib/src/nomos_ref.dart +3 -1
- package/dart_types/lib/src/principal.dart +2 -2
- package/dart_types/lib/src/proto/google/protobuf/any.pb.dart +163 -0
- package/dart_types/lib/src/proto/google/protobuf/any.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/discovery/v1/workspace_placement.pb.dart +137 -0
- package/dart_types/lib/src/proto/nomos/discovery/v1/workspace_placement.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pb.dart +20721 -10433
- package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pbenum.dart +555 -27
- package/dart_types/lib/src/proto/nomos/runtime/v2/application_desk.pb.dart +387 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/application_desk.pbenum.dart +46 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/application_readiness_desk.pb.dart +295 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/application_readiness_desk.pbenum.dart +139 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/authentication_desk.pb.dart +269 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/authentication_desk.pbenum.dart +103 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/compatibility_desk.pb.dart +417 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/compatibility_desk.pbenum.dart +62 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/correspondence_desk.pb.dart +9968 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/correspondence_desk.pbenum.dart +133 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/credentials_desk.pb.dart +204 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/credentials_desk.pbenum.dart +54 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/custody_desk.pb.dart +1550 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/custody_desk.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/framework.pb.dart +710 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/framework.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/identity_desk.pb.dart +845 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/identity_desk.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/interaction_desk.pb.dart +198 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/interaction_desk.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/law_desk.pb.dart +369 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/law_desk.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/maintenance_desk.pb.dart +609 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/maintenance_desk.pbenum.dart +65 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/model_adoption_desk.pb.dart +358 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/model_adoption_desk.pbenum.dart +100 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/observability_desk.pb.dart +2231 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/observability_desk.pbenum.dart +271 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/placement_desk.pb.dart +1286 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/placement_desk.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/receiving_group_desk.pb.dart +636 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/receiving_group_desk.pbenum.dart +116 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/records_desk.pb.dart +1637 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/records_desk.pbenum.dart +175 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/recovery_desk.pb.dart +1269 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/recovery_desk.pbenum.dart +129 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/residency_desk.pb.dart +2782 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/residency_desk.pbenum.dart +97 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pb.dart +2232 -8627
- package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pbenum.dart +0 -358
- package/dart_types/lib/src/proto/nomos/runtime/v2/sealing_desk.pb.dart +1639 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/sealing_desk.pbenum.dart +46 -0
- package/dart_types/lib/src/runtime_outcome.dart +133 -0
- package/dart_types/lib/src/subscriptions.dart +116 -23
- package/dart_types/pubspec.yaml +1 -1
- package/dart_types/test/extremum_subscriptions_test.dart +40 -0
- package/dart_types/test/foreign_ref_resolution_test.dart +75 -0
- package/dart_types/test/nomos_ref_address_test.dart +25 -0
- package/dart_types/test/ordered_subscriptions_test.dart +34 -0
- package/operation_contract_check.mjs +24 -0
- package/package.json +11 -6
- package/src/aggregate.ts +70 -10
- package/src/application_topology.ts +18 -11
- package/src/attested.ts +3 -0
- package/src/attested_core.ts +46 -3
- package/src/birth_meter_ensure.ts +19 -7
- package/src/births.ts +29 -4
- package/src/build_package.ts +140 -13
- package/src/business_birth.ts +181 -4
- package/src/codegen_call_proto.ts +1276 -0
- package/src/codegen_call_usda.ts +49 -6
- package/src/codegen_dart.ts +83 -44
- package/src/codegen_dart_client.ts +458 -800
- package/src/{codegen_dart_application.ts → codegen_dart_facade.ts} +331 -582
- package/src/codegen_dart_framework_calls.ts +320 -37
- package/src/codegen_dart_indexed_variant.ts +159 -0
- package/src/codegen_dart_scenario.ts +42 -13
- package/src/codegen_proof.ts +3 -3
- package/src/codegen_provider_dart.ts +5 -0
- package/src/codegen_query_proto.ts +158 -0
- package/src/codegen_refusal.ts +189 -0
- package/src/codegen_result_proto.ts +931 -0
- package/src/codegen_result_usda.ts +4 -0
- package/src/codegen_ts.ts +464 -616
- package/src/codegen_workspace_access.ts +105 -0
- package/src/compatibility_graph.ts +759 -0
- package/src/compatibility_usda.ts +264 -0
- package/src/compile_package_main.ts +2017 -1195
- package/src/custody_placement.ts +156 -0
- package/src/custody_placement_usda.ts +91 -0
- package/src/decl_shapes.ts +21 -2
- package/src/describe_model.ts +1 -0
- package/src/directive.ts +59 -2
- package/src/drivers.ts +51 -0
- package/src/engine_entry.ts +52 -8
- package/src/evolve_preview.ts +11 -4
- package/src/exists.ts +2 -0
- package/src/fields.ts +75 -11
- package/src/flow_gate.ts +2 -1
- package/src/framework/application_home.ts +170 -18
- package/src/framework/attested_receipts.ts +8 -3
- package/src/framework/auth_provider_law.ts +169 -9
- package/src/framework/birth_certificate_law.ts +4 -0
- package/src/framework/capability.ts +34 -3
- package/src/framework/child_authentication.ts +346 -0
- package/src/framework/console_governance.ts +295 -0
- package/src/framework/delegated_roles.ts +301 -0
- package/src/framework/domain_lifecycle.ts +26 -13
- package/src/framework/founding_genesis.ts +193 -0
- package/src/framework/framework_aggregates.ts +1 -1
- package/src/framework/genesis.ts +6 -1
- package/src/framework/governance_relations.ts +19 -0
- package/src/framework/home.ts +5 -734
- package/src/framework/legacy/child_auth_provider_epoch.ts +73 -0
- package/src/framework/model_authority_repair.ts +116 -0
- package/src/framework/model_authority_seed.ts +185 -0
- package/src/framework/model_transition.ts +211 -0
- package/src/framework/owned_custody.ts +1 -1
- package/src/framework/principal_enrollment.ts +302 -0
- package/src/framework/receiving_group.ts +857 -0
- package/src/framework/receiving_group_recovery.ts +314 -0
- package/src/framework/relations.ts +4 -8
- package/src/framework/signing_identity.ts +242 -95
- package/src/framework/source_roster.ts +11 -5
- package/src/framework/workspace_access.ts +149 -0
- package/src/framework/workspace_invariant.ts +73 -52
- package/src/framework/workspaces.ts +407 -40
- package/src/framework_call_definitions.ts +32 -3
- package/src/generated_client_bundle_boundary.ts +97 -0
- package/src/generated_client_names.ts +1 -0
- package/src/identity_usda.ts +27 -0
- package/src/index.ts +183 -12
- package/src/indexed_variant.ts +83 -0
- package/src/intent.ts +173 -45
- package/src/law_check.ts +8 -5
- package/src/law_dependency_index.ts +231 -0
- package/src/law_graph.ts +508 -71
- package/src/law_graph_usda.ts +170 -24
- package/src/law_identity.ts +119 -81
- package/src/law_source_map.ts +4 -1
- package/src/law_units.ts +498 -0
- package/src/law_value_type.ts +7 -3
- package/src/member_authentication.ts +302 -0
- package/src/null_meta.ts +1 -1
- package/src/openusd_compiled_layer.ts +132 -0
- package/src/operation_contract_check.ts +31 -0
- package/src/ordered_read.ts +2 -1
- package/src/package_config.ts +33 -12
- package/src/package_dependencies.ts +1 -0
- package/src/plan_source_slice.ts +30 -1
- package/src/protobuf_field_number.ts +36 -0
- package/src/provenance_wire.ts +6 -0
- package/src/query.ts +2 -1
- package/src/read.ts +50 -0
- package/src/relation.ts +4 -1
- package/src/relation_schema.ts +15 -2
- package/src/report.ts +2 -2
- package/src/sqlite_computation_bundle.ts +78 -0
- package/src/sqlite_computed.ts +102 -0
- package/src/sqlite_counts.ts +154 -0
- package/src/sqlite_layout.ts +823 -0
- package/src/sqlite_reads.ts +275 -0
- package/src/sqlite_samples.ts +185 -0
- package/src/stable_id_identity_bridge.ts +1 -1
- package/src/stable_ids_for_module.ts +16 -4
- package/src/test_call_usda.ts +6 -6
- package/src/usda_relationship_integrity.ts +20 -3
- package/src/usda_text.ts +21 -1
- package/src/value_object.ts +81 -11
- package/src/wire.ts +22 -0
- package/src/wire_encode.ts +227 -20
- package/src/workspace_sharding.ts +15 -6
- package/src/workspace_sharing.ts +51 -49
- package/src/zod_introspection.ts +2 -0
- package/compat_package.mjs +0 -46
- package/dart/lib/src/home.dart +0 -15
- package/dart/lib/src/runner/offline-install.mjs +0 -15367
- package/dart/lib/src/source_trust.dart +0 -51
- package/dart/lib/src/webview_bridge.dart +0 -6540
- package/dart/lib/src/workspace_name.dart +0 -30
- package/dart/test/acquire_session_credentials_test.dart +0 -150
- package/dart/test/acquire_session_test.dart +0 -534
- package/dart/test/adv_realm_interference_test.dart +0 -600
- package/dart/test/cloud_bound_topology_test.dart +0 -168
- package/dart/test/cluster_births_test.dart +0 -202
- package/dart/test/cluster_device_keyed_acceptance_test.dart +0 -105
- package/dart/test/cluster_local_autosync_test.dart +0 -123
- package/dart/test/cluster_scale_test.dart +0 -122
- package/dart/test/compat_test.dart +0 -61
- package/dart/test/dlq_session_surface_test.dart +0 -222
- package/dart/test/first_app_gauntlet_test.dart +0 -386
- package/dart/test/fixtures/wedge/fake-install.mjs +0 -11
- package/dart/test/four_layer_nested_topology_test.dart +0 -290
- package/dart/test/home_parity_test.dart +0 -13
- package/dart/test/local_sync_inert_test.dart +0 -107
- package/dart/test/node_runner_transport_test.dart +0 -78
- package/dart/test/parent_signer_recovery_test.dart +0 -155
- package/dart/test/residency_refusal_test.dart +0 -49
- package/dart/test/sealing_client_test.dart +0 -181
- package/dart/test/session_bound_test.dart +0 -285
- package/dart/test/stale_bundle_test.dart +0 -80
- package/dart/test/vo_read_typing_test.dart +0 -131
- package/dart/test/watch_after_offer_stall_test.dart +0 -100
- package/dart/test/webview_bridge_test.dart +0 -1930
- package/dart/test/workspace_name_test.dart +0 -24
- package/runtime/generated-application-host.js +0 -22860
- package/src/codegen_query_usda.ts +0 -214
- package/src/compat_manifest.ts +0 -26
- package/src/compat_package_main.ts +0 -224
- package/src/shape_compat.ts +0 -352
- package/src/usd_state.ts +0 -505
|
@@ -0,0 +1,214 @@
|
|
|
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
|
+
// Public broadcast streams can have paused UI listeners. Their close()
|
|
198
|
+
// futures wait for those listeners to resume, so signal done without
|
|
199
|
+
// letting an external subscriber hold reception teardown open.
|
|
200
|
+
if (!_copyChanges.isClosed) unawaited(_copyChanges.close());
|
|
201
|
+
await typedWatches.close();
|
|
202
|
+
if (!_sync.isClosed) unawaited(_sync.close());
|
|
203
|
+
if (!_custody.isClosed) unawaited(_custody.close());
|
|
204
|
+
if (!_localWorkRejected.isClosed) unawaited(_localWorkRejected.close());
|
|
205
|
+
if (!_receivingGroupConvergence.isClosed) {
|
|
206
|
+
unawaited(_receivingGroupConvergence.close());
|
|
207
|
+
}
|
|
208
|
+
if (!_modelAdoption.isClosed) unawaited(_modelAdoption.close());
|
|
209
|
+
if (!_preserved.isClosed) unawaited(_preserved.close());
|
|
210
|
+
if (!_foreignPlacements.isClosed) unawaited(_foreignPlacements.close());
|
|
211
|
+
await progress.close();
|
|
212
|
+
await syncStatuses.close();
|
|
213
|
+
}
|
|
214
|
+
}
|
|
@@ -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 {}
|