@githolon/dsl 0.114.0 → 0.116.2
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/dart/CHANGELOG.md +55 -0
- package/dart/lib/src/application_framework_calls.dart +7 -1
- package/dart/lib/src/console_enrolment.dart +7 -0
- package/dart/lib/src/console_http_io.dart +22 -15
- package/dart/lib/src/dev_cloud.dart +62 -0
- package/dart/lib/src/nms_generated_runtime.dart +1 -0
- package/dart/lib/src/operation_receipts.dart +74 -7
- package/dart/lib/src/reception/dart_reception.dart +26 -6
- package/dart/lib/src/result_usda.dart +64 -27
- package/dart/lib/src/runner/node-entry.mjs +4733 -1534
- package/dart/lib/src/runtime_v2_transport.dart +3 -0
- package/dart/lib/src/sync_status_projection.dart +11 -0
- package/dart/pubspec.lock +1 -1
- package/dart/pubspec.yaml +2 -2
- package/dart/test/console_enrolment_test.dart +47 -0
- package/dart/test/kernel_refused_follow_test.dart +36 -0
- package/dart/test/model_adoption_test.dart +49 -0
- package/dart/test/result_usda_test.dart +67 -0
- package/dart/test/runtime_projections_test.dart +41 -0
- package/dart_types/CHANGELOG.md +30 -0
- package/dart_types/lib/src/approved_model.dart +78 -1
- package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pb.dart +528 -2
- package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pbenum.dart +24 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/correspondence_desk.pb.dart +1897 -112
- package/dart_types/lib/src/proto/nomos/runtime/v2/model_adoption_desk.pb.dart +98 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/observability_desk.pbenum.dart +11 -1
- package/dart_types/lib/src/proto/nomos/runtime/v2/records_desk.pb.dart +16 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pb.dart +43 -2
- package/dart_types/lib/src/vo_canonical.dart +185 -0
- package/dart_types/pubspec.lock +1 -1
- package/dart_types/pubspec.yaml +3 -1
- package/dart_types/test/vo_canonical_test.dart +91 -0
- package/package.json +4 -2
- package/src/aggregate.ts +95 -0
- package/src/anonymous_value_interning.ts +205 -0
- package/src/baseline.ts +27 -0
- package/src/baseline_export.ts +432 -0
- package/src/baseline_import.ts +312 -0
- package/src/baseline_usda.ts +185 -0
- package/src/birth_key_rule.ts +472 -0
- package/src/births.ts +207 -24
- package/src/build_package.ts +47 -7
- package/src/build_provenance.ts +10 -0
- package/src/business_birth.ts +50 -4
- package/src/check_package_main.ts +50 -6
- package/src/codegen_call_proto.ts +5 -18
- package/src/codegen_call_usda.ts +6 -3
- package/src/codegen_dart.ts +114 -60
- package/src/codegen_dart_client.ts +52 -6
- package/src/codegen_dart_facade.ts +57 -35
- package/src/codegen_dart_framework_calls.ts +20 -1
- package/src/codegen_proof.ts +5 -2
- package/src/codegen_result_proto.ts +8 -6
- package/src/codegen_result_usda.ts +12 -4
- package/src/codegen_ts.ts +109 -10
- package/src/compatibility_graph.ts +41 -4
- package/src/compatibility_usda.ts +11 -1
- package/src/compile_package_main.ts +222 -52
- package/src/composed_wire_identity.ts +24 -0
- package/src/directive.ts +6 -0
- package/src/domain_requirements.ts +75 -0
- package/src/engine_entry.ts +12 -4
- package/src/engine_javascript.ts +12 -6
- package/src/fields.ts +109 -0
- package/src/identity_usda.ts +80 -103
- package/src/index.ts +35 -1
- package/src/intent.ts +33 -3
- package/src/law_check.ts +34 -0
- package/src/law_graph.ts +142 -1
- package/src/law_graph_usda.ts +27 -144
- package/src/law_layer_prims.ts +174 -0
- package/src/law_unit_selection.ts +45 -0
- package/src/law_units.ts +7 -6
- package/src/law_version.ts +108 -0
- package/src/package_config.ts +44 -0
- package/src/package_dependencies.ts +8 -0
- package/src/point_guard.ts +5 -1
- package/src/release_inspection.ts +6 -4
- package/src/release_publication.ts +6 -5
- package/src/usda_text.ts +78 -3
- package/src/value_identity.ts +355 -0
- package/src/value_object.ts +35 -4
- package/src/wire.ts +2 -0
- package/src/wire_paths.ts +17 -0
- package/src/workspace_routing.ts +1 -1
|
@@ -280,6 +280,9 @@ mixin NmsPlatformCredentialProviderHost
|
|
|
280
280
|
} on NomosConsoleEnrolmentRefused catch (refusal) {
|
|
281
281
|
return refused(refusal.status, refusal.message,
|
|
282
282
|
code: refusal.code, retryable: refusal.retryable);
|
|
283
|
+
} on TimeoutException {
|
|
284
|
+
return failed('the console did not answer within '
|
|
285
|
+
'${nomosConsoleEnrolmentTimeout.inSeconds} s; asking again');
|
|
283
286
|
} catch (error) {
|
|
284
287
|
// Never echo the request: it carries the token.
|
|
285
288
|
return failed('the console could not be reached (${error.runtimeType})');
|
|
@@ -126,6 +126,14 @@ enum WorkspaceFollowPhase {
|
|
|
126
126
|
rebornRemotely,
|
|
127
127
|
replacingLocal,
|
|
128
128
|
localCopyUnreadable,
|
|
129
|
+
|
|
130
|
+
/// This peer's kernel deterministically refused the last round at the same
|
|
131
|
+
/// local head and remote frontier: sync is blocked, not retrying. No timer
|
|
132
|
+
/// re-runs it; it runs again on new local work, an upstream head change, a
|
|
133
|
+
/// socket reopen or a changed kernel/runtime. [WorkspaceFollowStatus.retryAt]
|
|
134
|
+
/// is set only once such an event made it due, and
|
|
135
|
+
/// [WorkspaceFollowStatus.detail] carries the kernel's refusal.
|
|
136
|
+
kernelRefused,
|
|
129
137
|
unknown,
|
|
130
138
|
}
|
|
131
139
|
|
|
@@ -182,6 +190,9 @@ final class WorkspaceFollowStatus {
|
|
|
182
190
|
nomos_protocol.FollowObservationPhase
|
|
183
191
|
.FOLLOW_OBSERVATION_PHASE_LOCAL_COPY_UNREADABLE =>
|
|
184
192
|
WorkspaceFollowPhase.localCopyUnreadable,
|
|
193
|
+
nomos_protocol.FollowObservationPhase
|
|
194
|
+
.FOLLOW_OBSERVATION_PHASE_KERNEL_REFUSED =>
|
|
195
|
+
WorkspaceFollowPhase.kernelRefused,
|
|
185
196
|
_ => WorkspaceFollowPhase.unknown,
|
|
186
197
|
},
|
|
187
198
|
live: report.live,
|
package/dart/pubspec.lock
CHANGED
package/dart/pubspec.yaml
CHANGED
|
@@ -7,7 +7,7 @@ repository: https://github.com/Captain-App/nomos2
|
|
|
7
7
|
description: >-
|
|
8
8
|
Nomos 2 Dart client — generated domain values, intent payloads and application
|
|
9
9
|
lifecycle types over the typed Nomos kernel protocol and USDA custody model.
|
|
10
|
-
version: 0.
|
|
10
|
+
version: 0.70.1
|
|
11
11
|
|
|
12
12
|
environment:
|
|
13
13
|
sdk: ^3.5.0
|
|
@@ -18,7 +18,7 @@ dependencies:
|
|
|
18
18
|
# The pure-data core (wire types, offer codec, NomosReads, schema validation, error
|
|
19
19
|
# info). nomos_client depends on and re-exports it, so existing imports are unchanged.
|
|
20
20
|
# For local monorepo dev, pubspec_overrides.yaml points this at ../dart_types.
|
|
21
|
-
nomos_types: ^0.
|
|
21
|
+
nomos_types: ^0.15.0
|
|
22
22
|
fixnum: ^1.1.1
|
|
23
23
|
json_schema: ^5.2.2
|
|
24
24
|
crypto: ^3.0.0
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import 'dart:async';
|
|
1
2
|
import 'dart:convert';
|
|
2
3
|
import 'dart:io';
|
|
3
4
|
import 'dart:typed_data';
|
|
4
5
|
|
|
5
6
|
import 'package:fixnum/fixnum.dart';
|
|
6
7
|
import 'package:nomos_client/src/console_enrolment.dart';
|
|
8
|
+
import 'package:nomos_client/src/console_http_io.dart';
|
|
7
9
|
import 'package:nomos_client/src/runtime_v2_transport.dart';
|
|
8
10
|
import 'package:nomos_peer_host/nomos_peer_host.dart'
|
|
9
11
|
show NomosDeviceIdentityStore, NomosProviderCredentialStore;
|
|
@@ -224,4 +226,49 @@ void main() {
|
|
|
224
226
|
final receipt = await noKey.performConsoleEnrolment(effect);
|
|
225
227
|
expect(receipt.failure.message, contains('no usable identity'));
|
|
226
228
|
});
|
|
229
|
+
|
|
230
|
+
test(
|
|
231
|
+
'a console that does not answer is a bounded, retryable transport failure (CAP-807)',
|
|
232
|
+
() async {
|
|
233
|
+
// The default transport gives up on its own deadline instead of holding the write.
|
|
234
|
+
final silent = await ServerSocket.bind(InternetAddress.loopbackIPv4, 0);
|
|
235
|
+
final held = <Socket>[];
|
|
236
|
+
silent.listen(held.add);
|
|
237
|
+
try {
|
|
238
|
+
final started = DateTime.now();
|
|
239
|
+
await expectLater(
|
|
240
|
+
nomosDefaultConsolePost(
|
|
241
|
+
Uri.parse('http://127.0.0.1:${silent.port}/v1/enrol'), '{}',
|
|
242
|
+
timeout: const Duration(milliseconds: 300)),
|
|
243
|
+
throwsA(isA<TimeoutException>()));
|
|
244
|
+
expect(DateTime.now().difference(started).inSeconds, lessThan(5));
|
|
245
|
+
} finally {
|
|
246
|
+
for (final socket in held) {
|
|
247
|
+
socket.destroy();
|
|
248
|
+
}
|
|
249
|
+
await silent.close();
|
|
250
|
+
}
|
|
251
|
+
// The shell reports it typed, as a failure Peer Office asks again after.
|
|
252
|
+
final seed = Uint8List(32)..[0] = 7;
|
|
253
|
+
final platform = _Platform([])
|
|
254
|
+
..registerDeviceIdentityStore(_Store({'device': seed}))
|
|
255
|
+
..registerCredentialProvider(
|
|
256
|
+
capability: 'home',
|
|
257
|
+
cloud: 'x',
|
|
258
|
+
signIn: ({String? deviceChallenge}) async => 'token')
|
|
259
|
+
..registerConsolePost(
|
|
260
|
+
(url, text) async => throw TimeoutException('slow'));
|
|
261
|
+
final receipt = await platform.performConsoleEnrolment(
|
|
262
|
+
p.PeerConsoleEnrolmentEffect(
|
|
263
|
+
effectId: 'e',
|
|
264
|
+
deviceIdentity: 'device',
|
|
265
|
+
capability: 'home',
|
|
266
|
+
console: 'http://console.test',
|
|
267
|
+
tenant: 't',
|
|
268
|
+
scope: 'user',
|
|
269
|
+
workspaces: ['estate-a']));
|
|
270
|
+
expect(receipt.hasFailure(), isTrue);
|
|
271
|
+
expect(receipt.failure.message,
|
|
272
|
+
'the console did not answer within 20 s; asking again');
|
|
273
|
+
});
|
|
227
274
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import 'package:fixnum/fixnum.dart' as fixnum;
|
|
2
|
+
import 'package:nomos_client/src/sync_status_projection.dart';
|
|
3
|
+
import 'package:nomos_types/nomos_kernel_protocol.dart' as protocol;
|
|
4
|
+
import 'package:test/test.dart';
|
|
5
|
+
|
|
6
|
+
void main() {
|
|
7
|
+
test('a follow the kernel refused is blocked, not retrying', () {
|
|
8
|
+
final blocked =
|
|
9
|
+
WorkspaceFollowStatus.fromRuntime(protocol.FollowObservation(
|
|
10
|
+
workspace: 'estate',
|
|
11
|
+
phase: protocol
|
|
12
|
+
.FollowObservationPhase.FOLLOW_OBSERVATION_PHASE_KERNEL_REFUSED,
|
|
13
|
+
detail: 'NMS-KERNEL-CALL: refused',
|
|
14
|
+
attempt: 2,
|
|
15
|
+
));
|
|
16
|
+
expect(blocked.phase, WorkspaceFollowPhase.kernelRefused);
|
|
17
|
+
expect(blocked.retryAt, isNull,
|
|
18
|
+
reason: 'no timer re-runs a blocked refusal');
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test('an event made a refused follow due again at its re-run time', () {
|
|
22
|
+
final retryAt = DateTime.utc(2026, 10, 8, 9, 0, 10);
|
|
23
|
+
final status = WorkspaceFollowStatus.fromRuntime(protocol.FollowObservation(
|
|
24
|
+
workspace: 'estate',
|
|
25
|
+
phase: protocol
|
|
26
|
+
.FollowObservationPhase.FOLLOW_OBSERVATION_PHASE_KERNEL_REFUSED,
|
|
27
|
+
detail:
|
|
28
|
+
'NMS-KERNEL-CALL: invalid or repeated command frontier commit marker',
|
|
29
|
+
retryAtUnixMillis: fixnum.Int64(retryAt.millisecondsSinceEpoch),
|
|
30
|
+
attempt: 2,
|
|
31
|
+
));
|
|
32
|
+
expect(status.phase, WorkspaceFollowPhase.kernelRefused);
|
|
33
|
+
expect(status.detail, startsWith('NMS-KERNEL-CALL:'));
|
|
34
|
+
expect(status.retryAt, retryAt.toLocal());
|
|
35
|
+
});
|
|
36
|
+
}
|
|
@@ -11,6 +11,7 @@ import 'package:nomos_client/src/application_model_adoption.dart';
|
|
|
11
11
|
import 'package:nomos_client/src/runtime_v2_transport.dart';
|
|
12
12
|
import 'package:nomos_client/src/sync_status_projection.dart';
|
|
13
13
|
import 'package:nomos_types/nomos_kernel_protocol.dart' as p;
|
|
14
|
+
import 'package:nomos_types/nomos_types.dart' show NomosDomainRequirement;
|
|
14
15
|
import 'package:test/test.dart';
|
|
15
16
|
|
|
16
17
|
const lawSha = '5efef545fdadae764e29ba678833073e0245b1b76e315d3a5fe71c6a65240a45';
|
|
@@ -89,6 +90,54 @@ void main() {
|
|
|
89
90
|
throwsArgumentError);
|
|
90
91
|
});
|
|
91
92
|
|
|
93
|
+
test('per-domain requirements (CAP-666) are optional, keyed and checked',
|
|
94
|
+
() {
|
|
95
|
+
expect(model().domainRequirements, isEmpty);
|
|
96
|
+
final pinned = NomosApprovedModel(
|
|
97
|
+
unitSet: unitSet,
|
|
98
|
+
lawSha256: lawSha,
|
|
99
|
+
reason: 'r',
|
|
100
|
+
domainKeys: const ['home'],
|
|
101
|
+
loadPackage: () async => Uint8List(0),
|
|
102
|
+
domainRequirements: {
|
|
103
|
+
'home': NomosDomainRequirement(
|
|
104
|
+
domainKey: 'home',
|
|
105
|
+
unitSha256: '3' * 64,
|
|
106
|
+
requirementSha256: '4' * 64),
|
|
107
|
+
});
|
|
108
|
+
expect(pinned.domainRequirements['home']!.unitSha256, '3' * 64);
|
|
109
|
+
expect(() => pinned.domainRequirements['x'] = pinned.domainRequirements['home']!,
|
|
110
|
+
throwsUnsupportedError);
|
|
111
|
+
expect(
|
|
112
|
+
() => NomosApprovedModel(
|
|
113
|
+
unitSet: unitSet,
|
|
114
|
+
lawSha256: lawSha,
|
|
115
|
+
reason: 'r',
|
|
116
|
+
domainKeys: const ['home'],
|
|
117
|
+
loadPackage: () async => Uint8List(0),
|
|
118
|
+
domainRequirements: {
|
|
119
|
+
'estate': NomosDomainRequirement(
|
|
120
|
+
domainKey: 'home',
|
|
121
|
+
unitSha256: '3' * 64,
|
|
122
|
+
requirementSha256: '4' * 64),
|
|
123
|
+
}),
|
|
124
|
+
throwsArgumentError);
|
|
125
|
+
expect(
|
|
126
|
+
() => NomosApprovedModel(
|
|
127
|
+
unitSet: unitSet,
|
|
128
|
+
lawSha256: lawSha,
|
|
129
|
+
reason: 'r',
|
|
130
|
+
domainKeys: const ['home'],
|
|
131
|
+
loadPackage: () async => Uint8List(0),
|
|
132
|
+
domainRequirements: {
|
|
133
|
+
'home': NomosDomainRequirement(
|
|
134
|
+
domainKey: 'home',
|
|
135
|
+
unitSha256: 'nope',
|
|
136
|
+
requirementSha256: '4' * 64),
|
|
137
|
+
}),
|
|
138
|
+
throwsArgumentError);
|
|
139
|
+
});
|
|
140
|
+
|
|
92
141
|
test('its package source answers only the identity it was released with',
|
|
93
142
|
() async {
|
|
94
143
|
final source = NmsApprovedModelLawPackageSource(model());
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import 'dart:convert';
|
|
2
|
+
import 'dart:io';
|
|
2
3
|
import 'dart:typed_data';
|
|
3
4
|
|
|
4
5
|
import 'package:nomos_client/src/nms_generated_runtime.dart';
|
|
@@ -46,4 +47,70 @@ def NomosReadResult "Result"
|
|
|
46
47
|
'Ship',
|
|
47
48
|
);
|
|
48
49
|
});
|
|
50
|
+
|
|
51
|
+
// CAP-862: the shared conformance vectors. Every canonical literal, and every legacy `\uXXXX`
|
|
52
|
+
// spelling an older kernel wrote, reads back as the value it names.
|
|
53
|
+
test('decodes the canonical and legacy USDA string vectors', () {
|
|
54
|
+
final vectors = jsonDecode(
|
|
55
|
+
File('../conformance/usda_string.v1.json').readAsStringSync())
|
|
56
|
+
as Map<String, dynamic>;
|
|
57
|
+
final cases = [
|
|
58
|
+
...(vectors['encode'] as List).cast<Map<String, dynamic>>(),
|
|
59
|
+
...(vectors['legacyDecode'] as List).cast<Map<String, dynamic>>(),
|
|
60
|
+
];
|
|
61
|
+
expect(cases.length, greaterThan(60));
|
|
62
|
+
for (final vector in cases) {
|
|
63
|
+
final result = NmsUsdaResult.parse(
|
|
64
|
+
Uint8List.fromList(
|
|
65
|
+
utf8.encode('''#usda 1.0
|
|
66
|
+
(
|
|
67
|
+
defaultPrim = "Result"
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
def NomosReadResult "Result"
|
|
71
|
+
{
|
|
72
|
+
custom uniform bool nomos:done = true
|
|
73
|
+
|
|
74
|
+
def NomosListValue "Rows"
|
|
75
|
+
{
|
|
76
|
+
def NomosRecordValue "i_00000000"
|
|
77
|
+
{
|
|
78
|
+
custom uniform string nomos:id = "note:1"
|
|
79
|
+
custom rel nomos:type = </Nomos/Domains/d_1/Aggregates/a_note>
|
|
80
|
+
|
|
81
|
+
def NomosStringValue "f_title"
|
|
82
|
+
{
|
|
83
|
+
custom rel nomos:field = </Nomos/Domains/d_1/Aggregates/a_note/Fields/f_title>
|
|
84
|
+
custom uniform string nomos:value = ${vector['usda']}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
'''),
|
|
90
|
+
),
|
|
91
|
+
);
|
|
92
|
+
expect(
|
|
93
|
+
result.rows.single
|
|
94
|
+
.requiredField('/Nomos/Domains/d_1/Aggregates/a_note/Fields/f_title')
|
|
95
|
+
.stringValue(),
|
|
96
|
+
vector['value'],
|
|
97
|
+
reason: vector['name'] as String,
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test('framework-call quoting writes every vector canonically', () {
|
|
103
|
+
final vectors = jsonDecode(
|
|
104
|
+
File('../conformance/usda_string.v1.json').readAsStringSync())
|
|
105
|
+
as Map<String, dynamic>;
|
|
106
|
+
for (final vector
|
|
107
|
+
in (vectors['encode'] as List).cast<Map<String, dynamic>>()) {
|
|
108
|
+
expect(NmsUsdaLayer.quote(vector['value'] as String), vector['usda'],
|
|
109
|
+
reason: vector['name'] as String);
|
|
110
|
+
}
|
|
111
|
+
for (final point in (vectors['refusedCodePoints'] as List).cast<int>()) {
|
|
112
|
+
expect(() => NmsUsdaLayer.quote('a${String.fromCharCode(point)}b'),
|
|
113
|
+
throwsArgumentError);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
49
116
|
}
|
|
@@ -61,6 +61,47 @@ void main() {
|
|
|
61
61
|
expect(receipt.current.phase, NomosOperationPhase.converged);
|
|
62
62
|
});
|
|
63
63
|
|
|
64
|
+
test(
|
|
65
|
+
'a birth custody refused as already parented fails its creation receipt, '
|
|
66
|
+
'typed and terminal (CAP-804)', () async {
|
|
67
|
+
final projection = NmsOperationReceiptProjection();
|
|
68
|
+
final birth = projection.register('home-bob', 'intent-birth');
|
|
69
|
+
projection.rememberBirth('notebook-1', birth);
|
|
70
|
+
final other = projection.register('home-bob', 'intent-other');
|
|
71
|
+
projection.advance(
|
|
72
|
+
'home-bob',
|
|
73
|
+
protocol.SyncWorkspaceResponse(
|
|
74
|
+
pushFailed: true,
|
|
75
|
+
admittedIntentIds: const ['intent-other'],
|
|
76
|
+
birthOutcomes: [
|
|
77
|
+
protocol.BirthOutcome(
|
|
78
|
+
workspace: 'notebook-1',
|
|
79
|
+
childWorkspace: 'notebook-1',
|
|
80
|
+
parentWorkspace: 'home-bob',
|
|
81
|
+
status: protocol.BirthOutcomeStatus.BIRTH_OUTCOME_STATUS_REFUSED,
|
|
82
|
+
code: 'birth-child-already-parented',
|
|
83
|
+
refusal: protocol.KernelRefusal(
|
|
84
|
+
terminal: true,
|
|
85
|
+
message: "[birth-child-already-parented] workspace 'notebook-1' "
|
|
86
|
+
'already has a parent',
|
|
87
|
+
),
|
|
88
|
+
),
|
|
89
|
+
],
|
|
90
|
+
),
|
|
91
|
+
);
|
|
92
|
+
await expectLater(
|
|
93
|
+
birth.admitted,
|
|
94
|
+
throwsA(isA<NomosOperationRefused>()
|
|
95
|
+
.having((r) => r.code, 'code', 'birth-child-already-parented')
|
|
96
|
+
.having((r) => r.childWorkspace, 'child', 'notebook-1')),
|
|
97
|
+
);
|
|
98
|
+
await expectLater(birth.converged, throwsA(isA<NomosOperationRefused>()));
|
|
99
|
+
expect(birth.current.isRefused, isTrue);
|
|
100
|
+
expect(birth.current.phase, NomosOperationPhase.locallyAccepted);
|
|
101
|
+
// The parent's other write in the same round is unaffected.
|
|
102
|
+
await other.admitted;
|
|
103
|
+
});
|
|
104
|
+
|
|
64
105
|
test('typed watch registry only correlates runtime events and cancellation',
|
|
65
106
|
() async {
|
|
66
107
|
final registry = NmsTypedWatchRegistry();
|
package/dart_types/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,33 @@
|
|
|
1
|
+
## 0.15.0
|
|
2
|
+
|
|
3
|
+
- `FollowObservationPhase.FOLLOW_OBSERVATION_PHASE_KERNEL_REFUSED`: this peer's kernel deterministically refused a replica follow's round, so the follow's sync is blocked and is not retrying.
|
|
4
|
+
|
|
5
|
+
- Generated value objects compare by the law's canonical value encoding, `nomos.vo-canonical.v1` (RFC 8785 over the value's `toJson()`): `NmsInternalValueIdentity.equals` / `hash` / `canonical` (CAP-853). Member order never matters, `2` and `2.0` are one number, `-0` is `0`, and an omitted optional member differs from `null`.
|
|
6
|
+
|
|
7
|
+
## 0.14.0
|
|
8
|
+
|
|
9
|
+
- Live stream frames for peer catch-up (CAP-826): `LiveOfferFrame` gains checkpoint, history, ref, pack and
|
|
10
|
+
refusal frames; `PeerStreamEffect`/`PeerStreamReceipt`; the runtime command `serveLiveStream`; and the kernel's
|
|
11
|
+
shallow pack request (`PackDeltaRequest.depth`, `below_head`, `also_heads`).
|
|
12
|
+
|
|
13
|
+
- `NomosDomainRequirement` and `NomosApprovedModel.domainRequirements` (CAP-666): per application domain key,
|
|
14
|
+
the exact law unit (`domain:<key>` of the unit set) and the generated consumer requirement identity a client
|
|
15
|
+
was compiled against. A workspace serving that unit for the key is current for the release whatever else its
|
|
16
|
+
unit set carries. `AdoptApplicationModelRequest` carries them as `domain_requirements` (field 7,
|
|
17
|
+
`DomainUnitRequirement`). Empty on clients generated before they existed: `unitSet` alone then decides.
|
|
18
|
+
- `KeyedBirthName.parent` (field 3) is reserved and unused (CAP-803): a business child is named by namespace and
|
|
19
|
+
key, fixed at birth. CAP-788's parent-scoped naming is withdrawn before release; one parent per node is the
|
|
20
|
+
kernel's `[birth-child-already-parented]` refusal.
|
|
21
|
+
- Carry the current generated kernel Protobuf contract: `FrontierTransitionRequest.candidateUnits`,
|
|
22
|
+
`InterfaceCompatibilityQuery.candidateUnits` and `InterfaceCompatibilityResponse.candidateHash` qualify a law
|
|
23
|
+
release without installing it (CAP-789).
|
|
24
|
+
`ApplyPackRequest.work_budget_bytes` / `continue_pending` and `ApplyPackResponse.import_pending` /
|
|
25
|
+
`work_done_bytes` import a pack in bounded steps (CAP-806). `LawIdentity`, `LawVersion`, `LawVersionClaim` and
|
|
26
|
+
`OfferAdmitted.law_version_warnings` (`LawVersionWarning`, `LawVersionOrder`) report an install that does not
|
|
27
|
+
move its law's claimed version forward (CAP-811). `PeerGitFetchEffect.alongside_refs` (`PeerGitRefsAlongside`)
|
|
28
|
+
and `PeerGitFetchResponse.alongside_refs` (`PeerGitRefsFetched`) carry a head-only mount's settled-letter outcome
|
|
29
|
+
refs beside main.
|
|
30
|
+
|
|
1
31
|
## 0.13.0
|
|
2
32
|
|
|
3
33
|
- `NomosApprovedModel` requires `unitSet`: the law a release approves is its unit set identity (the generated
|
|
@@ -12,6 +12,55 @@ import 'dart:typed_data';
|
|
|
12
12
|
|
|
13
13
|
final RegExp _lowerHex64 = RegExp(r'^[0-9a-f]{64}$');
|
|
14
14
|
|
|
15
|
+
/// ONE APPLICATION DOMAIN'S REQUIREMENT (CAP-666), as the compiler generated it
|
|
16
|
+
/// beside the unit set: the exact law unit the client was compiled against
|
|
17
|
+
/// (`domain:<key>` in `build/<name>.units`) and the identity of the generated
|
|
18
|
+
/// consumer requirement for that domain (the domain's slice of
|
|
19
|
+
/// `<name>.compatibility.usda`, which the kernel's Compatibility Desk judges).
|
|
20
|
+
///
|
|
21
|
+
/// A workspace serving exactly [unitSha256] for [domainKey] satisfies this
|
|
22
|
+
/// release for that domain even when its unit set carries other domains the
|
|
23
|
+
/// application never touches. Identities only; the bytes stay in the generated
|
|
24
|
+
/// client. Const-constructible so generated code can bake it; the approved
|
|
25
|
+
/// model validates it.
|
|
26
|
+
final class NomosDomainRequirement {
|
|
27
|
+
const NomosDomainRequirement({
|
|
28
|
+
required this.domainKey,
|
|
29
|
+
required this.unitSha256,
|
|
30
|
+
required this.requirementSha256,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
/// The application domain key this requirement is about.
|
|
34
|
+
final String domainKey;
|
|
35
|
+
|
|
36
|
+
/// The hash of the domain's law unit (`domain:<key>`), 64 lowercase hex.
|
|
37
|
+
final String unitSha256;
|
|
38
|
+
|
|
39
|
+
/// The sha256 of the domain's generated compatibility requirement, 64
|
|
40
|
+
/// lowercase hex. Observation and qualification name the contract by it.
|
|
41
|
+
final String requirementSha256;
|
|
42
|
+
|
|
43
|
+
/// The wire shape the inventory carries (identities only).
|
|
44
|
+
Map<String, String> toJson() => {
|
|
45
|
+
'unit': unitSha256,
|
|
46
|
+
'requirement': requirementSha256,
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
@override
|
|
50
|
+
bool operator ==(Object other) =>
|
|
51
|
+
other is NomosDomainRequirement &&
|
|
52
|
+
other.domainKey == domainKey &&
|
|
53
|
+
other.unitSha256 == unitSha256 &&
|
|
54
|
+
other.requirementSha256 == requirementSha256;
|
|
55
|
+
|
|
56
|
+
@override
|
|
57
|
+
int get hashCode => Object.hash(domainKey, unitSha256, requirementSha256);
|
|
58
|
+
|
|
59
|
+
@override
|
|
60
|
+
String toString() =>
|
|
61
|
+
'NomosDomainRequirement($domainKey: unit $unitSha256, requirement $requirementSha256)';
|
|
62
|
+
}
|
|
63
|
+
|
|
15
64
|
/// The law model an application release approves, supplied once at the
|
|
16
65
|
/// application's Reception. Every field is required: the office refuses to
|
|
17
66
|
/// adopt without the law (its unit set), the package identity, the domain keys
|
|
@@ -24,7 +73,9 @@ final class NomosApprovedModel {
|
|
|
24
73
|
required this.reason,
|
|
25
74
|
required List<String> domainKeys,
|
|
26
75
|
required this.loadPackage,
|
|
27
|
-
|
|
76
|
+
Map<String, NomosDomainRequirement> domainRequirements = const {},
|
|
77
|
+
}) : domainKeys = List.unmodifiable(domainKeys),
|
|
78
|
+
domainRequirements = Map.unmodifiable(domainRequirements) {
|
|
28
79
|
if (!_lowerHex64.hasMatch(unitSet)) {
|
|
29
80
|
throw ArgumentError.value(
|
|
30
81
|
unitSet,
|
|
@@ -54,6 +105,24 @@ final class NomosApprovedModel {
|
|
|
54
105
|
'must name the application domain keys the office observes on each workspace',
|
|
55
106
|
);
|
|
56
107
|
}
|
|
108
|
+
for (final entry in this.domainRequirements.entries) {
|
|
109
|
+
final requirement = entry.value;
|
|
110
|
+
if (entry.key.trim().isEmpty || requirement.domainKey != entry.key) {
|
|
111
|
+
throw ArgumentError.value(
|
|
112
|
+
domainRequirements,
|
|
113
|
+
'domainRequirements',
|
|
114
|
+
'must be keyed by the domain key each requirement names',
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
if (!_lowerHex64.hasMatch(requirement.unitSha256) ||
|
|
118
|
+
!_lowerHex64.hasMatch(requirement.requirementSha256)) {
|
|
119
|
+
throw ArgumentError.value(
|
|
120
|
+
requirement,
|
|
121
|
+
'domainRequirements',
|
|
122
|
+
"'${entry.key}' must carry the generated domain unit hash and requirement identity (64 lowercase hex each)",
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
57
126
|
}
|
|
58
127
|
|
|
59
128
|
/// THE LAW this release approves (CAP-773): the unit set identity of the
|
|
@@ -76,6 +145,14 @@ final class NomosApprovedModel {
|
|
|
76
145
|
/// alone; keys it does not serve are ignored.
|
|
77
146
|
final List<String> domainKeys;
|
|
78
147
|
|
|
148
|
+
/// THE PER-DOMAIN REQUIREMENTS this release was generated against (CAP-666):
|
|
149
|
+
/// the generated `frameworkCalls.domainRequirements`, by domain key. A served
|
|
150
|
+
/// key whose workspace serves exactly that domain unit is current for this
|
|
151
|
+
/// release whatever else its unit set carries; the office reports them and
|
|
152
|
+
/// the client inventory records them as this build's contract. Empty on a
|
|
153
|
+
/// client generated before they existed: [unitSet] alone then decides.
|
|
154
|
+
final Map<String, NomosDomainRequirement> domainRequirements;
|
|
155
|
+
|
|
79
156
|
/// The exact compiled package bytes, read only when a workspace must stage
|
|
80
157
|
/// them (a bundled asset, a file beside the generated facade).
|
|
81
158
|
final Future<Uint8List> Function() loadPackage;
|