@githolon/dsl 0.101.6 → 0.102.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.
Files changed (120) hide show
  1. package/dart/CHANGELOG.md +13 -0
  2. package/dart/lib/nomos_client.dart +3 -52
  3. package/dart/lib/src/dev_cloud.dart +5 -0
  4. package/dart/lib/src/home.dart +10 -15
  5. package/dart/lib/src/nms_conformance_runtime.dart +12 -0
  6. package/dart/lib/src/nms_generated_runtime.dart +29 -0
  7. package/dart/lib/src/nms_test_environment.dart +8 -0
  8. package/dart/lib/src/node_runner_transport.dart +56 -18
  9. package/dart/lib/src/provider.dart +5 -1
  10. package/dart/lib/src/record_origin.dart +55 -0
  11. package/dart/lib/src/runner/node-entry.mjs +9105 -0
  12. package/dart/lib/src/runner/offline-install.mjs +4729 -0
  13. package/dart/lib/src/session_bound.dart +23 -10
  14. package/dart/lib/src/source_trust.dart +51 -0
  15. package/dart/lib/src/test_harness.dart +490 -58
  16. package/dart/lib/src/webview_bridge.dart +167 -58
  17. package/dart/lib/src/workspace_name.dart +7 -1
  18. package/dart/pubspec.lock +3 -3
  19. package/dart/pubspec.yaml +4 -2
  20. package/dart/test/acquire_session_credentials_test.dart +34 -17
  21. package/dart/test/acquire_session_test.dart +109 -24
  22. package/dart/test/adv_realm_interference_test.dart +227 -99
  23. package/dart/test/bundle_version_pairing_test.dart +1 -1
  24. package/dart/test/cloud_bound_topology_test.dart +1 -1
  25. package/dart/test/cluster_attested_test.dart +52 -35
  26. package/dart/test/cluster_births_test.dart +5 -2
  27. package/dart/test/cluster_device_keyed_acceptance_test.dart +5 -2
  28. package/dart/test/cluster_local_autosync_test.dart +5 -2
  29. package/dart/test/cluster_scale_test.dart +5 -2
  30. package/dart/test/compat_test.dart +1 -1
  31. package/dart/test/dlq_session_surface_test.dart +2 -1
  32. package/dart/test/errors_test.dart +1 -1
  33. package/dart/test/first_app_gauntlet_test.dart +78 -51
  34. package/dart/test/four_layer_nested_topology_test.dart +1 -1
  35. package/dart/test/harness_phase_timeout_test.dart +1 -1
  36. package/dart/test/home_parity_test.dart +9 -5
  37. package/dart/test/local_sync_inert_test.dart +22 -14
  38. package/dart/test/node_runner_transport_test.dart +9 -5
  39. package/dart/test/null_slot_test.dart +1 -1
  40. package/dart/test/parent_signer_recovery_test.dart +5 -2
  41. package/dart/test/schema_validation_test.dart +1 -1
  42. package/dart/test/sealing_client_test.dart +2 -1
  43. package/dart/test/session_bound_test.dart +92 -119
  44. package/dart/test/stale_bundle_test.dart +1 -1
  45. package/dart/test/test_harness_test.dart +77 -22
  46. package/dart/test/vo_read_typing_test.dart +32 -14
  47. package/dart/test/watch_after_offer_stall_test.dart +2 -1
  48. package/dart/test/webview_bridge_test.dart +17 -4
  49. package/dart/test/wire_test.dart +1 -1
  50. package/dart_types/CHANGELOG.md +8 -0
  51. package/dart_types/lib/nomos_types.dart +7 -6
  52. package/dart_types/lib/src/activity.dart +23 -13
  53. package/dart_types/lib/src/foreign_ref.dart +61 -112
  54. package/dart_types/lib/src/invitation.dart +96 -0
  55. package/dart_types/lib/src/nomos_ref.dart +97 -59
  56. package/dart_types/pubspec.yaml +1 -1
  57. package/dart_types/test/surfaced_test.dart +125 -19
  58. package/package.json +7 -3
  59. package/runtime/generated-application-host.js +8851 -0
  60. package/src/activity.ts +2 -2
  61. package/src/aggregate.ts +24 -1
  62. package/src/application_composition.ts +282 -0
  63. package/src/application_topology.ts +151 -0
  64. package/src/attested_core.ts +2 -2
  65. package/src/authoring_context.ts +9 -0
  66. package/src/birth_meter_ensure.ts +1 -1
  67. package/src/births.ts +53 -5
  68. package/src/build_package.ts +79 -71
  69. package/src/business_birth.ts +93 -10
  70. package/src/clear_directive.ts +3 -1
  71. package/src/codegen_dart.ts +369 -420
  72. package/src/codegen_dart_application.ts +1508 -0
  73. package/src/codegen_dart_client.ts +156 -95
  74. package/src/codegen_dart_scenario.ts +299 -0
  75. package/src/codegen_openapi.ts +8 -3
  76. package/src/codegen_proof.ts +1113 -1137
  77. package/src/codegen_provider_dart.ts +12 -1
  78. package/src/codegen_ts.ts +1176 -496
  79. package/src/compat_package_main.ts +22 -10
  80. package/src/compile_package_main.ts +1536 -337
  81. package/src/contract.ts +10 -4
  82. package/src/dart_barrel_guard.ts +5 -1
  83. package/src/describe_model.ts +13 -5
  84. package/src/directive.ts +244 -5
  85. package/src/engine_entry.ts +56 -13
  86. package/src/engine_javascript.ts +31 -0
  87. package/src/evolve_preview.ts +3 -12
  88. package/src/framework/application_home.ts +24 -10
  89. package/src/framework/capability.ts +15 -1
  90. package/src/framework/domain_lifecycle.ts +8 -0
  91. package/src/framework/framework_aggregates.ts +2 -2
  92. package/src/framework/genesis.ts +11 -1
  93. package/src/framework/home.ts +178 -75
  94. package/src/framework/impure_capability.ts +24 -7
  95. package/src/framework/relations.ts +13 -5
  96. package/src/framework/workspaces.ts +13 -12
  97. package/src/generated_client_names.ts +42 -3
  98. package/src/idof_lint.ts +65 -13
  99. package/src/index.ts +46 -12
  100. package/src/intent.ts +587 -0
  101. package/src/law_check.ts +64 -16
  102. package/src/precondition.ts +16 -4
  103. package/src/read_projection_namespace.ts +2 -7
  104. package/src/recipient.ts +33 -0
  105. package/src/relation_schema.ts +93 -0
  106. package/src/secondary_ensure.ts +11 -2
  107. package/src/shape_compat.ts +11 -1
  108. package/src/usd.ts +30 -8
  109. package/src/usd_layers.ts +447 -246
  110. package/src/usd_state.ts +1 -1
  111. package/src/value_object.ts +49 -13
  112. package/src/wire_encode.ts +124 -26
  113. package/src/workspace_sharing.ts +269 -0
  114. package/src/zod_introspection.ts +84 -0
  115. package/dart/example/nomos_secure_key_store.dart +0 -82
  116. package/dart/example/nomos_webview_transport.dart +0 -63
  117. package/dart/lib/nomos_headless.dart +0 -50
  118. package/dart/lib/testing.dart +0 -14
  119. package/dart/test/co2_product_gauntlet_test.dart +0 -244
  120. 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 TYPED EstateClient bound to `harness.session
13
- // ('estate')` — proving a NomosSession satisfies the generated client's `NomosBridge` constructor.
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/nomos_headless.dart';
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
- // estate.client.dart re-exports estate.dart (payloads/read-models) AND the nomos_client symbols it needs
25
- // (NomosBridgeError, NomosBridge, …), so this one import carries the whole typed surface.
26
- import '../../../bench/scale/fixtures/catalogue-reader/build/dart/src/generated/estate.client.dart';
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 => '$_root/bench/scale/fixtures/catalogue-src/build/cat.deploy.json';
31
- String get _estateDeploy => '$_root/bench/scale/fixtures/catalogue-reader/build/estate.deploy.json';
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.client.dart';
34
- String get _runtimeDir => '${Platform.environment['HOME'] ?? ''}/.holon/runtime';
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()) return 'in-repo runner not found at $_repoEntry';
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('cluster attested reads: colocated source served + signed → enrolled → typed import read back',
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: 'the read is signed by the source session device key the resolver will use');
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> importOnce(String importedAt) => estate.offerCreates(
137
+ Future<NomosOfferOutcome> importRawForFrameworkTest(String importedAt) =>
138
+ estate.offerCreates(
129
139
  domain: 'estate',
130
140
  directiveId: 'importListing',
131
- payload: ImportListingPayload(
132
- listingId: 'L-100',
133
- catalogueWs: 'catalogue',
134
- importedAt: importedAt,
135
- ).toPayloadJson(),
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
- await importOnce('2026-07-03T12:00:00Z');
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 = EstateClient(estate, actor: 'user:estate-owner');
155
- final enrolled = await app.enrollCatalogue(EnrollCataloguePayload(
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.head, isNotEmpty);
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 importOnce('2026-07-03T12:05:00Z');
166
- expect(imported.head, isNotEmpty);
167
- expect(imported.created, isNotEmpty,
168
- reason: 'the importListing plan minted the EstateListing');
169
- final createdId = imported.created.first.id;
170
-
171
- // 6. TYPED read-back through the EstateClient bound to the estate SESSION (by the minted id).
172
- final rows = await app.estateListingById(createdId);
173
- expect(rows, isNotEmpty,
174
- reason: 'the imported EstateListing reads back on the estate session');
175
- final row = rows.first;
176
- expect(row.title, 'Oak dresser',
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/nomos_headless.dart';
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 => '${Platform.environment['HOME'] ?? ''}/.holon/runtime';
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/nomos_headless.dart';
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 => '${Platform.environment['HOME'] ?? ''}/.holon/runtime';
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/nomos_headless.dart';
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 => '${Platform.environment['HOME'] ?? ''}/.holon/runtime';
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/nomos_headless.dart';
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 => '${Platform.environment['HOME'] ?? ''}/.holon/runtime';
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/nomos_client.dart';
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/nomos_headless.dart';
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/nomos_client.dart';
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 FIRST-FIVE-MINUTES GAUNTLET — one sequential journey through EVERYTHING the test harness +
2
- // session-bound client surface promises a NEW app developer, using ONLY the public API (the way a
3
- // tenant would). Every lifecycle bug co2 found in their first minutes (session watch delegation,
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 uses the one-business-birth CO2 example: the same tenant source and
9
- // generated client a real Flutter app consumes, never a harness-only birth recipe.
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/nomos_headless.dart';
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 FIRST-FIVE-MINUTES GAUNTLET: harness → blessed shape → local posture → '
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: the blessed session-bound shape — one business birth, then Estate → Site → Asset
141
- // through the generated Dart client. Zero routing/security strings. ──
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: generated business shape (Estate → Site → Asset)',
145
- () async {
146
- final homeClient = await Co2Client.bind(home, actor: _owner);
147
- expect(homeClient.session!.workspace, home.workspace,
148
- reason: 'inspectable session context');
149
- final ref = await homeClient.birth(
150
- NomosBirthEstatePayload(
151
- reference: 'E-001',
152
- name: 'Foundry',
153
- country: 'GB',
154
- baselineTonnesCo2e: 4200,
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(ref.workspace, startsWith('estate-'));
158
- expect(ref.type, 'Estate');
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, ref.workspace);
176
+ expect(estateSession.workspace, NmsInternalNomosRefs.workspace(ref));
165
177
 
166
- final estateClient = await Co2Client.bind(estateSession, actor: _owner);
167
- final rows = await estateClient.estateById(ref.id);
168
- expect(rows, hasLength(1),
169
- reason: 'the born business root reads back typed');
170
- expect(rows.single.reference, 'E-001');
171
- expect(rows.single.name, 'Foundry');
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 estateClient.addSite(
174
- AddSitePayload(estateId: ref.id, name: 'Trafford Depot'),
185
+ final siteOutcome = await estateSession.offerOutcome(
186
+ domain: 'co2',
187
+ directiveId: 'addSite',
188
+ payload: {'name': 'Trafford Depot'},
189
+ actor: _owner,
175
190
  );
176
- final siteRef = siteOutcome.created.single.ref;
177
- expect(siteRef.type, 'co2.Site');
178
- final sites = await estateClient.sitesByEstate(estateId: ref.id);
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
- expect(sites.single.name, 'Trafford Depot');
199
+ final siteData = (sites.single['data'] as Map).cast<String, Object?>();
200
+ expect(siteData['name'], 'Trafford Depot');
181
201
 
182
- final assetOutcome = await estateClient.addAsset(
183
- AddAssetPayload(
184
- siteId: siteRef.id,
185
- name: 'Main electricity meter',
186
- operationalStatus: 'commissioned',
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 assetRef = assetOutcome.created.single.ref;
190
- expect(assetRef.type, 'co2.Asset');
191
- final assets = await estateClient.assetsBySite(siteId: siteRef.id);
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
- expect(assets.single.name, 'Main electricity meter');
194
- expect(assets.single.operationalStatus?.valueOrNull, 'commissioned');
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 = await estate.queryById(bornEstate.ref.id);
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: Co2Client.interface.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/nomos_headless.dart';
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/nomos_headless.dart';
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/nomos_client.dart';
1
+ import 'package:nomos_client/src/nms_generated_runtime.dart';
2
2
  import 'package:test/test.dart';
3
+
3
4
  void main() {
4
- test('homeNameOf matches the JS/law formula', () {
5
- expect(homeNameOf('user:abc-123'), 'home-5094641143043f9281b6b9146cc345a254a5d3af');
6
- expect(homeNameOf('user:abc-123').startsWith('home-'), isTrue);
7
- expect(homeNameOf('user:abc-123').length, 45); // 'home-' + 40 hex
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/nomos_headless.dart';
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.client.dart';
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
- final client = await HomeClient.bind(session, actor: _owner);
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 birth = await client.birthEstateWorkspace(
60
- payload: BirthEstateWorkspacePayload(
61
- owner: _owner,
62
- frameworkHash: harness.frameworkHash!,
63
- lawHash: harness.lawHashes(_workspace).first,
64
- bornAt: DateTime.now().toUtc().toIso8601String(),
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 = await session
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 = await session
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/nomos_client.dart';
10
- import 'package:nomos_client/nomos_headless.dart';
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(entry: _repoEntry());
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>().having((e) => e.message, 'message',
45
- contains('not connected'))),
48
+ throwsA(isA<NomosBridgeError>()
49
+ .having((e) => e.message, 'message', contains('not connected'))),
46
50
  );
47
51
  });
48
52
 
@@ -1,4 +1,4 @@
1
- import 'package:nomos_client/nomos_client.dart';
1
+ import 'package:nomos_client/src/nms_generated_runtime.dart';
2
2
  import 'package:test/test.dart';
3
3
 
4
4
  void main() {