@githolon/dsl 0.14.0 → 0.15.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.
@@ -15,8 +15,8 @@
15
15
  // final bridge = NomosBridge(transport);
16
16
  // await bridge.ready; // resolves on the runner's {event:ready}
17
17
  // await bridge.connect(cloud: 'https://nomos.captainapp.co.uk', workspace: myWs, clientId: deviceId);
18
- // final head = await bridge.dispatch(domain: 'guestbook', directiveId: 'signGuestbook',
19
- // payload: {'author': 'ada', 'message': 'hi', 'mood': 'delighted'}, domainHash: GUESTBOOK_DOMAIN_HASH);
18
+ // final app = GuestbookClient(bridge);
19
+ // final head = await app.signGuestbook(SignGuestbookPayload(author: 'ada', message: 'hi', mood: 'delighted'));
20
20
  // final rows = await bridge.query('entriesByAuthor', {'author': 'ada'});
21
21
  //
22
22
  // (Put the runner bundle at `assets/nomos/nomos-runner.{html,js}` and declare it under `flutter: assets:`.)
@@ -10,7 +10,7 @@
10
10
  /// - The hand-written kernel WIRE types (`Value`, `Field`/`WireField`, `Hlc`,
11
11
  /// `Op`, `FieldOp`, `Event`, `Schema`/`WireDriver`) — byte-compatible with
12
12
  /// serde_json. See `src/wire.dart`, `src/driver.dart`.
13
- /// - The ONE write verb `dispatch(intent)` (`src/dispatch.dart`) + the typed
13
+ /// - The ONE effectful write verb `offer(intent)` (`src/offer.dart`) + the typed
14
14
  /// reactive read engine `NomosReads` (`src/subscriptions.dart`).
15
15
  /// - The framework PRIMITIVES ONLY. The CODE-GENERATED per-domain types
16
16
  /// (aggregates + public intent payloads + enums + `watch…` read accessors) NO LONGER
@@ -18,14 +18,14 @@
18
18
  /// `co2_nomos_domains` (`ts_packages/co2-nomos-domains/dart/`), emitted there by
19
19
  /// `ts_packages/co2-nomos-domains/src/emit_dart.ts`. Tenant domains squatting in
20
20
  /// the framework package was the wrong topology; this barrel now exports ONLY the
21
- /// hand-written framework wire/dispatch/read/provider primitives. App code that
21
+ /// hand-written framework wire/offer/read/provider primitives. App code that
22
22
  /// wants the typed domain surface imports `package:co2_nomos_domains/co2_nomos_domains.dart`,
23
23
  /// which re-exports this framework barrel PLUS every generated domain.
24
24
  library;
25
25
 
26
26
  export 'src/wire.dart';
27
27
  export 'src/driver.dart';
28
- export 'src/dispatch.dart';
28
+ export 'src/offer.dart';
29
29
  export 'src/subscriptions.dart';
30
30
  export 'src/schema_validation.dart';
31
31
  // THE WEBVIEW BRIDGE (app-binding boundary) — the async Dart runtime that drives the REAL githolon running
@@ -33,7 +33,7 @@ export 'src/schema_validation.dart';
33
33
  export 'src/webview_bridge.dart';
34
34
  // The PROVIDER boundary (server-side capability-provider SDK runtime: TaskOutcome /
35
35
  // TaskSuccess / TaskFailure / TaskResult / TaskProvider / HostClock). The symmetric twin
36
- // of `dispatch.dart`; the generated per-task provider classes build on it.
36
+ // of `offer.dart`; the generated per-task provider classes build on it.
37
37
  export 'src/provider.dart';
38
38
 
39
39
  // ── NO generated domains here ──────────────────────────────────────────────
@@ -5,19 +5,19 @@
5
5
  // wasm = determinism. No native, no wasmtime, no 2nd artifact, no domain-JS on bare V8.
6
6
  // If a file isn't this / hosting this / authoring for this / proving this — it's gone.
7
7
 
8
- /// The ONE write verb: `dispatch(intent)`.
8
+ /// The ONE effectful write verb: `offer(intent)`.
9
9
  ///
10
- /// END-STATE (the "dispatch(intent) purge", Jack 2026-06-01): app code's only
11
- /// write verb is `dispatch(intent)`. The frontend constructs ONLY a typed
10
+ /// END-STATE (the "offer(intent) purge", Jack 2026-06-18): app code's only
11
+ /// effectful write verb is `offer(intent)`. The frontend constructs ONLY a typed
12
12
  /// generated intent DTO (a [NomosIntent]) — it never hand-types an engine rule
