@githolon/dsl 0.101.5 → 0.102.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dart/CHANGELOG.md +13 -0
- package/dart/lib/nomos_client.dart +3 -52
- package/dart/lib/src/dev_cloud.dart +5 -0
- package/dart/lib/src/home.dart +10 -15
- package/dart/lib/src/nms_conformance_runtime.dart +12 -0
- package/dart/lib/src/nms_generated_runtime.dart +29 -0
- package/dart/lib/src/nms_test_environment.dart +8 -0
- package/dart/lib/src/node_runner_transport.dart +56 -18
- package/dart/lib/src/provider.dart +5 -1
- package/dart/lib/src/record_origin.dart +55 -0
- package/dart/lib/src/runner/node-entry.mjs +9105 -0
- package/dart/lib/src/runner/offline-install.mjs +4729 -0
- package/dart/lib/src/session_bound.dart +23 -10
- package/dart/lib/src/source_trust.dart +51 -0
- package/dart/lib/src/test_harness.dart +490 -58
- package/dart/lib/src/webview_bridge.dart +167 -58
- package/dart/lib/src/workspace_name.dart +7 -1
- package/dart/pubspec.lock +3 -3
- package/dart/pubspec.yaml +4 -2
- package/dart/test/acquire_session_credentials_test.dart +34 -17
- package/dart/test/acquire_session_test.dart +109 -24
- package/dart/test/adv_realm_interference_test.dart +227 -99
- package/dart/test/bundle_version_pairing_test.dart +1 -1
- package/dart/test/cloud_bound_topology_test.dart +1 -1
- package/dart/test/cluster_attested_test.dart +52 -35
- package/dart/test/cluster_births_test.dart +5 -2
- package/dart/test/cluster_device_keyed_acceptance_test.dart +5 -2
- package/dart/test/cluster_local_autosync_test.dart +5 -2
- package/dart/test/cluster_scale_test.dart +5 -2
- package/dart/test/compat_test.dart +1 -1
- package/dart/test/dlq_session_surface_test.dart +2 -1
- package/dart/test/errors_test.dart +1 -1
- package/dart/test/first_app_gauntlet_test.dart +78 -51
- package/dart/test/four_layer_nested_topology_test.dart +1 -1
- package/dart/test/harness_phase_timeout_test.dart +1 -1
- package/dart/test/home_parity_test.dart +9 -5
- package/dart/test/local_sync_inert_test.dart +22 -14
- package/dart/test/node_runner_transport_test.dart +9 -5
- package/dart/test/null_slot_test.dart +1 -1
- package/dart/test/parent_signer_recovery_test.dart +5 -2
- package/dart/test/schema_validation_test.dart +1 -1
- package/dart/test/sealing_client_test.dart +2 -1
- package/dart/test/session_bound_test.dart +92 -119
- package/dart/test/stale_bundle_test.dart +1 -1
- package/dart/test/test_harness_test.dart +77 -22
- package/dart/test/vo_read_typing_test.dart +32 -14
- package/dart/test/watch_after_offer_stall_test.dart +2 -1
- package/dart/test/webview_bridge_test.dart +17 -4
- package/dart/test/wire_test.dart +1 -1
- package/dart_types/CHANGELOG.md +8 -0
- package/dart_types/lib/nomos_types.dart +7 -6
- package/dart_types/lib/src/activity.dart +23 -13
- package/dart_types/lib/src/foreign_ref.dart +61 -112
- package/dart_types/lib/src/invitation.dart +96 -0
- package/dart_types/lib/src/nomos_ref.dart +97 -59
- package/dart_types/pubspec.yaml +1 -1
- package/dart_types/test/surfaced_test.dart +125 -19
- package/package.json +7 -3
- package/runtime/generated-application-host.js +8851 -0
- package/src/activity.ts +2 -2
- package/src/aggregate.ts +24 -1
- package/src/application_composition.ts +282 -0
- package/src/application_topology.ts +151 -0
- package/src/attested_core.ts +2 -2
- package/src/authoring_context.ts +9 -0
- package/src/birth_meter_ensure.ts +1 -1
- package/src/births.ts +53 -5
- package/src/build_package.ts +79 -71
- package/src/business_birth.ts +93 -10
- package/src/clear_directive.ts +3 -1
- package/src/codegen_dart.ts +369 -420
- package/src/codegen_dart_application.ts +1508 -0
- package/src/codegen_dart_client.ts +156 -95
- package/src/codegen_dart_scenario.ts +299 -0
- package/src/codegen_openapi.ts +8 -3
- package/src/codegen_proof.ts +1113 -1137
- package/src/codegen_provider_dart.ts +12 -1
- package/src/codegen_ts.ts +1176 -496
- package/src/compat_package_main.ts +22 -10
- package/src/compile_package_main.ts +1536 -337
- package/src/contract.ts +10 -4
- package/src/dart_barrel_guard.ts +5 -1
- package/src/describe_model.ts +13 -5
- package/src/directive.ts +244 -5
- package/src/engine_entry.ts +56 -13
- package/src/engine_javascript.ts +31 -0
- package/src/evolve_preview.ts +3 -12
- package/src/framework/application_home.ts +24 -10
- package/src/framework/capability.ts +15 -1
- package/src/framework/domain_lifecycle.ts +8 -0
- package/src/framework/framework_aggregates.ts +2 -2
- package/src/framework/genesis.ts +11 -1
- package/src/framework/home.ts +178 -75
- package/src/framework/impure_capability.ts +24 -7
- package/src/framework/relations.ts +13 -5
- package/src/framework/workspaces.ts +13 -12
- package/src/generated_client_names.ts +42 -3
- package/src/idof_lint.ts +65 -13
- package/src/index.ts +46 -12
- package/src/intent.ts +587 -0
- package/src/law_check.ts +64 -16
- package/src/precondition.ts +16 -4
- package/src/read_projection_namespace.ts +2 -7
- package/src/recipient.ts +33 -0
- package/src/relation_schema.ts +93 -0
- package/src/secondary_ensure.ts +11 -2
- package/src/shape_compat.ts +11 -1
- package/src/usd.ts +30 -8
- package/src/usd_layers.ts +447 -246
- package/src/usd_state.ts +1 -1
- package/src/value_object.ts +49 -13
- package/src/wire_encode.ts +124 -26
- package/src/workspace_sharing.ts +269 -0
- package/src/zod_introspection.ts +84 -0
- package/dart/example/nomos_secure_key_store.dart +0 -82
- package/dart/example/nomos_webview_transport.dart +0 -63
- package/dart/lib/nomos_headless.dart +0 -50
- package/dart/lib/testing.dart +0 -14
- package/dart/test/co2_product_gauntlet_test.dart +0 -244
- package/src/framework/identity.ts +0 -537
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
// • NEGATIVE arm: offering `importListing` with that envelope BEFORE enrolling the catalogue refuses
|
|
10
10
|
// `AttestedReadUntrustedSource` — surfaced to Dart as a NomosBridgeError carrying that name.
|
|
11
11
|
// • HAPPY arm: enrol the source genesis + attestor key, offer `importListing` carrying the signed
|
|
12
|
-
// envelope, and read the imported row back through the
|
|
13
|
-
// ('estate')
|
|
12
|
+
// envelope, and read the imported row back through the generated EstateApplication bound to
|
|
13
|
+
// `harness.session('estate')`.
|
|
14
14
|
@TestOn('vm')
|
|
15
15
|
library;
|
|
16
16
|
|
|
@@ -18,23 +18,30 @@ import 'dart:convert';
|
|
|
18
18
|
import 'dart:io';
|
|
19
19
|
|
|
20
20
|
import 'package:crypto/crypto.dart';
|
|
21
|
-
import 'package:nomos_client/
|
|
21
|
+
import 'package:nomos_client/src/nms_conformance_runtime.dart';
|
|
22
|
+
import 'package:nomos_client/src/nms_generated_runtime.dart';
|
|
22
23
|
import 'package:test/test.dart';
|
|
23
24
|
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
import '../../../bench/scale/fixtures/catalogue-reader/build/dart/src/generated/estate.
|
|
25
|
+
// Framework acceptance tests may bind a generated application to an already-mounted harness session. The
|
|
26
|
+
// raw client is a private `part` and is deliberately not importable, even here.
|
|
27
|
+
import '../../../bench/scale/fixtures/catalogue-reader/build/dart/src/generated/estate.application.dart';
|
|
27
28
|
|
|
28
29
|
String get _root => '${Directory.current.path}/../..';
|
|
29
30
|
String get _repoEntry => '$_root/cloud/web-client/runner/node-entry.ts';
|
|
30
|
-
String get _catDeploy =>
|
|
31
|
-
|
|
31
|
+
String get _catDeploy =>
|
|
32
|
+
'$_root/bench/scale/fixtures/catalogue-src/build/cat.deploy.json';
|
|
33
|
+
String get _estateDeploy =>
|
|
34
|
+
'$_root/bench/scale/fixtures/catalogue-reader/build/estate.deploy.json';
|
|
32
35
|
String get _estateClientDart =>
|
|
33
|
-
'$_root/bench/scale/fixtures/catalogue-reader/build/dart/src/generated/estate.
|
|
34
|
-
String get _runtimeDir =>
|
|
36
|
+
'$_root/bench/scale/fixtures/catalogue-reader/build/dart/src/generated/estate.application.dart';
|
|
37
|
+
String get _runtimeDir =>
|
|
38
|
+
Platform.environment['NOMOS_DART_RUNTIME'] ??
|
|
39
|
+
Platform.environment['NOMOS_OFFLINE_RUNTIME'] ??
|
|
40
|
+
'${Platform.environment['HOME'] ?? ''}/.holon/runtime';
|
|
35
41
|
|
|
36
42
|
String? _missingPrereq() {
|
|
37
|
-
if (!File(_repoEntry).existsSync())
|
|
43
|
+
if (!File(_repoEntry).existsSync())
|
|
44
|
+
return 'in-repo runner not found at $_repoEntry';
|
|
38
45
|
for (final p in [_catDeploy, _estateDeploy, _estateClientDart]) {
|
|
39
46
|
if (!File(p).existsSync()) {
|
|
40
47
|
return 'compile the catalogue fixtures with dart output: '
|
|
@@ -55,7 +62,8 @@ String _keyHashOf(String base64Public) =>
|
|
|
55
62
|
sha256.convert(base64Decode(base64Public)).toString();
|
|
56
63
|
|
|
57
64
|
void main() {
|
|
58
|
-
test(
|
|
65
|
+
test(
|
|
66
|
+
'cluster attested reads: colocated source served + signed → enrolled → typed import read back',
|
|
59
67
|
() async {
|
|
60
68
|
final skip = _missingPrereq();
|
|
61
69
|
if (skip != null) {
|
|
@@ -120,19 +128,21 @@ void main() {
|
|
|
120
128
|
expect(sourceGenesis.length, greaterThanOrEqualTo(40),
|
|
121
129
|
reason: 'the source genesis oid resolves off the signed envelope');
|
|
122
130
|
expect(signingKey, harness.devicePublicKey('catalogue'),
|
|
123
|
-
reason:
|
|
131
|
+
reason:
|
|
132
|
+
'the read is signed by the source session device key the resolver will use');
|
|
124
133
|
|
|
125
134
|
// The one importListing offer, offered TWICE (unenrolled then enrolled). ZERO injection: the payload
|
|
126
135
|
// names `catalogueWs`, and the runner's colocation resolver serves+signs the foreign read IN-PROCESS —
|
|
127
136
|
// NO `attestations` param. The gate judges the served envelope's genesis against the reader's allow-list.
|
|
128
|
-
Future<NomosOfferOutcome>
|
|
137
|
+
Future<NomosOfferOutcome> importRawForFrameworkTest(String importedAt) =>
|
|
138
|
+
estate.offerCreates(
|
|
129
139
|
domain: 'estate',
|
|
130
140
|
directiveId: 'importListing',
|
|
131
|
-
payload:
|
|
132
|
-
listingId: 'L-100',
|
|
133
|
-
catalogueWs: 'catalogue',
|
|
134
|
-
importedAt: importedAt,
|
|
135
|
-
|
|
141
|
+
payload: {
|
|
142
|
+
'listingId': 'L-100',
|
|
143
|
+
'catalogueWs': 'catalogue',
|
|
144
|
+
'importedAt': importedAt,
|
|
145
|
+
},
|
|
136
146
|
actor: 'user:estate-owner',
|
|
137
147
|
);
|
|
138
148
|
|
|
@@ -140,7 +150,9 @@ void main() {
|
|
|
140
150
|
// (the resolver still serves+signs; the gate refuses on the untrusted genesis).
|
|
141
151
|
Object? negError;
|
|
142
152
|
try {
|
|
143
|
-
|
|
153
|
+
// Deliberately raw: this framework test needs the refused kernel outcome itself. This is framework
|
|
154
|
+
// test instrumentation, not public API; tenant code gets only the generated application.
|
|
155
|
+
await importRawForFrameworkTest('2026-07-03T12:00:00Z');
|
|
144
156
|
} catch (e) {
|
|
145
157
|
negError = e;
|
|
146
158
|
}
|
|
@@ -151,29 +163,34 @@ void main() {
|
|
|
151
163
|
|
|
152
164
|
// 4. ENROL the catalogue: its genesis + the source device keyHash become folded law-state in the
|
|
153
165
|
// reader's own chain (typed write — the reader's own directive, no attestation).
|
|
154
|
-
final app =
|
|
155
|
-
|
|
166
|
+
final app =
|
|
167
|
+
await nomosInternalBindEstateApplication(estate, 'user:estate-owner');
|
|
168
|
+
final enrolled =
|
|
169
|
+
await app.trustedCatalogues.enrollCatalogue(EnrollCataloguePayload(
|
|
156
170
|
sourceGenesis: sourceGenesis,
|
|
157
171
|
keyHashes: [keyHash],
|
|
158
172
|
label: 'Acme Catalogue',
|
|
159
173
|
enrolledAt: '2026-07-03T10:00:00Z',
|
|
160
174
|
));
|
|
161
|
-
expect(enrolled.
|
|
175
|
+
expect(NmsInternalNomosRefs.workspace(enrolled.trustedCatalogue), 'estate');
|
|
162
176
|
|
|
163
177
|
// 5. HAPPY — the SAME zero-injection offer now admits: the resolver serves+signs, the gate judges the
|
|
164
178
|
// genesis against the folded allow-list, and the catalogue title lands on EstateListing.
|
|
165
|
-
final imported = await
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
final row =
|
|
176
|
-
expect(row
|
|
179
|
+
final imported = await app.estateListings.importListing(
|
|
180
|
+
const ImportListingPayload(
|
|
181
|
+
listingId: 'L-100',
|
|
182
|
+
catalogueWs: 'catalogue',
|
|
183
|
+
importedAt: '2026-07-03T12:05:00Z',
|
|
184
|
+
),
|
|
185
|
+
);
|
|
186
|
+
expect(NmsInternalNomosRefs.workspace(imported.estateListing), 'estate');
|
|
187
|
+
|
|
188
|
+
// 6. TYPED read-back through the generated application bound to the estate session.
|
|
189
|
+
final row = await app.estateListings.find(imported.estateListing);
|
|
190
|
+
expect(row, isNotNull,
|
|
191
|
+
reason:
|
|
192
|
+
'the imported EstateListing reads back on the estate session');
|
|
193
|
+
expect(row!.title, 'Oak dresser',
|
|
177
194
|
reason: 'the imported title was read through the policy edge, typed');
|
|
178
195
|
expect(row.catalogue, 'catalogue');
|
|
179
196
|
expect(row.listingRef, 'L-100');
|
|
@@ -23,14 +23,17 @@ library;
|
|
|
23
23
|
|
|
24
24
|
import 'dart:io';
|
|
25
25
|
|
|
26
|
-
import 'package:nomos_client/
|
|
26
|
+
import 'package:nomos_client/src/nms_conformance_runtime.dart';
|
|
27
27
|
import 'package:test/test.dart';
|
|
28
28
|
|
|
29
29
|
String get _root => '${Directory.current.path}/../..';
|
|
30
30
|
String get _repoEntry => '$_root/cloud/web-client/runner/node-entry.ts';
|
|
31
31
|
String get _birthDeploy =>
|
|
32
32
|
'$_root/bench/scale/fixtures/estate-birth/build/estate-birth.deploy.json';
|
|
33
|
-
String get _runtimeDir =>
|
|
33
|
+
String get _runtimeDir =>
|
|
34
|
+
Platform.environment['NOMOS_DART_RUNTIME'] ??
|
|
35
|
+
Platform.environment['NOMOS_OFFLINE_RUNTIME'] ??
|
|
36
|
+
'${Platform.environment['HOME'] ?? ''}/.holon/runtime';
|
|
34
37
|
|
|
35
38
|
String? _missingPrereq() {
|
|
36
39
|
if (!File(_repoEntry).existsSync()) return 'in-repo runner not found at $_repoEntry';
|
|
@@ -13,14 +13,17 @@ library;
|
|
|
13
13
|
|
|
14
14
|
import 'dart:io';
|
|
15
15
|
|
|
16
|
-
import 'package:nomos_client/
|
|
16
|
+
import 'package:nomos_client/src/nms_conformance_runtime.dart';
|
|
17
17
|
import 'package:test/test.dart';
|
|
18
18
|
|
|
19
19
|
String get _root => '${Directory.current.path}/../..';
|
|
20
20
|
String get _repoEntry => '$_root/cloud/web-client/runner/node-entry.ts';
|
|
21
21
|
String get _catDeploy => '$_root/bench/scale/fixtures/catalogue-src/build/cat.deploy.json';
|
|
22
22
|
String get _estateDeploy => '$_root/bench/scale/fixtures/catalogue-reader/build/estate.deploy.json';
|
|
23
|
-
String get _runtimeDir =>
|
|
23
|
+
String get _runtimeDir =>
|
|
24
|
+
Platform.environment['NOMOS_DART_RUNTIME'] ??
|
|
25
|
+
Platform.environment['NOMOS_OFFLINE_RUNTIME'] ??
|
|
26
|
+
'${Platform.environment['HOME'] ?? ''}/.holon/runtime';
|
|
24
27
|
|
|
25
28
|
String? _missingPrereq() {
|
|
26
29
|
if (!File(_repoEntry).existsSync()) return 'in-repo runner not found at $_repoEntry';
|
|
@@ -11,13 +11,16 @@ library;
|
|
|
11
11
|
|
|
12
12
|
import 'dart:io';
|
|
13
13
|
|
|
14
|
-
import 'package:nomos_client/
|
|
14
|
+
import 'package:nomos_client/src/nms_conformance_runtime.dart';
|
|
15
15
|
import 'package:test/test.dart';
|
|
16
16
|
|
|
17
17
|
String get _root => '${Directory.current.path}/../..';
|
|
18
18
|
String get _repoEntry => '$_root/cloud/web-client/runner/node-entry.ts';
|
|
19
19
|
String get _guestbookDeploy => '$_root/examples/guestbook/build/guestbook.deploy.json';
|
|
20
|
-
String get _runtimeDir =>
|
|
20
|
+
String get _runtimeDir =>
|
|
21
|
+
Platform.environment['NOMOS_DART_RUNTIME'] ??
|
|
22
|
+
Platform.environment['NOMOS_OFFLINE_RUNTIME'] ??
|
|
23
|
+
'${Platform.environment['HOME'] ?? ''}/.holon/runtime';
|
|
21
24
|
|
|
22
25
|
String? _missingPrereq() {
|
|
23
26
|
if (!File(_repoEntry).existsSync()) return 'in-repo runner not found at $_repoEntry';
|
|
@@ -11,13 +11,16 @@ library;
|
|
|
11
11
|
|
|
12
12
|
import 'dart:io';
|
|
13
13
|
|
|
14
|
-
import 'package:nomos_client/
|
|
14
|
+
import 'package:nomos_client/src/nms_conformance_runtime.dart';
|
|
15
15
|
import 'package:test/test.dart';
|
|
16
16
|
|
|
17
17
|
String get _root => '${Directory.current.path}/../..';
|
|
18
18
|
String get _repoEntry => '$_root/cloud/web-client/runner/node-entry.ts';
|
|
19
19
|
String get _guestbookDeploy => '$_root/examples/guestbook/build/guestbook.deploy.json';
|
|
20
|
-
String get _runtimeDir =>
|
|
20
|
+
String get _runtimeDir =>
|
|
21
|
+
Platform.environment['NOMOS_DART_RUNTIME'] ??
|
|
22
|
+
Platform.environment['NOMOS_OFFLINE_RUNTIME'] ??
|
|
23
|
+
'${Platform.environment['HOME'] ?? ''}/.holon/runtime';
|
|
21
24
|
|
|
22
25
|
/// How many colocated workspaces to open on the one plane. Dozens (CI-friendly), tunable via env for a
|
|
23
26
|
/// heavier local soak (`NOMOS_SCALE_N=100 dart test test/cluster_scale_test.dart`).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// COMPAT SUPERPOWER (#72b) — the Dart mirror of `holon.compat`. NomosCompat.fromJson round-trips
|
|
2
2
|
// the bridge's plain verdict snapshot; has() is the dark-launch feature flag over the per-member map.
|
|
3
|
-
import 'package:nomos_client/
|
|
3
|
+
import 'package:nomos_client/src/nms_generated_runtime.dart';
|
|
4
4
|
import 'package:test/test.dart';
|
|
5
5
|
|
|
6
6
|
Map<String, Object?> verdict({
|
|
@@ -15,7 +15,7 @@ import 'dart:async';
|
|
|
15
15
|
import 'dart:convert';
|
|
16
16
|
import 'dart:io';
|
|
17
17
|
|
|
18
|
-
import 'package:nomos_client/
|
|
18
|
+
import 'package:nomos_client/src/nms_conformance_runtime.dart';
|
|
19
19
|
import 'package:test/test.dart';
|
|
20
20
|
|
|
21
21
|
String get _root => '${Directory.current.path}/../..';
|
|
@@ -24,6 +24,7 @@ String get _geoDeploy => '$_root/bench/scale/fixtures/estate-geo/build/estate-ge
|
|
|
24
24
|
String get _docsDeploy => '$_root/bench/scale/fixtures/surfaced/build/surfaced.deploy.json';
|
|
25
25
|
String get _runtimeDir =>
|
|
26
26
|
Platform.environment['NOMOS_DART_RUNTIME'] ??
|
|
27
|
+
Platform.environment['NOMOS_OFFLINE_RUNTIME'] ??
|
|
27
28
|
'${Platform.environment['HOME'] ?? ''}/.holon/runtime';
|
|
28
29
|
|
|
29
30
|
String? _missingPrereq() {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// NOMOS — TYPED ERROR MINTING (§7 structured runtime error DX). `nomosErrorFromInfo` routes a structured
|
|
2
2
|
// `NomosErrorInfo` to the MOST SPECIFIC typed class by stable code prefix, so an app's `errorBuilder` branches
|
|
3
3
|
// on `is` and reads structured fields (not scraped prose). Every typed error still extends `NomosBridgeError`.
|
|
4
|
-
import 'package:nomos_client/
|
|
4
|
+
import 'package:nomos_client/src/nms_generated_runtime.dart';
|
|
5
5
|
import 'package:test/test.dart';
|
|
6
6
|
|
|
7
7
|
NomosErrorInfo info(String code,
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
// THE
|
|
2
|
-
//
|
|
3
|
-
//
|
|
1
|
+
// THE LOCAL-RUNTIME GAUNTLET — one sequential journey through the internal test harness and runtime
|
|
2
|
+
// lifecycle beneath the generated application. Tenant DX is compiled and exercised separately by
|
|
3
|
+
// dsl/src/dart_packages.test.ts through the generated application/scenario barrels; this file must not
|
|
4
|
+
// pretend that framework-conformance setup is tenant API. Every lifecycle bug co2 found (session watch delegation,
|
|
4
5
|
// local autoSync deadlock, the keyed-reconnect lane, …) has a leg here, so the NEXT one is found
|
|
5
6
|
// by CI, not by a tenant.
|
|
6
7
|
//
|
|
7
8
|
// Structure: ONE test, numbered legs, fail-fast — a failure names its leg, so CI output reads as
|
|
8
|
-
// a checklist. Its first act
|
|
9
|
-
//
|
|
9
|
+
// a checklist. Its first act drives the compiled CO2 law through the internal runtime lane solely to
|
|
10
|
+
// establish the child workspace used by the remaining runtime checks.
|
|
10
11
|
//
|
|
11
12
|
// Prereqs (fixtures compiled + a warm ~/.holon/runtime): locally the test SKIPS with the recipe
|
|
12
13
|
// when they are missing; in CI the job sets NOMOS_GAUNTLET_REQUIRED=1 so a missing prereq is a
|
|
@@ -16,11 +17,10 @@ library;
|
|
|
16
17
|
|
|
17
18
|
import 'dart:io';
|
|
18
19
|
|
|
19
|
-
import 'package:nomos_client/
|
|
20
|
+
import 'package:nomos_client/src/nms_conformance_runtime.dart';
|
|
21
|
+
import 'package:nomos_types/src/nomos_ref.dart' show NmsInternalNomosRefs;
|
|
20
22
|
import 'package:test/test.dart';
|
|
21
23
|
|
|
22
|
-
import '../../../examples/co2-birth/build/dart/src/generated/co2.client.dart';
|
|
23
|
-
|
|
24
24
|
String get _root => '${Directory.current.path}/../..';
|
|
25
25
|
String get _repoEntry => '$_root/cloud/web-client/runner/node-entry.ts';
|
|
26
26
|
String get _homeDeploy => '$_root/examples/co2-birth/build/co2.deploy.json';
|
|
@@ -32,11 +32,16 @@ String get _readerDeploy =>
|
|
|
32
32
|
'$_root/bench/scale/fixtures/catalogue-reader/build/estate.deploy.json';
|
|
33
33
|
String get _runtimeDir =>
|
|
34
34
|
Platform.environment['NOMOS_DART_RUNTIME'] ??
|
|
35
|
+
Platform.environment['NOMOS_OFFLINE_RUNTIME'] ??
|
|
35
36
|
'${Platform.environment['HOME'] ?? ''}/.holon/runtime';
|
|
36
37
|
|
|
37
38
|
const _owner = 'user:gauntlet-owner';
|
|
38
39
|
const _keyed = 'catalogue';
|
|
39
40
|
|
|
41
|
+
/// Phantom test-only aggregate type for the internal runtime locator below. Tenant code gets the real
|
|
42
|
+
/// generated `NomosRef<Estate>` from its application package.
|
|
43
|
+
final class _GauntletEstate {}
|
|
44
|
+
|
|
40
45
|
String? _missingPrereq() {
|
|
41
46
|
if (!File(_repoEntry).existsSync())
|
|
42
47
|
return 'in-repo runner not found at $_repoEntry';
|
|
@@ -78,7 +83,7 @@ Future<T> _leg<T>(String name, Future<T> Function() body) async {
|
|
|
78
83
|
|
|
79
84
|
void main() {
|
|
80
85
|
test(
|
|
81
|
-
'THE
|
|
86
|
+
'THE LOCAL-RUNTIME GAUNTLET: harness → law setup → local posture → '
|
|
82
87
|
'acquire → reactive reads → attested read → diagnostics → disposal',
|
|
83
88
|
() async {
|
|
84
89
|
final required = Platform.environment['NOMOS_GAUNTLET_REQUIRED'] == '1';
|
|
@@ -137,61 +142,82 @@ void main() {
|
|
|
137
142
|
});
|
|
138
143
|
|
|
139
144
|
try {
|
|
140
|
-
// ── LEG 2:
|
|
141
|
-
//
|
|
145
|
+
// ── LEG 2: internal conformance setup — establish Estate → Site → Asset directly against the
|
|
146
|
+
// compiled law. The generated, business-only surface has its own compile-and-run proof. ──
|
|
142
147
|
final home = harness.session('home');
|
|
143
148
|
final bornEstate = await _leg(
|
|
144
|
-
'leg 2:
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
149
|
+
'leg 2: internal CO2 law setup (Estate → Site → Asset)', () async {
|
|
150
|
+
final birth = await home.offerOutcome(
|
|
151
|
+
domain: 'co2',
|
|
152
|
+
directiveId: 'nomosBirthEstate',
|
|
153
|
+
payload: {
|
|
154
|
+
'reference': 'E-001',
|
|
155
|
+
'name': 'Foundry',
|
|
156
|
+
'country': 'GB',
|
|
157
|
+
'baselineTonnesCo2e': 4200,
|
|
158
|
+
'principal': _owner,
|
|
159
|
+
'bornAt': DateTime.now().toUtc().toIso8601String(),
|
|
160
|
+
},
|
|
161
|
+
actor: _owner,
|
|
162
|
+
);
|
|
163
|
+
expect(birth.born, hasLength(1));
|
|
164
|
+
final ref = NmsInternalNomosRefs.create<_GauntletEstate>(
|
|
165
|
+
workspace: birth.born.single,
|
|
166
|
+
type: 'Estate',
|
|
167
|
+
id: 'estate:self',
|
|
156
168
|
);
|
|
157
|
-
expect(
|
|
158
|
-
expect(
|
|
169
|
+
expect(NmsInternalNomosRefs.workspace(ref), startsWith('estate-'));
|
|
170
|
+
expect(NmsInternalNomosRefs.type(ref), 'Estate');
|
|
159
171
|
|
|
160
172
|
final estateSession = await harness.bridge.follow(
|
|
161
173
|
ref,
|
|
162
174
|
authorSecret: harness.deviceSecret(home.workspace),
|
|
163
175
|
);
|
|
164
|
-
expect(estateSession.workspace,
|
|
176
|
+
expect(estateSession.workspace, NmsInternalNomosRefs.workspace(ref));
|
|
165
177
|
|
|
166
|
-
final
|
|
167
|
-
|
|
168
|
-
expect(rows, hasLength(1),
|
|
169
|
-
|
|
170
|
-
expect(
|
|
171
|
-
expect(
|
|
178
|
+
final rows =
|
|
179
|
+
await estateSession.queryById(NmsInternalNomosRefs.id(ref));
|
|
180
|
+
expect(rows, hasLength(1), reason: 'the born business root reads back');
|
|
181
|
+
final estateData = (rows.single['data'] as Map).cast<String, Object?>();
|
|
182
|
+
expect(estateData['reference'], 'E-001');
|
|
183
|
+
expect(estateData['name'], 'Foundry');
|
|
172
184
|
|
|
173
|
-
final siteOutcome = await
|
|
174
|
-
|
|
185
|
+
final siteOutcome = await estateSession.offerOutcome(
|
|
186
|
+
domain: 'co2',
|
|
187
|
+
directiveId: 'addSite',
|
|
188
|
+
payload: {'name': 'Trafford Depot'},
|
|
189
|
+
actor: _owner,
|
|
175
190
|
);
|
|
176
|
-
final
|
|
177
|
-
expect(
|
|
178
|
-
|
|
191
|
+
final site = siteOutcome.created.single;
|
|
192
|
+
expect(site.type, 'co2.Site');
|
|
193
|
+
// An estate is the workspace boundary, so its Site records need no copied
|
|
194
|
+
// estateId foreign key. This framework test uses the primitive type read;
|
|
195
|
+
// tenant code gets estate.sites from the generated application.
|
|
196
|
+
final sites = await estateSession
|
|
197
|
+
.query('aggregatesByType', {'__type': 'co2.Site'});
|
|
179
198
|
expect(sites, hasLength(1));
|
|
180
|
-
|
|
199
|
+
final siteData = (sites.single['data'] as Map).cast<String, Object?>();
|
|
200
|
+
expect(siteData['name'], 'Trafford Depot');
|
|
181
201
|
|
|
182
|
-
final assetOutcome = await
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
202
|
+
final assetOutcome = await estateSession.offerOutcome(
|
|
203
|
+
domain: 'co2',
|
|
204
|
+
directiveId: 'commissionAsset',
|
|
205
|
+
payload: {
|
|
206
|
+
'siteId': site.id,
|
|
207
|
+
'name': 'Main electricity meter',
|
|
208
|
+
'rfidQrIdentity': 'E20034120123456789012345',
|
|
209
|
+
},
|
|
210
|
+
actor: _owner,
|
|
188
211
|
);
|
|
189
|
-
final
|
|
190
|
-
expect(
|
|
191
|
-
final assets =
|
|
212
|
+
final asset = assetOutcome.created.single;
|
|
213
|
+
expect(asset.type, 'co2.Asset');
|
|
214
|
+
final assets =
|
|
215
|
+
await estateSession.query('assetsBySite', {'siteId': site.id});
|
|
192
216
|
expect(assets, hasLength(1));
|
|
193
|
-
|
|
194
|
-
|
|
217
|
+
final assetData =
|
|
218
|
+
(assets.single['data'] as Map).cast<String, Object?>();
|
|
219
|
+
expect(assetData['name'], 'Main electricity meter');
|
|
220
|
+
expect(assetData['operationalStatus'], 'commissioned');
|
|
195
221
|
return (session: estateSession, ref: ref);
|
|
196
222
|
});
|
|
197
223
|
final estate = bornEstate.session;
|
|
@@ -239,7 +265,8 @@ void main() {
|
|
|
239
265
|
// all deliver a FIRST SNAPSHOT (the 0.48.x dead-delegation class). ──
|
|
240
266
|
await _leg('leg 5: session reactive reads emit their first snapshot',
|
|
241
267
|
() async {
|
|
242
|
-
final raw =
|
|
268
|
+
final raw =
|
|
269
|
+
await estate.queryById(NmsInternalNomosRefs.id(bornEstate.ref));
|
|
243
270
|
final aggId = ((raw.single as Map)['id'] ?? '').toString();
|
|
244
271
|
expect(aggId, isNotEmpty);
|
|
245
272
|
final byId = await estate.watchById(aggId).first.timeout(
|
|
@@ -305,7 +332,7 @@ void main() {
|
|
|
305
332
|
'leg 7: harness diagnostics (assertDomainInstalled / reset / seed)',
|
|
306
333
|
() async {
|
|
307
334
|
await harness.assertDomainInstalled(
|
|
308
|
-
workspace: estate.workspace, domain:
|
|
335
|
+
workspace: estate.workspace, domain: 'co2');
|
|
309
336
|
// The negative arm names the active domains.
|
|
310
337
|
await expectLater(
|
|
311
338
|
harness.assertDomainInstalled(
|
|
@@ -25,7 +25,7 @@ import 'dart:convert';
|
|
|
25
25
|
import 'dart:io';
|
|
26
26
|
|
|
27
27
|
import 'package:crypto/crypto.dart' show sha256;
|
|
28
|
-
import 'package:nomos_client/
|
|
28
|
+
import 'package:nomos_client/src/nms_conformance_runtime.dart';
|
|
29
29
|
import 'package:test/test.dart';
|
|
30
30
|
|
|
31
31
|
String get _root => '${Directory.current.path}/../..';
|
|
@@ -9,7 +9,7 @@ library;
|
|
|
9
9
|
|
|
10
10
|
import 'dart:io';
|
|
11
11
|
|
|
12
|
-
import 'package:nomos_client/
|
|
12
|
+
import 'package:nomos_client/src/nms_conformance_runtime.dart';
|
|
13
13
|
import 'package:test/test.dart';
|
|
14
14
|
|
|
15
15
|
String get _fixtures => '${Directory.current.path}/test/fixtures/wedge';
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import 'package:nomos_client/
|
|
1
|
+
import 'package:nomos_client/src/nms_generated_runtime.dart';
|
|
2
2
|
import 'package:test/test.dart';
|
|
3
|
+
|
|
3
4
|
void main() {
|
|
4
|
-
test('
|
|
5
|
-
expect(
|
|
6
|
-
|
|
7
|
-
expect(
|
|
5
|
+
test('the private receiving-group address matches the JS/law formula', () {
|
|
6
|
+
expect(nmsInternalReceivingGroupNameOf('user:abc-123'),
|
|
7
|
+
'nomos-rg-5094641143043f9281b6b9146cc345a254a5d3af');
|
|
8
|
+
expect(
|
|
9
|
+
nmsInternalReceivingGroupNameOf('user:abc-123').startsWith('nomos-rg-'),
|
|
10
|
+
isTrue);
|
|
11
|
+
expect(nmsInternalReceivingGroupNameOf('user:abc-123').length, 49);
|
|
8
12
|
});
|
|
9
13
|
}
|
|
@@ -7,10 +7,10 @@ library;
|
|
|
7
7
|
|
|
8
8
|
import 'dart:io';
|
|
9
9
|
|
|
10
|
-
import 'package:nomos_client/
|
|
10
|
+
import 'package:nomos_client/src/nms_conformance_runtime.dart';
|
|
11
11
|
import 'package:test/test.dart';
|
|
12
12
|
|
|
13
|
-
import '../../../bench/scale/fixtures/estate-birth/build/dart/src/generated/home.
|
|
13
|
+
import '../../../bench/scale/fixtures/estate-birth/build/dart/src/generated/home.application.dart';
|
|
14
14
|
|
|
15
15
|
String get _root => '${Directory.current.path}/../..';
|
|
16
16
|
String get _repoEntry => '$_root/cloud/web-client/runner/node-entry.ts';
|
|
@@ -18,6 +18,7 @@ String get _deployJson =>
|
|
|
18
18
|
'$_root/bench/scale/fixtures/estate-birth/build/estate-birth.deploy.json';
|
|
19
19
|
String get _runtimeDir =>
|
|
20
20
|
Platform.environment['NOMOS_DART_RUNTIME'] ??
|
|
21
|
+
Platform.environment['NOMOS_OFFLINE_RUNTIME'] ??
|
|
21
22
|
'${Platform.environment['HOME'] ?? ''}/.holon/runtime';
|
|
22
23
|
|
|
23
24
|
const _workspace = 'estate-birth';
|
|
@@ -53,23 +54,30 @@ void main() {
|
|
|
53
54
|
);
|
|
54
55
|
try {
|
|
55
56
|
final session = harness.session(_workspace);
|
|
56
|
-
|
|
57
|
+
// This is a nomos_client runtime regression test, so the raw offer below is
|
|
58
|
+
// deliberate infrastructure setup. Tenant code imports the generated package
|
|
59
|
+
// application; it cannot import the private generated client implementation.
|
|
60
|
+
await nomosInternalBindHomeApplication(session, _owner);
|
|
57
61
|
|
|
58
62
|
// 1-2. offer a write on the snapshot-opened local session.
|
|
59
|
-
final
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
63
|
+
final facts = BirthEstateWorkspacePayload(
|
|
64
|
+
owner: _owner,
|
|
65
|
+
frameworkHash: harness.frameworkHash!,
|
|
66
|
+
lawHash: harness.lawHashes(_workspace).first,
|
|
67
|
+
bornAt: DateTime.now().toUtc().toIso8601String(),
|
|
68
|
+
);
|
|
69
|
+
final birth = await session.offerOutcome(
|
|
70
|
+
domain: 'home',
|
|
71
|
+
directiveId: 'birthEstateWorkspace',
|
|
72
|
+
payload: facts.nmsInternalToPayloadJson(),
|
|
73
|
+
actor: _owner,
|
|
66
74
|
);
|
|
67
75
|
expect(birth.born, hasLength(1));
|
|
68
76
|
|
|
69
77
|
// 3. Infrastructure assertion: inspect Nomos's private birth record through the raw harness session.
|
|
70
78
|
// Generated tenant clients deliberately do not expose this framework query.
|
|
71
|
-
final before =
|
|
72
|
-
.query('birthRecordsByPrincipal', {'principal': _owner});
|
|
79
|
+
final before =
|
|
80
|
+
await session.query('birthRecordsByPrincipal', {'principal': _owner});
|
|
73
81
|
expect(before, hasLength(1),
|
|
74
82
|
reason: 'the offer must be readable BEFORE sync');
|
|
75
83
|
final statusBefore = await session.custodyStatus();
|
|
@@ -86,8 +94,8 @@ void main() {
|
|
|
86
94
|
expect(statusAfter.pendingLocalIntents, statusBefore.pendingLocalIntents,
|
|
87
95
|
reason:
|
|
88
96
|
'local-only sync must not consume/move pending local intents');
|
|
89
|
-
final after =
|
|
90
|
-
.query('birthRecordsByPrincipal', {'principal': _owner});
|
|
97
|
+
final after =
|
|
98
|
+
await session.query('birthRecordsByPrincipal', {'principal': _owner});
|
|
91
99
|
expect(after, hasLength(1),
|
|
92
100
|
reason:
|
|
93
101
|
'local-only sync must be observationally inert — the row must still read');
|
|
@@ -6,8 +6,8 @@ library;
|
|
|
6
6
|
|
|
7
7
|
import 'dart:io';
|
|
8
8
|
|
|
9
|
-
import 'package:nomos_client/
|
|
10
|
-
import 'package:nomos_client/
|
|
9
|
+
import 'package:nomos_client/src/nms_generated_runtime.dart';
|
|
10
|
+
import 'package:nomos_client/src/nms_conformance_runtime.dart';
|
|
11
11
|
import 'package:test/test.dart';
|
|
12
12
|
|
|
13
13
|
String _repoEntry() {
|
|
@@ -25,7 +25,11 @@ void main() {
|
|
|
25
25
|
late NomosBridge bridge;
|
|
26
26
|
|
|
27
27
|
setUp(() async {
|
|
28
|
-
transport = await NodeRunnerTransport.start(
|
|
28
|
+
transport = await NodeRunnerTransport.start(
|
|
29
|
+
entry: _repoEntry(),
|
|
30
|
+
// An explicit packaged entry is self-contained; a stale discovery root must not become its cwd.
|
|
31
|
+
resolveFrom: '${Directory.systemTemp.path}/nomos-does-not-exist',
|
|
32
|
+
);
|
|
29
33
|
bridge = NomosBridge(transport);
|
|
30
34
|
});
|
|
31
35
|
|
|
@@ -41,8 +45,8 @@ void main() {
|
|
|
41
45
|
await bridge.ready.timeout(const Duration(seconds: 15));
|
|
42
46
|
await expectLater(
|
|
43
47
|
bridge.head(),
|
|
44
|
-
throwsA(isA<NomosBridgeError>()
|
|
45
|
-
contains('not connected'))),
|
|
48
|
+
throwsA(isA<NomosBridgeError>()
|
|
49
|
+
.having((e) => e.message, 'message', contains('not connected'))),
|
|
46
50
|
);
|
|
47
51
|
});
|
|
48
52
|
|