@githolon/dsl 0.100.5 → 0.101.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.
Files changed (97) hide show
  1. package/dart/CHANGELOG.md +12 -0
  2. package/dart/lib/src/dev_cloud.dart +46 -15
  3. package/dart/lib/src/test_harness.dart +220 -71
  4. package/dart/lib/src/webview_bridge.dart +640 -126
  5. package/dart/pubspec.lock +1 -1
  6. package/dart/pubspec.yaml +2 -2
  7. package/dart/test/acquire_session_credentials_test.dart +1 -1
  8. package/dart/test/adv_realm_interference_test.dart +1 -1
  9. package/dart/test/bundle_version_pairing_test.dart +11 -22
  10. package/dart/test/cluster_attested_test.dart +1 -1
  11. package/dart/test/cluster_births_test.dart +1 -1
  12. package/dart/test/cluster_device_keyed_acceptance_test.dart +1 -1
  13. package/dart/test/cluster_local_autosync_test.dart +1 -1
  14. package/dart/test/cluster_scale_test.dart +1 -1
  15. package/dart/test/co2_product_gauntlet_test.dart +228 -0
  16. package/dart/test/dlq_session_surface_test.dart +1 -1
  17. package/dart/test/errors_test.dart +63 -12
  18. package/dart/test/first_app_gauntlet_test.dart +132 -87
  19. package/dart/test/local_sync_inert_test.dart +10 -5
  20. package/dart/test/parent_signer_recovery_test.dart +1 -1
  21. package/dart/test/sealing_client_test.dart +1 -1
  22. package/dart/test/session_bound_test.dart +1 -1
  23. package/dart/test/test_harness_test.dart +2 -2
  24. package/dart/test/vo_read_typing_test.dart +1 -1
  25. package/dart/test/watch_after_offer_stall_test.dart +1 -1
  26. package/dart/test/webview_bridge_test.dart +274 -0
  27. package/dart_types/CHANGELOG.md +6 -0
  28. package/dart_types/lib/src/errors.dart +136 -30
  29. package/dart_types/lib/src/surfaced.dart +48 -2
  30. package/dart_types/lib/src/wire.dart +3 -1
  31. package/dart_types/pubspec.yaml +1 -1
  32. package/dart_types/test/surfaced_test.dart +19 -0
  33. package/package.json +1 -1
  34. package/src/activity.ts +43 -4
  35. package/src/aggregate.ts +132 -22
  36. package/src/attested_core.ts +1 -1
  37. package/src/authoring.ts +119 -6
  38. package/src/birth_meter.ts +4 -4
  39. package/src/birth_meter_ensure.ts +165 -29
  40. package/src/births.ts +53 -22
  41. package/src/build_package.ts +96 -20
  42. package/src/business_birth.ts +79 -16
  43. package/src/codegen_dart.ts +267 -37
  44. package/src/codegen_dart_client.ts +930 -87
  45. package/src/codegen_openapi.ts +28 -5
  46. package/src/codegen_proof.ts +107 -11
  47. package/src/codegen_ts.ts +961 -135
  48. package/src/compile_package_main.ts +172 -53
  49. package/src/conflicts.ts +252 -0
  50. package/src/describe_model.ts +448 -0
  51. package/src/directive.ts +5 -38
  52. package/src/drivers.ts +12 -4
  53. package/src/engine_entry.ts +4 -0
  54. package/src/evolve_preview.ts +72 -11
  55. package/src/fields.ts +201 -55
  56. package/src/framework/application_home.ts +103 -0
  57. package/src/framework/application_home_domain.ts +2 -0
  58. package/src/framework/attested_receipts.ts +2 -2
  59. package/src/framework/auth_provider_law.ts +51 -24
  60. package/src/framework/business_corrections.ts +170 -0
  61. package/src/framework/disclosure.ts +1 -1
  62. package/src/framework/domain_lifecycle.ts +250 -16
  63. package/src/framework/encryption_identity.ts +1 -1
  64. package/src/framework/encryption_scope.ts +21 -13
  65. package/src/framework/era_certification.ts +1 -1
  66. package/src/framework/framework_aggregates.ts +2 -0
  67. package/src/framework/genesis.ts +1 -1
  68. package/src/framework/home.ts +22 -9
  69. package/src/framework/identity.ts +5 -5
  70. package/src/framework/impure_capability.ts +2 -2
  71. package/src/framework/owned_custody.ts +561 -0
  72. package/src/framework/platform_admin.ts +1 -1
  73. package/src/framework/relations.ts +9 -1
  74. package/src/framework/repair.ts +1 -1
  75. package/src/framework/signing_identity.ts +2 -2
  76. package/src/framework/source_roster.ts +1 -1
  77. package/src/framework/workspaces.ts +17 -10
  78. package/src/generated_client_names.ts +39 -0
  79. package/src/index.ts +20 -15
  80. package/src/kernel_capabilities.ts +25 -1
  81. package/src/law_check.ts +4 -1
  82. package/src/manifest.ts +356 -63
  83. package/src/read_projection_manifest.ts +8 -0
  84. package/src/read_projection_namespace.ts +4 -0
  85. package/src/relation.ts +1 -1
  86. package/src/shape_compat.ts +61 -5
  87. package/src/stable_ids.ts +38 -6
  88. package/src/stable_ids_types.ts +30 -0
  89. package/src/surfaced_lint.ts +0 -0
  90. package/src/usd.ts +62 -11
  91. package/src/usd_layers.ts +54 -3
  92. package/src/value_object.ts +23 -19
  93. package/src/wire.ts +1 -0
  94. package/src/wire_encode.ts +48 -4
  95. package/src/workspace_routing.ts +57 -0
  96. package/src/workspace_sharding.ts +9 -9
  97. package/src/certified_read.ts +0 -313