13
- /// id, never builds an `Event`, never holds an `Hlc`. `dispatch` ships the
13
+ /// id, never builds an `Event`, never holds an `Hlc`. `offer` ships the
14
14
  /// intent payload as DATA to the kernel's FRB `author(domain, directiveId, payloadJson,
15
15
  /// actor)`; the sealed engine runs the REAL `.plan()` and is the SOLE lowering
16
16
  /// authority (HLC + intent id are kernel-allocated host-side).
17
17
  ///
18
18
  /// This file is HAND-WRITTEN and domain-AGNOSTIC (declared ONCE, here): the
19
19
  /// generated per-domain intent classes `implements NomosIntent`, so a single
20
- /// generic `dispatch` covers every public intent of every domain — replacing the
20
+ /// generic `offer` covers every public intent of every domain — replacing the
21
21
  /// ~63-method write façade.
22
22
  library;
23
23
 
@@ -39,7 +39,7 @@ abstract interface class NomosIntent {
39
39
  }
40
40
 
41
41
  /// The kernel write seam: the FRB `NomosClient.author` signature, as a function
42
- /// type. `dispatch` takes this (rather than importing the FRB client) so the
42
+ /// type. `offer` takes this (rather than importing the FRB client) so the
43
43
  /// generated `nomos_dsl` package stays free of a `flutter_rust_bridge` dependency
44
44
  /// — the app threads `client.author` in. Returns the new HEAD commit oid (hex).
