@githolon/dsl 0.113.4 → 0.114.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 (58) hide show
  1. package/assets/operation-contract.wasm +0 -0
  2. package/compile_package.mjs +23 -3
  3. package/compile_proof.d.mts +7 -0
  4. package/compile_proof.mjs +38 -3
  5. package/dart/CHANGELOG.md +20 -0
  6. package/dart/lib/src/application_framework_calls.dart +9 -5
  7. package/dart/lib/src/generated_call.dart +14 -3
  8. package/dart/lib/src/nms_generated_runtime.dart +7 -0
  9. package/dart/lib/src/node_runner_transport.dart +77 -8
  10. package/dart/lib/src/nomos_trace.dart +107 -0
  11. package/dart/lib/src/reception/dart_reception.dart +148 -11
  12. package/dart/lib/src/rows_watch.dart +390 -0
  13. package/dart/lib/src/runner/node-entry.mjs +2803 -690
  14. package/dart/lib/src/sync_status_projection.dart +94 -1
  15. package/dart/lib/src/sync_status_reducer.dart +5 -2
  16. package/dart/lib/src/test_harness.dart +107 -41
  17. package/dart/lib/src/testing/test_peer.dart +107 -99
  18. package/dart/lib/src/testing/test_peer_host.dart +305 -0
  19. package/dart/lib/src/typed_watch_registry.dart +26 -3
  20. package/dart/pubspec.lock +1 -1
  21. package/dart/pubspec.yaml +2 -2
  22. package/dart/test/background_model_adoption_test.dart +1 -0
  23. package/dart/test/custodian_warming_test.dart +105 -0
  24. package/dart/test/fixtures/offer_watch_order_peer.dart +74 -0
  25. package/dart/test/kernel_author_after_read_test.dart +6 -3
  26. package/dart/test/kernel_fence_test.dart +4 -1
  27. package/dart/test/model_adoption_test.dart +17 -0
  28. package/dart/test/nomos_trace_test.dart +91 -0
  29. package/dart/test/own_offer_watch_order_test.dart +90 -0
  30. package/dart/test/receiving_group_open_test.dart +4 -8
  31. package/dart/test/replica_readiness_test.dart +14 -4
  32. package/dart/test/rows_watch_test.dart +331 -0
  33. package/dart/test/test_peer_host_selection_test.dart +49 -0
  34. package/dart_types/CHANGELOG.md +15 -0
  35. package/dart_types/lib/src/approved_model.dart +22 -5
  36. package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pb.dart +535 -1
  37. package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pbenum.dart +65 -0
  38. package/dart_types/lib/src/proto/nomos/runtime/v2/application_desk.pb.dart +14 -0
  39. package/dart_types/lib/src/proto/nomos/runtime/v2/correspondence_desk.pb.dart +359 -2
  40. package/dart_types/lib/src/proto/nomos/runtime/v2/correspondence_desk.pbenum.dart +65 -0
  41. package/dart_types/lib/src/proto/nomos/runtime/v2/model_adoption_desk.pb.dart +20 -2
  42. package/dart_types/lib/src/proto/nomos/runtime/v2/observability_desk.pb.dart +278 -9
  43. package/dart_types/lib/src/proto/nomos/runtime/v2/receiving_group_desk.pb.dart +7 -85
  44. package/dart_types/lib/src/proto/nomos/runtime/v2/residency_desk.pb.dart +35 -0
  45. package/dart_types/pubspec.yaml +1 -1
  46. package/package.json +4 -2
  47. package/src/build_provenance.ts +7 -2
  48. package/src/codegen_dart_client.ts +21 -9
  49. package/src/codegen_dart_facade.ts +1 -0
  50. package/src/codegen_dart_framework_calls.ts +12 -9
  51. package/src/codegen_dart_scenario.ts +7 -0
  52. package/src/codegen_ts.ts +26 -24
  53. package/src/compile_package_main.ts +65 -61
  54. package/src/engine_entry.ts +4 -48
  55. package/src/law_unit_set_identity.ts +44 -0
  56. package/src/query/compile.ts +0 -0
  57. package/src/release_inspection.ts +24 -0
  58. package/src/release_publication.ts +298 -0
@@ -51,7 +51,8 @@ import '../generated_call.dart'
51
51
  NmsGeneratedCall,
52
52
  NmsGeneratedQuery,
53
53
  NmsGeneratedResult,
54
- NmsInternalGeneratedResults;
54
+ NmsInternalGeneratedResults,
55
+ nmsGeneratedCallCreatedAt;
55
56
  import '../application_model_adoption.dart'
