@githolon/dsl 0.107.4 → 0.108.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/dart/CHANGELOG.md +24 -0
- package/dart/lib/src/application_framework_calls.dart +299 -0
- package/dart/lib/src/generated_call.dart +96 -0
- package/dart/lib/src/nms_generated_runtime.dart +29 -0
- package/dart/lib/src/node_runner_transport.dart +77 -1
- package/dart/lib/src/result_usda.dart +487 -0
- package/dart/lib/src/runner/node-entry.mjs +10634 -6122
- package/dart/lib/src/runner/offline-install.mjs +4187 -2716
- package/dart/lib/src/runtime_v2_gateway.dart +54 -0
- package/dart/lib/src/runtime_v2_transport.dart +117 -0
- package/dart/lib/src/session_bound.dart +7 -2
- package/dart/lib/src/test_harness.dart +373 -282
- package/dart/lib/src/webview_bridge.dart +2146 -725
- package/dart/pubspec.lock +17 -1
- package/dart/pubspec.yaml +3 -2
- package/dart/test/acquire_session_credentials_test.dart +1 -1
- package/dart/test/acquire_session_test.dart +68 -14
- package/dart/test/adv_realm_interference_test.dart +6 -4
- package/dart/test/cluster_births_test.dart +11 -8
- package/dart/test/cluster_local_autosync_test.dart +1 -1
- package/dart/test/cluster_scale_test.dart +3 -2
- package/dart/test/dlq_session_surface_test.dart +52 -35
- package/dart/test/first_app_gauntlet_test.dart +1 -1
- package/dart/test/local_sync_inert_test.dart +23 -26
- package/dart/test/offer_authentication_proof_test.dart +193 -0
- package/dart/test/result_usda_test.dart +49 -0
- package/dart/test/session_bound_test.dart +8 -11
- package/dart/test/stale_bundle_test.dart +18 -3
- package/dart/test/test_harness_test.dart +14 -27
- package/dart/test/webview_bridge_test.dart +504 -83
- package/dart_types/CHANGELOG.md +17 -0
- package/dart_types/lib/nomos_kernel_protocol.dart +11 -0
- package/dart_types/lib/src/custody.dart +64 -19
- package/dart_types/lib/src/local_work_rejected.dart +30 -45
- package/dart_types/lib/src/proto/nomos/custody/v1/snapshot.pb.dart +169 -0
- package/dart_types/lib/src/proto/nomos/custody/v1/snapshot.pbenum.dart +11 -0
- package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pb.dart +17945 -0
- package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pbenum.dart +933 -0
- package/dart_types/lib/src/proto/nomos/kernel/v1/progress.pb.dart +245 -0
- package/dart_types/lib/src/proto/nomos/kernel/v1/progress.pbenum.dart +160 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pb.dart +8664 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pbenum.dart +369 -0
- package/dart_types/lib/src/surfaced.dart +30 -25
- package/dart_types/pubspec.lock +16 -0
- package/dart_types/pubspec.yaml +3 -1
- package/dart_types/test/surfaced_test.dart +2 -1
- package/package.json +1 -1
- package/runtime/generated-application-host.js +5760 -1879
- package/src/authoring.ts +3 -2
- package/src/birth_meter_ensure.ts +2 -0
- package/src/births.ts +21 -0
- package/src/build_package.ts +30 -0
- package/src/business_birth.ts +41 -35
- package/src/codegen_call_usda.ts +1111 -0
- package/src/codegen_dart.ts +207 -282
- package/src/codegen_dart_application.ts +195 -252
- package/src/codegen_dart_client.ts +1978 -593
- package/src/codegen_dart_framework_calls.ts +291 -0
- package/src/codegen_dart_scenario.ts +7 -0
- package/src/codegen_proof.ts +3 -4
- package/src/codegen_provider_dart.ts +21 -7
- package/src/codegen_query_usda.ts +214 -0
- package/src/codegen_result_usda.ts +685 -0
- package/src/codegen_ts.ts +3945 -1111
- package/src/compile_package_main.ts +392 -46
- package/src/directive.ts +19 -4
- package/src/engine_entry.ts +45 -4
- package/src/framework/application_home.ts +4 -0
- package/src/framework/auth_provider_law.ts +296 -20
- package/src/framework/birth_certificate_law.ts +24 -0
- package/src/framework/home.ts +83 -40
- package/src/framework/owned_custody.ts +25 -12
- package/src/framework/owned_custody_value.ts +51 -0
- package/src/framework/relations.ts +47 -21
- package/src/framework/signing_identity.ts +100 -17
- package/src/framework/workspaces.ts +39 -10
- package/src/framework_call_definitions.ts +53 -0
- package/src/framework_read_definitions.ts +45 -0
- package/src/identity_frontier.ts +58 -0
- package/src/index.ts +22 -1
- package/src/intent.ts +216 -16
- package/src/law_check.ts +19 -1
- package/src/law_graph.ts +57 -8
- package/src/law_graph_usda.ts +73 -5
- package/src/law_value_type.ts +106 -19
- package/src/read.ts +47 -0
- package/src/read_projection_namespace.ts +7 -0
- package/src/shape_compat.ts +44 -42
- package/src/stable_ids.ts +37 -2
- package/src/test_call_usda.ts +83 -0
- package/src/wire.ts +36 -2
- package/src/wire_encode.ts +45 -1
- package/src/workspace_sharing.ts +27 -10
|
@@ -6,15 +6,123 @@
|
|
|
6
6
|
import 'dart:async';
|
|
7
7
|
import 'dart:convert';
|
|
8
8
|
import 'dart:io';
|
|
9
|
+
import 'dart:typed_data';
|
|
9
10
|
|
|
10
11
|
import 'package:nomos_client/src/nms_generated_runtime.dart';
|
|
12
|
+
import 'package:nomos_types/nomos_kernel_protocol.dart' as protocol;
|
|
13
|
+
import 'package:fixnum/fixnum.dart' as fixnum;
|
|
11
14
|
import 'package:test/test.dart';
|
|
12
15
|
|
|
16
|
+
protocol.RuntimeResponse _runtimeLifecycleResponse(
|
|
17
|
+
protocol.RuntimeRequest request,
|
|
18
|
+
) {
|
|
19
|
+
final response = protocol.RuntimeResponse(
|
|
20
|
+
protocolVersion: 2,
|
|
21
|
+
requestId: request.requestId,
|
|
22
|
+
);
|
|
23
|
+
switch (request.whichCommand()) {
|
|
24
|
+
case protocol.RuntimeRequest_Command.listWorkspaces:
|
|
25
|
+
response.workspaceList = protocol.WorkspaceList();
|
|
26
|
+
break;
|
|
27
|
+
case protocol.RuntimeRequest_Command.prepareDomain:
|
|
28
|
+
response.domainPrepared = protocol.DomainPrepared(
|
|
29
|
+
domain: request.prepareDomain.domain,
|
|
30
|
+
packageSha256: request.prepareDomain.packageSha256,
|
|
31
|
+
);
|
|
32
|
+
break;
|
|
33
|
+
case protocol.RuntimeRequest_Command.resolveCustodyBreak:
|
|
34
|
+
response.custodyBreakResolved = protocol.CustodyBreakResolved(
|
|
35
|
+
session: request.resolveCustodyBreak.session,
|
|
36
|
+
decision: request.resolveCustodyBreak.decision,
|
|
37
|
+
);
|
|
38
|
+
break;
|
|
39
|
+
case protocol.RuntimeRequest_Command.startAutoSync:
|
|
40
|
+
response.autoSyncStarted =
|
|
41
|
+
protocol.AutoSyncStarted(session: request.startAutoSync.session);
|
|
42
|
+
break;
|
|
43
|
+
case protocol.RuntimeRequest_Command.stopAutoSync:
|
|
44
|
+
response.autoSyncStopped =
|
|
45
|
+
protocol.AutoSyncStopped(session: request.stopAutoSync.session);
|
|
46
|
+
break;
|
|
47
|
+
case protocol.RuntimeRequest_Command.syncWorkspace:
|
|
48
|
+
response.syncWorkspace = protocol.SyncWorkspaceResponse(
|
|
49
|
+
workspace: request.syncWorkspace.session,
|
|
50
|
+
);
|
|
51
|
+
break;
|
|
52
|
+
case protocol.RuntimeRequest_Command.unwatch:
|
|
53
|
+
response.watchStopped = protocol.WatchStopped();
|
|
54
|
+
break;
|
|
55
|
+
case protocol.RuntimeRequest_Command.closeRealm:
|
|
56
|
+
response.realmClosed = protocol.RealmClosed();
|
|
57
|
+
break;
|
|
58
|
+
case protocol.RuntimeRequest_Command.modelLifecycle:
|
|
59
|
+
final lifecycle = request.modelLifecycle;
|
|
60
|
+
switch (lifecycle.whichOperation()) {
|
|
61
|
+
case protocol.ModelLifecycleRequest_Operation.stage:
|
|
62
|
+
response.modelLifecycle = protocol.ModelLifecycleResponse(
|
|
63
|
+
stage: protocol.ModelLifecycleStage.MODEL_LIFECYCLE_STAGE_PENDING,
|
|
64
|
+
accepted: true,
|
|
65
|
+
);
|
|
66
|
+
break;
|
|
67
|
+
case protocol.ModelLifecycleRequest_Operation.adopt:
|
|
68
|
+
response.modelLifecycle = protocol.ModelLifecycleResponse(
|
|
69
|
+
stage: protocol
|
|
70
|
+
.ModelLifecycleStage.MODEL_LIFECYCLE_STAGE_ACCEPTANCE_REQUIRED,
|
|
71
|
+
accepted: false,
|
|
72
|
+
review: protocol.ModelReview(
|
|
73
|
+
checkedActions: fixnum.Int64(1),
|
|
74
|
+
candidateActions: fixnum.Int64(1),
|
|
75
|
+
sameOutcome: false,
|
|
76
|
+
differences: [
|
|
77
|
+
protocol.ModelDifference(
|
|
78
|
+
kind: protocol
|
|
79
|
+
.ModelDifferenceKind.MODEL_DIFFERENCE_KIND_OUTCOME,
|
|
80
|
+
action: 'registerSite',
|
|
81
|
+
summary: 'registerSite has a different outcome',
|
|
82
|
+
),
|
|
83
|
+
],
|
|
84
|
+
),
|
|
85
|
+
);
|
|
86
|
+
break;
|
|
87
|
+
case protocol.ModelLifecycleRequest_Operation.restore:
|
|
88
|
+
response.modelLifecycle = protocol.ModelLifecycleResponse(
|
|
89
|
+
stage: protocol
|
|
90
|
+
.ModelLifecycleStage.MODEL_LIFECYCLE_STAGE_ACCEPTANCE_REQUIRED,
|
|
91
|
+
accepted: false,
|
|
92
|
+
review: protocol.ModelReview(
|
|
93
|
+
checkedActions: fixnum.Int64(1),
|
|
94
|
+
candidateActions: fixnum.Int64(1),
|
|
95
|
+
sameOutcome: false,
|
|
96
|
+
differences: [
|
|
97
|
+
protocol.ModelDifference(
|
|
98
|
+
kind:
|
|
99
|
+
protocol.ModelDifferenceKind.MODEL_DIFFERENCE_KIND_RULES,
|
|
100
|
+
action: 'setMood',
|
|
101
|
+
summary: 'setMood is governed by a different rule',
|
|
102
|
+
),
|
|
103
|
+
],
|
|
104
|
+
),
|
|
105
|
+
);
|
|
106
|
+
break;
|
|
107
|
+
case protocol.ModelLifecycleRequest_Operation.notSet:
|
|
108
|
+
throw StateError('Model lifecycle operation is required');
|
|
109
|
+
}
|
|
110
|
+
break;
|
|
111
|
+
default:
|
|
112
|
+
throw StateError(
|
|
113
|
+
'Fake lifecycle transport does not implement '
|
|
114
|
+
'${request.whichCommand().name}',
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
return response;
|
|
118
|
+
}
|
|
119
|
+
|
|
13
120
|
/// A fake runner-over-a-transport: records sent requests, replies the way `webview-runner.mjs` does, and can
|
|
14
121
|
/// push reactive `watch` events. Lets us drive [NomosBridge] without a real WebView.
|
|
15
122
|
class FakeRunner implements BridgeTransport {
|
|
16
123
|
final _incoming = StreamController<Map<String, Object?>>.broadcast();
|
|
17
124
|
final List<Map<String, Object?>> sent = [];
|
|
125
|
+
final List<protocol.RuntimeRequest> runtimeRequests = [];
|
|
18
126
|
String? lastWatchSubId;
|
|
19
127
|
bool acknowledgeWatch = true;
|
|
20
128
|
bool acknowledgeUnwatch = true;
|
|
@@ -31,6 +139,29 @@ class FakeRunner implements BridgeTransport {
|
|
|
31
139
|
@override
|
|
32
140
|
Stream<Map<String, Object?>> get messages => _incoming.stream;
|
|
33
141
|
|
|
142
|
+
@override
|
|
143
|
+
Future<protocol.RuntimeResponse> invokeRuntime(
|
|
144
|
+
protocol.RuntimeRequest request,
|
|
145
|
+
) async {
|
|
146
|
+
runtimeRequests.add(request.deepCopy());
|
|
147
|
+
if (!acknowledgeUnwatch && request.hasUnwatch()) {
|
|
148
|
+
return Completer<protocol.RuntimeResponse>().future;
|
|
149
|
+
}
|
|
150
|
+
if (request.hasSyncWorkspace() && !request.syncWorkspace.admit) {
|
|
151
|
+
return protocol.RuntimeResponse(
|
|
152
|
+
protocolVersion: 2,
|
|
153
|
+
requestId: request.requestId,
|
|
154
|
+
failure: protocol.RuntimeFailure(
|
|
155
|
+
code: 'nomos.sync.refused',
|
|
156
|
+
message: 'typed sync failed',
|
|
157
|
+
component: 'test.runner',
|
|
158
|
+
workspace: request.syncWorkspace.session,
|
|
159
|
+
),
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
return _runtimeLifecycleResponse(request);
|
|
163
|
+
}
|
|
164
|
+
|
|
34
165
|
@override
|
|
35
166
|
void send(Map<String, Object?> message) {
|
|
36
167
|
sent.add(message);
|
|
@@ -193,15 +324,33 @@ class FakeRunner implements BridgeTransport {
|
|
|
193
324
|
}));
|
|
194
325
|
break;
|
|
195
326
|
case 'cryptoOwnedDeviceRequest':
|
|
196
|
-
_incoming.add(reply({
|
|
327
|
+
_incoming.add(reply({
|
|
328
|
+
'request': {
|
|
329
|
+
'v': 1,
|
|
330
|
+
'workspace': 'notes',
|
|
331
|
+
'principal': 'user:alice',
|
|
332
|
+
'scope': 'nomos_internal_owned_read_7c1f5e',
|
|
333
|
+
'signingPublic': 'AA==',
|
|
334
|
+
'wrappingPublic': 'AQ==',
|
|
335
|
+
'signature': 'Ag==',
|
|
336
|
+
},
|
|
337
|
+
}));
|
|
197
338
|
break;
|
|
198
339
|
case 'cryptoOwnedPrepareApproval':
|
|
199
340
|
_incoming.add(reply({
|
|
200
341
|
'newKeySubject': 'key:${'a' * 64}',
|
|
201
|
-
'ownedCustody':
|
|
342
|
+
'ownedCustody': {
|
|
343
|
+
'v': 1,
|
|
344
|
+
'request': args['request'],
|
|
345
|
+
'hpkeEpk': 'Aw==',
|
|
346
|
+
'ct': 'BA==',
|
|
347
|
+
'keyCommitment': '0' * 64,
|
|
348
|
+
'principalWrappingPublic': 'BQ==',
|
|
349
|
+
},
|
|
202
350
|
'verifiedVia': 'nomos:test-root',
|
|
203
351
|
'validFromEpoch': 0,
|
|
204
352
|
'approvedAt': '2026-07-18T14:20:00.000Z',
|
|
353
|
+
'__nomos_owned_device_key_subject_7c1f5e': 'key:${'b' * 64}',
|
|
205
354
|
}));
|
|
206
355
|
break;
|
|
207
356
|
case 'cryptoOwnedScopeKeys':
|
|
@@ -220,9 +369,11 @@ class FakeRunner implements BridgeTransport {
|
|
|
220
369
|
break;
|
|
221
370
|
case 'cryptoOwnedPrepareRecordAction':
|
|
222
371
|
_incoming.add(reply({
|
|
372
|
+
'__nomos_owned_device_key_subject_7c1f5e': 'key:${'c' * 64}',
|
|
223
373
|
'recordId': 'note-1',
|
|
224
374
|
'peer': 'user:bob',
|
|
225
375
|
'epoch': 2,
|
|
376
|
+
'sharedAt': '2026-07-18T14:25:00.000Z',
|
|
226
377
|
'wraps': <Object?>[],
|
|
227
378
|
}));
|
|
228
379
|
break;
|
|
@@ -351,12 +502,160 @@ class FakeRunner implements BridgeTransport {
|
|
|
351
502
|
});
|
|
352
503
|
}
|
|
353
504
|
|
|
505
|
+
/// Proves that generated application reads bypass the legacy operation bus.
|
|
506
|
+
/// The ordinary bridge remains present for lifecycle setup, but a query can
|
|
507
|
+
/// only succeed through the generated Runtime v2 kernel-call capability.
|
|
508
|
+
class FakeTypedRunner extends FakeRunner
|
|
509
|
+
implements NomosKernelCallTransport, NomosRuntimeV2Transport {
|
|
510
|
+
protocol.CallRequest? lastKernelCall;
|
|
511
|
+
String? lastKernelSession;
|
|
512
|
+
@override
|
|
513
|
+
Future<protocol.CallResponse> callKernel({
|
|
514
|
+
required String session,
|
|
515
|
+
required protocol.CallRequest request,
|
|
516
|
+
}) async {
|
|
517
|
+
lastKernelSession = session;
|
|
518
|
+
lastKernelCall = request;
|
|
519
|
+
if (request.hasQuery() && request.query.hasOwnedDeviceRequest()) {
|
|
520
|
+
final value = OwnedDeviceRequest(
|
|
521
|
+
v: 1,
|
|
522
|
+
workspace: 'home',
|
|
523
|
+
principal: 'user:alice',
|
|
524
|
+
scope: request.query.ownedDeviceRequest.scope,
|
|
525
|
+
signingPublic: 'AA==',
|
|
526
|
+
wrappingPublic: 'AQ==',
|
|
527
|
+
signature: 'Ag==',
|
|
528
|
+
);
|
|
529
|
+
return protocol.CallResponse(
|
|
530
|
+
protocolVersion: 1,
|
|
531
|
+
requestId: request.requestId,
|
|
532
|
+
query: protocol.QueryResponse(
|
|
533
|
+
ownedDeviceRequest: protocol.OwnedDeviceRequestResponse(
|
|
534
|
+
requestUsda: value.encodeUsda(),
|
|
535
|
+
),
|
|
536
|
+
),
|
|
537
|
+
);
|
|
538
|
+
}
|
|
539
|
+
if (request.hasQuery() && request.query.hasOwnedPrepareApproval()) {
|
|
540
|
+
final device = OwnedDeviceRequest.decodeUsda(
|
|
541
|
+
Uint8List.fromList(
|
|
542
|
+
request.query.ownedPrepareApproval.requestUsda,
|
|
543
|
+
),
|
|
544
|
+
);
|
|
545
|
+
final custody = OwnedCustody(
|
|
546
|
+
v: 1,
|
|
547
|
+
request: device,
|
|
548
|
+
hpkeEpk: 'Aw==',
|
|
549
|
+
ct: 'BA==',
|
|
550
|
+
keyCommitment: '0' * 64,
|
|
551
|
+
principalWrappingPublic: 'BQ==',
|
|
552
|
+
);
|
|
553
|
+
return protocol.CallResponse(
|
|
554
|
+
protocolVersion: 1,
|
|
555
|
+
requestId: request.requestId,
|
|
556
|
+
query: protocol.QueryResponse(
|
|
557
|
+
ownedPrepareApproval: protocol.OwnedPrepareApprovalResponse(
|
|
558
|
+
newKeySubject: 'key:${'a' * 64}',
|
|
559
|
+
ownedCustodyUsda: custody.encodeUsda(),
|
|
560
|
+
verifiedVia: 'nomos:test-root',
|
|
561
|
+
validFromEpoch: fixnum.Int64.ZERO,
|
|
562
|
+
approvedAtUnixMillis: fixnum.Int64(1787062800000),
|
|
563
|
+
ownedKeySubject: 'key:${'b' * 64}',
|
|
564
|
+
),
|
|
565
|
+
),
|
|
566
|
+
);
|
|
567
|
+
}
|
|
568
|
+
return protocol.CallResponse(
|
|
569
|
+
protocolVersion: 1,
|
|
570
|
+
requestId: request.requestId,
|
|
571
|
+
query: protocol.QueryResponse(
|
|
572
|
+
resultUsda: utf8.encode('''#usda 1.0
|
|
573
|
+
(
|
|
574
|
+
defaultPrim = "Result"
|
|
575
|
+
)
|
|
576
|
+
def NomosReadResult "Result"
|
|
577
|
+
{
|
|
578
|
+
def NomosListValue "Rows"
|
|
579
|
+
{
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
'''),
|
|
583
|
+
),
|
|
584
|
+
);
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
@override
|
|
588
|
+
Future<protocol.RuntimeResponse> invokeRuntime(
|
|
589
|
+
protocol.RuntimeRequest request) async {
|
|
590
|
+
runtimeRequests.add(request.deepCopy());
|
|
591
|
+
final response = protocol.RuntimeResponse(
|
|
592
|
+
protocolVersion: 2,
|
|
593
|
+
requestId: request.requestId,
|
|
594
|
+
);
|
|
595
|
+
switch (request.whichCommand()) {
|
|
596
|
+
case protocol.RuntimeRequest_Command.listWorkspaces:
|
|
597
|
+
response.workspaceList = protocol.WorkspaceList(workspaces: [
|
|
598
|
+
protocol.WorkspaceSummary(
|
|
599
|
+
session: 'home',
|
|
600
|
+
workspace: 'home',
|
|
601
|
+
residency: protocol.WorkspaceResidency.WORKSPACE_RESIDENCY_MOUNTED,
|
|
602
|
+
syncPosture: protocol
|
|
603
|
+
.WorkspaceSyncPosture.WORKSPACE_SYNC_POSTURE_CLOUD_BOUND,
|
|
604
|
+
),
|
|
605
|
+
]);
|
|
606
|
+
break;
|
|
607
|
+
case protocol.RuntimeRequest_Command.prepareDomain:
|
|
608
|
+
response.domainPrepared = protocol.DomainPrepared(
|
|
609
|
+
domain: request.prepareDomain.domain,
|
|
610
|
+
packageSha256: request.prepareDomain.packageSha256,
|
|
611
|
+
);
|
|
612
|
+
break;
|
|
613
|
+
case protocol.RuntimeRequest_Command.resolveCustodyBreak:
|
|
614
|
+
response.custodyBreakResolved = protocol.CustodyBreakResolved(
|
|
615
|
+
session: request.resolveCustodyBreak.session,
|
|
616
|
+
decision: request.resolveCustodyBreak.decision,
|
|
617
|
+
);
|
|
618
|
+
break;
|
|
619
|
+
case protocol.RuntimeRequest_Command.startAutoSync:
|
|
620
|
+
response.autoSyncStarted =
|
|
621
|
+
protocol.AutoSyncStarted(session: request.startAutoSync.session);
|
|
622
|
+
break;
|
|
623
|
+
case protocol.RuntimeRequest_Command.stopAutoSync:
|
|
624
|
+
response.autoSyncStopped =
|
|
625
|
+
protocol.AutoSyncStopped(session: request.stopAutoSync.session);
|
|
626
|
+
break;
|
|
627
|
+
case protocol.RuntimeRequest_Command.syncWorkspace:
|
|
628
|
+
response.syncWorkspace = protocol.SyncWorkspaceResponse(
|
|
629
|
+
workspace: request.syncWorkspace.session,
|
|
630
|
+
);
|
|
631
|
+
break;
|
|
632
|
+
case protocol.RuntimeRequest_Command.closeRealm:
|
|
633
|
+
response.realmClosed = protocol.RealmClosed();
|
|
634
|
+
break;
|
|
635
|
+
case protocol.RuntimeRequest_Command.modelLifecycle:
|
|
636
|
+
response.modelLifecycle =
|
|
637
|
+
_runtimeLifecycleResponse(request).modelLifecycle;
|
|
638
|
+
break;
|
|
639
|
+
default:
|
|
640
|
+
throw StateError(
|
|
641
|
+
'FakeTypedRunner does not implement ${request.whichCommand().name}');
|
|
642
|
+
}
|
|
643
|
+
return response;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
|
|
354
647
|
class ErrorRunner implements BridgeTransport {
|
|
355
648
|
final _incoming = StreamController<Map<String, Object?>>.broadcast();
|
|
356
649
|
|
|
357
650
|
@override
|
|
358
651
|
Stream<Map<String, Object?>> get messages => _incoming.stream;
|
|
359
652
|
|
|
653
|
+
@override
|
|
654
|
+
Future<protocol.RuntimeResponse> invokeRuntime(
|
|
655
|
+
protocol.RuntimeRequest request,
|
|
656
|
+
) async =>
|
|
657
|
+
_runtimeLifecycleResponse(request);
|
|
658
|
+
|
|
360
659
|
@override
|
|
361
660
|
void send(Map<String, Object?> message) {}
|
|
362
661
|
|
|
@@ -380,6 +679,11 @@ class ReplayTransport implements BridgeTransport {
|
|
|
380
679
|
@override
|
|
381
680
|
Stream<Map<String, Object?>> get messages => _incoming.stream;
|
|
382
681
|
@override
|
|
682
|
+
Future<protocol.RuntimeResponse> invokeRuntime(
|
|
683
|
+
protocol.RuntimeRequest request,
|
|
684
|
+
) async =>
|
|
685
|
+
_runtimeLifecycleResponse(request);
|
|
686
|
+
@override
|
|
383
687
|
void send(Map<String, Object?> message) {
|
|
384
688
|
lastRequest = message;
|
|
385
689
|
final id = message['id'];
|
|
@@ -459,6 +763,7 @@ Object? _expectedTyped(String op, Map<String, Object?> result) {
|
|
|
459
763
|
case 'sum':
|
|
460
764
|
return result['sum'];
|
|
461
765
|
case 'sync':
|
|
766
|
+
return isA<protocol.SyncWorkspaceResponse>();
|
|
462
767
|
case 'lawStatus':
|
|
463
768
|
return result;
|
|
464
769
|
default:
|
|
@@ -492,6 +797,8 @@ void main() {
|
|
|
492
797
|
() => expect(corpus['version'], kWebviewBridgeVersion));
|
|
493
798
|
for (final c in cases) {
|
|
494
799
|
final op = c['op'] as String;
|
|
800
|
+
if (op == 'sync')
|
|
801
|
+
continue; // Runtime v2 has its own protobuf conformance tests.
|
|
495
802
|
final args = (c['args'] as Map).cast<String, Object?>();
|
|
496
803
|
final result = (c['result'] as Map).cast<String, Object?>();
|
|
497
804
|
test("'$op' request args + parsed result match the corpus", () async {
|
|
@@ -636,6 +943,93 @@ void main() {
|
|
|
636
943
|
await bridge.ready.timeout(const Duration(seconds: 1));
|
|
637
944
|
});
|
|
638
945
|
|
|
946
|
+
test('nominal queries use Runtime v2 protobuf and return USDA bytes',
|
|
947
|
+
() async {
|
|
948
|
+
final typedRunner = FakeTypedRunner();
|
|
949
|
+
final typedBridge = NomosBridge(typedRunner);
|
|
950
|
+
addTearDown(typedBridge.dispose);
|
|
951
|
+
await typedBridge.ready;
|
|
952
|
+
await typedBridge.connect(
|
|
953
|
+
cloud: 'https://c',
|
|
954
|
+
workspace: 'home',
|
|
955
|
+
session: 'home',
|
|
956
|
+
);
|
|
957
|
+
typedRunner.sent.clear();
|
|
958
|
+
|
|
959
|
+
final result = await typedBridge.nmsQueryUsda(
|
|
960
|
+
NmsInternalGeneratedQueries.create(
|
|
961
|
+
domain: 'entries',
|
|
962
|
+
query: 'entriesByOwner',
|
|
963
|
+
canonicalArgumentsUsda: Uint8List.fromList(utf8.encode('''#usda 1.0
|
|
964
|
+
(
|
|
965
|
+
defaultPrim = "Arguments"
|
|
966
|
+
)
|
|
967
|
+
def NomosQueryArguments "Arguments"
|
|
968
|
+
{
|
|
969
|
+
custom string nomos:owner = "user:ada"
|
|
970
|
+
}
|
|
971
|
+
''')),
|
|
972
|
+
),
|
|
973
|
+
null,
|
|
974
|
+
'user:ada',
|
|
975
|
+
'home',
|
|
976
|
+
);
|
|
977
|
+
|
|
978
|
+
expect(result, isA<Uint8List>());
|
|
979
|
+
expect(utf8.decode(result), startsWith('#usda 1.0'));
|
|
980
|
+
expect(typedRunner.sent, isEmpty,
|
|
981
|
+
reason: 'the JSON-shaped BridgeTransport must not carry the query');
|
|
982
|
+
expect(typedRunner.lastKernelSession, 'home');
|
|
983
|
+
expect(typedRunner.lastKernelCall!.hasQuery(), isTrue);
|
|
984
|
+
expect(typedRunner.lastKernelCall!.query.rows.id, 'entriesByOwner');
|
|
985
|
+
expect(
|
|
986
|
+
typedRunner.lastKernelCall!.query.resultFormat,
|
|
987
|
+
protocol.QueryResultFormat.QUERY_RESULT_FORMAT_NOMINAL_USDA,
|
|
988
|
+
);
|
|
989
|
+
});
|
|
990
|
+
|
|
991
|
+
test('steady-state lifecycle uses generated Runtime v2 commands', () async {
|
|
992
|
+
final typedRunner = FakeTypedRunner();
|
|
993
|
+
final typedBridge = NomosBridge(typedRunner);
|
|
994
|
+
await typedBridge.ready;
|
|
995
|
+
await typedBridge.connect(
|
|
996
|
+
cloud: 'https://c',
|
|
997
|
+
workspace: 'home',
|
|
998
|
+
session: 'home',
|
|
999
|
+
);
|
|
1000
|
+
typedRunner.sent.clear();
|
|
1001
|
+
|
|
1002
|
+
final workspaces = await typedBridge.listWorkspaces();
|
|
1003
|
+
await typedBridge.session('home').prepareDomain(
|
|
1004
|
+
domain: 'guestbook',
|
|
1005
|
+
packageHash: 'a' * 64,
|
|
1006
|
+
);
|
|
1007
|
+
await typedBridge.session('home').autoSync(fallbackMs: 60000);
|
|
1008
|
+
await typedBridge.session('home').stopAutoSync();
|
|
1009
|
+
final custody = await typedBridge.session('home').resolveCustodyBreak(
|
|
1010
|
+
protocol.CustodyBreakDecision.CUSTODY_BREAK_DECISION_ADOPT,
|
|
1011
|
+
);
|
|
1012
|
+
|
|
1013
|
+
expect(workspaces.single.workspace, 'home');
|
|
1014
|
+
expect(
|
|
1015
|
+
custody.decision,
|
|
1016
|
+
protocol.CustodyBreakDecision.CUSTODY_BREAK_DECISION_ADOPT,
|
|
1017
|
+
);
|
|
1018
|
+
expect(
|
|
1019
|
+
typedRunner.runtimeRequests.map((request) => request.whichCommand()),
|
|
1020
|
+
[
|
|
1021
|
+
protocol.RuntimeRequest_Command.listWorkspaces,
|
|
1022
|
+
protocol.RuntimeRequest_Command.prepareDomain,
|
|
1023
|
+
protocol.RuntimeRequest_Command.startAutoSync,
|
|
1024
|
+
protocol.RuntimeRequest_Command.stopAutoSync,
|
|
1025
|
+
protocol.RuntimeRequest_Command.resolveCustodyBreak,
|
|
1026
|
+
],
|
|
1027
|
+
);
|
|
1028
|
+
expect(typedRunner.sent, isEmpty,
|
|
1029
|
+
reason: 'no JSON command envelope carries steady-state lifecycle');
|
|
1030
|
+
await typedBridge.dispose();
|
|
1031
|
+
});
|
|
1032
|
+
|
|
639
1033
|
test('a local durability span remains workspace/head specific', () async {
|
|
640
1034
|
await bridge.ready;
|
|
641
1035
|
bridge.noteLocalSpan(
|
|
@@ -750,28 +1144,35 @@ void main() {
|
|
|
750
1144
|
expect(bridge.principal, 'user:ada');
|
|
751
1145
|
});
|
|
752
1146
|
|
|
753
|
-
test(
|
|
754
|
-
'generated model restoration crosses one framework-private bridge operation',
|
|
1147
|
+
test('generated model restoration uses one exact Runtime v2 command',
|
|
755
1148
|
() async {
|
|
756
1149
|
await bridge.ready;
|
|
1150
|
+
await bridge.connect(cloud: 'https://c', workspace: 'evo');
|
|
1151
|
+
runner.runtimeRequests.clear();
|
|
757
1152
|
final verdict = await bridge.nomosFrameworkRestorePreviousGeneratedModel(
|
|
758
1153
|
domain: 'evo',
|
|
759
1154
|
currentHash: 'current-law-hash',
|
|
760
1155
|
because: 'the previous operating policy is required',
|
|
761
1156
|
);
|
|
762
1157
|
|
|
763
|
-
expect(verdict
|
|
764
|
-
expect(
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
final request = runner.sent.firstWhere(
|
|
768
|
-
(message) => message['op'] == 'restorePreviousGeneratedModel',
|
|
1158
|
+
expect(verdict.accepted, isFalse);
|
|
1159
|
+
expect(
|
|
1160
|
+
verdict.stage,
|
|
1161
|
+
protocol.ModelLifecycleStage.MODEL_LIFECYCLE_STAGE_ACCEPTANCE_REQUIRED,
|
|
769
1162
|
);
|
|
770
|
-
expect(
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
1163
|
+
expect(verdict.review.differences.single.action, 'setMood');
|
|
1164
|
+
final request = runner.runtimeRequests.singleWhere(
|
|
1165
|
+
(request) =>
|
|
1166
|
+
request.hasModelLifecycle() && request.modelLifecycle.hasRestore(),
|
|
1167
|
+
);
|
|
1168
|
+
expect(request.modelLifecycle.restore.domain, 'evo');
|
|
1169
|
+
expect(request.modelLifecycle.restore.currentHash, 'current-law-hash');
|
|
1170
|
+
expect(request.modelLifecycle.restore.acceptanceReason,
|
|
1171
|
+
'the previous operating policy is required');
|
|
1172
|
+
expect(
|
|
1173
|
+
runner.sent.where(
|
|
1174
|
+
(message) => message['op'] == 'restorePreviousGeneratedModel'),
|
|
1175
|
+
isEmpty);
|
|
775
1176
|
});
|
|
776
1177
|
|
|
777
1178
|
test(
|
|
@@ -788,7 +1189,7 @@ void main() {
|
|
|
788
1189
|
expect(page.done, isFalse);
|
|
789
1190
|
expect((await bridge.queryById('Entry_1')).first['id'], 'Entry_1');
|
|
790
1191
|
expect(await bridge.count('entries'), 7);
|
|
791
|
-
expect(await bridge.sync(),
|
|
1192
|
+
expect((await bridge.sync()).workspace, 'ws');
|
|
792
1193
|
expect(
|
|
793
1194
|
await bridge.lawStatus('abc'), {'installed': true, 'drifted': false});
|
|
794
1195
|
});
|
|
@@ -868,50 +1269,53 @@ void main() {
|
|
|
868
1269
|
await readBridge.dispose();
|
|
869
1270
|
});
|
|
870
1271
|
|
|
871
|
-
test(
|
|
1272
|
+
test(
|
|
1273
|
+
'devices retain nominal request and custody types through one atomic approval',
|
|
872
1274
|
() async {
|
|
873
|
-
|
|
1275
|
+
final typedRunner = FakeTypedRunner();
|
|
1276
|
+
final typedBridge = NomosBridge(typedRunner);
|
|
1277
|
+
addTearDown(typedBridge.dispose);
|
|
1278
|
+
await typedBridge.ready;
|
|
1279
|
+
await typedBridge.connect(
|
|
1280
|
+
cloud: 'https://c',
|
|
1281
|
+
workspace: 'home',
|
|
1282
|
+
session: 'home',
|
|
1283
|
+
authorSecret: base64Encode(List<int>.filled(32, 7)),
|
|
1284
|
+
authToken: 'e30.eyJzdWIiOiJhbGljZSJ9.',
|
|
1285
|
+
);
|
|
1286
|
+
NomosOwnedDeviceApprovalPreparation? approved;
|
|
874
1287
|
final devices = NomosDevices(
|
|
875
|
-
bridge:
|
|
1288
|
+
bridge: typedBridge.session('home'),
|
|
876
1289
|
domain: 'notes',
|
|
877
1290
|
domainHash: 'a' * 64,
|
|
878
1291
|
actor: 'user:alice',
|
|
879
1292
|
scope: 'nomos_internal_owned_read_7c1f5e',
|
|
1293
|
+
approvePrepared: (preparation) async {
|
|
1294
|
+
approved = preparation;
|
|
1295
|
+
return const NomosOfferOutcome(
|
|
1296
|
+
head: 'HEAD-owned-approval',
|
|
1297
|
+
created: [],
|
|
1298
|
+
workspace: 'notes',
|
|
1299
|
+
);
|
|
1300
|
+
},
|
|
880
1301
|
);
|
|
881
1302
|
|
|
882
1303
|
final request = await devices.request();
|
|
883
|
-
expect(request, '
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
);
|
|
887
|
-
expect((requestCall['args'] as Map)['scope'],
|
|
888
|
-
'nomos_internal_owned_read_7c1f5e');
|
|
1304
|
+
expect(request.workspace, 'home');
|
|
1305
|
+
expect(request.principal, 'user:alice');
|
|
1306
|
+
expect(request.scope, 'nomos_internal_owned_read_7c1f5e');
|
|
1307
|
+
expect(typedRunner.lastKernelCall!.query.hasOwnedDeviceRequest(), isTrue);
|
|
889
1308
|
|
|
890
1309
|
final outcome = await devices.approve(request);
|
|
891
1310
|
expect(outcome.head, 'HEAD-owned-approval');
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
);
|
|
895
|
-
expect(
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
(message) => message['op'] == 'offerDirective',
|
|
901
|
-
);
|
|
902
|
-
final offerArgs = (offerCall['args'] as Map).cast<String, Object?>();
|
|
903
|
-
expect(offerArgs['domain'], 'notes');
|
|
904
|
-
expect(
|
|
905
|
-
offerArgs['directiveId'], 'nomos_internal_approve_owned_device_7c1f5e');
|
|
906
|
-
expect(offerArgs['actor'], 'user:alice');
|
|
907
|
-
expect(offerArgs['domainHash'], 'a' * 64);
|
|
908
|
-
expect(offerArgs['payload'], {
|
|
909
|
-
'newKeySubject': 'key:${'a' * 64}',
|
|
910
|
-
'ownedCustody': 'opaque-owned-custody',
|
|
911
|
-
'verifiedVia': 'nomos:test-root',
|
|
912
|
-
'validFromEpoch': 0,
|
|
913
|
-
'approvedAt': '2026-07-18T14:20:00.000Z',
|
|
914
|
-
});
|
|
1311
|
+
expect(typedRunner.lastKernelCall!.query.hasOwnedPrepareApproval(), isTrue);
|
|
1312
|
+
expect(approved?.newKeySubject, 'key:${'a' * 64}');
|
|
1313
|
+
expect(approved?.ownedCustody.request.workspace, 'home');
|
|
1314
|
+
expect(approved?.ownedCustody.keyCommitment, '0' * 64);
|
|
1315
|
+
expect(approved?.verifiedVia, 'nomos:test-root');
|
|
1316
|
+
expect(approved?.validFromEpoch, 0);
|
|
1317
|
+
expect(approved?.approvedAt, '2026-08-18T14:20:00.000Z');
|
|
1318
|
+
expect(approved?.ownedKeySubject, 'key:${'b' * 64}');
|
|
915
1319
|
});
|
|
916
1320
|
|
|
917
1321
|
test(
|
|
@@ -941,7 +1345,9 @@ void main() {
|
|
|
941
1345
|
),
|
|
942
1346
|
peer: 'user:bob',
|
|
943
1347
|
);
|
|
944
|
-
expect(payload,
|
|
1348
|
+
expect(payload, isA<NomosOwnedSharePreparation>());
|
|
1349
|
+
expect((payload as NomosOwnedSharePreparation).recordId, 'note-1');
|
|
1350
|
+
expect(payload.ownedKeySubject, 'key:${'c' * 64}');
|
|
945
1351
|
|
|
946
1352
|
final keyCall = runner.sent.firstWhere(
|
|
947
1353
|
(message) => message['op'] == 'cryptoOwnedScopeKeys',
|
|
@@ -969,48 +1375,57 @@ void main() {
|
|
|
969
1375
|
});
|
|
970
1376
|
});
|
|
971
1377
|
|
|
972
|
-
test(
|
|
973
|
-
'generated model adoption crosses one framework-private bridge operation',
|
|
974
|
-
() async {
|
|
1378
|
+
test('generated model adoption uses one exact Runtime v2 command', () async {
|
|
975
1379
|
await bridge.ready;
|
|
1380
|
+
await bridge.connect(cloud: 'https://c', workspace: 'evo');
|
|
1381
|
+
runner.runtimeRequests.clear();
|
|
976
1382
|
final verdict = await bridge.nomosFrameworkAdoptGeneratedModel(
|
|
977
1383
|
domain: 'evo',
|
|
978
1384
|
candidateHash: 'candidate-law-hash',
|
|
979
1385
|
because: 'the renamed business action is intentional',
|
|
980
1386
|
);
|
|
981
1387
|
|
|
982
|
-
expect(verdict
|
|
983
|
-
expect(
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
final request = runner.sent.firstWhere(
|
|
987
|
-
(message) => message['op'] == 'adoptGeneratedModel',
|
|
1388
|
+
expect(verdict.accepted, isFalse);
|
|
1389
|
+
expect(
|
|
1390
|
+
verdict.stage,
|
|
1391
|
+
protocol.ModelLifecycleStage.MODEL_LIFECYCLE_STAGE_ACCEPTANCE_REQUIRED,
|
|
988
1392
|
);
|
|
989
|
-
expect(
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
1393
|
+
expect(verdict.review.differences.single.action, 'registerSite');
|
|
1394
|
+
final request = runner.runtimeRequests.singleWhere(
|
|
1395
|
+
(request) =>
|
|
1396
|
+
request.hasModelLifecycle() && request.modelLifecycle.hasAdopt(),
|
|
1397
|
+
);
|
|
1398
|
+
expect(request.modelLifecycle.adopt.domain, 'evo');
|
|
1399
|
+
expect(request.modelLifecycle.adopt.candidateHash, 'candidate-law-hash');
|
|
1400
|
+
expect(request.modelLifecycle.adopt.acceptanceReason,
|
|
1401
|
+
'the renamed business action is intentional');
|
|
1402
|
+
expect(
|
|
1403
|
+
runner.sent.where((message) => message['op'] == 'adoptGeneratedModel'),
|
|
1404
|
+
isEmpty);
|
|
994
1405
|
});
|
|
995
1406
|
|
|
996
1407
|
test(
|
|
997
|
-
'generated model staging carries
|
|
1408
|
+
'generated model staging carries USDA bytes in one exact Runtime v2 command',
|
|
998
1409
|
() async {
|
|
999
1410
|
await bridge.ready;
|
|
1411
|
+
await bridge.connect(cloud: 'https://c', workspace: 'evo');
|
|
1412
|
+
runner.runtimeRequests.clear();
|
|
1000
1413
|
await bridge.nomosInternalStageGeneratedModel(
|
|
1001
1414
|
domain: 'evo',
|
|
1002
1415
|
candidateHash: 'candidate-law-hash',
|
|
1003
1416
|
lawUsdz: const [1, 2, 3],
|
|
1004
1417
|
);
|
|
1005
1418
|
|
|
1006
|
-
final request = runner.
|
|
1007
|
-
(
|
|
1419
|
+
final request = runner.runtimeRequests.singleWhere(
|
|
1420
|
+
(request) =>
|
|
1421
|
+
request.hasModelLifecycle() && request.modelLifecycle.hasStage(),
|
|
1008
1422
|
);
|
|
1009
|
-
expect(
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1423
|
+
expect(request.modelLifecycle.stage.domain, 'evo');
|
|
1424
|
+
expect(request.modelLifecycle.stage.candidateHash, 'candidate-law-hash');
|
|
1425
|
+
expect(request.modelLifecycle.stage.lawUsdz, [1, 2, 3]);
|
|
1426
|
+
expect(
|
|
1427
|
+
runner.sent.where((message) => message['op'] == 'stageGeneratedModel'),
|
|
1428
|
+
isEmpty);
|
|
1014
1429
|
});
|
|
1015
1430
|
|
|
1016
1431
|
test(
|
|
@@ -1036,7 +1451,8 @@ void main() {
|
|
|
1036
1451
|
]
|
|
1037
1452
|
]);
|
|
1038
1453
|
await sub.cancel();
|
|
1039
|
-
expect(
|
|
1454
|
+
expect(
|
|
1455
|
+
runner.runtimeRequests.any((request) => request.hasUnwatch()), isTrue);
|
|
1040
1456
|
});
|
|
1041
1457
|
|
|
1042
1458
|
test('watch cancellation is local and never waits for the runner', () async {
|
|
@@ -1046,7 +1462,8 @@ void main() {
|
|
|
1046
1462
|
await Future<void>.delayed(Duration.zero);
|
|
1047
1463
|
|
|
1048
1464
|
await sub.cancel().timeout(const Duration(milliseconds: 100));
|
|
1049
|
-
expect(
|
|
1465
|
+
expect(
|
|
1466
|
+
runner.runtimeRequests.any((request) => request.hasUnwatch()), isTrue);
|
|
1050
1467
|
});
|
|
1051
1468
|
|
|
1052
1469
|
test('signal events are forwarded on their own stream', () async {
|
|
@@ -1071,9 +1488,10 @@ void main() {
|
|
|
1071
1488
|
|
|
1072
1489
|
test('autoSync forwards a scoped signal id', () async {
|
|
1073
1490
|
await bridge.ready;
|
|
1074
|
-
await bridge.autoSync(signalId: 'signal:ws:list:main');
|
|
1075
|
-
final
|
|
1076
|
-
|
|
1491
|
+
await bridge.session('ws').autoSync(signalId: 'signal:ws:list:main');
|
|
1492
|
+
final request = runner.runtimeRequests
|
|
1493
|
+
.firstWhere((request) => request.hasStartAutoSync());
|
|
1494
|
+
expect(request.startAutoSync.signalId, 'signal:ws:list:main');
|
|
1077
1495
|
});
|
|
1078
1496
|
|
|
1079
1497
|
test(
|
|
@@ -1463,10 +1881,13 @@ void main() {
|
|
|
1463
1881
|
expect(e.message, contains('shallow-insufficient'));
|
|
1464
1882
|
});
|
|
1465
1883
|
|
|
1466
|
-
test(
|
|
1467
|
-
'legacy string-only runner errors still get operation and trace metadata',
|
|
1468
|
-
() async {
|
|
1884
|
+
test('Runtime v2 failures preserve their generated error identity', () async {
|
|
1469
1885
|
await bridge.ready;
|
|
1886
|
+
await bridge.connect(
|
|
1887
|
+
cloud: 'https://c',
|
|
1888
|
+
workspace: 'ws-1',
|
|
1889
|
+
session: 'ws-1',
|
|
1890
|
+
);
|
|
1470
1891
|
Object? err;
|
|
1471
1892
|
try {
|
|
1472
1893
|
await bridge.sync(admit: false);
|
|
@@ -1475,10 +1896,10 @@ void main() {
|
|
|
1475
1896
|
}
|
|
1476
1897
|
expect(err, isA<NomosBridgeError>());
|
|
1477
1898
|
final e = err as NomosBridgeError;
|
|
1478
|
-
expect(e.message, '
|
|
1479
|
-
expect(e.info.code, 'nomos.
|
|
1480
|
-
expect(e.info.
|
|
1481
|
-
expect(e.info.
|
|
1899
|
+
expect(e.message, 'typed sync failed');
|
|
1900
|
+
expect(e.info.code, 'nomos.sync.refused');
|
|
1901
|
+
expect(e.info.component, 'test.runner');
|
|
1902
|
+
expect(e.info.workspace, 'ws-1');
|
|
1482
1903
|
});
|
|
1483
1904
|
|
|
1484
1905
|
test('typed kernel progress preserves the measured verification fraction',
|