@githolon/dsl 0.108.7 → 0.110.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 (307) hide show
  1. package/assets/operation-contract.wasm +0 -0
  2. package/check_package.mjs +12 -15
  3. package/compile_package.mjs +17 -18
  4. package/compile_proof.mjs +16 -1
  5. package/dart/CHANGELOG.md +76 -1
  6. package/dart/README.md +25 -2
  7. package/dart/lib/src/admission_decision.dart +41 -0
  8. package/dart/lib/src/application_framework_calls.dart +52 -2
  9. package/dart/lib/src/application_model_adoption.dart +187 -0
  10. package/dart/lib/src/application_status.dart +73 -0
  11. package/dart/lib/src/console_enrolment.dart +271 -0
  12. package/dart/lib/src/console_http_io.dart +26 -0
  13. package/dart/lib/src/console_http_stub.dart +7 -0
  14. package/dart/lib/src/dev_cloud.dart +69 -22
  15. package/dart/lib/src/generated_call.dart +83 -23
  16. package/dart/lib/src/kernel_primitives.dart +119 -0
  17. package/dart/lib/src/nms_conformance_runtime.dart +1 -1
  18. package/dart/lib/src/nms_generated_runtime.dart +32 -10
  19. package/dart/lib/src/nms_test_environment.dart +1 -1
  20. package/dart/lib/src/node_runner_transport.dart +41 -46
  21. package/dart/lib/src/observed_session_directory.dart +70 -0
  22. package/dart/lib/src/operation_receipts.dart +112 -0
  23. package/dart/lib/src/peer_application_streams.dart +103 -0
  24. package/dart/lib/src/reception/dart_reception.dart +4280 -0
  25. package/dart/lib/src/reception/event_desk.dart +211 -0
  26. package/dart/lib/src/reception/extremum_read.dart +46 -0
  27. package/dart/lib/src/reception/local_copies.dart +371 -0
  28. package/dart/lib/src/reception/peer_office_connection.dart +11 -0
  29. package/dart/lib/src/reception/progress_desk.dart +267 -0
  30. package/dart/lib/src/reception/reception_contract.dart +11 -0
  31. package/dart/lib/src/reception/reception_session.dart +284 -0
  32. package/dart/lib/src/reception/sync_diagnostics.dart +26 -0
  33. package/dart/lib/src/reception/workspace_preparation_report.dart +126 -0
  34. package/dart/lib/src/replica_readiness.dart +123 -0
  35. package/dart/lib/src/runner/node-entry.mjs +23905 -15774
  36. package/dart/lib/src/runtime_v2_gateway.dart +56 -3
  37. package/dart/lib/src/runtime_v2_transport.dart +544 -3
  38. package/dart/lib/src/session_bound.dart +200 -311
  39. package/dart/lib/src/signing_identity_kernel.dart +84 -0
  40. package/dart/lib/src/sync_status_projection.dart +548 -0
  41. package/dart/lib/src/sync_status_reducer.dart +170 -0
  42. package/dart/lib/src/test_harness.dart +809 -1153
  43. package/dart/lib/src/testing/test_custody.dart +66 -0
  44. package/dart/lib/src/testing/test_peer.dart +328 -0
  45. package/dart/lib/src/typed_watch_registry.dart +169 -0
  46. package/dart/lib/src/workspace_open_progress.dart +27 -0
  47. package/dart/pubspec.lock +24 -1
  48. package/dart/pubspec.yaml +7 -2
  49. package/dart/pubspec_overrides.yaml +2 -0
  50. package/dart/test/admission_decision_test.dart +48 -0
  51. package/dart/test/background_model_adoption_test.dart +228 -0
  52. package/dart/test/bundle_version_pairing_test.dart +4 -4
  53. package/dart/test/child_authentication_repair_test.dart +359 -0
  54. package/dart/test/cloud_bound_local_shell_test.dart +119 -0
  55. package/dart/test/console_enrolment_refusal_test.dart +52 -0
  56. package/dart/test/console_enrolment_test.dart +227 -0
  57. package/dart/test/errors_test.dart +5 -5
  58. package/dart/test/event_plane_seam_test.dart +50 -164
  59. package/dart/test/extremum_read_test.dart +58 -0
  60. package/dart/test/fixtures/wedge/wedge-entry.mjs +3 -21
  61. package/dart/test/generated_query_test.dart +32 -0
  62. package/dart/test/harness_phase_timeout_test.dart +18 -23
  63. package/dart/test/kernel_author_after_read_test.dart +242 -0
  64. package/dart/test/kernel_fence_test.dart +137 -0
  65. package/dart/test/local_copies_test.dart +222 -0
  66. package/dart/test/model_adoption_test.dart +198 -0
  67. package/dart/test/node_peer_local_custody_test.dart +153 -0
  68. package/dart/test/offer_authentication_proof_test.dart +352 -52
  69. package/dart/test/operation_compatibility_test.dart +151 -0
  70. package/dart/test/platform_credential_effect_test.dart +386 -0
  71. package/dart/test/receiving_group_open_test.dart +213 -0
  72. package/dart/test/reception/workspace_preparation_report_test.dart +103 -0
  73. package/dart/test/reception_span_trace_test.dart +23 -0
  74. package/dart/test/replica_readiness_test.dart +156 -0
  75. package/dart/test/runtime_projections_test.dart +92 -0
  76. package/dart/test/runtime_v2_gateway_test.dart +131 -0
  77. package/dart/test/signing_identity_kernel_test.dart +75 -0
  78. package/dart/test/sync_status_preparation_report_test.dart +29 -0
  79. package/dart/test/sync_status_reducer_test.dart +419 -0
  80. package/dart/test/test_harness_test.dart +71 -95
  81. package/dart/test/typed_query_watch_test.dart +170 -0
  82. package/dart/test/typed_watch_registry_test.dart +249 -0
  83. package/dart_lints/README.md +18 -0
  84. package/dart_lints/lib/nomos_lints.dart +70 -0
  85. package/dart_lints/pubspec.lock +580 -0
  86. package/dart_lints/pubspec.yaml +12 -0
  87. package/dart_lints/test/reference_identity_test.dart +75 -0
  88. package/dart_types/CHANGELOG.md +18 -0
  89. package/dart_types/lib/nomos_kernel_protocol.dart +21 -1
  90. package/dart_types/lib/nomos_types.dart +9 -1
  91. package/dart_types/lib/src/admission_decision.dart +37 -0
  92. package/dart_types/lib/src/aggregate_meta.dart +1 -1
  93. package/dart_types/lib/src/approved_model.dart +65 -0
  94. package/dart_types/lib/src/custody.dart +10 -18
  95. package/dart_types/lib/src/error_info.dart +4 -4
  96. package/dart_types/lib/src/errors.dart +29 -29
  97. package/dart_types/lib/src/foreign_ref.dart +62 -33
  98. package/dart_types/lib/src/local_work_rejected.dart +3 -3
  99. package/dart_types/lib/src/nomos_ref.dart +3 -1
  100. package/dart_types/lib/src/principal.dart +2 -2
  101. package/dart_types/lib/src/proto/google/protobuf/any.pb.dart +163 -0
  102. package/dart_types/lib/src/proto/google/protobuf/any.pbenum.dart +11 -0
  103. package/dart_types/lib/src/proto/nomos/discovery/v1/workspace_placement.pb.dart +137 -0
  104. package/dart_types/lib/src/proto/nomos/discovery/v1/workspace_placement.pbenum.dart +11 -0
  105. package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pb.dart +20721 -10433
  106. package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pbenum.dart +555 -27
  107. package/dart_types/lib/src/proto/nomos/runtime/v2/application_desk.pb.dart +387 -0
  108. package/dart_types/lib/src/proto/nomos/runtime/v2/application_desk.pbenum.dart +46 -0
  109. package/dart_types/lib/src/proto/nomos/runtime/v2/application_readiness_desk.pb.dart +295 -0
  110. package/dart_types/lib/src/proto/nomos/runtime/v2/application_readiness_desk.pbenum.dart +139 -0
  111. package/dart_types/lib/src/proto/nomos/runtime/v2/authentication_desk.pb.dart +269 -0
  112. package/dart_types/lib/src/proto/nomos/runtime/v2/authentication_desk.pbenum.dart +103 -0
  113. package/dart_types/lib/src/proto/nomos/runtime/v2/compatibility_desk.pb.dart +417 -0
  114. package/dart_types/lib/src/proto/nomos/runtime/v2/compatibility_desk.pbenum.dart +62 -0
  115. package/dart_types/lib/src/proto/nomos/runtime/v2/correspondence_desk.pb.dart +9968 -0
  116. package/dart_types/lib/src/proto/nomos/runtime/v2/correspondence_desk.pbenum.dart +133 -0
  117. package/dart_types/lib/src/proto/nomos/runtime/v2/credentials_desk.pb.dart +204 -0
  118. package/dart_types/lib/src/proto/nomos/runtime/v2/credentials_desk.pbenum.dart +54 -0
  119. package/dart_types/lib/src/proto/nomos/runtime/v2/custody_desk.pb.dart +1550 -0
  120. package/dart_types/lib/src/proto/nomos/runtime/v2/custody_desk.pbenum.dart +11 -0
  121. package/dart_types/lib/src/proto/nomos/runtime/v2/framework.pb.dart +710 -0
  122. package/dart_types/lib/src/proto/nomos/runtime/v2/framework.pbenum.dart +11 -0
  123. package/dart_types/lib/src/proto/nomos/runtime/v2/identity_desk.pb.dart +845 -0
  124. package/dart_types/lib/src/proto/nomos/runtime/v2/identity_desk.pbenum.dart +11 -0
  125. package/dart_types/lib/src/proto/nomos/runtime/v2/interaction_desk.pb.dart +198 -0
  126. package/dart_types/lib/src/proto/nomos/runtime/v2/interaction_desk.pbenum.dart +11 -0
  127. package/dart_types/lib/src/proto/nomos/runtime/v2/law_desk.pb.dart +369 -0
  128. package/dart_types/lib/src/proto/nomos/runtime/v2/law_desk.pbenum.dart +11 -0
  129. package/dart_types/lib/src/proto/nomos/runtime/v2/maintenance_desk.pb.dart +609 -0
  130. package/dart_types/lib/src/proto/nomos/runtime/v2/maintenance_desk.pbenum.dart +65 -0
  131. package/dart_types/lib/src/proto/nomos/runtime/v2/model_adoption_desk.pb.dart +358 -0
  132. package/dart_types/lib/src/proto/nomos/runtime/v2/model_adoption_desk.pbenum.dart +100 -0
  133. package/dart_types/lib/src/proto/nomos/runtime/v2/observability_desk.pb.dart +2231 -0
  134. package/dart_types/lib/src/proto/nomos/runtime/v2/observability_desk.pbenum.dart +271 -0
  135. package/dart_types/lib/src/proto/nomos/runtime/v2/placement_desk.pb.dart +1286 -0
  136. package/dart_types/lib/src/proto/nomos/runtime/v2/placement_desk.pbenum.dart +11 -0
  137. package/dart_types/lib/src/proto/nomos/runtime/v2/receiving_group_desk.pb.dart +636 -0
  138. package/dart_types/lib/src/proto/nomos/runtime/v2/receiving_group_desk.pbenum.dart +116 -0
  139. package/dart_types/lib/src/proto/nomos/runtime/v2/records_desk.pb.dart +1637 -0
  140. package/dart_types/lib/src/proto/nomos/runtime/v2/records_desk.pbenum.dart +175 -0
  141. package/dart_types/lib/src/proto/nomos/runtime/v2/recovery_desk.pb.dart +1269 -0
  142. package/dart_types/lib/src/proto/nomos/runtime/v2/recovery_desk.pbenum.dart +129 -0
  143. package/dart_types/lib/src/proto/nomos/runtime/v2/residency_desk.pb.dart +2782 -0
  144. package/dart_types/lib/src/proto/nomos/runtime/v2/residency_desk.pbenum.dart +97 -0
  145. package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pb.dart +2232 -8627
  146. package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pbenum.dart +0 -358
  147. package/dart_types/lib/src/proto/nomos/runtime/v2/sealing_desk.pb.dart +1639 -0
  148. package/dart_types/lib/src/proto/nomos/runtime/v2/sealing_desk.pbenum.dart +46 -0
  149. package/dart_types/lib/src/runtime_outcome.dart +133 -0
  150. package/dart_types/lib/src/subscriptions.dart +116 -23
  151. package/dart_types/pubspec.yaml +1 -1
  152. package/dart_types/test/extremum_subscriptions_test.dart +40 -0
  153. package/dart_types/test/foreign_ref_resolution_test.dart +75 -0
  154. package/dart_types/test/nomos_ref_address_test.dart +25 -0
  155. package/dart_types/test/ordered_subscriptions_test.dart +34 -0
  156. package/operation_contract_check.mjs +24 -0
  157. package/package.json +11 -6
  158. package/src/aggregate.ts +70 -10
  159. package/src/application_topology.ts +18 -11
  160. package/src/attested.ts +3 -0
  161. package/src/attested_core.ts +46 -3
  162. package/src/birth_meter_ensure.ts +19 -7
  163. package/src/births.ts +29 -4
  164. package/src/build_package.ts +140 -13
  165. package/src/business_birth.ts +181 -4
  166. package/src/codegen_call_proto.ts +1274 -0
  167. package/src/codegen_call_usda.ts +49 -6
  168. package/src/codegen_dart.ts +79 -44
  169. package/src/codegen_dart_client.ts +458 -800
  170. package/src/{codegen_dart_application.ts → codegen_dart_facade.ts} +331 -582
  171. package/src/codegen_dart_framework_calls.ts +320 -37
  172. package/src/codegen_dart_indexed_variant.ts +159 -0
  173. package/src/codegen_dart_scenario.ts +42 -13
  174. package/src/codegen_proof.ts +3 -3
  175. package/src/codegen_provider_dart.ts +5 -0
  176. package/src/codegen_query_proto.ts +158 -0
  177. package/src/codegen_refusal.ts +189 -0
  178. package/src/codegen_result_proto.ts +931 -0
  179. package/src/codegen_result_usda.ts +4 -0
  180. package/src/codegen_ts.ts +464 -616
  181. package/src/codegen_workspace_access.ts +105 -0
  182. package/src/compatibility_graph.ts +759 -0
  183. package/src/compatibility_usda.ts +264 -0
  184. package/src/compile_package_main.ts +1994 -1189
  185. package/src/custody_placement.ts +156 -0
  186. package/src/custody_placement_usda.ts +91 -0
  187. package/src/decl_shapes.ts +21 -2
  188. package/src/describe_model.ts +1 -0
  189. package/src/directive.ts +59 -2
  190. package/src/drivers.ts +51 -0
  191. package/src/engine_entry.ts +52 -8
  192. package/src/evolve_preview.ts +11 -4
  193. package/src/exists.ts +2 -0
  194. package/src/fields.ts +75 -11
  195. package/src/flow_gate.ts +2 -1
  196. package/src/framework/application_home.ts +170 -18
  197. package/src/framework/attested_receipts.ts +8 -3
  198. package/src/framework/auth_provider_law.ts +169 -9
  199. package/src/framework/birth_certificate_law.ts +4 -0
  200. package/src/framework/capability.ts +34 -3
  201. package/src/framework/child_authentication.ts +346 -0
  202. package/src/framework/console_governance.ts +295 -0
  203. package/src/framework/delegated_roles.ts +301 -0
  204. package/src/framework/domain_lifecycle.ts +26 -13
  205. package/src/framework/founding_genesis.ts +193 -0
  206. package/src/framework/framework_aggregates.ts +1 -1
  207. package/src/framework/genesis.ts +6 -1
  208. package/src/framework/governance_relations.ts +19 -0
  209. package/src/framework/home.ts +5 -734
  210. package/src/framework/legacy/child_auth_provider_epoch.ts +73 -0
  211. package/src/framework/model_authority_repair.ts +116 -0
  212. package/src/framework/model_authority_seed.ts +185 -0
  213. package/src/framework/model_transition.ts +211 -0
  214. package/src/framework/owned_custody.ts +1 -1
  215. package/src/framework/principal_enrollment.ts +302 -0
  216. package/src/framework/receiving_group.ts +857 -0
  217. package/src/framework/receiving_group_recovery.ts +314 -0
  218. package/src/framework/relations.ts +4 -8
  219. package/src/framework/signing_identity.ts +242 -95
  220. package/src/framework/source_roster.ts +11 -5
  221. package/src/framework/workspace_access.ts +149 -0
  222. package/src/framework/workspace_invariant.ts +73 -52
  223. package/src/framework/workspaces.ts +407 -40
  224. package/src/framework_call_definitions.ts +32 -3
  225. package/src/generated_client_bundle_boundary.ts +97 -0
  226. package/src/generated_client_names.ts +1 -0
  227. package/src/identity_usda.ts +27 -0
  228. package/src/index.ts +183 -12
  229. package/src/indexed_variant.ts +83 -0
  230. package/src/intent.ts +173 -45
  231. package/src/law_check.ts +8 -5
  232. package/src/law_dependency_index.ts +231 -0
  233. package/src/law_graph.ts +508 -71
  234. package/src/law_graph_usda.ts +170 -24
  235. package/src/law_identity.ts +119 -81
  236. package/src/law_source_map.ts +4 -1
  237. package/src/law_units.ts +498 -0
  238. package/src/law_value_type.ts +7 -3
  239. package/src/member_authentication.ts +302 -0
  240. package/src/null_meta.ts +1 -1
  241. package/src/openusd_compiled_layer.ts +132 -0
  242. package/src/operation_contract_check.ts +31 -0
  243. package/src/ordered_read.ts +2 -1
  244. package/src/package_config.ts +33 -12
  245. package/src/package_dependencies.ts +1 -0
  246. package/src/plan_source_slice.ts +30 -1
  247. package/src/protobuf_field_number.ts +36 -0
  248. package/src/provenance_wire.ts +6 -0
  249. package/src/query.ts +2 -1
  250. package/src/read.ts +50 -0
  251. package/src/relation.ts +4 -1
  252. package/src/relation_schema.ts +15 -2
  253. package/src/report.ts +2 -2
  254. package/src/sqlite_computation_bundle.ts +78 -0
  255. package/src/sqlite_computed.ts +102 -0
  256. package/src/sqlite_counts.ts +154 -0
  257. package/src/sqlite_layout.ts +823 -0
  258. package/src/sqlite_reads.ts +275 -0
  259. package/src/sqlite_samples.ts +185 -0
  260. package/src/stable_id_identity_bridge.ts +1 -1
  261. package/src/stable_ids_for_module.ts +16 -4
  262. package/src/test_call_usda.ts +6 -6
  263. package/src/usda_relationship_integrity.ts +20 -3
  264. package/src/usda_text.ts +21 -1
  265. package/src/value_object.ts +81 -11
  266. package/src/wire.ts +22 -0
  267. package/src/wire_encode.ts +227 -20
  268. package/src/workspace_sharding.ts +15 -6
  269. package/src/workspace_sharing.ts +51 -49
  270. package/src/zod_introspection.ts +2 -0
  271. package/compat_package.mjs +0 -46
  272. package/dart/lib/src/home.dart +0 -15
  273. package/dart/lib/src/runner/offline-install.mjs +0 -15367
  274. package/dart/lib/src/source_trust.dart +0 -51
  275. package/dart/lib/src/webview_bridge.dart +0 -6540
  276. package/dart/lib/src/workspace_name.dart +0 -30
  277. package/dart/test/acquire_session_credentials_test.dart +0 -150
  278. package/dart/test/acquire_session_test.dart +0 -534
  279. package/dart/test/adv_realm_interference_test.dart +0 -600
  280. package/dart/test/cloud_bound_topology_test.dart +0 -168
  281. package/dart/test/cluster_births_test.dart +0 -202
  282. package/dart/test/cluster_device_keyed_acceptance_test.dart +0 -105
  283. package/dart/test/cluster_local_autosync_test.dart +0 -123
  284. package/dart/test/cluster_scale_test.dart +0 -122
  285. package/dart/test/compat_test.dart +0 -61
  286. package/dart/test/dlq_session_surface_test.dart +0 -222
  287. package/dart/test/first_app_gauntlet_test.dart +0 -386
  288. package/dart/test/fixtures/wedge/fake-install.mjs +0 -11
  289. package/dart/test/four_layer_nested_topology_test.dart +0 -290
  290. package/dart/test/home_parity_test.dart +0 -13
  291. package/dart/test/local_sync_inert_test.dart +0 -107
  292. package/dart/test/node_runner_transport_test.dart +0 -78
  293. package/dart/test/parent_signer_recovery_test.dart +0 -155
  294. package/dart/test/residency_refusal_test.dart +0 -49
  295. package/dart/test/sealing_client_test.dart +0 -181
  296. package/dart/test/session_bound_test.dart +0 -285
  297. package/dart/test/stale_bundle_test.dart +0 -80
  298. package/dart/test/vo_read_typing_test.dart +0 -131
  299. package/dart/test/watch_after_offer_stall_test.dart +0 -100
  300. package/dart/test/webview_bridge_test.dart +0 -1930
  301. package/dart/test/workspace_name_test.dart +0 -24
  302. package/runtime/generated-application-host.js +0 -22860
  303. package/src/codegen_query_usda.ts +0 -214
  304. package/src/compat_manifest.ts +0 -26
  305. package/src/compat_package_main.ts +0 -224
  306. package/src/shape_compat.ts +0 -352
  307. package/src/usd_state.ts +0 -505