56
57
  show
57
58
  NmsApprovedModelLawPackageSource,
@@ -63,8 +64,10 @@ import '../application_model_adoption.dart'
63
64
  import '../application_framework_calls.dart'
64
65
  show OwnedCustody, OwnedDeviceRequest;
65
66
  import '../kernel_primitives.dart' show NmsKernelPrimitives;
67
+ import '../nomos_trace.dart' show NomosTrace;
66
68
  import '../observed_session_directory.dart' show NmsObservedSessionDirectory;
67
69
  import '../replica_readiness.dart' show nmsUntilReplicaReady;
70
+ import '../rows_watch.dart' show NmsRowsMerge, nmsMergeRows;
68
71
  import '../operation_receipts.dart'
69
72
  show NmsOperationReceiptProjection, NomosOperationReceipt;
70
73
  import 'event_desk.dart' show ReceptionEventDesk;
@@ -565,6 +568,17 @@ class NomosOwnedDeviceApprovalPreparation {
565
568
  });
566
569
  }
567
570
 
571
+ /// Whether generated offers ask the kernel for its phase timings, which this
572
+ /// reception prints as `[nomos-kernel-perf]` diagnostics. On by default in
573
+ /// debug and profile builds. A release build leaves them off: carrying the spans
574
+ /// costs the kernel, the Peer Office and this isolate work on every write that
575
+ /// nobody reads. `--dart-define=NOMOS_KERNEL_SPANS=false` measures a profile
576
+ /// build as a release user experiences it; `=true` restores them in release.
577
+ const bool kNomosOfferKernelSpans = bool.fromEnvironment(
578
+ 'NOMOS_KERNEL_SPANS',
579
+ defaultValue: !bool.fromEnvironment('dart.vm.product'),
580
+ );
581
+
568
582
  /// The result of [DartReception.offerCreates]: the new local [head], every aggregate the plan minted, and —
569
583
  /// for a `.births()` directive — the child workspace(s) the offer brought into being on this local plane.
570
584
  /// The proof material a generated offer presents to the kernel.
@@ -890,6 +904,15 @@ class DartReception {
890
904
  );
891
905
  return;
892
906
  }