@@ -5,8 +5,8 @@
5
5
  // by CI, not by a tenant.
6
6
  //
7
7
  // Structure: ONE test, numbered legs, fail-fast — a failure names its leg, so CI output reads as
8
- // a checklist. Reuses the existing fixtures (estate-birth, surfaced, catalogue-src/-reader); no
9
- // new law.
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.
10
10
  //
11
11
  // Prereqs (fixtures compiled + a warm ~/.holon/runtime): locally the test SKIPS with the recipe
12
12
  // when they are missing; in CI the job sets NOMOS_GAUNTLET_REQUIRED=1 so a missing prereq is a
@@ -14,24 +14,20 @@
14
14
  @TestOn('vm')
15
15
  library;
16
16
 
17
- import 'dart:convert';
18
17
  import 'dart:io';
19
18
 
20
- import 'package:crypto/crypto.dart' show sha256;
21
-
22
19
  import 'package:nomos_client/nomos_headless.dart';
23
20
  import 'package:test/test.dart';
24
21
 
25
- import '../../../bench/scale/fixtures/estate-birth/build/dart/src/generated/home.client.dart';
26
- import '../../../bench/scale/fixtures/estate-birth/build/dart/src/generated/estate.client.dart'
27
- show EstateClient, SeedEstateWorkspacePayload;
22
+ import '../../../examples/co2-birth/build/dart/src/generated/co2.client.dart';
28
23
 
29
24
  String get _root => '${Directory.current.path}/../..';
30
25
  String get _repoEntry => '$_root/cloud/web-client/runner/node-entry.ts';
31
- String get _homeDeploy =>
32
- '$_root/bench/scale/fixtures/estate-birth/build/estate-birth.deploy.json';
33
- String get _docsDeploy => '$_root/bench/scale/fixtures/surfaced/build/surfaced.deploy.json';
34
- String get _catDeploy => '$_root/bench/scale/fixtures/catalogue-src/build/cat.deploy.json';
26
+ String get _homeDeploy => '$_root/examples/co2-birth/build/co2.deploy.json';
27
+ String get _docsDeploy =>
28
+ '$_root/bench/scale/fixtures/surfaced/build/surfaced.deploy.json';
29
+ String get _catDeploy =>
30
+ '$_root/bench/scale/fixtures/catalogue-src/build/cat.deploy.json';
35
31
  String get _readerDeploy =>
36
32
  '$_root/bench/scale/fixtures/catalogue-reader/build/estate.deploy.json';
37
33
  String get _runtimeDir =>
@@ -42,9 +38,10 @@ const _owner = 'user:gauntlet-owner';
42
38
  const _keyed = 'catalogue';
43
39
 