package/src/read.ts CHANGED
@@ -172,6 +172,56 @@ export function readFrameworkDeclaredRows<
172
172
  return z.array(row).parse(readFrameworkDeclared(query.id, args));
173
173
  }
174
174
 
175
+ /**
176
+ * Typed framework foreign read. This is the attested twin of
177
+ * {@link readFrameworkDeclaredRows}: the aggregate declaration remains the
178
+ * only field/type source, while the ordinary foreign-read lane captures the
179
+ * source kernel's proof on the authored intent.
180
+ *
181
+ * Framework laws use this when an admitted local transition copies a typed
182
+ * value from another sovereign workspace. The peer may cache and relay the
183
+ * attestation, but neither it nor a generated application client decodes or
184
+ * vouches for the returned rows.
185
+ */
186
+ export function readFrameworkAttestedRows<
187
+ const Id extends string,
188
+ F extends Record<string, Field>,
189
+ >(
190
+ query: QueryDecl,
191
+ aggregate: AggregateHandle<Id, F>,
192
+ args: Record<string, string>,
193
+ from: string,
194
+ ): Array<ReadModelRow<F>> {
195
+ if (query.returns !== aggregate.id) {
196
+ throw new Error(
197
+ `framework attested read '${query.id}' returns '${query.returns}', not '${aggregate.id}'`,
198
+ );
199
+ }
200
+ const fields = aggregate.fields as Record<string, Field>;
201
+ const shape = Object.fromEntries(
202
+ Object.entries(fields).map(([name, field]) => [name, field.zod.optional()]),
203
+ ) as ProjectionShape<F>;
204
+ const data = z.object(shape).strip() as z.ZodType<ReadModelRow<F>>;
205
+ const envelope = z.object({ data: z.unknown() }).passthrough();
206
+ const row = z.union([envelope, z.unknown()])
207
+ .transform((value) => {
208
+ const wrapped = envelope.safeParse(value);
209
+ const projected = wrapped.success ? wrapped.data.data : value;
210
+ if (projected === null || typeof projected !== "object" || Array.isArray(projected)) {
211
+ return projected;
212
+ }
213
+ const lifted = { ...(projected as Record<string, unknown>) };
214
+ for (const name in fields) {
215
+ if (fields[name]?.kind !== "bool") continue;
216
+ if (lifted[name] === "true") lifted[name] = true;
217
+ else if (lifted[name] === "false") lifted[name] = false;
218
+ }
219
+ return lifted;
220
+ })
221
+ .pipe(data);
222
+ return z.array(row).parse(read(query, args, { from }));
223
+ }
224
+
175
225
  function readForeign<T = unknown>(query: QueryDecl | { id: string }, args: Record<string, string>, from: string): T {
176
226
  // ── THE FOREIGN (attested cross-workspace) LANE (slice B — attested_reads_design.md §4.1).
177
227
  // The port answers the `{rows, attestation}` wrapper: at AUTHOR the kernel verified the
package/src/relation.ts CHANGED
@@ -99,7 +99,10 @@ export interface RelationDecl {
99
99
 
100
100
  /** Stage 1 of the builder: id + the two endpoints. */
101
101
  class RelationSourceStep<Id extends string> {
102
- constructor(private readonly id: Id) {}
102
+ private readonly id: Id;
103
+ constructor(id: Id) {
104
+ this.id = id;
105
+ }
103
106
  /** Declare the SOURCE → TARGET endpoints (aggregate TYPE ids). */
104
107
  endpoints(source: string, target: string): RelationProposesStep<Id> {
105
108
  return new RelationProposesStep(this.id, source, target);
@@ -198,9 +198,11 @@ export function mergeRelationTypeDeclarations(
198
198
  // Framework-owned declarations can cross the published-CLI/package bundle boundary as
199
199
  // distinct object identities. The private brand plus byte-identical definition identifies
200
200
  // that one canonical concept; tenant-authored collisions remain a loud hard failure.
201
+ // A tenant may also re-export the framework's own fragment (e.g. `workspaceOperatorRelations`,
202
+ // which a business birth composes too): one side branded and byte-identical is that same concept.
201
203
  const repeatedFrameworkDeclaration =
202
- (first as RelationTypeDecl & { businessBirthInternal?: boolean }).businessBirthInternal === true &&
203
- (declaration as RelationTypeDecl & { businessBirthInternal?: boolean }).businessBirthInternal === true &&
204
+ ((first as RelationTypeDecl & { businessBirthInternal?: boolean }).businessBirthInternal === true ||
205
+ (declaration as RelationTypeDecl & { businessBirthInternal?: boolean }).businessBirthInternal === true) &&
204
206
  JSON.stringify(existing) === JSON.stringify(definition);
205
207
  if (repeatedFrameworkDeclaration) continue;
206
208
  throw new Error(
@@ -398,6 +400,17 @@ export function relationType(type: string, caps?: Partial<RelationCaps>): Relati
398
400
  relation(name: string, opts?: { rewrite?: Rewrite; allow?: AllowedSubject[] }): RelationTypeBuilder {
399
401
  requireName(name, "relation");
400
402
  if (relations.has(name)) throw new Error(`relationType("${type}"): relation "${name}" declared twice`);
403
+ // Law is compiled without a type check, so an option this builder does not know would otherwise
404
+ // vanish silently — a declared intent the compiled law never carries.
405
+ for (const option of Object.keys(opts ?? {})) {
406
+ if (option === "rewrite" || option === "allow") continue;
407
+ throw new Error(
408
+ option === "seededFromParent"
409
+ ? `relationType("${type}"): relation "${name}" cannot be seeded from the parent; only the framework's own ` +
410
+ `operator relation is carried at birth (identity_target_model.md D19)`
411
+ : `relationType("${type}"): relation "${name}" has unknown option "${option}"`,
412
+ );
413
+ }
401
414
  const allowed = opts?.allow ?? [];
402
415
  validateAllowed(type, name, allowed);
403
416
  relations.set(name, { rewrite: opts?.rewrite ?? null, allowed });
package/src/report.ts CHANGED
@@ -60,14 +60,14 @@ import {
60
60
 
61
61
  /**
62
62
  * The declarative query AST a `.select` produces. Mirrors the Rust
63
- * `engine_host::query_port::QueryAst` (tagged union). The HOST resolves this; the
63
+ * `deterministic_rquickjs::query_port::QueryAst` (tagged union). The HOST resolves this; the
64
64
  * author only constructs it via the fluent `SelectBuilder`.
65
65
  *
66
66
  * Two variants now:
67
67
  * * `touchedBy` — the original provenance predicate (escape-hatch / disclosure).
68
68
  * * `entityGraph` — the PRIMARY path: a typed entity-graph query Nomos compiles
69
69
  * into sealed SQL. Carries the certified relation chain + filters + optional
70
- * touchedBy + agg. Mirrors `engine_host::query_port::QueryAst::EntityGraph`.
70
+ * touchedBy + agg. Mirrors `deterministic_rquickjs::query_port::QueryAst::EntityGraph`.
71
71
  */
72
72
  export type QueryAst =
73
73
  | {
@@ -0,0 +1,78 @@
1
+ /** Diagnostic only: execute real declarations through the existing sealed engine.
2
+ * This is not an installed law asset or an alternative tenant compiler. */
3
+ import { createHash } from "node:crypto";
4
+ import { createRequire } from "node:module";
5
+ import { dirname, join, resolve } from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+ import { readFileSync } from "node:fs";
8
+ import { build } from "esbuild";
9
+ import type { collectEngineRouting } from "./engine_entry.js";
10
+
11
+ export async function sqliteComputationBundle(
12
+ sources: ReadonlyMap<string, string>,
13
+ routing: ReturnType<typeof collectEngineRouting>
14
+ ) {
15
+ const src = dirname(fileURLToPath(import.meta.url));
16
+ const zod = dirname(
17
+ createRequire(import.meta.url).resolve("zod/package.json")
18
+ );
19
+ const domains = [
20
+ ...new Set([
21
+ ...Object.values(routing.derivedOf ?? {}).flat(),
22
+ ...Object.values(routing.combinedOf ?? {}).flat(),
23
+ ]),
24
+ ].sort();
25
+ if (domains.length === 0) return null;
26
+ const result = await build({
27
+ stdin: {
28
+ contents: [
29
+ `import {registerEngine} from ${JSON.stringify(
30
+ join(src, "engine_entry.ts")
31
+ )};`,
32
+ ...["core", "registries"].map(
33
+ (n, i) =>
34
+ `import * as seed${i} from ${JSON.stringify(
35
+ join(zod, "v4/core", n + ".js")
36
+ )};`
37
+ ),
38
+ "registerEngine({domains:{",
39
+ ...domains.map((d) => {
40
+ const s = sources.get(d);
41
+ if (!s) throw Error(`missing computation domain ${d}`);
42
+ return s;
43
+ }),
44
+ `},routing:${JSON.stringify(routing)},seeds:[seed0,seed1]});`,
45
+ ].join("\n"),
46
+ loader: "ts",
47
+ resolveDir: resolve(src, ".."),
48
+ },
49
+ bundle: true,
50
+ write: false,
51
+ format: "iife",
52
+ target: "es2020",
53
+ platform: "neutral",
54
+ charset: "utf8",
55
+ minify: true,
56
+ metafile: true,
57
+ define: { __nmsRuntimeLaw: "true" },
58
+ alias: {
59
+ zod: join(src, "runtime_zod.ts"),
60
+ "zod/v4": join(zod, "v4/index.js"),
61
+ },
62
+ });
63
+ const javascript = result.outputFiles[0]!.text;
64
+ return {
65
+ kind: "diagnostic-sealed-computations",
66
+ javascript,
67
+ sha256: createHash("sha256").update(javascript).digest("hex"),
68
+ domains,
69
+ inputs: Object.keys(result.metafile!.inputs)
70
+ .filter((p) => p !== "<stdin>")
71
+ .map((p) => ({
72
+ path: resolve(p),
73
+ sha256: createHash("sha256")
74
+ .update(readFileSync(resolve(p)))
75
+ .digest("hex"),
76
+ })),
77
+ };
78
+ }
@@ -0,0 +1,102 @@
1
+ /** Fixed read declarations lower to SQL. Arbitrary function bodies remain in
2
+ * the existing sealed engine. No derived copies or invalidation queue. */
3
+ import type { LawGraph } from "./law_graph.js";
4
+ import type { SqliteLayout } from "./sqlite_layout.js";
5
+ import { scalarSlot } from "./sqlite_reads.js";
6
+ export interface SqliteComputedPlan {
7
+ sid: string;
8
+ name: string;
9
+ kind: "derived" | "combined" | "temporalEnum";
10
+ via: string | null;
11
+ relatedType: string | null;
12
+ temporal: {
13
+ id: string;
14
+ of: string;
15
+ source_field: string;
16
+ missing: string;
17
+ initial: string;
18
+ transitions: { after_millis: number; value: string }[];
19
+ expression: string;
20
+ } | null;
21
+ }
22
+ const quote = (s: string) => `'${s.replaceAll("'", "''")}'`;
23
+ export function planSqliteComputations(
24
+ nodes: ReadonlyMap<string, LawGraph["nodes"][number]>,
25
+ aggregateId: string,
26
+ layout: Pick<SqliteLayout, "table" | "wireType" | "fields">
27
+ ) {
28
+ const plans: SqliteComputedPlan[] = [],
29
+ refusals: { sid: string; reason: string }[] = [];
30
+ for (const read of nodes.values()) {
31
+ if (
32
+ read.kind !== "read" ||
33
+ read.of.id !== aggregateId ||
34
+ (read.readKind !== "derived" &&
35
+ read.readKind !== "combined" &&
36
+ read.readKind !== "temporalEnum")
37
+ )
38
+ continue;
39
+ try {
40
+ if (read.predicate) throw Error("computed read predicate not supported");
41
+ if (layout.fields.some((f) => f.name === read.entity.label))
42
+ throw Error("computed output shadows an authored field");
43
+ const p: SqliteComputedPlan = {
44
+ sid: read.entity.sid,
45
+ name: read.entity.label,
46
+ kind: read.readKind,
47
+ via: null,
48
+ relatedType: null,
49
+ temporal: null,
50
+ };
51
+ if (read.readKind === "temporalEnum") {
52
+ const path = read.source.authoredPath.split(".");
53
+ const f = layout.fields.find((f) => f.name === path[0]);
54
+ if (!f || path.length !== 1 || scalarSlot(f, []).kind !== "integer")
55
+ throw Error("temporal source requires a mapped scalar timestamp");
56
+ const source = scalarSlot(f, []).sql;
57
+ const transitions = read.transitions.map((t) => {
58
+ if (!Number.isSafeInteger(t.afterMillis) || t.afterMillis < 0)
59
+ throw Error("invalid temporal threshold");
60
+ return { after_millis: t.afterMillis, value: t.value };
61
+ });
62
+ // ?1 is the captured clock. Guard subtraction against signed-i64
63
+ // underflow; no REAL promotion or ambient SQLite wall clock.
64
+ const cases = [...transitions].reverse().map((t) => {
65
+ const safe = -(1n << 63n) + BigInt(t.after_millis);
66
+ const condition =
67
+ t.after_millis === 0
68
+ ? "1"
69
+ : `(?1>=${safe} AND (${source})<=?1-${t.after_millis})`;
70
+ return `WHEN ${condition} THEN ${quote(t.value)}`;
71
+ });
72
+ p.temporal = {
73
+ id: p.name,
74
+ of: layout.wireType,
75
+ source_field: path[0]!,
76
+ missing: read.missing,
77
+ initial: read.initial,
78
+ transitions,
79
+ expression: `CASE WHEN (${source}) IS NULL THEN ${quote(
80
+ read.missing
81
+ )} ${cases.join(" ")} ELSE ${quote(read.initial)} END`,
82
+ };
83
+ } else if (read.readKind === "combined") {
84
+ const path = read.via.authoredPath.split(".");
85
+ const f = layout.fields.find((f) => f.name === path[0]);
86
+ if (!f || path.length !== 1 || scalarSlot(f, []).kind !== "string")
87
+ throw Error(
88
+ "combined join requires a mapped direct string reference"
89
+ );
90
+ const related = nodes.get(read.reads.id);
91
+ if (related?.kind !== "aggregate")
92
+ throw Error("combined related aggregate unavailable");
93
+ p.via = path[0]!;
94
+ p.relatedType = related.wireType;
95
+ }
96
+ plans.push(p);
97
+ } catch (error) {
98
+ refusals.push({ sid: read.entity.sid, reason: (error as Error).message });
99
+ }
100
+ }
101
+ return { plans: plans.sort((a, b) => a.sid.localeCompare(b.sid)), refusals };
102
+ }
@@ -0,0 +1,154 @@
1
+ /** Maintained count plans. Predicates stay typed Rust values, never SQL WHERE
2
+ * fragments. A replacement reads only the old/new scalar inputs by primary key.
3
+ */
4
+ import type { LawGraph, LawStructuralRef } from "./law_graph.js";
5
+ import type { SqliteLayout } from "./sqlite_layout.js";
6
+ import { scalarSlot } from "./sqlite_reads.js";
7
+
8
+ type Nodes = ReadonlyMap<string, LawGraph["nodes"][number]>;
9
+ // Existing projection::CountPred serde representation; not a new predicate VM.
10
+ export type SqliteCountPredicate =
11
+ | { Eq: { field: string; value: string } }
12
+ | { Ne: { field: string; value: string } }
13
+ | { And: SqliteCountPredicate[] }
14
+ | { Or: SqliteCountPredicate[] };
15
+ export interface SqliteCountPlan {
16
+ sid: string;
17
+ name: string;
18
+ groupBy: string[] | null;
19
+ groupColumn: number | null;
20
+ predicate: SqliteCountPredicate | null;
21
+ }
22
+ export interface SqliteCountSnapshot {
23
+ sql: string;
24
+ columns: number;
25
+ fields: { name: string; kind: "string" | "integer"; column: number }[];
26
+ }
27
+ export function planSqliteCounts(
28
+ nodes: Nodes,
29
+ aggregateId: string,
30
+ layout: Pick<SqliteLayout, "table" | "wireType" | "fields">
31
+ ) {
32
+ const plans: SqliteCountPlan[] = [];
33
+ const refusals: { sid: string; reason: string }[] = [];
34
+ const inputs = new Map<string, { kind: "string" | "integer"; sql: string }>();
35
+ const groups = new Map<string, string>();
36
+ for (const read of nodes.values()) {
37
+ if (
38
+ read.kind !== "read" ||
39
+ read.readKind !== "count" ||
40
+ read.of.id !== aggregateId
41
+ )
42
+ continue;
43
+ try {
44
+ const local = new Map<
45
+ string,
46
+ { kind: "string" | "integer"; sql: string }
47
+ >();
48
+ function predicate(
49
+ ref: LawStructuralRef<"predicate">,
50
+ active = new Set<string>()
51
+ ): SqliteCountPredicate {
52
+ if (active.has(ref.id)) throw Error("recursive count predicate");
53
+ const node = nodes.get(ref.id);
54
+ if (node?.kind !== "structural" || node.structuralKind !== "predicate")
55
+ throw Error("missing count predicate node");
56
+ const e = node.expression;
57
+ if (e.kind === "and" || e.kind === "or") {
58
+ const clauses = e.terms.map((t) =>
59
+ predicate(t, new Set(active).add(ref.id))
60
+ );
61
+ return e.kind === "and" ? { And: clauses } : { Or: clauses };
62
+ }
63
+ if (e.kind !== "eq" && e.kind !== "ne")
64
+ throw Error("unsupported count predicate");
65
+ const path = e.field.authoredPath.split(".");
66
+ if (path.length !== 1)
67
+ throw Error("count predicates require an own-aggregate scalar field");
68
+ const slot = layout.fields.find((f) => f.name === path[0]);
69
+ if (!slot) throw Error("unmapped count predicate field");
70
+ const scalar = scalarSlot(slot, []);
71
+ // CountPred currently handles Str/Int only. Do not pretend the DSL's
72
+ // boolean support is correct until the shared old/new evaluator agrees.
73
+ if (scalar.kind !== "string" && scalar.kind !== "integer")
74
+ throw Error(
75
+ "shared count predicate evaluator does not support this scalar kind"
76
+ );
77
+ if (
78
+ scalar.kind === "integer" &&
79
+ (!/^-?\d+$/.test(e.value) ||
80
+ BigInt(e.value) < -(1n << 63n) ||
81
+ BigInt(e.value) >= 1n << 63n)
82
+ )
83
+ throw Error("count predicate integer outside i64");
84
+ local.set(path[0]!, { kind: scalar.kind, sql: scalar.sql });
85
+ const clause = { field: path[0]!, value: e.value };
86
+ return e.kind === "eq" ? { Eq: clause } : { Ne: clause };
87
+ }
88
+ const pred = read.predicate ? predicate(read.predicate) : null;
89
+ const path = read.groupBy?.authoredPath.split(".") ?? null;
90
+ let groupSql: string | undefined;
91
+ if (path) {
92
+ const slot = layout.fields.find((f) => f.name === path[0]);
93
+ if (!slot) throw Error("unmapped count group field");
94
+ const scalar = scalarSlot(slot, path.slice(1));
95
+ if (scalar.kind !== "string")
96
+ throw Error("count group keys must be strings");
97
+ groupSql = scalar.sql;
98
+ }
99
+ // A refused read contributes no inputs to supported maintenance plans.
100
+ for (const [name, value] of local) inputs.set(name, value);
101
+ if (groupSql !== undefined) groups.set(read.entity.sid, groupSql);
102
+ plans.push({
103
+ sid: read.entity.sid,
104
+ name: read.entity.label,
105
+ groupBy: path,
106
+ groupColumn: null,
107
+ predicate: pred,
108
+ });
109
+ } catch (error) {
110
+ refusals.push({ sid: read.entity.sid, reason: (error as Error).message });
111
+ }
112
+ }
113
+ plans.sort((a, b) => a.sid.localeCompare(b.sid));
114
+ if (!plans.length) return { plans, refusals, snapshot: null };
115
+ // c0 is not used; one constant permits predicate-free, ungrouped counts too.
116
+ const expressions = ["1"];
117
+ const fields = [...inputs]
118
+ .sort(([a], [b]) => a.localeCompare(b))
119
+ .map(([name, value]) => {
120
+ const column = expressions.length;
121
+ expressions.push(value.sql);
122
+ return { name, kind: value.kind, column };
123
+ });
124
+ const groupColumns = new Map<string, number>();
125
+ for (const plan of plans) {
126
+ const sql = groups.get(plan.sid);
127
+ if (sql === undefined) continue;
128
+ let column = groupColumns.get(sql);
129
+ if (column === undefined) {
130
+ column = expressions.length;
131
+ expressions.push(sql);
132
+ groupColumns.set(sql, column);
133
+ }
134
+ plan.groupColumn = column;
135
+ }
136
+ if (expressions.length > 2000)
137
+ throw Error("count snapshot exceeds 2000-column SQLite target");
138
+ const type = layout.fields.find((f) => f.name === "__type")!;
139
+ const archive = layout.fields.find((f) => f.name === "__archived")!;
140
+ const literal = `'${layout.wireType.replaceAll("'", "''")}'`;
141
+ return {
142
+ plans,
143
+ refusals,
144
+ snapshot: {
145
+ sql: `SELECT ${expressions.join(",")} FROM ${
146
+ layout.table
147
+ } WHERE id=?1 AND c${type.presence}=2 AND c${
148
+ type.value.column
149
+ }=${literal} AND COALESCE(c${archive.value.column},0)<>1`,
150
+ columns: expressions.length,
151
+ fields,
152
+ } satisfies SqliteCountSnapshot,
153
+ };
154
+ }