907
+ if (event.hasReadAccessPreparation()) {
908
+ // The read itself still ends typed (rows, or NomosUnavailable with
909
+ // credentialUnavailable); this only says why it is taking a moment.
910
+ final preparation = event.readAccessPreparation;
911
+ // ignore: avoid_print
912
+ print('[nomos-read-access] enrolling this device to read '
913
+ 'workspace=${preparation.workspace} request=${preparation.requestId}');
914
+ return;
915
+ }
893
916
  if (event.hasReady()) {
894
917
  final stale = _staleBundleError(event.ready.runtimeVersion);
895
918
  if (stale != null && !allowStaleRunnerBundle) {
@@ -946,6 +969,19 @@ class DartReception {
946
969
  if (event.hasLinkChanged()) {
947
970
  _eventPlane._events.publishSync(event);
948
971
  final session = event.hasSession() ? event.session : null;
972
+ if (NomosTrace.enabled && event.linkChanged.hasClosure()) {
973
+ // How the live connection ended (CAP-683): who closed it, how, and what it had carried.
974
+ final closure = event.linkChanged.closure;
975
+ NomosTrace.emit(
976
+ 'dart',
977
+ 'link.closed',
978
+ 'ws=${closure.workspace} conn=${closure.connectionId} '
979
+ 'by=${closure.socket.initiator.name} '
980
+ 'code=${closure.socket.hasCode() ? closure.socket.code : '-'} '
981
+ 'clean=${closure.socket.clean} openMs=${closure.openMillis} '
982
+ 'admissions=${closure.admissions} '
983
+ 'unanswered=${closure.unansweredBatches}');
984
+ }
949
985
  if (event.linkChanged.status ==
950
986
  nomos_protocol.LinkStatus.LINK_STATUS_CLOSED) {
951
987
  final closedAt = DateTime.now();
@@ -1692,7 +1728,6 @@ class DartReception {
1692
1728
  Future<NomosOfferOutcome> offerGeneratedCallOutcome({
1693
1729
  required NmsGeneratedCall call,
1694
1730
  String? actor,
1695
- String? domainHash,
1696
1731
  String? session,
1697
1732
  String? authorSecret,
1698
1733
  NomosBirthCertificate? birthCertificate,
@@ -1729,11 +1764,27 @@ class DartReception {
1729
1764
  // ignore: avoid_print
1730
1765
  print('[nomos-offer] dispatch ${call.domain}/${call.directive} in '
1731
1766
  '$workspace using ${authenticationProof.name}');
1767
+ // Opt-in timeline (nomos_trace.dart): this call's id, and when the generated code made it.
1768
+ final traceCall = NomosTrace.enabled ? NomosTrace.nextCall() : 0;
1769
+ final traceBegin = NomosTrace.enabled ? NomosTrace.now() : 0;
1770
+ if (NomosTrace.enabled) {
1771
+ final created = nmsGeneratedCallCreatedAt(call);
1772
+ NomosTrace.emit(
1773
+ 'dart',
1774
+ 'call.begin',
1775
+ 'c=$traceCall op=offer:${call.domain}/${call.directive} '
1776
+ 'sinceCreateUs=${created == 0 ? -1 : traceBegin - created}');
1777
+ }
1732
1778
  Future<nomos_protocol.CallResponse> attempt() async {
1733
1779
  final requestNumber = ++plane._sequences.request;
1734
1780
  final requestId = '$runtimeSession:offer:$requestNumber';
1735
1781
  final observer = NomosWrite.captureObserver();
1736
1782
  if (observer != null) plane._writeObservers[requestId] = observer;
1783
+ final sent = NomosTrace.enabled ? NomosTrace.now() : 0;
1784
+ if (NomosTrace.enabled) {
1785
+ NomosTrace.emit('dart', 'call.send',
1786
+ 'c=$traceCall lr=$requestId sinceBeginUs=${sent - traceBegin}');
1787
+ }
1737
1788
  try {
1738
1789
  return await kernelTransport.callKernel(
1739
1790
  session: runtimeSession,
@@ -1758,9 +1809,8 @@ class DartReception {
1758
1809
  ? const <int>[]
1759
1810
  : base64Decode(explicitSecret),
1760
1811
  deferProjection: true,
1761
- spans: true,
1812
+ spans: kNomosOfferKernelSpans,
1762
1813
  ),
1763
- controllerLawHash: domainHash,
1764
1814
  conflictSnapshots: conflictSnapshots,
1765
1815
  birthCertificate: birthCertificate,
1766
1816
  ),
@@ -1770,6 +1820,10 @@ class DartReception {
1770
1820
  } finally {
1771
1821
  plane._writeObservers.remove(requestId);
1772
1822
  observer?.call(const NomosWriteProgress(NomosWritePhase.running));
1823
+ if (NomosTrace.enabled) {
1824
+ NomosTrace.emit('dart', 'call.reply',
1825
+ 'c=$traceCall lr=$requestId us=${NomosTrace.now() - sent}');
1826
+ }
1773
1827
  }
1774
1828
  }
1775
1829
 
@@ -1791,6 +1845,10 @@ class DartReception {
1791
1845
  response = await attempt();
1792
1846
  }
1793
1847
  if (response.hasFailure()) {
1848
+ if (NomosTrace.enabled) {
1849
+ NomosTrace.emit('dart', 'call.end',
1850
+ 'c=$traceCall outcome=failure us=${NomosTrace.now() - traceBegin}');
1851
+ }
1794
1852
  // ignore: avoid_print
1795
1853
  print('[nomos-offer] refused ${call.domain}/${call.directive} in '
1796
1854
  '$workspace: ${response.failure.code}: ${response.failure.message}');
@@ -1850,6 +1908,10 @@ class DartReception {
1850
1908
  for (final child in born) {
1851
1909
  plane._receipts.rememberBirth(child, receipt);
1852
1910
  }
1911
+ if (NomosTrace.enabled) {
1912
+ NomosTrace.emit('dart', 'call.end',
1913
+ 'c=$traceCall outcome=admitted us=${NomosTrace.now() - traceBegin}');
1914
+ }
1853
1915
  return NomosOfferOutcome(
1854
1916
  head: admitted.head,
1855
1917
  intentId: admitted.intentId,
@@ -2550,9 +2612,22 @@ class DartReception {
2550
2612
  // overlapping logical request identities despite sharing one executor.
2551
2613
  // A copy still being fetched or opened answers "not ready yet": ask again
2552
2614
  // rather than hand every caller a state that passes by itself.
2615
+ final traceCall = NomosTrace.enabled ? NomosTrace.nextCall() : 0;
2616
+ final traceBegin = NomosTrace.enabled ? NomosTrace.now() : 0;
2617
+ if (NomosTrace.enabled) {
2618
+ NomosTrace.emit('dart', 'call.begin',
2619
+ 'c=$traceCall op=${NomosTrace.describeCall(nomos_protocol.CallRequest(query: query))}');
2620
+ }
2553
2621
  final response = await nmsUntilReplicaReady(
2554
2622
  () {
2555
2623
  final requestNumber = ++plane._sequences.request;
2624
+ if (NomosTrace.enabled) {
2625
+ NomosTrace.emit(
2626
+ 'dart',
2627
+ 'call.send',
2628
+ 'c=$traceCall lr=$runtimeSession:query:$requestNumber '
2629
+ 'sinceBeginUs=${NomosTrace.now() - traceBegin}');
2630
+ }
2556
2631
  return (transport as NomosKernelCallTransport).callKernel(
2557
2632
  session: runtimeSession,
2558
2633
  // An explicit device key is an additional proof, not a replacement for
@@ -2569,6 +2644,13 @@ class DartReception {
2569
2644
  },
2570
2645
  synced: _eventPlane._events.workspacesSynced,
2571
2646
  );
2647
+ if (NomosTrace.enabled) {
2648
+ NomosTrace.emit(
2649
+ 'dart',
2650
+ 'call.end',
2651
+ 'c=$traceCall outcome=${response.whichOutcome().name} '
2652
+ 'us=${NomosTrace.now() - traceBegin}');
2653
+ }
2572
2654
  if (response.hasFailure()) {
2573
2655
  throw StateError('${response.failure.code}: ${response.failure.message}');
2574
2656
  }
@@ -2664,10 +2746,16 @@ class DartReception {
2664
2746
  birthEvidence: posture.birthEvidence.status,
2665
2747
  birthEvidenceDetail: posture.birthEvidence.detail,
2666
2748
  );
2749
+ // An enrolled device proves its principal with its own key and carries no
2750
+ // provider token by design (D22): name that, rather than `missingToken`
2751
+ // and `unresolved`, which read like a fault.
2752
+ final tokenless = result.enrolledDevice &&
2753
+ result.providerToken == NomosProviderTokenVerification.missingToken;
2667
2754
  print(
2668
2755
  '[nomos-auth-posture] workspace=${_eventPlane._sessions.workspaceFor(session ?? _sessionName ?? '')} '
2669
- 'token=${result.providerToken.name} enrolled=${result.enrolledDevice} '
2670
- 'principal=${result.resolvedPrincipal.isEmpty ? 'unresolved' : 'resolved'}');
2756
+ 'token=${tokenless ? 'notCarried(enrolledDevice)' : result.providerToken.name} '
2757
+ 'enrolled=${result.enrolledDevice} '
2758
+ 'principal=${result.resolvedPrincipal.isNotEmpty ? 'resolved' : tokenless ? 'byDeviceSigner' : 'unresolved'}');
2671
2759
  return result;
2672
2760
  }
2673
2761
 
@@ -2676,16 +2764,15 @@ class DartReception {
2676
2764
  /// must already be bound to the principal's receiving-group workspace. The
2677
2765
  /// shared desk owns whatever placement, identity and birth work the operation
2678
2766
  /// requires. Its convergence tail runs as background correspondence and reports on
2679
- /// [receivingGroupConvergence]. [contract] is the application's law identity
2680
- /// from the compiled descriptor; tenant seed steps are law, never carried
2681
- /// here. A typed refusal surfaces as a [NomosRuntimeError] carrying the
2767
+ /// [receivingGroupConvergence]. The Home is born under the law its platform
2768
+ /// serves, which the desk observes at birth; tenant seed steps are law, never
2769
+ /// carried here. A typed refusal surfaces as a [NomosRuntimeError] carrying the
2682
2770
  /// desk's own code (`nomos.runtime.receiving_group_*`).
2683
2771
  @internal
2684
2772
  Future<nomos_protocol.ReceivingGroupOpened> nmsOpenReceivingGroup({
2685
2773
  required String application,
2686
2774
  required String principal,
2687
2775
  required String authToken,
2688
- required nomos_protocol.ApplicationBirthContract contract,
2689
2776
  bool verifyHistory = false,
2690
2777
  String? session,
2691
2778
  nomos_protocol.ConsoleEnrolmentRoute? enrolment,
@@ -2697,7 +2784,6 @@ class DartReception {
2697
2784
  application: application,
2698
2785
  principal: principal,
2699
2786
  authToken: utf8.encode(authToken),
2700
- contract: contract,
2701
2787
  verifyHistory: verifyHistory,
2702
2788
  enrolment: enrolment,
2703
2789
  ),
@@ -2954,6 +3040,51 @@ class DartReception {
2954
3040
  intervalMs: intervalMs,
2955
3041
  );
2956
3042
 
3043
+ /// Reactive rows of a declared query, kept current by kernel deltas (CAP-731).
3044
+ ///
3045
+ /// The watch opts into row deltas: after its first complete result, each
3046
+ /// local frontier advance delivers only the rows that changed (decoded with
3047
+ /// the same generated [decode]) and the ids that left. The rows are merged
3048
+ /// by [idOf] in the kernel's id order; a row the change did not touch keeps
3049
+ /// its identity, and nothing is emitted when nothing changed. A delta that
3050
+ /// does not start at this watch's position ends the stream with
3051
+ /// [NomosWatchPositionMismatch].
3052
+ Stream<List<T>> nmsWatchRows<T>(
3053
+ NmsGeneratedQuery query, {
3054
+ required List<T> Function(NmsGeneratedResult result) decode,
3055
+ required String Function(T row) idOf,
3056
+ List<NomosScopeKey>? keys,
3057
+ String? principal,
3058
+ String? session,
3059
+ int intervalMs = _defaultWatchSafetyPollMs,
3060
+ }) =>
3061
+ NomosTrace.timedListener(
3062
+ nmsMergeRows(
3063
+ _nmsWatchQuery<nomos_protocol.WatchChanged>(
3064
+ nomos_protocol.QueryRequest(
3065
+ rows: nomos_protocol.RowsQuery(
3066
+ id: query.query,
3067
+ principal: principal ?? '',
3068
+ applicationArguments: google_protobuf.Any(
3069
+ typeUrl: query.protobufType,
3070
+ value: query.protobufPayload,
3071
+ ),
3072
+ ),
3073
+ ),
3074
+ resultFormat: nomos_protocol
3075
+ .QueryResultFormat.QUERY_RESULT_FORMAT_APPLICATION_PROTOBUF,
3076
+ decode: (changed) => changed,
3077
+ acceptRowDelta: true,
3078
+ keys: keys,
3079
+ principal: principal,
3080
+ session: session,
3081
+ intervalMs: intervalMs,
3082
+ ),
3083
+ NmsRowsMerge<T>(decode: decode, idOf: idOf),
3084
+ ),
3085
+ // The application's own listener time per emission (the inner watch's is the merge).
3086
+ 'q=query:rows:${query.query} stage=app');
3087
+
2957
3088
  /// Reactive form of [nmsQueryUsda]. Subscription mechanics are Runtime v2
2958
3089
  /// protobuf; each emission is the kernel's nominal USDA result and is decoded
2959
3090
  /// only by the generated domain client which owns [query].
@@ -3054,6 +3185,7 @@ class DartReception {
3054
3185
  nomos_protocol.QueryRequest request, {
3055
3186
  required nomos_protocol.QueryResultFormat resultFormat,
3056
3187
  required T Function(nomos_protocol.WatchChanged) decode,
3188
+ bool acceptRowDelta = false,
3057
3189
  List<NomosScopeKey>? keys,
3058
3190
  String? principal,
3059
3191
  String? session,
@@ -3070,6 +3202,9 @@ class DartReception {
3070
3202
  ..resultFormat = resultFormat;
3071
3203
  final NmsTypedWatchHandle<T> watch = plane._events.typedWatches.open<T>(
3072
3204
  session: runtimeSession,
3205
+ label: NomosTrace.enabled
3206
+ ? NomosTrace.describeCall(nomos_protocol.CallRequest(query: request))
3207
+ : '',
3073
3208
  decode: decode,
3074
3209
  stop: _unwatch,
3075
3210
  start: (subscriptionId) async {
@@ -3081,6 +3216,7 @@ class DartReception {
3081
3216
  kind: nomos_protocol.WatchKind.WATCH_KIND_QUERY,
3082
3217
  query: request,
3083
3218
  intervalMillis: intervalMs,
3219
+ acceptRowDelta: acceptRowDelta,
3084
3220
  ),
3085
3221
  ),
3086
3222
  );
@@ -4160,6 +4296,7 @@ class NomosSession extends DartReception {
4160
4296
  adoptApplicationModel: nomos_protocol.AdoptApplicationModelRequest(
4161
4297
  session: workspace,
4162
4298
  lawSha256: model.lawSha256,
4299
+ unitSet: model.unitSet,
4163
4300
  domainKeys: model.domainKeys,
4164
4301
  acceptanceReason: model.reason,
4165
4302
  dryRun: dryRun,