44
40
  String? _missingPrereq() {
45
- if (!File(_repoEntry).existsSync()) return 'in-repo runner not found at $_repoEntry';
41
+ if (!File(_repoEntry).existsSync())
42
+ return 'in-repo runner not found at $_repoEntry';
46
43
  final fixtures = {
47
- _homeDeploy: 'bench/scale/fixtures/estate-birth',
44
+ _homeDeploy: 'examples/co2-birth',
48
45
  _docsDeploy: 'bench/scale/fixtures/surfaced',
49
46
  _catDeploy: 'bench/scale/fixtures/catalogue-src',
50
47
  _readerDeploy: 'bench/scale/fixtures/catalogue-reader',
@@ -54,10 +51,10 @@ String? _missingPrereq() {
54
51
  return 'missing fixture ${e.key} — compile it: (cd ${e.value} && node ../../../../dsl/compile_package.mjs)';
55
52
  }
56
53
  }
57
- if (!File('$_runtimeDir/holon.wasm').existsSync() ||
54
+ if (!File('$_runtimeDir/holon-testmint.wasm').existsSync() ||
58
55
  !File('$_runtimeDir/packages.json').existsSync()) {
59
- return 'warm ~/.holon/runtime first (run any `githolon` command once, or curl '
60
- '/v1/runtime/holon.wasm + /v1/runtime/packages from the cloud)';
56
+ return 'warm ~/.holon/runtime first (run any `githolon` command once, or fetch '
57
+ '/v1/runtime/holon-testmint.wasm + /v1/runtime/packages from the cloud)';
61
58
  }
62
59
  return null;
63
60
  }
@@ -74,18 +71,22 @@ Future<T> _leg<T>(String name, Future<T> Function() body) async {
74
71
  print('✔ GAUNTLET $name (${sw.elapsedMilliseconds}ms)');
75
72
  return r;
76
73
  } catch (e, st) {
77
- throw TestFailure('GAUNTLET $name FAILED after ${sw.elapsedMilliseconds}ms:\n$e\n$st');
74
+ throw TestFailure(
75
+ 'GAUNTLET $name FAILED after ${sw.elapsedMilliseconds}ms:\n$e\n$st');
78
76
  }
79
77
  }
80
78
 
