@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,16 @@
|
|
|
1
|
+
import 'package:nomos_client/src/reception/event_desk.dart';
|
|
2
|
+
import 'package:test/test.dart';
|
|
3
|
+
|
|
4
|
+
void main() {
|
|
5
|
+
test('reception closes while presentation observers are paused', () async {
|
|
6
|
+
final desk = ReceptionEventDesk();
|
|
7
|
+
final copies = desk.copyChanges.listen((_) {})..pause();
|
|
8
|
+
final application = desk.syncStatuses.applicationStream.listen((_) {})
|
|
9
|
+
..pause();
|
|
10
|
+
|
|
11
|
+
await desk.close().timeout(const Duration(seconds: 1));
|
|
12
|
+
|
|
13
|
+
await copies.cancel();
|
|
14
|
+
await application.cancel();
|
|
15
|
+
});
|
|
16
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import 'package:fixnum/fixnum.dart';
|
|
2
|
+
import 'package:nomos_client/src/reception/progress_desk.dart';
|
|
3
|
+
import 'package:nomos_types/nomos_kernel_protocol.dart' as protocol;
|
|
4
|
+
import 'package:test/test.dart';
|
|
5
|
+
|
|
6
|
+
void main() {
|
|
7
|
+
test('reception preserves the peer trace id and measured duration', () {
|
|
8
|
+
final span = protocol.RuntimeSpan(
|
|
9
|
+
traceId: List<int>.generate(16, (index) => index),
|
|
10
|
+
spanId: List<int>.filled(8, 1),
|
|
11
|
+
name: 'peer.correspondence.inspect-outbox',
|
|
12
|
+
startedUnixNanos: Int64(1700000000000000000),
|
|
13
|
+
durationNanos: Int64(22000000),
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
final observed = NomosSpanEvent.fromRuntime(span, session: 'home');
|
|
17
|
+
|
|
18
|
+
expect(observed.traceId, '000102030405060708090a0b0c0d0e0f');
|
|
19
|
+
expect(observed.startedAtMillis, 1700000000000);
|
|
20
|
+
expect(observed.endedAtMillis, 1700000000022);
|
|
21
|
+
expect(observed.session, 'home');
|
|
22
|
+
});
|
|
23
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// One-shot reads wait out a copy that is not ready yet; nothing else waits.
|
|
2
|
+
import 'dart:async';
|
|
3
|
+
import 'dart:io';
|
|
4
|
+
|
|
5
|
+
import 'package:nomos_client/src/replica_readiness.dart';
|
|
6
|
+
import 'package:nomos_types/nomos_types.dart'
|
|
7
|
+
show NomosUnavailable, NomosUnavailableReason;
|
|
8
|
+
import 'package:test/test.dart';
|
|
9
|
+
|
|
10
|
+
NomosUnavailable _unavailable(
|
|
11
|
+
NomosUnavailableReason reason, {
|
|
12
|
+
bool retryable = true,
|
|
13
|
+
}) =>
|
|
14
|
+
NomosUnavailable(
|
|
15
|
+
reason: reason,
|
|
16
|
+
workspace: 'catalogue-cars',
|
|
17
|
+
retryable: retryable,
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
void main() {
|
|
21
|
+
setUp(() {
|
|
22
|
+
nmsReplicaReadyFirstDelay = const Duration(milliseconds: 1);
|
|
23
|
+
nmsReplicaReadyGiveUpAfter = const Duration(minutes: 10);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test('a copy still arriving is asked again until it answers', () async {
|
|
27
|
+
var reads = 0;
|
|
28
|
+
final rows = await nmsUntilReplicaReady(() async {
|
|
29
|
+
reads++;
|
|
30
|
+
if (reads == 1) {
|
|
31
|
+
throw _unavailable(NomosUnavailableReason.workspaceOpening);
|
|
32
|
+
}
|
|
33
|
+
if (reads < 4) {
|
|
34
|
+
throw _unavailable(NomosUnavailableReason.localReplicaNotReady);
|
|
35
|
+
}
|
|
36
|
+
return ['Hatchback', 'Saloon'];
|
|
37
|
+
});
|
|
38
|
+
expect(rows, ['Hatchback', 'Saloon']);
|
|
39
|
+
expect(reads, 4);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
for (final (label, error) in [
|
|
43
|
+
(
|
|
44
|
+
'a non-retryable unavailable answer',
|
|
45
|
+
_unavailable(NomosUnavailableReason.localReplicaNotReady,
|
|
46
|
+
retryable: false),
|
|
47
|
+
),
|
|
48
|
+
(
|
|
49
|
+
'a remote-side unavailable answer',
|
|
50
|
+
_unavailable(NomosUnavailableReason.remoteUnreachable),
|
|
51
|
+
),
|
|
52
|
+
('any other error', StateError('NMS-KERNEL-CALL: query failed')),
|
|
53
|
+
]) {
|
|
54
|
+
test('$label is reported at once', () async {
|
|
55
|
+
var reads = 0;
|
|
56
|
+
await expectLater(
|
|
57
|
+
nmsUntilReplicaReady<void>(() async {
|
|
58
|
+
reads++;
|
|
59
|
+
throw error;
|
|
60
|
+
}),
|
|
61
|
+
throwsA(same(error)),
|
|
62
|
+
);
|
|
63
|
+
expect(reads, 1);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
test('a copy that never arrives still ends in an error', () async {
|
|
68
|
+
nmsReplicaReadyGiveUpAfter = const Duration(milliseconds: 20);
|
|
69
|
+
await expectLater(
|
|
70
|
+
nmsUntilReplicaReady<void>(
|
|
71
|
+
() async =>
|
|
72
|
+
throw _unavailable(NomosUnavailableReason.localReplicaNotReady),
|
|
73
|
+
),
|
|
74
|
+
throwsA(isA<NomosUnavailable>()),
|
|
75
|
+
);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
group('a completed sync wakes the wait', () {
|
|
79
|
+
// The runtime asks for a long pause; only the sync event can end it early.
|
|
80
|
+
NomosUnavailable notReady(String workspace) => NomosUnavailable(
|
|
81
|
+
reason: NomosUnavailableReason.localReplicaNotReady,
|
|
82
|
+
workspace: workspace,
|
|
83
|
+
retryable: true,
|
|
84
|
+
retryAfter: const Duration(minutes: 1),
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
test('the read asks again the moment its workspace syncs', () async {
|
|
88
|
+
final synced = StreamController<String>.broadcast();
|
|
89
|
+
final asked = Completer<void>();
|
|
90
|
+
var reads = 0;
|
|
91
|
+
final rows = nmsUntilReplicaReady(() async {
|
|
92
|
+
reads++;
|
|
93
|
+
if (!asked.isCompleted) asked.complete();
|
|
94
|
+
if (reads == 1) throw notReady('estate-a');
|
|
95
|
+
return ['Boiler'];
|
|
96
|
+
}, synced: synced.stream);
|
|
97
|
+
await asked.future;
|
|
98
|
+
await pumpEventQueue();
|
|
99
|
+
synced.add('estate-b');
|
|
100
|
+
await pumpEventQueue();
|
|
101
|
+
expect(reads, 1, reason: 'another workspace syncing is not this copy');
|
|
102
|
+
synced.add('estate-a');
|
|
103
|
+
expect(
|
|
104
|
+
await rows.timeout(const Duration(seconds: 1)),
|
|
105
|
+
['Boiler'],
|
|
106
|
+
);
|
|
107
|
+
expect(reads, 2);
|
|
108
|
+
await synced.close();
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test('a sync that lands before the wait begins is not missed', () async {
|
|
112
|
+
final synced = StreamController<String>.broadcast(sync: true);
|
|
113
|
+
var reads = 0;
|
|
114
|
+
final rows = await nmsUntilReplicaReady(() async {
|
|
115
|
+
reads++;
|
|
116
|
+
if (reads == 1) {
|
|
117
|
+
// The copy becomes ready while the "not yet" answer is in flight.
|
|
118
|
+
synced.add('estate-a');
|
|
119
|
+
throw notReady('estate-a');
|
|
120
|
+
}
|
|
121
|
+
return ['Boiler'];
|
|
122
|
+
}, synced: synced.stream)
|
|
123
|
+
.timeout(const Duration(seconds: 1));
|
|
124
|
+
expect(rows, ['Boiler']);
|
|
125
|
+
await synced.close();
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// The guard: every one-shot read reaches the kernel through one of these two
|
|
130
|
+
// request shapes. Each must sit inside nmsUntilReplicaReady, so a new read
|
|
131
|
+
// path cannot hand callers a "not ready yet" as an error.
|
|
132
|
+
test('every kernel query request is built inside nmsUntilReplicaReady', () {
|
|
133
|
+
final source = File(
|
|
134
|
+
'lib/src/reception/dart_reception.dart',
|
|
135
|
+
).readAsLinesSync();
|
|
136
|
+
final requestSites = <int>[];
|
|
137
|
+
for (var i = 0; i < source.length; i++) {
|
|
138
|
+
final line = source[i];
|
|
139
|
+
if (line.contains(r":query:$") ||
|
|
140
|
+
line.contains(
|
|
141
|
+
'historicQuery: nomos_protocol.HistoricQueryRequest(')) {
|
|
142
|
+
requestSites.add(i);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
expect(requestSites, hasLength(2), reason: 'query request sites moved');
|
|
146
|
+
for (final site in requestSites) {
|
|
147
|
+
final window = source.sublist(site - 16 < 0 ? 0 : site - 16, site);
|
|
148
|
+
expect(
|
|
149
|
+
window.any((line) => line.contains('nmsUntilReplicaReady(')),
|
|
150
|
+
isTrue,
|
|
151
|
+
reason: 'dart_reception.dart:${site + 1} sends a kernel query outside '
|
|
152
|
+
'nmsUntilReplicaReady',
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import 'dart:async';
|
|
2
|
+
|
|
3
|
+
import 'package:nomos_client/src/observed_session_directory.dart';
|
|
4
|
+
import 'package:nomos_client/src/operation_receipts.dart';
|
|
5
|
+
import 'package:nomos_client/src/sync_status_projection.dart';
|
|
6
|
+
import 'package:nomos_client/src/typed_watch_registry.dart';
|
|
7
|
+
import 'package:nomos_types/nomos_kernel_protocol.dart' as protocol;
|
|
8
|
+
import 'package:test/test.dart';
|
|
9
|
+
|
|
10
|
+
void main() {
|
|
11
|
+
test('observed session directory is a stable facade over successful opens',
|
|
12
|
+
() {
|
|
13
|
+
final directory = NmsObservedSessionDirectory<Object>();
|
|
14
|
+
final handle = Object();
|
|
15
|
+
directory.observeBound(
|
|
16
|
+
session: 'estate',
|
|
17
|
+
workspace: 'estate-1',
|
|
18
|
+
credentialCapability: 'device:jack',
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
expect(directory.isBound('estate'), isTrue);
|
|
22
|
+
expect(directory.workspaceFor('estate'), 'estate-1');
|
|
23
|
+
expect(directory.credentialCapabilityFor('estate'), 'device:jack');
|
|
24
|
+
expect(directory.handle('estate', () => handle), same(handle));
|
|
25
|
+
expect(directory.handle('estate', Object.new), same(handle));
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('sync projection folds typed per-session observations for the UI', () {
|
|
29
|
+
final projection = NmsSyncStatusProjection();
|
|
30
|
+
projection.ensureSession(
|
|
31
|
+
'home',
|
|
32
|
+
const SyncStatus(phase: SyncPhase.idle, behind: 0, saved: 2),
|
|
33
|
+
);
|
|
34
|
+
projection.ensureSession(
|
|
35
|
+
'estate',
|
|
36
|
+
const SyncStatus(phase: SyncPhase.behind, behind: 3, saved: 5),
|
|
37
|
+
);
|
|
38
|
+
projection.foldApplication(const ['home', 'estate']);
|
|
39
|
+
|
|
40
|
+
expect(projection.applicationStatus.phase, SyncPhase.behind);
|
|
41
|
+
expect(projection.applicationStatus.behind, 3);
|
|
42
|
+
expect(projection.applicationStatus.saved, 7);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('operation receipts advance only from runtime-issued stable identities',
|
|
46
|
+
() async {
|
|
47
|
+
final projection = NmsOperationReceiptProjection();
|
|
48
|
+
final receipt = projection.register('estate', 'intent-1');
|
|
49
|
+
projection.advance(
|
|
50
|
+
'estate',
|
|
51
|
+
protocol.SyncWorkspaceResponse(admittedIntentIds: const ['intent-1']),
|
|
52
|
+
);
|
|
53
|
+
await receipt.admitted;
|
|
54
|
+
expect(receipt.current.phase, NomosOperationPhase.admittedToRemoteCustody);
|
|
55
|
+
|
|
56
|
+
projection.advance(
|
|
57
|
+
'estate',
|
|
58
|
+
protocol.SyncWorkspaceResponse(convergedIntentIds: const ['intent-1']),
|
|
59
|
+
);
|
|
60
|
+
await receipt.converged;
|
|
61
|
+
expect(receipt.current.phase, NomosOperationPhase.converged);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test('typed watch registry only correlates runtime events and cancellation',
|
|
65
|
+
() async {
|
|
66
|
+
final registry = NmsTypedWatchRegistry();
|
|
67
|
+
final stopped = <String>[];
|
|
68
|
+
final handle = registry.open<List<int>>(
|
|
69
|
+
session: 'estate',
|
|
70
|
+
decode: (event) => event.resultUsda,
|
|
71
|
+
start: (_) async {},
|
|
72
|
+
stop: (id) async => stopped.add(id),
|
|
73
|
+
);
|
|
74
|
+
final values = <List<int>>[];
|
|
75
|
+
final subscription = handle.stream.listen(values.add);
|
|
76
|
+
|
|
77
|
+
registry.deliver(
|
|
78
|
+
protocol.WatchChanged(
|
|
79
|
+
subscriptionId: handle.id,
|
|
80
|
+
resultUsda: const [1, 2, 3],
|
|
81
|
+
),
|
|
82
|
+
);
|
|
83
|
+
await Future<void>.delayed(Duration.zero);
|
|
84
|
+
expect(values, const [
|
|
85
|
+
<int>[1, 2, 3]
|
|
86
|
+
]);
|
|
87
|
+
|
|
88
|
+
await subscription.cancel();
|
|
89
|
+
expect(stopped, [handle.id]);
|
|
90
|
+
registry.close();
|
|
91
|
+
});
|
|
92
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import 'package:nomos_client/src/runtime_v2_gateway.dart';
|
|
2
|
+
import 'package:nomos_client/src/runtime_v2_transport.dart';
|
|
3
|
+
import 'package:nomos_types/nomos_kernel_protocol.dart' as protocol;
|
|
4
|
+
import 'package:nomos_types/nomos_types.dart';
|
|
5
|
+
import 'package:test/test.dart';
|
|
6
|
+
|
|
7
|
+
final class _ScriptedRuntime implements NomosRuntimeV2Transport {
|
|
8
|
+
_ScriptedRuntime(this.answer);
|
|
9
|
+
|
|
10
|
+
final protocol.RuntimeResponse Function(protocol.RuntimeRequest request)
|
|
11
|
+
answer;
|
|
12
|
+
var _requestId = 0;
|
|
13
|
+
|
|
14
|
+
@override
|
|
15
|
+
int nextRuntimeRequestId() => ++_requestId;
|
|
16
|
+
|
|
17
|
+
@override
|
|
18
|
+
Future<protocol.RuntimeResponse> invokeRuntime(
|
|
19
|
+
protocol.RuntimeRequest request,
|
|
20
|
+
) async =>
|
|
21
|
+
answer(request);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
final class _ScriptedKernelCalls extends _ScriptedRuntime
|
|
25
|
+
with NomosRuntimeV2KernelCalls {
|
|
26
|
+
_ScriptedKernelCalls(super.answer);
|
|
27
|
+
|
|
28
|
+
@override
|
|
29
|
+
int nextRuntimeRequestId() => super.nextRuntimeRequestId();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
void main() {
|
|
33
|
+
test('a kernel call on a copy not ready yet is the typed wait reads sit out',
|
|
34
|
+
() async {
|
|
35
|
+
// A fresh device's first read of a workspace it is still fetching (node, web and in-app
|
|
36
|
+
// transports): once a bare "Runtime v2 returned unavailable for a kernel call".
|
|
37
|
+
final runtime = _ScriptedKernelCalls(
|
|
38
|
+
(request) => protocol.RuntimeResponse(
|
|
39
|
+
protocolVersion: 2,
|
|
40
|
+
requestId: request.requestId,
|
|
41
|
+
unavailable: protocol.RuntimeUnavailable(
|
|
42
|
+
reason: protocol.RuntimeUnavailableReason
|
|
43
|
+
.RUNTIME_UNAVAILABLE_REASON_LOCAL_REPLICA_NOT_READY,
|
|
44
|
+
workspace: 'estate',
|
|
45
|
+
retryable: true,
|
|
46
|
+
retryAfterMillis: 250,
|
|
47
|
+
detail:
|
|
48
|
+
'placement requires a local replica which Replica Follow has not established yet',
|
|
49
|
+
),
|
|
50
|
+
),
|
|
51
|
+
);
|
|
52
|
+
await expectLater(
|
|
53
|
+
runtime.callKernel(
|
|
54
|
+
session: 'estate',
|
|
55
|
+
request: protocol.CallRequest(),
|
|
56
|
+
credentialUse: protocol.CredentialUse.CREDENTIAL_USE_SESSION,
|
|
57
|
+
),
|
|
58
|
+
throwsA(
|
|
59
|
+
isA<NomosUnavailable>()
|
|
60
|
+
.having((value) => value.reason, 'reason',
|
|
61
|
+
NomosUnavailableReason.localReplicaNotReady)
|
|
62
|
+
.having((value) => value.workspace, 'workspace', 'estate')
|
|
63
|
+
.having((value) => value.retryable, 'retryable', true),
|
|
64
|
+
),
|
|
65
|
+
);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test('unavailability is exhaustive application control state', () async {
|
|
69
|
+
final runtime = _ScriptedRuntime(
|
|
70
|
+
(request) => protocol.RuntimeResponse(
|
|
71
|
+
protocolVersion: 2,
|
|
72
|
+
requestId: request.requestId,
|
|
73
|
+
unavailable: protocol.RuntimeUnavailable(
|
|
74
|
+
reason: protocol.RuntimeUnavailableReason
|
|
75
|
+
.RUNTIME_UNAVAILABLE_REASON_REMOTE_ONLY_OFFLINE,
|
|
76
|
+
workspace: 'catalogue',
|
|
77
|
+
retryable: true,
|
|
78
|
+
retryAfterMillis: 1200,
|
|
79
|
+
detail: 'diagnostic text is not control flow',
|
|
80
|
+
),
|
|
81
|
+
),
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
await expectLater(
|
|
85
|
+
NmsRuntimeV2Gateway(runtime).invoke(protocol.RuntimeRequest()),
|
|
86
|
+
throwsA(
|
|
87
|
+
isA<NomosUnavailable>()
|
|
88
|
+
.having(
|
|
89
|
+
(value) => value.reason,
|
|
90
|
+
'reason',
|
|
91
|
+
NomosUnavailableReason.remoteOnlyOffline,
|
|
92
|
+
)
|
|
93
|
+
.having((value) => value.workspace, 'workspace', 'catalogue')
|
|
94
|
+
.having(
|
|
95
|
+
(value) => value.retryAfter,
|
|
96
|
+
'retryAfter',
|
|
97
|
+
const Duration(milliseconds: 1200),
|
|
98
|
+
),
|
|
99
|
+
),
|
|
100
|
+
);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
test('policy refusal does not collapse into a string failure', () async {
|
|
104
|
+
final runtime = _ScriptedRuntime(
|
|
105
|
+
(request) => protocol.RuntimeResponse(
|
|
106
|
+
protocolVersion: 2,
|
|
107
|
+
requestId: request.requestId,
|
|
108
|
+
refused: protocol.RuntimeRefusal(
|
|
109
|
+
reason: protocol
|
|
110
|
+
.RuntimeRefusalReason.RUNTIME_REFUSAL_REASON_PLACEMENT_POLICY,
|
|
111
|
+
workspace: 'catalogue',
|
|
112
|
+
retryable: false,
|
|
113
|
+
detail: 'local residency is not permitted',
|
|
114
|
+
),
|
|
115
|
+
),
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
await expectLater(
|
|
119
|
+
NmsRuntimeV2Gateway(runtime).invoke(protocol.RuntimeRequest()),
|
|
120
|
+
throwsA(
|
|
121
|
+
isA<NomosRefused>()
|
|
122
|
+
.having(
|
|
123
|
+
(value) => value.reason,
|
|
124
|
+
'reason',
|
|
125
|
+
NomosRefusalReason.placementPolicy,
|
|
126
|
+
)
|
|
127
|
+
.having((value) => value.retryable, 'retryable', false),
|
|
128
|
+
),
|
|
129
|
+
);
|
|
130
|
+
});
|
|
131
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import 'dart:typed_data';
|
|
2
|
+
|
|
3
|
+
import 'package:nomos_client/src/runtime_v2_transport.dart'
|
|
4
|
+
show NomosKernelCallTransport;
|
|
5
|
+
import 'package:nomos_client/src/signing_identity_kernel.dart'
|
|
6
|
+
show NmsSigningIdentityKernel;
|
|
7
|
+
import 'package:nomos_types/nomos_kernel_protocol.dart' as protocol;
|
|
8
|
+
import 'package:test/test.dart';
|
|
9
|
+
|
|
10
|
+
final class _KernelTransport implements NomosKernelCallTransport {
|
|
11
|
+
final List<protocol.CallRequest> requests = [];
|
|
12
|
+
|
|
13
|
+
@override
|
|
14
|
+
Future<protocol.CallResponse> callKernel({
|
|
15
|
+
required String session,
|
|
16
|
+
required protocol.CallRequest request,
|
|
17
|
+
protocol.CredentialUse credentialUse =
|
|
18
|
+
protocol.CredentialUse.CREDENTIAL_USE_UNSPECIFIED,
|
|
19
|
+
}) async {
|
|
20
|
+
expect(session, 'home-123');
|
|
21
|
+
expect(credentialUse, protocol.CredentialUse.CREDENTIAL_USE_NONE);
|
|
22
|
+
requests.add(request);
|
|
23
|
+
final signing = request.signingIdentity;
|
|
24
|
+
return switch (signing.whichOperation()) {
|
|
25
|
+
protocol.SigningIdentityRequest_Operation.generate =>
|
|
26
|
+
protocol.CallResponse(
|
|
27
|
+
protocolVersion: 1,
|
|
28
|
+
requestId: request.requestId,
|
|
29
|
+
signingIdentity: protocol.SigningIdentityResponse(
|
|
30
|
+
generated: protocol.SigningKeyPair(
|
|
31
|
+
secret: List<int>.filled(32, 7),
|
|
32
|
+
publicKey: List<int>.filled(32, 9),
|
|
33
|
+
),
|
|
34
|
+
),
|
|
35
|
+
),
|
|
36
|
+
protocol.SigningIdentityRequest_Operation.derivePublic =>
|
|
37
|
+
protocol.CallResponse(
|
|
38
|
+
protocolVersion: 1,
|
|
39
|
+
requestId: request.requestId,
|
|
40
|
+
signingIdentity: protocol.SigningIdentityResponse(
|
|
41
|
+
derivedPublic: protocol.SigningPublicKey(
|
|
42
|
+
publicKey: List<int>.filled(32, 11),
|
|
43
|
+
),
|
|
44
|
+
),
|
|
45
|
+
),
|
|
46
|
+
protocol.SigningIdentityRequest_Operation.notSet =>
|
|
47
|
+
throw StateError('missing signing operation'),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
void main() {
|
|
53
|
+
test('signing identity crosses only the generated kernel contract', () async {
|
|
54
|
+
final transport = _KernelTransport();
|
|
55
|
+
final identity = NmsSigningIdentityKernel(
|
|
56
|
+
transport: transport,
|
|
57
|
+
session: 'home-123',
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
final generated = await identity.generate(requestId: 'generate-1');
|
|
61
|
+
expect(generated.secret, List<int>.filled(32, 7));
|
|
62
|
+
expect(generated.publicKey, List<int>.filled(32, 9));
|
|
63
|
+
|
|
64
|
+
final derived = await identity.derivePublic(
|
|
65
|
+
requestId: 'derive-1',
|
|
66
|
+
secret: Uint8List.fromList(List<int>.filled(32, 7)),
|
|
67
|
+
);
|
|
68
|
+
expect(derived.publicKey, List<int>.filled(32, 11));
|
|
69
|
+
|
|
70
|
+
expect(transport.requests, hasLength(2));
|
|
71
|
+
expect(transport.requests.first.hasSigningIdentity(), isTrue);
|
|
72
|
+
expect(transport.requests.last.signingIdentity.derivePublic.secret,
|
|
73
|
+
List<int>.filled(32, 7));
|
|
74
|
+
});
|
|
75
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import 'package:nomos_client/src/sync_status_projection.dart';
|
|
2
|
+
import 'package:test/test.dart';
|
|
3
|
+
|
|
4
|
+
void main() {
|
|
5
|
+
test(
|
|
6
|
+
'peer preparation reaches application status without a workspace session',
|
|
7
|
+
() async {
|
|
8
|
+
final projection = NmsSyncStatusProjection();
|
|
9
|
+
projection.updatePreparationCounts(1, 1,
|
|
10
|
+
activity: 'Installing workspace rules');
|
|
11
|
+
expect(projection.applicationStatus.preparingWorkspaces, 1);
|
|
12
|
+
expect(projection.applicationStatus.retryingWorkspaces, 1);
|
|
13
|
+
expect(projection.applicationStatus.preparationActivity,
|
|
14
|
+
'Installing workspace rules');
|
|
15
|
+
|
|
16
|
+
// Ordinary sync folding cannot erase the independently reported work.
|
|
17
|
+
projection.foldApplication(const []);
|
|
18
|
+
expect(projection.applicationStatus.preparingWorkspaces, 1);
|
|
19
|
+
expect(projection.applicationStatus.retryingWorkspaces, 1);
|
|
20
|
+
expect(projection.applicationStatus.preparationActivity,
|
|
21
|
+
'Installing workspace rules');
|
|
22
|
+
|
|
23
|
+
projection.updatePreparationCounts(0, 0);
|
|
24
|
+
expect(projection.applicationStatus.preparingWorkspaces, 0);
|
|
25
|
+
expect(projection.applicationStatus.retryingWorkspaces, 0);
|
|
26
|
+
expect(projection.applicationStatus.preparationActivity, isNull);
|
|
27
|
+
await projection.close();
|
|
28
|
+
});
|
|
29
|
+
}
|