45
45
  typedef Authorer = String Function({
@@ -54,7 +54,7 @@ typedef Authorer = String Function({
54
54
  /// intent object — nothing is hand-typed. Builds NO `Event` and NO `Hlc`: the
55
55
  /// engine lowers. [actor] is the authenticated actor the caller threads from auth.
56
56
  /// Returns the new HEAD commit oid (hex).
57
- String dispatch(NomosIntent intent,
57
+ String offer(NomosIntent intent,
58
58
  {required Authorer author, required String actor}) =>
59
59
  author(
60
60
  domain: intent.domain,
@@ -7,22 +7,22 @@
7
7
 
8
8
  /// The PROVIDER boundary: the typed server-side capability-provider SDK runtime.
9
9
  ///
10
- /// This is the SYMMETRIC TWIN of `dispatch.dart` (the peer write boundary). Where
11
- /// the peer authors an Order (`createTranscribeVoiceNote(...)` -> `dispatch`), a
10
+ /// This is the SYMMETRIC TWIN of `offer.dart` (the peer write boundary). Where
11
+ /// the peer authors an Obligation (`createTranscribeVoiceNote(...)` -> `offer`), a
12
12
  /// PROVIDER (Whisper, a renderer, a multi-target PR transporter) is the
13
- /// other end of the framework `impureCapability` Order→Receipt pair: it WATCHES `requested`
13
+ /// other end of the framework `impureCapability` Obligation→Receipt pair: it WATCHES `requested`
14
14
  /// task rows, performs the impure side-effect OUTSIDE the fold, and authors the RECEIPT
15
15
  /// (`complete…`/`fail…`/`block…`/`deadLetter…`) back through the SAME write path. The receipt is an ordinary
16
16
  /// intent — the provider is a Nomos author, NOT a bypass (ONE-WRITE-PATH).
17
- /// Order and Receipt are intent roles, not provider-owned jobs or privileged server
17
+ /// Obligation and Receipt are intent roles, not provider-owned jobs or privileged server
18
18
  /// mutation channels.
19
19
  ///
20
20
  /// PRINCIPLE (Jack 2026-06-04): code is ~free; INTEGRATION POINTS are expensive +
21
21
  /// fuckup-guaranteed. So the generated provider SDK is fully TYPED to the boundary —
22
- /// the dev writes a typed `handler(Order) -> Result | Failure | Blocked | DeadLetter`; the generated
23
- /// dispatcher DECODES the incoming Order JSON into the typed Order and ENCODES the typed
22
+ /// the dev writes a typed `handler(Obligation) -> Result | Failure | Blocked | DeadLetter`; the generated
23
+ /// dispatcher DECODES the incoming Obligation JSON into the typed Obligation and ENCODES the typed
24
24
  /// outcome into the ordinary Receipt intent. NO dynamic / `Map<String, dynamic>` / raw-JSON leaks
25
- /// into the dev-facing API; the types stop ONLY at the actual JSON serde (`handleOrder`).
25
+ /// into the dev-facing API; the types stop ONLY at the actual JSON serde (`handleObligation`).
26
26
  ///
27
27
  /// This file is HAND-WRITTEN and domain-AGNOSTIC (declared ONCE, here): the generated
28
28
  /// per-task provider classes build on these interfaces, so the round-trip mechanism is
@@ -31,9 +31,9 @@ library;
31
31
 
32
32
  import 'dart:convert';
33
33
 
34
- import 'dispatch.dart' show NomosIntent;
34
+ import 'offer.dart' show NomosIntent;
35
35
 
36
- /// The typed OUTCOME a provider handler returns for one Order: success, failure, blocked,
36
+ /// The typed OUTCOME a provider handler returns for one Obligation: success, failure, blocked,
37
37
  /// or dead-lettered.
38
38
  /// SEALED so a generated dispatcher's `switch` is EXHAUSTIVE — a new outcome variant is
39
39
  /// a compile error at every dispatcher, never a silent fall-through. The mirror of the
@@ -44,7 +44,7 @@ sealed class TaskOutcome<R> {
44
44
 
45
45
  /// The SUCCESS outcome: the typed [result] the handler produced. The generated
46
46
  /// dispatcher maps this → the `complete…` Receipt directive (status:completed +
47
- /// resultRef + closesOrder).
47
+ /// resultRef + closesObligation).
48
48
  final class TaskSuccess<R> extends TaskOutcome<R> {
49
49
  /// The typed result the handler produced (e.g. a transcription's `resultRef`).
50
50
  final R result;
@@ -53,7 +53,7 @@ final class TaskSuccess<R> extends TaskOutcome<R> {
53
53
 
54
54
  /// The FAILURE outcome: the [failureReason] the handler recorded. The generated
55
55
  /// dispatcher maps this → the `fail…` Receipt directive (status:failed + failureReason +
56
- /// closesOrder). A recorded failure is the terminal state — NOT a retry storm
56
+ /// closesObligation). A recorded failure is the terminal state — NOT a retry storm
57
57
  /// (conformance X1's "declined is recorded" discipline at the task scale).
58
58
  final class TaskFailure<R> extends TaskOutcome<R> {
59
59
  /// Why the side-effect failed (recorded onto the task, never re-thrown into the fold).
@@ -63,13 +63,13 @@ final class TaskFailure<R> extends TaskOutcome<R> {
63
63
 
64
64
  /// The BLOCKED outcome: the provider cannot proceed until an external condition changes.
65
65
  /// The generated dispatcher maps this -> the `block...` Receipt directive
66
- /// (status:blocked + blockedReason + nextAction + closesOrder). This is terminal for this
67
- /// order; recovery is a fresh explicit Order after the next action is satisfied.
66
+ /// (status:blocked + blockedReason + nextAction + closesObligation). This is terminal for this
67
+ /// obligation; recovery is a fresh explicit Obligation after the next action is satisfied.
68
68
  final class TaskBlocked<R> extends TaskOutcome<R> {
69
69
  /// Why the provider cannot proceed.
70
70
  final String blockedReason;
71
71
 
72
- /// What the host/human must do before a fresh order can proceed.
72
+ /// What the host/human must do before a fresh obligation can proceed.
73
73
  final String nextAction;
74
74
 
75
75
  const TaskBlocked({
@@ -78,11 +78,11 @@ final class TaskBlocked<R> extends TaskOutcome<R> {
78
78
  });
79
79
  }
80
80
 
81
- /// The DEAD-LETTER outcome: stop retrying this order and park it in the DLQ. The generated
81
+ /// The DEAD-LETTER outcome: stop retrying this obligation and park it in the DLQ. The generated
82
82
  /// dispatcher maps this -> the `deadLetter...` Receipt directive
83
- /// (status:deadLettered + deadLetterReason + closesOrder).
83
+ /// (status:deadLettered + deadLetterReason + closesObligation).
84
84
  final class TaskDeadLetter<R> extends TaskOutcome<R> {
85
- /// Why this order was moved to the DLQ.
85
+ /// Why this obligation was moved to the DLQ.
86
86
  final String deadLetterReason;
87
87
  const TaskDeadLetter(this.deadLetterReason);
88
88
  }
@@ -106,34 +106,34 @@ abstract interface class TaskResult {
106
106
  typedef HostClock = int Function();
107
107
 
108
108
  /// The minimal contract a generated per-task provider exposes. Generic in the typed
109
- /// Order/Result; the generated subtype binds them. `handleOrder` is the ONE seam a host
109
+ /// Obligation/Result; the generated subtype binds them. `handleObligation` is the ONE seam a host
110
110
  /// loop calls per `requested` row.
111
111
  abstract interface class TaskProvider<O, R> {
112
112
  /// The framework `impureCapability` ids this provider is bound to (provenance — the host
113
113
  /// can assert it is draining the right capability). Carried as DATA, never hand-typed.
114
- String get orderDirectiveId;
114
+ String get obligationDirectiveId;
115
115
  String get completeDirectiveId;
116
116
  String get failDirectiveId;
117
117
  String get blockDirectiveId;
118
118
  String get deadLetterDirectiveId;
119
119
 
120
- /// DECODE an incoming Order intent's payload JSON into the typed [O], run the
120
+ /// DECODE an incoming Obligation intent's payload JSON into the typed [O], run the
121
121
  /// registered typed handler, and ENCODE the outcome into the ordinary Receipt intent — a
122
- /// [NomosIntent] ready for the ONE write path (`dispatch`). `now` stamps the
122
+ /// [NomosIntent] ready for the ONE write path (`offer`). `now` stamps the
123
123
  /// terminal time. Decoding raw JSON happens HERE and only here; the handler the dev
124
124
  /// writes sees ONLY the typed [O] and returns ONLY a typed [TaskOutcome].
125
- NomosIntent handleOrder(String orderPayloadJson, {required HostClock now});
125
+ NomosIntent handleObligation(String obligationPayloadJson, {required HostClock now});
126
126
 
127
- /// Convenience: decode an Order payload from an already-parsed map (the host may have
128
- /// the row's `data` map in hand from a read). Same path as [handleOrder].
129
- NomosIntent handleOrderMap(
130
- Map<String, Object?> orderPayload, {
127
+ /// Convenience: decode an Obligation payload from an already-parsed map (the host may have
128
+ /// the row's `data` map in hand from a read). Same path as [handleObligation].
129
+ NomosIntent handleObligationMap(
130
+ Map<String, Object?> obligationPayload, {
131
131
  required HostClock now,
132
132
  });
133
133
  }
134
134
 
135
- /// Decode an Order payload JSON string to a map for a generated `…Order.fromJson`.
136
- /// Shared so every generated provider decodes Orders identically (the symmetry of the
135
+ /// Decode an Obligation payload JSON string to a map for a generated `…Obligation.fromJson`.
136
+ /// Shared so every generated provider decodes Obligations identically (the symmetry of the
137
137
  /// client's `jsonEncode(toPayloadJson())`).
138
- Map<String, Object?> decodeOrderPayload(String orderPayloadJson) =>
139
- (jsonDecode(orderPayloadJson) as Map<String, Object?>);
138
+ Map<String, Object?> decodeObligationPayload(String obligationPayloadJson) =>
139
+ (jsonDecode(obligationPayloadJson) as Map<String, Object?>);
@@ -7,8 +7,8 @@
7
7
 
8
8
  /// The READ half of the client boundary: typed, reactive subscriptions.
9
9
  ///
10
- /// END-STATE (the "dispatch(intent) purge", Jack 2026-06-01): the app's ONLY
11
- /// Nomos surface is `dispatch(intent)` (write — see `dispatch.dart`) + TYPED
10
+ /// END-STATE (the "offer(intent) purge", Jack 2026-06-18): the app's ONLY
11
+ /// Nomos surface is `offer(intent)` (write — see `offer.dart`) + TYPED
12
12
  /// PUB/SUB SUBSCRIPTIONS (read — here + the generated per-domain accessors). The
13
13
  /// app reads ONLY through generated typed accessors (`watchSites()`,
14
14
  /// `watchSite(id)`, indexed-field queries → typed results); it never hand-writes a
@@ -75,7 +75,7 @@ typedef Summer = int Function(String sumId, String groupKey);
75
75
  /// A "projection changed" tick: fires (any value) whenever a write may have
76
76
  /// advanced the projection, so the subscription re-runs its indexed read. The
77
77
  /// `query()`/`query_by_id()` closures are SYNCHRONOUS point-in-time reads; this tick is what
78
- /// makes a typed accessor REACTIVE. The app threads its existing post-`dispatch`
78
+ /// makes a typed accessor REACTIVE. The app threads its existing post-`offer`
79
79
  /// invalidation signal in here (today the runtime's ~750ms projection poll / the
80
80
  /// write-completion broadcast). A read with no live tick is a one-shot current read.
81
81
  typedef ReadTick = Stream<void>;
@@ -8,7 +8,7 @@
8
8
  /// stable message protocol, so the generated typed Dart client drives the real kernel — never a
9
9
  /// `MemoryPersistence` pretending to be a GitHolon.
10
10
  ///
11
- /// A WebView round-trip is ASYNC, so the bridge is async (unlike the sync FRB `Authorer` in `dispatch.dart`).
11
+ /// A WebView round-trip is ASYNC, so the bridge is async (unlike the sync FRB `Authorer` in `offer.dart`).
12
12
  /// The generated per-domain Dart client wraps a [NomosBridge]; the bridge owns request/reply correlation +
13
13
  /// reactive `watch` streams. The platform TRANSPORT ([BridgeTransport]) is injected — `dart:js_util` on web,
14
14
  /// a WebView JS-channel on mobile — so this protocol logic is pure Dart + fully unit-testable.
@@ -153,26 +153,9 @@ class NomosBridge {
153
153
  });
154
154
  }
155
155
 
156
- /// LOCAL-FIRST write: author `directiveId` under `domainHash`. Returns the new local head; durable on [sync].
157
- Future<String> dispatch(
158
- {required String domain,
159
- required String directiveId,
160
- required Map<String, Object?> payload,
161
- required String domainHash}) async {
162
- final r = _asMap(await _call('dispatch', {
163
- 'domain': domain,
164
- 'directiveId': directiveId,
165
- 'payload': payload,
166
- 'domainHash': domainHash
167
- }));
168
- return r['head'].toString();
169
- }
170
-
171
- /// §5 cross-custody delivery: a `recordShare` carrying a pre-signed §3 quote into a home holon.
172
- Future<String> deliverShare(
173
- {required Map<String, Object?> quote, required String domainHash}) async {
174
- final r = _asMap(await _call(
175
- 'deliverShare', {'quote': quote, 'domainHash': domainHash}));
156
+ /// LOCAL-FIRST offer: carry opaque intent bytes into the GitHolon. Returns the new local head; durable on [sync].
157
+ Future<String> offer({required String intentBytes}) async {
158
+ final r = _asMap(await _call('offer', {'intentBytes': intentBytes}));
176
159
  return r['head'].toString();
177
160
  }
178
161
 
@@ -40,9 +40,11 @@ class FakeRunner implements BridgeTransport {
40
40
  case 'connect':
41
41
  _incoming.add(reply({'workspace': args['workspace']}));
42
42
  break;
43
- case 'dispatch':
43
+ case 'offer':
44
44
  // a directive the law refuses answers ok:false (the runner frames the gate's verdict).
45
- if (args['directiveId'] == 'refuseMe') {
45
+ final intentJson =
46
+ utf8.decode(base64Decode(args['intentBytes'] as String));
47
+ if (intentJson.contains('"directiveId":"refuseMe"')) {
46
48
  _incoming.add({
47
49
  'v': kWebviewBridgeVersion,
48
50
  'id': id,
@@ -50,12 +52,9 @@ class FakeRunner implements BridgeTransport {
50
52
  'error': 'the law refused this intent'
51
53
  });
52
54
  } else {
53
- _incoming.add(reply({'head': 'HEAD-${args['directiveId']}'}));
55
+ _incoming.add(reply({'head': 'HEAD-offer'}));
54
56
  }
55
57
  break;
56
- case 'deliverShare':
57
- _incoming.add(reply({'head': 'HEAD-share'}));
58
- break;
59
58
  case 'query':
60
59
  _incoming.add(reply({
61
60
  'rows': [
@@ -176,16 +175,8 @@ Future<Object?> _invoke(
176
175
  workspace: a['workspace'] as String,
177
176
  clientId: a['clientId'] as String?);
178
177
  return null;
179
- case 'dispatch':
180
- return b.dispatch(
181
- domain: a['domain'] as String,
182
- directiveId: a['directiveId'] as String,
183
- payload: (a['payload'] as Map).cast<String, Object?>(),
184
- domainHash: a['domainHash'] as String);
185
- case 'deliverShare':
186
- return b.deliverShare(
187
- quote: (a['quote'] as Map).cast<String, Object?>(),
188
- domainHash: a['domainHash'] as String);
178
+ case 'offer':
179
+ return b.offer(intentBytes: a['intentBytes'] as String);
189
180
  case 'query':
190
181
  return b.query(
191
182
  a['queryId'] as String, (a['params'] as Map).cast<String, Object?>());
@@ -207,8 +198,9 @@ Future<Object?> _invoke(
207
198
  /// What the corpus says the typed (unwrapped) return value should be, given the reply's `result`.
208
199
  Object? _expectedTyped(String op, Map<String, Object?> result) {
209
200
  switch (op) {
210
- case 'dispatch':
211
- case 'deliverShare':
201
+ case 'offer':
202
+ return result['head'];
203
+ case 'offer':
212
204
  return result['head'];
213
205
  case 'query':
214
206
  case 'queryById':
@@ -267,28 +259,29 @@ void main() {
267
259
  await bridge.ready.timeout(const Duration(seconds: 1));
268
260
  });
269
261
 
270
- test('dispatch round-trips a typed head; args reach the runner verbatim',
262
+ test('offer round-trips a typed head; args reach the runner verbatim',
271
263
  () async {
272
264
  await bridge.ready;
273
- final head = await bridge.dispatch(
274
- domain: 'guestbook',
275
- directiveId: 'signGuestbook',
276
- payload: {'author': 'ada'},
277
- domainHash: 'abc');
278
- expect(head, 'HEAD-signGuestbook');
279
- final req = runner.sent.firstWhere((m) => m['op'] == 'dispatch');
280
- expect((req['args'] as Map)['payload'], {'author': 'ada'});
281
- expect((req['args'] as Map)['domainHash'], 'abc');
265
+ final intentBytes = base64Encode(utf8.encode(jsonEncode({
266
+ 'v': 2,
267
+ 'intent': {
268
+ 'domain': 'guestbook',
269
+ 'directiveId': 'signGuestbook',
270
+ 'payload': {'author': 'ada'},
271
+ 'domainHash': 'abc'
272
+ }
273
+ })));
274
+ final head = await bridge.offer(intentBytes: intentBytes);
275
+ expect(head, 'HEAD-offer');
276
+ final req = runner.sent.firstWhere((m) => m['op'] == 'offer');
277
+ expect((req['args'] as Map)['intentBytes'], intentBytes);
282
278
  });
283
279
 
284
280
  test(
285
- 'connect / deliverShare / query / queryById / count / sync / lawStatus all wrap the runner',
281
+ 'connect / query / queryById / count / sync / lawStatus all wrap the runner',
286
282
  () async {
287
283
  await bridge.ready;
288
284
  await bridge.connect(cloud: 'https://c', workspace: 'ws', clientId: 'c1');
289
- expect(
290
- await bridge.deliverShare(quote: {'publicKey': 'k'}, domainHash: 'h'),
291
- 'HEAD-share');
292
285
  expect((await bridge.query('byAuthor', {'author': 'ada'})).first['data'],
293
286
  {'q': 'byAuthor'});
294
287
  expect((await bridge.queryById('Entry_1')).first['id'], 'Entry_1');
@@ -356,8 +349,16 @@ void main() {
356
349
  await bridge.ready;
357
350
  Object? err;
358
351
  try {
359
- await bridge.dispatch(
360
- domain: 'x', directiveId: 'refuseMe', payload: {}, domainHash: 'h');
352
+ await bridge.offer(
353
+ intentBytes: base64Encode(utf8.encode(jsonEncode({
354
+ 'v': 2,
355
+ 'intent': {
356
+ 'domain': 'x',
357
+ 'directiveId': 'refuseMe',
358
+ 'payload': {},
359
+ 'domainHash': 'h'
360
+ }
361
+ }))));
361
362
  } on NomosBridgeError catch (e) {
362
363
  err = e;
363
364
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@githolon/dsl",
3
- "version": "0.14.0",
3
+ "version": "0.15.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",
@@ -11,8 +11,8 @@
11
11
  },
12
12
  "main": "src/index.ts",
13
13
  "bin": {
14
- "nomos-compile": "./compile_package.mjs",
15
- "holon-compile": "./compile_package.mjs"
14
+ "nomos-compile": "compile_package.mjs",
15
+ "holon-compile": "compile_package.mjs"
16
16
  },
17
17
  "exports": {
18
18
  ".": "./src/index.ts",
@@ -44,6 +44,8 @@
44
44
  "src",
45
45
  "!src/**/*.test.ts",
46
46
  "dart",
47
+ "!dart/.dart_tool",
48
+ "!dart/build",
47
49
  "compile_package.mjs"
48
50
  ],
49
51
  "publishConfig": {
@@ -157,7 +157,7 @@ export function composeDomainModule(spec: DomainModuleSpec): DomainModule {
157
157
  const aggregates = [...byId.values()];
158
158
  const directiveIds = new Set(directives.map((d) => d.id));
159
159
  for (const task of spec.impureCapabilities ?? []) {
160
- for (const directive of [task.order, task.complete, task.fail, task.block, task.deadLetter]) {
160
+ for (const directive of [task.obligation, task.complete, task.fail, task.block, task.deadLetter]) {
161
161
  if (!directiveIds.has(directive.id)) {
162
162
  throw new Error(
163
163
  `domain '${spec.domain ?? spec.name}' declares impureCapability '${task.aggregate.id}' ` +
@@ -16,7 +16,7 @@
16
16
  * properties — invisible to those walks. This helper, applied at each plane's
17
17
  * merge point (the engine lump's `mergeModules`, the package composer's merge,
18
18
  * the compile CLI's merge), ADDS the bundle's pieces to the exports bag under
19
- * synthetic names (`<export>$aggregate`, `<export>$order`, …) so every
19
+ * synthetic names (`<export>$aggregate`, `<export>$obligation`, …) so every
20
20
  * existing shape-walk discovers them with ZERO new walk semantics. The
21
21
  * original bundle export stays (config-named lanes still resolve it); the
22
22
  * walks ignore its unmatched shape exactly as before.
@@ -34,7 +34,7 @@ export function isCapabilityDecl(v: unknown): v is Record<string, unknown> {
34
34
  );
35
35
  }
36
36
 
37
- const PIECES = ["aggregate", "order", "complete", "fail", "block", "deadLetter", "tasks"] as const;
37
+ const PIECES = ["aggregate", "obligation", "complete", "fail", "block", "deadLetter", "tasks"] as const;
38
38
 
39
39
  /**
40
40
  * Expand every `capability()` bundle in an exports bag into discoverable
@@ -15,13 +15,13 @@
15
15
  * emit (e.g. `{name:"HQ", createdAt:1000}`);
16
16
  * - typed READ accessors per aggregate + per declared query — reactive
17
17
  * `watch…`/one-shot `read…` over the GitHolon `query()`/`query_by_id()`
18
- * surface (the read half of the dispatch(intent) boundary);
18
+ * surface (the read half of the offer/query boundary);
19
19
  * - a Dart enum per `t.enum([...])` field;
20
20
  * - a Dart intent class per domain action — a pure typed DTO. Each class exposes its
21
21
  * `domain` / `intentType` (so the call site never hand-types a string) and a
22
22
  * `toPayloadJson()` that serialises only its typed fields to data. It builds no
23
23
  * `Event` and no `Hlc`: the GitHolon executes the installed domain plan.
24
- * - a single generic write verb [`dispatch`] that ships {domain, intentType,
24
+ * - a single generic effectful write verb [`offer`] that ships {domain, intentType,
25
25
  * toPayloadJson()} to the GitHolon `author(domain, intentType, payloadJson, actor)`.
26
26
  *
27
27
  * It does NOT hand-write the fixed wire types (`Value`/`Op`/`Event`/...): those
@@ -828,7 +828,7 @@ function emitPermissionVocabulary(vocab: PermissionVocabulary | undefined): stri
828
828
  return [
829
829
  `/// Generated permission vocabulary from the domain role catalogue.`,
830
830
  `///`,
831
- `/// This is frontend read/dispatch vocabulary only. Domain execution and`,
831
+ `/// This is frontend read/offer vocabulary only. Domain execution and`,
832
832
  `/// admission still happen inside the installed GitHolon domain law.`,
833
833
  `class PermissionRole {`,
834
834
  ` const PermissionRole(this.value, this.capabilities);`,
@@ -1125,7 +1125,7 @@ function emitEvidenceRefClass(): string {
1125
1125
  ` );`,
1126
1126
  ` }`,
1127
1127
  ``,
1128
- ` /// The authored payload shape (for dispatch): the typed value-object the DSL`,
1128
+ ` /// The authored payload shape (for offer): the typed value-object the DSL`,
1129
1129
  ` /// \`t.evidence()\` field lowers to a kernel \`Value::Evidence\`.`,
1130
1130
  ` Map<String, Object?> toJson() => <String, Object?>{`,
1131
1131
  ` 'hash': hash,`,
@@ -1536,7 +1536,7 @@ function emitDirective(
1536
1536
  `/// Generated typed intent DTO for '${d.id}' (marker: ${d.marker},`,
1537
1537
  `/// aggregate: ${d.aggregateId}). It carries its [domain] + [intentType] and a`,
1538
1538
  `/// [toPayloadJson] that ships only typed fields as data. It builds no`,
1539
- `/// \`Event\` and no \`Hlc\`. Pass it to [dispatch]; the GitHolon executes`,
1539
+ `/// \`Event\` and no \`Hlc\`. Pass it to [offer]; the GitHolon executes`,
1540
1540
  `/// the installed domain plan.`,
1541
1541
  `class ${className} implements NomosIntent {`,
1542
1542
  ` /// The policy domain this intent belongs to (the kernel \`author\` \`domain\`).`,
@@ -1587,7 +1587,7 @@ export function toJsonExpr(spec: PayloadFieldSpec, accessor: string): string {
1587
1587
 
1588
1588
  // ---- read accessors (typed subscriptions) ----------------------------------
1589
1589
  //
1590
- // The READ half of the peer dispatch surface (Jack 2026-06-01): the app reads ONLY via
1590
+ // The READ half of the peer query surface (Jack 2026-06-18): the app reads ONLY via
1591
1591
  // these generated typed accessors over the GitHolon read surface
1592
1592
  // (`query(query_id, params_json)` + `query_by_id(aggregate_id)`, #140's indexed/PK
1593
1593
  // read-closure). It invents NO new Rust read primitive. Two emitters:
@@ -2503,11 +2503,11 @@ export interface DomainModule {
2503
2503
  */
2504
2504
  readModelAggregates?: string[];
2505
2505
  /**
2506
- * The domain's `impureCapability` capabilities (framework Order→Receipt; `impure_capability.ts`)
2506
+ * The domain's `impureCapability` capabilities (framework Obligation→Receipt; `impure_capability.ts`)
2507
2507
  * for which to ALSO emit the typed PROVIDER SDK — the symmetric twin of the peer
2508
- * payload classes. For each declared task the codegen emits a typed `XOrder` (+
2508
+ * payload classes. For each declared task the codegen emits a typed `XObligation` (+
2509
2509
  * `fromJson`), `XResult`/`XFailure`, a `XHandler` typedef and a `XProvider` dispatcher
2510
- * that decodes the incoming Order JSON and encodes the Receipt (reusing the
2510
+ * that decodes the incoming Obligation JSON and encodes the Receipt (reusing the
2511
2511
  * peer-codegen `CompleteXPayload`/`FailXPayload`, so the Receipt is an ordinary
2512
2512
  * intent through the ONE write path). ADDITIVE + OPTIONAL: a domain that omits this is
2513
2513
  * byte-identical to before. NOT carried into any manifest/hash — a pure provider-side
@@ -2571,10 +2571,10 @@ export function generateDartDomain(mod: DomainModule): string {
2571
2571
  const mintedBlock = emitMintedCreates(mod.aggregates, mod.directives, domainKey, dartTypes);
2572
2572
 
2573
2573
  // PROVIDER SDK (the symmetric twin of the peer payload classes): for each declared
2574
- // `impureCapability` capability, a typed Order/Result/Failure + handler typedef + dispatcher.
2574
+ // `impureCapability` capability, a typed Obligation/Result/Failure + handler typedef + dispatcher.
2575
2575
  // ADDITIVE + omit-when-empty: a domain with no `impureCapabilities` emits nothing (and the
2576
2576
  // `provider.dart` import is omitted), so it is byte-identical to before. The enum map is
2577
- // SHARED with the directive/aggregate codegen so an enum-typed order param references the
2577
+ // SHARED with the directive/aggregate codegen so an enum-typed obligation param references the
2578
2578
  // already-emitted domain enum (no duplicate decl).
2579
2579
  const providerBlock = emitProviderSdk(mod.impureCapabilities ?? [], dartTypes);
2580
2580
 
@@ -2766,7 +2766,7 @@ export function generateDartDomain(mod: DomainModule): string {
2766
2766
  ``,
2767
2767
  ]
2768
2768
  : []),
2769
- `// ---- public intents (typed DTOs; ship via the generic dispatch() verb) ----`,
2769
+ `// ---- public intents (typed DTOs; ship via the generic offer() verb) ----`,
2770
2770
  dirBlock,
2771
2771
  ``,
2772
2772
  ...(mintedBlock !== ""