81
79
  void main() {
82
- test('THE FIRST-FIVE-MINUTES GAUNTLET: harness → blessed shape → local posture → '
83
- 'acquire → reactive reads → attested read → diagnostics → disposal', () async {
80
+ test(
81
+ 'THE FIRST-FIVE-MINUTES GAUNTLET: harness → blessed shape → local posture → '
82
+ 'acquire → reactive reads → attested read → diagnostics → disposal',
83
+ () async {
84
84
  final required = Platform.environment['NOMOS_GAUNTLET_REQUIRED'] == '1';
85
85
  final missing = _missingPrereq();
86
86
  if (missing != null) {
87
87
  if (required) {
88
- fail('NOMOS_GAUNTLET_REQUIRED=1 but a prereq is missing — the CI job must provide it: '
88
+ fail(
89
+ 'NOMOS_GAUNTLET_REQUIRED=1 but a prereq is missing — the CI job must provide it: '
89
90
  '$missing');
90
91
  }
91
92
  markTestSkipped(missing);
@@ -95,7 +96,8 @@ void main() {
95
96
  final diagnostics = <String>[];
96
97
 
97
98
  // ── LEG 1: harness up — a 4-workspace cluster, one deviceKeyed, phase diagnostics on. ──
98
- final harness = await _leg('leg 1: NomosTestHarness.cluster (4 ws, one deviceKeyed)', () async {
99
+ final harness = await _leg(
100
+ 'leg 1: NomosTestHarness.cluster (4 ws, one deviceKeyed)', () async {
99
101
  final h = await NomosTestHarness.cluster(
100
102
  workspaces: {
101
103
  'home': [_homeDeploy],
@@ -113,88 +115,119 @@ void main() {
113
115
  // keyed 3b legs all log enter AND exit lines.
114
116
  expect(diagnostics.any((l) => l.contains('offline law install')), isTrue,
115
117
  reason: 'phase 1 install diagnostics must appear');
116
- expect(diagnostics.any((l) => l.contains('runner ready') && l.contains('done')), isTrue,
118
+ expect(diagnostics.any((l) => l.startsWith('[offline-install]')), isTrue,
119
+ reason:
120
+ 'an in-repo runner must install through its adjacent in-repo helper, never silently fall back to the published CLI');
121
+ expect(
122
+ diagnostics
123
+ .any((l) => l.contains('runner ready') && l.contains('done')),
124
+ isTrue,
117
125
  reason: 'the runner-ready phase must log its exit');
118
126
  expect(diagnostics.any((l) => l.contains('3b: device keygen')), isTrue,
119
127
  reason: 'the deviceKeyed keygen phase must log');
120
128
  expect(
121
- diagnostics.any(
122
- (l) => l.contains("3b: keyed reconnect of '$_keyed'") && l.contains('done')),
129
+ diagnostics.any((l) =>
130
+ l.contains("3b: keyed reconnect of '$_keyed'") &&
131
+ l.contains('done')),
123
132
  isTrue,
124
- reason: 'the keyed reconnect phase must log its exit (the reported wedge)');
133
+ reason:
134
+ 'the keyed reconnect phase must log its exit (the reported wedge)');
125
135
  expect(h.sessions.toSet(), {'home', 'docs-ws', _keyed, 'reader'});
126
136
  return h;
127
137
  });
128
138
 
129
139
  try {
130
- // ── LEG 2: the blessed session-bound shape — mount → bind (preflight) → PARENTLESS birth
131
- // → follow(ref) → second client → typed read + a directive. Zero routing strings. ──
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. ──
132
142
  final home = harness.session('home');
133
- final estate = await _leg(
134
- 'leg 2: blessed shape (bind → parentless birth → follow → 2nd client → read+directive)',
143
+ final bornEstate = await _leg(
144
+ 'leg 2: generated business shape (Estate → Site → Asset)',
135
145
  () async {
136
- final homeClient = await HomeClient.bind(home, actor: _owner);
146
+ final homeClient = await Co2Client.bind(home, actor: _owner);
137
147
  expect(homeClient.session!.workspace, home.workspace,
138
148
  reason: 'inspectable session context');
139
- final birth = await homeClient.birthEstateWorkspace(
140
- payload: BirthEstateWorkspacePayload(
141
- owner: _owner,
142
- frameworkHash: harness.frameworkHash!,
143
- lawHash: harness.lawHashes(home.workspace).first,
144
- bornAt: DateTime.now().toUtc().toIso8601String(),
145
- // era-0: the estate enrols the owner's device at birth (signer-ready) — the harness device.
146
- ownerKeyHash: sha256.convert(base64Decode(harness.devicePublicKey(home.workspace)!)).toString(),
149
+ final ref = await homeClient.birth(
150
+ NomosBirthEstatePayload(
151
+ reference: 'E-001',
152
+ name: 'Foundry',
153
+ country: 'GB',
154
+ baselineTonnesCo2e: 4200,
147
155
  ),
148
156
  );
149
- expect(birth.workspace, home.workspace,
150
- reason: 'the parentless birth lands in the SESSION workspace');
151
- expect(birth.born, hasLength(1));
152
- expect(birth.birthOutcomes.first['status'], 'born');
157
+ expect(ref.workspace, startsWith('estate-'));
158
+ expect(ref.type, 'Estate');
153
159
 
154
- final estateSession = await harness.bridge.follow(birth.bornRefs.single, authorSecret: harness.deviceSecret(home.workspace));
155
- expect(estateSession.workspace, birth.born.single);
160
+ final estateSession = await harness.bridge.follow(
161
+ ref,
162
+ authorSecret: harness.deviceSecret(home.workspace),
163
+ );
164
+ expect(estateSession.workspace, ref.workspace);
165
+
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');
156
172
 
157
- final estateClient = await EstateClient.bind(estateSession, actor: _owner);
158
- final rows = await estateClient.estatesByOwner(owner: _owner);
159
- expect(rows, hasLength(1), reason: 'the child genesis seed reads back typed');
160
- final seeded = rows.single;
161
- final reseed = await estateClient.seedEstateWorkspace(SeedEstateWorkspacePayload(
162
- owner: seeded.owner!,
163
- estateName: seeded.estateName!,
164
- bornAt: seeded.bornAt!,
165
- ));
166
- expect(reseed.head, isNotEmpty, reason: 'a directive on the followed second client');
167
- return estateSession;
173
+ final siteOutcome = await estateClient.addSite(
174
+ AddSitePayload(estateId: ref.id, name: 'Trafford Depot'),
175
+ );
176
+ final siteRef = siteOutcome.created.single.ref;
177
+ expect(siteRef.type, 'co2.Site');
178
+ final sites = await estateClient.sitesByEstate(estateId: ref.id);
179
+ expect(sites, hasLength(1));
180
+ expect(sites.single.name, 'Trafford Depot');
181
+
182
+ final assetOutcome = await estateClient.addAsset(
183
+ AddAssetPayload(
184
+ siteId: siteRef.id,
185
+ name: 'Main electricity meter',
186
+ operationalStatus: 'commissioned',
187
+ ),
188
+ );
189
+ final assetRef = assetOutcome.created.single.ref;
190
+ expect(assetRef.type, 'co2.Asset');
191
+ final assets = await estateClient.assetsBySite(siteId: siteRef.id);
192
+ expect(assets, hasLength(1));
193
+ expect(assets.single.name, 'Main electricity meter');
194
+ expect(assets.single.operationalStatus?.valueOrNull, 'commissioned');
195
+ return (session: estateSession, ref: ref);
168
196
  });
197
+ final estate = bornEstate.session;
169
198
 
170
199
  // ── LEG 3: local posture — autoSync on a local-only session returns promptly and never
171
200
  // monopolizes the plane; zero network fetch attempts (asserted again at the end). ──
172
- await _leg('leg 3: local-only autoSync completes promptly, plane stays responsive',
201
+ await _leg(
202
+ 'leg 3: local-only autoSync completes promptly, plane stays responsive',
173
203
  () async {
174
204
  await home.autoSync().timeout(const Duration(seconds: 10),
175
205
  onTimeout: () => throw StateError(
176
206
  'autoSync() on a local-only session did not return within 10s (the deadlock class)'));
177
207
  // The plane is NOT blocked: a sibling session still answers.
178
- final listed = await harness.bridge.listWorkspaces().timeout(const Duration(seconds: 10),
179
- onTimeout: () =>
180
- throw StateError('listWorkspaces() hung after a local-only autoSync'));
208
+ final listed = await harness.bridge.listWorkspaces().timeout(
209
+ const Duration(seconds: 10),
210
+ onTimeout: () => throw StateError(
211
+ 'listWorkspaces() hung after a local-only autoSync'));
181
212
  expect(listed.map((w) => w['session'].toString()).toSet(),
182
213
  containsAll({'home', 'docs-ws', _keyed, 'reader'}));
183
214
  await home.stopAutoSync().timeout(const Duration(seconds: 10),
184
- onTimeout: () => throw StateError('stopAutoSync() hung on a local-only session'));
215
+ onTimeout: () => throw StateError(
216
+ 'stopAutoSync() hung on a local-only session'));
185
217
  });
186
218
 
187
219
  // ── LEG 4: acquireSession — concurrent double-acquire single-flights to ONE handle; the
188
220
  // credentials callback is NEVER invoked for a plane-known workspace. ──
189
- await _leg('leg 4: acquireSession (concurrent, credential-free for a known workspace)',
221
+ await _leg(
222
+ 'leg 4: acquireSession (concurrent, credential-free for a known workspace)',
190
223
  () async {
191
224
  final acquired = await Future.wait([
192
225
  harness.bridge.acquireSession('reader',
193
- ifAbsentCredentials: () async =>
194
- fail('reader is on the plane — credentials must not be requested')),
226
+ ifAbsentCredentials: () async => fail(
227
+ 'reader is on the plane — credentials must not be requested')),
195
228
  harness.bridge.acquireSession('reader',
196
- ifAbsentCredentials: () async =>
197
- fail('reader is on the plane — credentials must not be requested')),
229
+ ifAbsentCredentials: () async => fail(
230
+ 'reader is on the plane — credentials must not be requested')),
198
231
  ]);
199
232
  expect(identical(acquired[0], acquired[1]), isTrue,
200
233
  reason: 'a concurrent double-acquire yields ONE handle');
@@ -204,21 +237,22 @@ void main() {
204
237
 
205
238
  // ── LEG 5: reactive reads on a SESSION — watchById / watch / watchPendingConflicts must
206
239
  // all deliver a FIRST SNAPSHOT (the 0.48.x dead-delegation class). ──
207
- await _leg('leg 5: session reactive reads emit their first snapshot', () async {
208
- final raw = await estate.query('estatesByOwner', {'owner': _owner});
240
+ await _leg('leg 5: session reactive reads emit their first snapshot',
241
+ () async {
242
+ final raw = await estate.queryById(bornEstate.ref.id);
209
243
  final aggId = ((raw.single as Map)['id'] ?? '').toString();
210
244
  expect(aggId, isNotEmpty);
211
- final byId = await estate
212
- .watchById(aggId)
213
- .first
214
- .timeout(const Duration(seconds: 30),
215
- onTimeout: () => throw StateError('watchById never emitted its first snapshot'));
245
+ final byId = await estate.watchById(aggId).first.timeout(
246
+ const Duration(seconds: 30),
247
+ onTimeout: () =>
248
+ throw StateError('watchById never emitted its first snapshot'));
216
249
  expect(byId, hasLength(1));
217
250
  final byQuery = await estate
218
- .watch('estatesByOwner', {'owner': _owner})
251
+ .watch('estatesByReference', {'reference': 'E-001'})
219
252
  .first
220
253
  .timeout(const Duration(seconds: 30),
221
- onTimeout: () => throw StateError('watch(query) never emitted its first snapshot'));
254
+ onTimeout: () => throw StateError(
255
+ 'watch(query) never emitted its first snapshot'));
222
256
  expect(byQuery, hasLength(1));
223
257
  // The docs-ws session carries the Surfaced law — its pending-conflicts stream must emit a
224
258
  // first snapshot (empty is correct; EMITTING at all is the regression under test).
@@ -234,10 +268,12 @@ void main() {
234
268
 
235
269
  // ── LEG 6: the keyed lane end-to-end — an attested read served + SIGNED with the device
236
270
  // key the 3b re-open installed. ──
237
- await _leg('leg 6: attested read from the deviceKeyed workspace', () async {
271
+ await _leg('leg 6: attested read from the deviceKeyed workspace',
272
+ () async {
238
273
  final public = harness.devicePublicKey(_keyed);
239
274
  expect(public, isNotNull);
240
- expect(public, isNotEmpty, reason: 'the 3b keygen public half rides the harness');
275
+ expect(public, isNotEmpty,
276
+ reason: 'the 3b keygen public half rides the harness');
241
277
  final cat = harness.session(_keyed);
242
278
  final seeded = await cat.offerCreates(
243
279
  domain: 'cat',
@@ -257,19 +293,23 @@ void main() {
257
293
  args: {'listingId': 'L-1'},
258
294
  );
259
295
  final entry = (served['entry'] as Map).cast<String, Object?>();
260
- final attestation = (entry['attestation'] as Map).cast<String, Object?>();
296
+ final attestation =
297
+ (entry['attestation'] as Map).cast<String, Object?>();
261
298
  expect((attestation['public_key'] ?? '').toString(), public,
262
299
  reason: 'the read is signed by the re-opened session device key');
263
300
  });
264
301
 
265
302
  // ── LEG 7: harness diagnostics — assertDomainInstalled, resetWorkspaceCustody, and a
266
303
  // mid-test seedWorkspaceFromDeployJson round-trip. ──
267
- await _leg('leg 7: harness diagnostics (assertDomainInstalled / reset / seed)', () async {
304
+ await _leg(
305
+ 'leg 7: harness diagnostics (assertDomainInstalled / reset / seed)',
306
+ () async {
268
307
  await harness.assertDomainInstalled(
269
- workspace: estate.workspace, domain: EstateClient.interface.domain);
308
+ workspace: estate.workspace, domain: Co2Client.interface.domain);
270
309
  // The negative arm names the active domains.
271
310
  await expectLater(
272
- harness.assertDomainInstalled(workspace: 'docs-ws', domain: 'definitely-not-here'),
311
+ harness.assertDomainInstalled(
312
+ workspace: 'docs-ws', domain: 'definitely-not-here'),
273
313
  throwsA(isA<NomosTestHarnessException>()));
274
314
  // Reset a workspace's local custody to its seed snapshot, then prove it still serves.
275
315
  await harness.resetWorkspaceCustody('docs-ws');
@@ -278,23 +318,28 @@ void main() {
278
318
  .watchPendingConflicts()
279
319
  .first
280
320
  .timeout(const Duration(seconds: 30),
281
- onTimeout: () =>
282
- throw StateError('the reset docs-ws session never served a read'));
283
- expect(postReset, isEmpty, reason: 'the reset workspace is back at its seed');
321
+ onTimeout: () => throw StateError(
322
+ 'the reset docs-ws session never served a read'));
323
+ expect(postReset, isEmpty,
324
+ reason: 'the reset workspace is back at its seed');
284
325
  // Seed a brand-new workspace mid-test from a deploy.json and use it immediately.
285
326
  final late = await harness.seedWorkspaceFromDeployJson(
286
327
  workspace: 'late-ws', deployJsonPaths: [_docsDeploy]);
287
328
  expect(late.workspace, 'late-ws');
288
- await harness.assertDomainInstalled(workspace: 'late-ws', domain: 'docs');
329
+ await harness.assertDomainInstalled(
330
+ workspace: 'late-ws', domain: 'docs');
289
331
  });
290
332
 
291
333
  // Local posture postscript (leg 3's zero-network promise, checked over the WHOLE run): no
292
334
  // session on this plane ever attempted a network fetch.
293
335
  final offending = diagnostics
294
- .where((l) => l.contains('intent-offers') || l.contains('refusing network fetch'))
336
+ .where((l) =>
337
+ l.contains('intent-offers') ||
338
+ l.contains('refusing network fetch'))
295
339
  .toList();
296
340
  expect(offending, isEmpty,
297
- reason: 'local-only sessions must perform NO network work — saw:\n${offending.join('\n')}');
341
+ reason:
342
+ 'local-only sessions must perform NO network work — saw:\n${offending.join('\n')}');
298
343
  } finally {
299
344
  // ── LEG 8: clean disposal within the deadline (a hung teardown is a failure, not a wedge). ──
300
345
  await _leg('leg 8: harness disposal within the deadline', () async {
@@ -29,7 +29,7 @@ String? _missingPrereq() {
29
29
  if (!File(_deployJson).existsSync()) {
30
30
  return 'compile the fixture: (cd bench/scale/fixtures/estate-birth && node ../../../../dsl/compile_package.mjs)';
31
31
  }
32
- if (!File('$_runtimeDir/holon.wasm').existsSync())
32
+ if (!File('$_runtimeDir/holon-testmint.wasm').existsSync())
33
33
  return 'warm ~/.holon/runtime first';
34
34
  return null;
35
35
  }
@@ -66,8 +66,10 @@ void main() {
66
66
  );
67
67
  expect(birth.born, hasLength(1));
68
68
 
69
- // 3. query confirms the row (the home law's birth-record read).
70
- final before = await client.birthRecordsByPrincipal(principal: _owner);
69
+ // 3. Infrastructure assertion: inspect Nomos's private birth record through the raw harness session.
70
+ // Generated tenant clients deliberately do not expose this framework query.
71
+ final before = await session
72
+ .query('birthRecordsByPrincipal', {'principal': _owner});
71
73
  expect(before, hasLength(1),
72
74
  reason: 'the offer must be readable BEFORE sync');
73
75
  final statusBefore = await session.custodyStatus();
@@ -84,11 +86,14 @@ void main() {
84
86
  expect(statusAfter.pendingLocalIntents, statusBefore.pendingLocalIntents,
85
87
  reason:
86
88
  'local-only sync must not consume/move pending local intents');
87
- final after = await client.birthRecordsByPrincipal(principal: _owner);
89
+ final after = await session
90
+ .query('birthRecordsByPrincipal', {'principal': _owner});
88
91
  expect(after, hasLength(1),
89
92
  reason:
90
93
  'local-only sync must be observationally inert — the row must still read');
91
- expect(after.single.principal, before.single.principal,
94
+ final beforeData = ((before.single as Map)['data'] as Map);
95
+ final afterData = ((after.single as Map)['data'] as Map);
96
+ expect(afterData['principal'], beforeData['principal'],
92
97
  reason: 'the SAME row, byte-for-byte semantics');
93
98
  } finally {
94
99
  await harness.dispose();
@@ -40,7 +40,7 @@ String? _missingPrereq() {
40
40
  if (!File(_deploy).existsSync()) {
41
41
  return 'compile the fixture: cd bench/scale/fixtures/estate-birth-signed && node ../../../../dsl/compile_package.mjs';
42
42
  }
43
- if (!File('$_runtimeDir/holon.wasm').existsSync()) {
43
+ if (!File('$_runtimeDir/holon-testmint.wasm').existsSync()) {
44
44
  return 'warm ~/.holon/runtime first (run any `githolon` command once)';
45
45
  }
46
46
  return null;
@@ -34,7 +34,7 @@ String? _missingPrereq() {
34
34
  if (!File(_deploy).existsSync() || !File(_lockfile).existsSync()) {
35
35
  return 'missing encrypted-notes fixture — compile it: (cd cloud/web-client/test/fixtures/encrypted-notes && node ../../../../../dsl/compile_package.mjs)';
36
36
  }
37
- if (!File('$_runtimeDir/holon.wasm').existsSync() ||
37
+ if (!File('$_runtimeDir/holon-testmint.wasm').existsSync() ||
38
38
  !File('$_runtimeDir/packages.json').existsSync()) {
39
39
  return 'warm ~/.holon/runtime first (run any `githolon` command once)';
40
40
  }
@@ -48,7 +48,7 @@ String? _missingPrereq() {
48
48
  return 'compile the fixtures: (cd bench/scale/fixtures/estate-birth && node ../../../../dsl/compile_package.mjs); '
49
49
  '(cd bench/scale/fixtures/surfaced && node ../../../../dsl/compile_package.mjs)';
50
50
  }
51
- if (!File('$_runtimeDir/holon.wasm').existsSync() ||
51
+ if (!File('$_runtimeDir/holon-testmint.wasm').existsSync() ||
52
52
  !File('$_runtimeDir/packages.json').existsSync()) {
53
53
  return 'warm ~/.holon/runtime first (run any `githolon` command once)';
54
54
  }
@@ -4,7 +4,7 @@
4
4
  // the app UI uses, under `dart test` / `flutter test`, with no network.
5
5
  //
6
6
  // Prerequisites (skipped-with-reason when absent, so CI stays green either way): `node` on PATH; the
7
- // in-repo runner; a warm `~/.holon/runtime` cache (holon.wasm + packages.json — one `githolon` run fills it);
7
+ // in-repo runner; a warm `~/.holon/runtime` cache (holon-testmint.wasm + packages.json — one `githolon` run fills it);
8
8
  // and the compiled `examples/guestbook/build/guestbook.deploy.json` (`cd examples/guestbook && npx nomos-compile`).
9
9
  @TestOn('vm')
10
10
  library;
@@ -31,7 +31,7 @@ String? _missingPrereq() {
31
31
  if (!File(_guestbookDeployJson).existsSync()) {
32
32
  return 'compile the fixture first: cd examples/guestbook && npx nomos-compile';
33
33
  }
34
- if (!File('$_runtimeDir/holon.wasm').existsSync() ||
34
+ if (!File('$_runtimeDir/holon-testmint.wasm').existsSync() ||
35
35
  !File('$_runtimeDir/packages.json').existsSync()) {
36
36
  return 'warm ~/.holon/runtime first (run any `githolon` command once to cache the runtime)';
37
37
  }
@@ -29,7 +29,7 @@ String? _missingPrereq() {
29
29
  if (!File(_deployJson).existsSync()) {
30
30
  return 'compile the fixture: cd bench/scale/fixtures/vo-read-typing && npx nomos-compile';
31
31
  }
32
- if (!File('$_runtimeDir/holon.wasm').existsSync() ||
32
+ if (!File('$_runtimeDir/holon-testmint.wasm').existsSync() ||
33
33
  !File('$_runtimeDir/packages.json').existsSync()) {
34
34
  return 'warm ~/.holon/runtime first (run any `githolon` command once)';
35
35
  }
@@ -23,7 +23,7 @@ String? _missingPrereq() {
23
23
  if (!File(_gbDeploy).existsSync()) {
24
24
  return 'missing $_gbDeploy — compile it (cd examples/guestbook && npx nomos-compile)';
25
25
  }
26
- if (!File('$_runtimeDir/holon.wasm').existsSync() ||
26
+ if (!File('$_runtimeDir/holon-testmint.wasm').existsSync() ||
27
27
  !File('$_runtimeDir/packages.json').existsSync()) {
28
28
  return 'warm ~/.holon/runtime first (run any `githolon` command once)';
29
29
  }