@githolon/dsl 0.76.0 → 0.77.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.
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// REGRESSION (co2, 0.76 offer-ack decoupling): the generated watch must emit the locally
|
|
2
|
+
// committed projection promptly after an offer's acknowledgement — with NO subsequent bridge op.
|
|
3
|
+
// co2's Flutter AppSim (NodeRunnerTransport → node-entry → realm sessions → watchById → Riverpod)
|
|
4
|
+
// saw the post-offer tick NEVER arrive after upgrading to @githolon/client 0.76 / nomos_client 0.52.
|
|
5
|
+
@TestOn('vm')
|
|
6
|
+
library;
|
|
7
|
+
|
|
8
|
+
import 'dart:async';
|
|
9
|
+
import 'dart:io';
|
|
10
|
+
|
|
11
|
+
import 'package:nomos_client/nomos_headless.dart';
|
|
12
|
+
import 'package:test/test.dart';
|
|
13
|
+
|
|
14
|
+
String get _root => '${Directory.current.path}/../..';
|
|
15
|
+
String get _repoEntry => '$_root/cloud/web-client/runner/node-entry.mjs';
|
|
16
|
+
String get _gbDeploy => '$_root/examples/guestbook/build/guestbook.deploy.json';
|
|
17
|
+
String get _runtimeDir =>
|
|
18
|
+
Platform.environment['NOMOS_DART_RUNTIME'] ??
|
|
19
|
+
'${Platform.environment['HOME'] ?? ''}/.holon/runtime';
|
|
20
|
+
|
|
21
|
+
String? _missingPrereq() {
|
|
22
|
+
if (!File(_repoEntry).existsSync()) return 'in-repo runner not found at $_repoEntry';
|
|
23
|
+
if (!File(_gbDeploy).existsSync()) {
|
|
24
|
+
return 'missing $_gbDeploy — compile it (cd examples/guestbook && npx nomos-compile)';
|
|
25
|
+
}
|
|
26
|
+
if (!File('$_runtimeDir/holon.wasm').existsSync() ||
|
|
27
|
+
!File('$_runtimeDir/packages.json').existsSync()) {
|
|
28
|
+
return 'warm ~/.holon/runtime first (run any `githolon` command once)';
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
void main() {
|
|
34
|
+
test('watch emits the post-offer projection under COMPLETE SILENCE (no follow-up ops)',
|
|
35
|
+
timeout: const Timeout(Duration(minutes: 4)), () async {
|
|
36
|
+
final missing = _missingPrereq();
|
|
37
|
+
if (missing != null) {
|
|
38
|
+
// ignore: avoid_print
|
|
39
|
+
print('SKIP: $missing');
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
final harness = await NomosTestHarness.ephemeral(
|
|
43
|
+
deployJsonPaths: [_gbDeploy],
|
|
44
|
+
workspace: 'stall-ws',
|
|
45
|
+
nodeEntry: _repoEntry,
|
|
46
|
+
resolveFrom: '$_root/cloud/web-client',
|
|
47
|
+
runtimeDir: _runtimeDir,
|
|
48
|
+
onDiagnostic: (l) {}, // keep output small
|
|
49
|
+
);
|
|
50
|
+
addTearDown(harness.dispose);
|
|
51
|
+
final s = harness.bridge;
|
|
52
|
+
|
|
53
|
+
// 1. create one entry, find its id.
|
|
54
|
+
await s.offerDirective(
|
|
55
|
+
domain: 'guestbook',
|
|
56
|
+
directiveId: 'signGuestbook',
|
|
57
|
+
payload: {
|
|
58
|
+
'author': 'ada',
|
|
59
|
+
'message': 'hi',
|
|
60
|
+
'mood': 'delighted',
|
|
61
|
+
'signedAt': DateTime.now().toUtc().toIso8601String(),
|
|
62
|
+
});
|
|
63
|
+
final rows = await s.query('entriesByAuthor', {'author': 'ada'});
|
|
64
|
+
expect(rows.length, 1);
|
|
65
|
+
final id = (rows.first as Map)['id'] as String;
|
|
66
|
+
|
|
67
|
+
// 2. subscribe (the app's watchById lane) and wait for the initial tick.
|
|
68
|
+
final ticks = <List<dynamic>>[];
|
|
69
|
+
final gotInitial = Completer<void>();
|
|
70
|
+
final gotMutated = Completer<void>();
|
|
71
|
+
final sub = s.watchById(id).listen((r) {
|
|
72
|
+
ticks.add(r);
|
|
73
|
+
if (!gotInitial.isCompleted) {
|
|
74
|
+
gotInitial.complete();
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
final tags = ((r.first as Map)['data'] as Map)['tags'];
|
|
78
|
+
if (tags is List && tags.contains('t-after') && !gotMutated.isCompleted) {
|
|
79
|
+
gotMutated.complete();
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
addTearDown(sub.cancel);
|
|
83
|
+
await gotInitial.future.timeout(const Duration(seconds: 20),
|
|
84
|
+
onTimeout: () => throw StateError('initial watch tick never arrived'));
|
|
85
|
+
|
|
86
|
+
// 3. THE TEST — mutate the watched row, then COMPLETE SILENCE: no further bridge ops.
|
|
87
|
+
// The post-ack deferred nudge (0.76) must still deliver the tick.
|
|
88
|
+
await s.offerDirective(
|
|
89
|
+
domain: 'guestbook',
|
|
90
|
+
directiveId: 'tagEntry',
|
|
91
|
+
payload: {'entryId': id, 'tags': ['t-after']});
|
|
92
|
+
await gotMutated.future.timeout(const Duration(seconds: 8), onTimeout: () {
|
|
93
|
+
throw StateError(
|
|
94
|
+
'REGRESSION: the post-offer watch tick never arrived under silence '
|
|
95
|
+
'(ticks seen: ${ticks.length})');
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@githolon/dsl",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.77.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Nomos 2 domain-authoring DSL: aggregates + directives in TS, executed and encoded to the Rust kernel's wire shapes.",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE.md",
|