@githolon/dsl 0.108.7 → 0.110.1

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 (308) 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 +80 -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 +214 -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 +268 -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 +23950 -15776
  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 +550 -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_event_desk_close_test.dart +16 -0
  74. package/dart/test/reception_span_trace_test.dart +23 -0
  75. package/dart/test/replica_readiness_test.dart +156 -0
  76. package/dart/test/runtime_projections_test.dart +92 -0
  77. package/dart/test/runtime_v2_gateway_test.dart +131 -0
  78. package/dart/test/signing_identity_kernel_test.dart +75 -0
  79. package/dart/test/sync_status_preparation_report_test.dart +29 -0
  80. package/dart/test/sync_status_reducer_test.dart +419 -0
  81. package/dart/test/test_harness_test.dart +71 -95
  82. package/dart/test/typed_query_watch_test.dart +170 -0
  83. package/dart/test/typed_watch_registry_test.dart +249 -0
  84. package/dart_lints/README.md +18 -0
  85. package/dart_lints/lib/nomos_lints.dart +70 -0
  86. package/dart_lints/pubspec.lock +580 -0
  87. package/dart_lints/pubspec.yaml +12 -0
  88. package/dart_lints/test/reference_identity_test.dart +75 -0
  89. package/dart_types/CHANGELOG.md +18 -0
  90. package/dart_types/lib/nomos_kernel_protocol.dart +21 -1
  91. package/dart_types/lib/nomos_types.dart +9 -1
  92. package/dart_types/lib/src/admission_decision.dart +37 -0
  93. package/dart_types/lib/src/aggregate_meta.dart +1 -1
  94. package/dart_types/lib/src/approved_model.dart +65 -0
  95. package/dart_types/lib/src/custody.dart +10 -18
  96. package/dart_types/lib/src/error_info.dart +4 -4
  97. package/dart_types/lib/src/errors.dart +29 -29
  98. package/dart_types/lib/src/foreign_ref.dart +62 -33
  99. package/dart_types/lib/src/local_work_rejected.dart +3 -3
  100. package/dart_types/lib/src/nomos_ref.dart +3 -1
  101. package/dart_types/lib/src/principal.dart +2 -2
  102. package/dart_types/lib/src/proto/google/protobuf/any.pb.dart +163 -0
  103. package/dart_types/lib/src/proto/google/protobuf/any.pbenum.dart +11 -0
  104. package/dart_types/lib/src/proto/nomos/discovery/v1/workspace_placement.pb.dart +137 -0
  105. package/dart_types/lib/src/proto/nomos/discovery/v1/workspace_placement.pbenum.dart +11 -0
  106. package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pb.dart +20721 -10433
  107. package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pbenum.dart +555 -27
  108. package/dart_types/lib/src/proto/nomos/runtime/v2/application_desk.pb.dart +387 -0
  109. package/dart_types/lib/src/proto/nomos/runtime/v2/application_desk.pbenum.dart +46 -0
  110. package/dart_types/lib/src/proto/nomos/runtime/v2/application_readiness_desk.pb.dart +295 -0
  111. package/dart_types/lib/src/proto/nomos/runtime/v2/application_readiness_desk.pbenum.dart +139 -0
  112. package/dart_types/lib/src/proto/nomos/runtime/v2/authentication_desk.pb.dart +269 -0
  113. package/dart_types/lib/src/proto/nomos/runtime/v2/authentication_desk.pbenum.dart +103 -0
  114. package/dart_types/lib/src/proto/nomos/runtime/v2/compatibility_desk.pb.dart +417 -0
  115. package/dart_types/lib/src/proto/nomos/runtime/v2/compatibility_desk.pbenum.dart +62 -0
  116. package/dart_types/lib/src/proto/nomos/runtime/v2/correspondence_desk.pb.dart +9968 -0
  117. package/dart_types/lib/src/proto/nomos/runtime/v2/correspondence_desk.pbenum.dart +133 -0
  118. package/dart_types/lib/src/proto/nomos/runtime/v2/credentials_desk.pb.dart +204 -0
  119. package/dart_types/lib/src/proto/nomos/runtime/v2/credentials_desk.pbenum.dart +54 -0
  120. package/dart_types/lib/src/proto/nomos/runtime/v2/custody_desk.pb.dart +1550 -0
  121. package/dart_types/lib/src/proto/nomos/runtime/v2/custody_desk.pbenum.dart +11 -0
  122. package/dart_types/lib/src/proto/nomos/runtime/v2/framework.pb.dart +710 -0
  123. package/dart_types/lib/src/proto/nomos/runtime/v2/framework.pbenum.dart +11 -0
  124. package/dart_types/lib/src/proto/nomos/runtime/v2/identity_desk.pb.dart +845 -0
  125. package/dart_types/lib/src/proto/nomos/runtime/v2/identity_desk.pbenum.dart +11 -0
  126. package/dart_types/lib/src/proto/nomos/runtime/v2/interaction_desk.pb.dart +198 -0
  127. package/dart_types/lib/src/proto/nomos/runtime/v2/interaction_desk.pbenum.dart +11 -0
  128. package/dart_types/lib/src/proto/nomos/runtime/v2/law_desk.pb.dart +369 -0
  129. package/dart_types/lib/src/proto/nomos/runtime/v2/law_desk.pbenum.dart +11 -0
  130. package/dart_types/lib/src/proto/nomos/runtime/v2/maintenance_desk.pb.dart +609 -0
  131. package/dart_types/lib/src/proto/nomos/runtime/v2/maintenance_desk.pbenum.dart +65 -0
  132. package/dart_types/lib/src/proto/nomos/runtime/v2/model_adoption_desk.pb.dart +358 -0
  133. package/dart_types/lib/src/proto/nomos/runtime/v2/model_adoption_desk.pbenum.dart +100 -0
  134. package/dart_types/lib/src/proto/nomos/runtime/v2/observability_desk.pb.dart +2231 -0
  135. package/dart_types/lib/src/proto/nomos/runtime/v2/observability_desk.pbenum.dart +271 -0
  136. package/dart_types/lib/src/proto/nomos/runtime/v2/placement_desk.pb.dart +1286 -0
  137. package/dart_types/lib/src/proto/nomos/runtime/v2/placement_desk.pbenum.dart +11 -0
  138. package/dart_types/lib/src/proto/nomos/runtime/v2/receiving_group_desk.pb.dart +636 -0
  139. package/dart_types/lib/src/proto/nomos/runtime/v2/receiving_group_desk.pbenum.dart +116 -0
  140. package/dart_types/lib/src/proto/nomos/runtime/v2/records_desk.pb.dart +1637 -0
  141. package/dart_types/lib/src/proto/nomos/runtime/v2/records_desk.pbenum.dart +175 -0
  142. package/dart_types/lib/src/proto/nomos/runtime/v2/recovery_desk.pb.dart +1269 -0
  143. package/dart_types/lib/src/proto/nomos/runtime/v2/recovery_desk.pbenum.dart +129 -0
  144. package/dart_types/lib/src/proto/nomos/runtime/v2/residency_desk.pb.dart +2782 -0
  145. package/dart_types/lib/src/proto/nomos/runtime/v2/residency_desk.pbenum.dart +97 -0
  146. package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pb.dart +2232 -8627
  147. package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pbenum.dart +0 -358
  148. package/dart_types/lib/src/proto/nomos/runtime/v2/sealing_desk.pb.dart +1639 -0
  149. package/dart_types/lib/src/proto/nomos/runtime/v2/sealing_desk.pbenum.dart +46 -0
  150. package/dart_types/lib/src/runtime_outcome.dart +133 -0
  151. package/dart_types/lib/src/subscriptions.dart +116 -23
  152. package/dart_types/pubspec.yaml +1 -1
  153. package/dart_types/test/extremum_subscriptions_test.dart +40 -0
  154. package/dart_types/test/foreign_ref_resolution_test.dart +75 -0
  155. package/dart_types/test/nomos_ref_address_test.dart +25 -0
  156. package/dart_types/test/ordered_subscriptions_test.dart +34 -0
  157. package/operation_contract_check.mjs +24 -0
  158. package/package.json +11 -6
  159. package/src/aggregate.ts +70 -10
  160. package/src/application_topology.ts +18 -11
  161. package/src/attested.ts +3 -0
  162. package/src/attested_core.ts +46 -3
  163. package/src/birth_meter_ensure.ts +19 -7
  164. package/src/births.ts +29 -4
  165. package/src/build_package.ts +140 -13
  166. package/src/business_birth.ts +181 -4
  167. package/src/codegen_call_proto.ts +1276 -0
  168. package/src/codegen_call_usda.ts +49 -6
  169. package/src/codegen_dart.ts +83 -44
  170. package/src/codegen_dart_client.ts +458 -800
  171. package/src/{codegen_dart_application.ts → codegen_dart_facade.ts} +331 -582
  172. package/src/codegen_dart_framework_calls.ts +320 -37
  173. package/src/codegen_dart_indexed_variant.ts +159 -0
  174. package/src/codegen_dart_scenario.ts +42 -13
  175. package/src/codegen_proof.ts +3 -3
  176. package/src/codegen_provider_dart.ts +5 -0
  177. package/src/codegen_query_proto.ts +158 -0
  178. package/src/codegen_refusal.ts +189 -0
  179. package/src/codegen_result_proto.ts +931 -0
  180. package/src/codegen_result_usda.ts +4 -0
  181. package/src/codegen_ts.ts +464 -616
  182. package/src/codegen_workspace_access.ts +105 -0
  183. package/src/compatibility_graph.ts +759 -0
  184. package/src/compatibility_usda.ts +264 -0
  185. package/src/compile_package_main.ts +2017 -1195
  186. package/src/custody_placement.ts +156 -0
  187. package/src/custody_placement_usda.ts +91 -0
  188. package/src/decl_shapes.ts +21 -2
  189. package/src/describe_model.ts +1 -0
  190. package/src/directive.ts +59 -2
  191. package/src/drivers.ts +51 -0
  192. package/src/engine_entry.ts +52 -8
  193. package/src/evolve_preview.ts +11 -4
  194. package/src/exists.ts +2 -0
  195. package/src/fields.ts +75 -11
  196. package/src/flow_gate.ts +2 -1
  197. package/src/framework/application_home.ts +170 -18
  198. package/src/framework/attested_receipts.ts +8 -3
  199. package/src/framework/auth_provider_law.ts +169 -9
  200. package/src/framework/birth_certificate_law.ts +4 -0
  201. package/src/framework/capability.ts +34 -3
  202. package/src/framework/child_authentication.ts +346 -0
  203. package/src/framework/console_governance.ts +295 -0
  204. package/src/framework/delegated_roles.ts +301 -0
  205. package/src/framework/domain_lifecycle.ts +26 -13
  206. package/src/framework/founding_genesis.ts +193 -0
  207. package/src/framework/framework_aggregates.ts +1 -1
  208. package/src/framework/genesis.ts +6 -1
  209. package/src/framework/governance_relations.ts +19 -0
  210. package/src/framework/home.ts +5 -734
  211. package/src/framework/legacy/child_auth_provider_epoch.ts +73 -0
  212. package/src/framework/model_authority_repair.ts +116 -0
  213. package/src/framework/model_authority_seed.ts +185 -0
  214. package/src/framework/model_transition.ts +211 -0
  215. package/src/framework/owned_custody.ts +1 -1
  216. package/src/framework/principal_enrollment.ts +302 -0
  217. package/src/framework/receiving_group.ts +857 -0
  218. package/src/framework/receiving_group_recovery.ts +314 -0
  219. package/src/framework/relations.ts +4 -8
  220. package/src/framework/signing_identity.ts +242 -95
  221. package/src/framework/source_roster.ts +11 -5
  222. package/src/framework/workspace_access.ts +149 -0
  223. package/src/framework/workspace_invariant.ts +73 -52
  224. package/src/framework/workspaces.ts +407 -40
  225. package/src/framework_call_definitions.ts +32 -3
  226. package/src/generated_client_bundle_boundary.ts +97 -0
  227. package/src/generated_client_names.ts +1 -0
  228. package/src/identity_usda.ts +27 -0
  229. package/src/index.ts +183 -12
  230. package/src/indexed_variant.ts +83 -0
  231. package/src/intent.ts +173 -45
  232. package/src/law_check.ts +8 -5
  233. package/src/law_dependency_index.ts +231 -0
  234. package/src/law_graph.ts +508 -71
  235. package/src/law_graph_usda.ts +170 -24
  236. package/src/law_identity.ts +119 -81
  237. package/src/law_source_map.ts +4 -1
  238. package/src/law_units.ts +498 -0
  239. package/src/law_value_type.ts +7 -3
  240. package/src/member_authentication.ts +302 -0
  241. package/src/null_meta.ts +1 -1
  242. package/src/openusd_compiled_layer.ts +132 -0
  243. package/src/operation_contract_check.ts +31 -0
  244. package/src/ordered_read.ts +2 -1
  245. package/src/package_config.ts +33 -12
  246. package/src/package_dependencies.ts +1 -0
  247. package/src/plan_source_slice.ts +30 -1
  248. package/src/protobuf_field_number.ts +36 -0
  249. package/src/provenance_wire.ts +6 -0
  250. package/src/query.ts +2 -1
  251. package/src/read.ts +50 -0
  252. package/src/relation.ts +4 -1
  253. package/src/relation_schema.ts +15 -2
  254. package/src/report.ts +2 -2
  255. package/src/sqlite_computation_bundle.ts +78 -0
  256. package/src/sqlite_computed.ts +102 -0
  257. package/src/sqlite_counts.ts +154 -0
  258. package/src/sqlite_layout.ts +823 -0
  259. package/src/sqlite_reads.ts +275 -0
  260. package/src/sqlite_samples.ts +185 -0
  261. package/src/stable_id_identity_bridge.ts +1 -1
  262. package/src/stable_ids_for_module.ts +16 -4
  263. package/src/test_call_usda.ts +6 -6
  264. package/src/usda_relationship_integrity.ts +20 -3
  265. package/src/usda_text.ts +21 -1
  266. package/src/value_object.ts +81 -11
  267. package/src/wire.ts +22 -0
  268. package/src/wire_encode.ts +227 -20
  269. package/src/workspace_sharding.ts +15 -6
  270. package/src/workspace_sharing.ts +51 -49
  271. package/src/zod_introspection.ts +2 -0
  272. package/compat_package.mjs +0 -46
  273. package/dart/lib/src/home.dart +0 -15
  274. package/dart/lib/src/runner/offline-install.mjs +0 -15367
  275. package/dart/lib/src/source_trust.dart +0 -51
  276. package/dart/lib/src/webview_bridge.dart +0 -6540
  277. package/dart/lib/src/workspace_name.dart +0 -30
  278. package/dart/test/acquire_session_credentials_test.dart +0 -150
  279. package/dart/test/acquire_session_test.dart +0 -534
  280. package/dart/test/adv_realm_interference_test.dart +0 -600
  281. package/dart/test/cloud_bound_topology_test.dart +0 -168
  282. package/dart/test/cluster_births_test.dart +0 -202
  283. package/dart/test/cluster_device_keyed_acceptance_test.dart +0 -105
  284. package/dart/test/cluster_local_autosync_test.dart +0 -123
  285. package/dart/test/cluster_scale_test.dart +0 -122
  286. package/dart/test/compat_test.dart +0 -61
  287. package/dart/test/dlq_session_surface_test.dart +0 -222
  288. package/dart/test/first_app_gauntlet_test.dart +0 -386
  289. package/dart/test/fixtures/wedge/fake-install.mjs +0 -11
  290. package/dart/test/four_layer_nested_topology_test.dart +0 -290
  291. package/dart/test/home_parity_test.dart +0 -13
  292. package/dart/test/local_sync_inert_test.dart +0 -107
  293. package/dart/test/node_runner_transport_test.dart +0 -78
  294. package/dart/test/parent_signer_recovery_test.dart +0 -155
  295. package/dart/test/residency_refusal_test.dart +0 -49
  296. package/dart/test/sealing_client_test.dart +0 -181
  297. package/dart/test/session_bound_test.dart +0 -285
  298. package/dart/test/stale_bundle_test.dart +0 -80
  299. package/dart/test/vo_read_typing_test.dart +0 -131
  300. package/dart/test/watch_after_offer_stall_test.dart +0 -100
  301. package/dart/test/webview_bridge_test.dart +0 -1930
  302. package/dart/test/workspace_name_test.dart +0 -24
  303. package/runtime/generated-application-host.js +0 -22860
  304. package/src/codegen_query_usda.ts +0 -214
  305. package/src/compat_manifest.ts +0 -26
  306. package/src/compat_package_main.ts +0 -224
  307. package/src/shape_compat.ts +0 -352
  308. package/src/usd_state.ts +0 -505
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Upgrade existing children from the former `child` epoch gate to the explicit
3
+ * epoch-consumer seat. New framework births already write that seat.
4
+ *
5
+ * This is an operator-authorised parent-local change, not device recovery and
6
+ * not a kernel exception. It uses canonical birth/lifecycle custody, never a
7
+ * tenant catalogue or a caller-supplied certificate. An explicit revocation is
8
+ * not a missing migration: neither it nor a withdrawn child may be resurrected.
9
+ * Remove this compatibility operation only after existing children are migrated.
10
+ */
11
+ import { z } from "zod";
12
+ import { directive, nomosImplementationDetail } from "../../directive.js";
13
+ import { authenticatesWithEnrolledDevice, intent } from "../../intent.js";
14
+ import { readFrameworkDeclaredRows } from "../../read.js";
15
+ import { AUTH_PROVIDER_EPOCH_CONSUMER } from "../auth_provider_law.js";
16
+ import {
17
+ NomosBirthRecord,
18
+ NomosChildLifecycle,
19
+ birthRecordsByPrincipal,
20
+ childLifecyclesByPrincipal,
21
+ } from "../birth_meter.js";
22
+ import { MODEL_LIFECYCLE_AUTHORITY } from "../domain_lifecycle.js";
23
+ import { RelationTuple, relationTuplesByObject, writeTuple } from "../relations.js";
24
+
25
+ export const REPAIR_CHILD_AUTH_PROVIDER_EPOCH_CONSUMER_ID =
26
+ "nomosInternalRepairChildAuthProviderEpochConsumer7c1f5e";
27
+
28
+ const repairMissingChildEpochConsumer = nomosImplementationDetail(
29
+ directive("nomosInternalRepairMissingChildEpochConsumer7c1f5e")
30
+ .ensures(RelationTuple)
31
+ .payload(z.object({ child: z.string().min(1), principal: z.string().min(1) }).strict())
32
+ .plan(({ child, principal }, ctx) => {
33
+ const births = readFrameworkDeclaredRows(birthRecordsByPrincipal, NomosBirthRecord, { principal })
34
+ .filter((birth) => birth.child === child && birth.principal === principal);
35
+ if (births.length !== 1 || !/^[0-9a-f]{64}$/.test(births[0]!.childGenesisHash ?? "")) {
36
+ throw new Error("epoch-consumer repair requires one canonical birth for the exact child and principal");
37
+ }
38
+ const lifecycles = readFrameworkDeclaredRows(childLifecyclesByPrincipal, NomosChildLifecycle, { principal })
39
+ .filter((lifecycle) => lifecycle.child === child);
40
+ if (lifecycles.some((lifecycle) => lifecycle.status !== "active")) {
41
+ throw new Error("epoch-consumer repair cannot restore a retired or reclaimed child");
42
+ }
43
+ const subject = `workspace:${births[0]!.child}`;
44
+ const tuples = readFrameworkDeclaredRows(relationTuplesByObject, RelationTuple, { object: "workspace:self" })
45
+ .filter((tuple) => tuple.object === "workspace:self");
46
+ const childGrants = tuples.filter((tuple) => tuple.relation === "child")
47
+ .flatMap((tuple) => tuple.subjects?.[subject] ? [tuple.subjects[subject]!] : []);
48
+ const epochGrants = tuples.filter((tuple) => tuple.relation === AUTH_PROVIDER_EPOCH_CONSUMER)
49
+ .flatMap((tuple) => tuple.subjects?.[subject] ? [tuple.subjects[subject]!] : []);
50
+ if ([...childGrants, ...epochGrants].some((grant) => grant.status !== "active")) {
51
+ throw new Error("epoch-consumer repair cannot overwrite an explicit child or consumer revocation");
52
+ }
53
+ // A repeat is a real no-op: preserve original grant provenance as well as
54
+ // every other child's seat. Never replace the entire subjects map.
55
+ if (epochGrants.length > 0) return [];
56
+ return writeTuple({
57
+ object: "workspace:self",
58
+ relation: AUTH_PROVIDER_EPOCH_CONSUMER,
59
+ subject,
60
+ grantedBy: ctx.principal().asAttribution(),
61
+ grantedAt: String(ctx.clock().physical),
62
+ });
63
+ })
64
+ .reads(birthRecordsByPrincipal, childLifecyclesByPrincipal, relationTuplesByObject)
65
+ // Gate the step itself too: presentation-internal is not an authority boundary.
66
+ .requires(MODEL_LIFECYCLE_AUTHORITY, { object: "workspace:self" }),
67
+ );
68
+
69
+ export const repairChildAuthProviderEpochConsumer = nomosImplementationDetail(
70
+ authenticatesWithEnrolledDevice(
71
+ intent(REPAIR_CHILD_AUTH_PROVIDER_EPOCH_CONSUMER_ID).performs(repairMissingChildEpochConsumer),
72
+ ),
73
+ );
@@ -0,0 +1,116 @@
1
+ // NOMOS — Nomos Sovereign: participants act · verify · remember LOCALLY; hosted
2
+ // remotes are replaceable custody/transport, not truth. ⇒ ONE Nomos GitHolon
3
+ // wasm32-wasip1 artifact {kernel · projection · embedded QuickJS engine}.
4
+ // If a file isn't this / hosting this / authoring for this / proving this — it's gone.
5
+
6
+ /**
7
+ * THE MODEL-AUTHORITY SELF-SEAT — a workspace's own model-lifecycle holder names who else may install
8
+ * law here. ONE directive, one gate, no handshake.
9
+ *
10
+ * Design: `architecture/parent_directed_model_transition.md` §9. Lane A seats the platform's holders in
11
+ * a child's GENESIS (`model_authority_seed.ts`); lane B seats them when the platform DIRECTS a
12
+ * transition (`model_transition.ts`). Both are forward-looking, and lane B's entry needs an operator who
13
+ * can author on the platform. The population neither reaches is the one that already exists: a workspace
14
+ * born before lane A whose platform never directed it, holding exactly one `workspace:self#installDomain`
15
+ * subject — its founder, the signed-in person. As the product owner put it: a platform whose every act
16
+ * still needs that person's device key does not hold authority, it holds an ask with a stamp.
17
+ *
18
+ * WHY THIS IS ONE DIRECTIVE AND NOT A HANDSHAKE. It was built first as a child-asks / parent-answers /
19
+ * child-accepts round trip, so the holders could be derived by parent law rather than supplied. That
20
+ * defends against a threat that does not exist: the founder already holds `installDomain` here and can
21
+ * therefore install ANY law into this workspace, including law that seats anyone. A directive that lets
22
+ * that same founder seat a named subject grants no privilege they do not already hold — the "attacker"
23
+ * would be the sole owner of the thing attacked. Every mechanism added to route around that was cost
24
+ * with no security return, and it was precisely what excluded the workspaces this exists to reach: the
25
+ * parent's `workspace:self#child` tuple is only written by births after 2026-09-11, and both live
26
+ * production receiving groups check `allowed: false` for it.
27
+ *
28
+ * THE GATE IS THE WHOLE ARGUMENT: {@link MODEL_LIFECYCLE_AUTHORITY} on `workspace:self`, and nothing
29
+ * else. Whoever may install law here may say who else may.
30
+ *
31
+ * THE EFFECT IS THE BIRTH SEED'S. {@link seatInheritedModelAuthorityOps} is shared by the genesis seed,
32
+ * the parent-directed acceptor and this directive, so a seeded, a directed and a self-seated workspace
33
+ * are indistinguishable afterwards. Idempotent by construction: `writeTuple`'s first op is `ensures` and
34
+ * the subject rides a `setEntry` on the same subject key, so a re-run writes the same tuple; the record
35
+ * is one constant-id row whose fields are Lww/AddWins. Only `grantedAt`/`seatedAt` move, which is what
36
+ * re-attesting a fact does.
37
+ */
38
+ import { aggregate, instance } from "../aggregate.js";
39
+ import { directive, nomosImplementationDetail } from "../directive.js";
40
+ import { AddWins, Lww } from "../drivers.js";
41
+ import { t } from "../fields.js";
42
+ import { intent } from "../intent.js";
43
+ import { addToSet, set, withMarker, type PlannedOp } from "../ops.js";
44
+ import { MODEL_LIFECYCLE_AUTHORITY } from "./domain_lifecycle.js";
45
+ import {
46
+ inheritedModelAuthorityEvidence,
47
+ seatInheritedModelAuthorityOps,
48
+ type InheritedModelAuthorityEvidence,
49
+ } from "./model_authority_seed.js";
50
+ import { RelationTuple } from "./relations.js";
51
+
52
+ /** Wire ids — framework-internal, obscure on purpose (the 7c1f5e suffix convention). */
53
+ export const SEAT_MODEL_AUTHORITY_ID = "nomosInternalSeatModelAuthority7c1f5e";
54
+ export const SEAT_DECLARED_MODEL_AUTHORITY_ID = "nomosInternalSeatDeclaredModelAuthority7c1f5e";
55
+ export const RECORD_MODEL_AUTHORITY_SEAT_ID = "nomosInternalRecordModelAuthoritySeat7c1f5e";
56
+ export const PARENT_MODEL_AUTHORITY_SEAT_AGGREGATE = "nomos_internal_ParentModelAuthoritySeat_7c1f5e";
57
+ /** A CONSTANT instance id (the RelationTuple discipline — a literal, never minted), so every peer reads
58
+ * the same address and a client can ask for it by id with nothing compiled in but this string. */
59
+ export const PARENT_MODEL_AUTHORITY_SEAT_ID = "nomos-parent-model-authority-seat";
60
+
61
+ /** THE IN-HISTORY RECORD that this workspace has seated model-lifecycle authority beyond its founder,
62
+ * and the peer-readable answer to "has this workspace been seated yet". One row, one constant id. */
63
+ export const ParentModelAuthoritySeat = aggregate(PARENT_MODEL_AUTHORITY_SEAT_AGGREGATE, {
64
+ /** The model-lifecycle holders seated (`user:`/`key:` subjects). */
65
+ holders: t.set(t.string()).merge(AddWins),
66
+ seatedAt: t.string().merge(Lww),
67
+ }).public();
68
+
69
+ /** Seat the named holders — THE VERY OPS the genesis seed writes, so a seeded, a directed and a
70
+ * self-seated workspace are indistinguishable afterwards. */
71
+ export const seatDeclaredModelAuthority = nomosImplementationDetail(
72
+ directive(SEAT_DECLARED_MODEL_AUTHORITY_ID)
73
+ .ensures(RelationTuple)
74
+ .payload(inheritedModelAuthorityEvidence)
75
+ .plan((evidence, ctx) => seatInheritedModelAuthorityOps(evidence, ctx.principal().asAttribution())),
76
+ );
77
+
78
+ /** Record the seat, so a peer can tell "already seated" from one by-id read. */
79
+ export const recordModelAuthoritySeat = nomosImplementationDetail(
80
+ directive(RECORD_MODEL_AUTHORITY_SEAT_ID)
81
+ .ensures(ParentModelAuthoritySeat)
82
+ .payload(inheritedModelAuthorityEvidence)
83
+ .plan((evidence: InheritedModelAuthorityEvidence): PlannedOp[] => {
84
+ const row = instance(ParentModelAuthoritySeat, PARENT_MODEL_AUTHORITY_SEAT_ID);
85
+ return [
86
+ withMarker(set(row, "seatedAt", evidence.seatedAt), "ensures"),
87
+ addToSet(row, "holders", evidence.holders.map((holder) => holder.principal)),
88
+ ];
89
+ }),
90
+ );
91
+
92
+ /**
93
+ * THE SELF-SEAT. Gated on THIS workspace's own model-lifecycle seat — the founder/admin principal
94
+ * `seedGenesis` wrote — and on nothing else. Seat and record are ONE atomic transition.
95
+ */
96
+ export const seatModelAuthority = nomosImplementationDetail(
97
+ intent(SEAT_MODEL_AUTHORITY_ID)
98
+ .contract({ accepts: inheritedModelAuthorityEvidence })
99
+ .directs(seatDeclaredModelAuthority, (evidence) => evidence)
100
+ .directs(recordModelAuthoritySeat, (evidence) => evidence)
101
+ .requires(MODEL_LIFECYCLE_AUTHORITY, { object: "workspace:self" })
102
+ .atomically(),
103
+ );
104
+
105
+ /**
106
+ * The export map the application-home policy law composes (keys are the obscure `__nomos_*` slots;
107
+ * values are THE singletons — the law graph folds an intent's step closure by object identity). The two
108
+ * consequences ride only the intent's step closure, as `child_authentication.ts` carries its gated
109
+ * acceptor effect.
110
+ */
111
+ export function modelAuthorityRepairExports(): Readonly<Record<string, object>> {
112
+ return {
113
+ __nomos_ParentModelAuthoritySeat: ParentModelAuthoritySeat,
114
+ __nomos_seatModelAuthority: seatModelAuthority,
115
+ };
116
+ }
@@ -0,0 +1,185 @@
1
+ // NOMOS — Nomos Sovereign: participants act · verify · remember LOCALLY; hosted
2
+ // remotes are replaceable custody/transport, not truth. ⇒ ONE Nomos GitHolon
3
+ // wasm32-wasip1 artifact {kernel · projection · embedded QuickJS engine}.
4
+ // If a file isn't this / hosting this / authoring for this / proving this — it's gone.
5
+
6
+ /**
7
+ * INHERITED MODEL AUTHORITY — the platform's own signer holds `installDomain` on every descendant.
8
+ *
9
+ * The authority model (`architecture/parent_directed_model_transition.md` §2): the framework holds no
10
+ * seat in a tenant workspace and the host holds none; the TENANT PLATFORM holds full model authority
11
+ * over its subtree; a user holds their own device seat. Until this module every child was born with
12
+ * exactly one `workspace:self#installDomain` holder — its founder (`seedGenesis`) — so the platform's
13
+ * operator could not lawfully install law into a child it had birthed.
14
+ *
15
+ * THE SEED. Every framework birth recipe (the receiving-group birth and the business `birth()`) reads
16
+ * the parent's committed model-lifecycle holders — the active `user:`/`key:` subjects of
17
+ * `workspace:self#installDomain` — and, for each `user:` holder, its active signer keys from
18
+ * `identity:<holder>#signer`, and embeds ONE genesis step that seats the same facts in the child. The
19
+ * read is the declared `relationTuplesByObject` query (captured, CAS-re-derived on every lane), the
20
+ * same idiom by which a birth copies the parent's verifier (`seedAuthProvider`). Authority therefore
21
+ * DESCENDS BY INDUCTION: a home inherits the platform's holders, an estate inherits the home's (the
22
+ * owner and the platform's operators). Root → platform is deliberately outside this lane.
23
+ *
24
+ * THE POSTURE. The seed carries no `.requires` (it runs on the warrant-free genesis prefix, like every
25
+ * child-genesis primitive) and is refused once the GenesisWarrant exists
26
+ * ({@link modelAuthoritySeedBeforeWarrant}, the `authProviderSeedBeforeWarrant` shape). After birth
27
+ * the ONLY way these seats enter a child is the parent-directed transition acceptor
28
+ * (`model_transition.ts`), admitted on the attested parent's cert chain.
29
+ *
30
+ * Signer leaves are carried VERBATIM (`grantedAt`, `verifiedVia`, `validFromEpoch`): provenance is
31
+ * preserved, never re-vouched. The relation schema already admits `user:`/`key:` subjects on
32
+ * `installDomain` (`modelLifecycleRelations`) and `key:` subjects on `signer` (`identityRelations`);
33
+ * nothing here changes a schema.
34
+ */
35
+ import { z } from "zod";
36
+ import { directive, nomosImplementationDetail } from "../directive.js";
37
+ import type { PlannedOp } from "../ops.js";
38
+ import type { AttributionPrincipal } from "../principal_evidence.js";
39
+ import { readFrameworkDeclaredRows } from "../read.js";
40
+ import { MODEL_LIFECYCLE_AUTHORITY } from "./domain_lifecycle.js";
41
+ import { GENESIS_WARRANT_ID } from "./genesis.js";
42
+ import { RelationTuple, relationTuplesByObject, writeTuple } from "./relations.js";
43
+ import { SIGNER_RELATION, signerObject } from "./signing_identity.js";
44
+ import { readRef, readSet, workspaceInvariant } from "./workspace_invariant.js";
45
+
46
+ /** Wire id — framework-internal, obscure on purpose (the 7c1f5e suffix convention). */
47
+ export const SEAT_INHERITED_MODEL_AUTHORITY_ID = "nomosInternalSeatInheritedModelAuthority7c1f5e";
48
+
49
+ const principalSubject = z.string().regex(/^(user|key):[A-Za-z0-9][A-Za-z0-9_.:/-]*$/);
50
+ const deviceKeySubject = z.string().regex(/^key:[0-9a-f]{64}$/);
51
+
52
+ /** One active signer leaf of a holder, carried verbatim from the parent's committed signer relation. */
53
+ export const inheritedSignerLeaf = z
54
+ .object({
55
+ deviceKeySubject,
56
+ grantedAt: z.string().min(1),
57
+ verifiedVia: z.string().min(1).optional(),
58
+ validFromEpoch: z.number().int().nonnegative().optional(),
59
+ })
60
+ .strict();
61
+
62
+ /** One model-lifecycle holder of the parent and the devices that may author as it. A `key:` holder
63
+ * self-authenticates and carries no signer leaves. */
64
+ export const inheritedModelAuthorityHolder = z
65
+ .object({
66
+ principal: principalSubject,
67
+ signers: z.array(inheritedSignerLeaf),
68
+ })
69
+ .strict();
70
+
71
+ /** The exact typed evidence a parent discloses: its current holders, and when it read them. */
72
+ export const inheritedModelAuthorityEvidence = z
73
+ .object({
74
+ holders: z.array(inheritedModelAuthorityHolder).min(1),
75
+ /** Caller-stamped (ISO-8601 or epoch string) — the timestamp doctrine; the plan reads no clock. */
76
+ seatedAt: z.string().min(1),
77
+ })
78
+ .strict();
79
+ export type InheritedModelAuthorityEvidence = z.infer<typeof inheritedModelAuthorityEvidence>;
80
+ export type InheritedModelAuthorityHolder = z.infer<typeof inheritedModelAuthorityHolder>;
81
+
82
+ /**
83
+ * Read THIS workspace's current model-lifecycle holders and their active devices. Returns `undefined`
84
+ * when the workspace holds no `installDomain` tuple row (a chain born before the seat existed), so a
85
+ * birth plan can omit the step rather than seed an empty list. Deterministic: both reads are declared
86
+ * captured reads and the output is sorted by subject.
87
+ */
88
+ export function readInheritedModelAuthority(): InheritedModelAuthorityHolder[] | undefined {
89
+ const rows = readFrameworkDeclaredRows(relationTuplesByObject, RelationTuple, { object: "workspace:self" });
90
+ const authority = rows.find(
91
+ (row) => row.object === "workspace:self" && row.relation === MODEL_LIFECYCLE_AUTHORITY,
92
+ );
93
+ if (authority === undefined) return undefined;
94
+ const principals = Object.entries(authority.subjects ?? {})
95
+ .filter(([subject, leaf]) => /^(user|key):/.test(subject) && leaf.status === "active")
96
+ .map(([subject]) => subject)
97
+ .sort();
98
+ if (principals.length === 0) return undefined;
99
+ return principals.map((principal) => {
100
+ if (!principal.startsWith("user:")) return { principal, signers: [] };
101
+ const signerRows = readFrameworkDeclaredRows(relationTuplesByObject, RelationTuple, {
102
+ object: signerObject(principal),
103
+ });
104
+ const signers = signerRows
105
+ .filter((row) => row.object === signerObject(principal) && row.relation === SIGNER_RELATION)
106
+ .flatMap((row) =>
107
+ Object.entries(row.subjects ?? {})
108
+ .filter(([subject, leaf]) => subject.startsWith("key:") && leaf.status === "active")
109
+ .map(([subject, leaf]) =>
110
+ inheritedSignerLeaf.parse({
111
+ deviceKeySubject: subject,
112
+ grantedAt: leaf.grantedAt,
113
+ ...(leaf.verifiedVia === undefined ? {} : { verifiedVia: leaf.verifiedVia }),
114
+ ...(leaf.validFromEpoch === undefined ? {} : { validFromEpoch: leaf.validFromEpoch }),
115
+ }),
116
+ ),
117
+ )
118
+ .sort((left, right) => left.deviceKeySubject.localeCompare(right.deviceKeySubject));
119
+ return { principal, signers };
120
+ });
121
+ }
122
+
123
+ /** The ops that seat one disclosed holder set: `workspace:self#installDomain@<holder>` and, per device,
124
+ * `identity:<holder>#signer@key:…`. Shared by the genesis seed and the parent-directed acceptor. */
125
+ export function seatInheritedModelAuthorityOps(
126
+ evidence: InheritedModelAuthorityEvidence,
127
+ grantedBy: string | AttributionPrincipal,
128
+ ): PlannedOp[] {
129
+ return evidence.holders.flatMap((holder) => [
130
+ ...writeTuple({
131
+ object: "workspace:self",
132
+ relation: MODEL_LIFECYCLE_AUTHORITY,
133
+ subject: holder.principal,
134
+ grantedBy,
135
+ grantedAt: evidence.seatedAt,
136
+ }),
137
+ ...holder.signers.flatMap((leaf) =>
138
+ writeTuple({
139
+ object: signerObject(holder.principal),
140
+ relation: SIGNER_RELATION,
141
+ subject: leaf.deviceKeySubject,
142
+ grantedBy,
143
+ grantedAt: leaf.grantedAt,
144
+ ...(leaf.verifiedVia === undefined ? {} : { verifiedVia: leaf.verifiedVia }),
145
+ ...(leaf.validFromEpoch === undefined ? {} : { validFromEpoch: leaf.validFromEpoch }),
146
+ }),
147
+ ),
148
+ ]);
149
+ }
150
+
151
+ /** THE GENESIS SEED: the child seats its parent's model-lifecycle holders as its own. */
152
+ export const seatInheritedModelAuthority = nomosImplementationDetail(
153
+ directive(SEAT_INHERITED_MODEL_AUTHORITY_ID)
154
+ .ensures(RelationTuple)
155
+ .payload(inheritedModelAuthorityEvidence)
156
+ .plan((evidence, ctx) => seatInheritedModelAuthorityOps(evidence, ctx.principal().asAttribution())),
157
+ );
158
+
159
+ /** A child-genesis primitive: refused once the GenesisWarrant exists. After birth the seats enter only
160
+ * through the parent-directed transition acceptor, admitted on the attested parent's cert chain. */
161
+ export const modelAuthoritySeedBeforeWarrant = workspaceInvariant("ModelAuthoritySeedBeforeWarrant")
162
+ .on(SEAT_INHERITED_MODEL_AUTHORITY_ID)
163
+ .reads(readSet(readRef("warrant", "GenesisWarrant").at(GENESIS_WARRANT_ID)))
164
+ .assert(({ warrant }) => {
165
+ const principal = (warrant as { principal?: unknown } | null | undefined)?.principal;
166
+ return typeof principal !== "string" || principal.length === 0
167
+ ? { accept: true }
168
+ : { reject: "inherited model authority is seated at genesis or by the parent-directed transition, never by a bare offer" };
169
+ });
170
+
171
+ /** Build the genesis step a birth recipe embeds, or `undefined` when the parent holds no seat to pass on. */
172
+ export function inheritedModelAuthorityGenesisStep(
173
+ domain: string,
174
+ actor: string,
175
+ seatedAt: string,
176
+ ): { domain: string; directiveId: string; actor: string; payload: Record<string, unknown> } | undefined {
177
+ const holders = readInheritedModelAuthority();
178
+ if (holders === undefined) return undefined;
179
+ return {
180
+ domain,
181
+ directiveId: SEAT_INHERITED_MODEL_AUTHORITY_ID,
182
+ actor,
183
+ payload: inheritedModelAuthorityEvidence.parse({ holders, seatedAt }),
184
+ };
185
+ }
@@ -0,0 +1,211 @@
1
+ // NOMOS — Nomos Sovereign: participants act · verify · remember LOCALLY; hosted
2
+ // remotes are replaceable custody/transport, not truth. ⇒ ONE Nomos GitHolon
3
+ // wasm32-wasip1 artifact {kernel · projection · embedded QuickJS engine}.
4
+ // If a file isn't this / hosting this / authoring for this / proving this — it's gone.
5
+
6
+ /**
7
+ * PARENT-DIRECTED MODEL TRANSITION — the platform adopts once and DIRECTS the transition into each
8
+ * child; the child accepts it on the strength of its attested parent, with no device signature.
9
+ *
10
+ * Design: `architecture/parent_directed_model_transition.md`. Two halves, both framework law composed
11
+ * into the application-home domain whenever a package births children (the same era rule as child
12
+ * authentication), so the parent door and the child acceptor are one exported pair in one module:
13
+ *
14
+ * THE CHILD ACCEPTOR ({@link acceptParentModelTransition}) — a recovery-door intent
15
+ * (`acceptsVerifiedBirthParentRecoveryEffect`): the kernel admits the carried effect only when the
16
+ * verified source workspace IS this workspace's persisted birth parent. It atomically records the
17
+ * direction in the child's own chain ({@link ParentModelTransition}: "my parent directed model X for
18
+ * domain D") and seats the parent's current model-lifecycle holders + their devices exactly as the
19
+ * birth seed does — so a child born before the seat existed heals itself on its first direction.
20
+ *
21
+ * THE PLATFORM DIRECTION ({@link directChildModelTransition}) — gated on the platform's own
22
+ * `workspace:self#installDomain` (whoever may install law here may direct it into a child); it
23
+ * addresses ONE exact child from its typed input and derives every payload member from the
24
+ * platform's committed state, so no caller can make a child seat a subject the platform does not hold.
25
+ *
26
+ * WHY THE ACCEPTOR DOES NOT STAGE/PROMOTE ITSELF (yet): the kernel keys the model lifecycle by the
27
+ * nominal labels `nomos/stageDomain` / `nomos/promoteDomain`, needs the closure bytes at the author
28
+ * lane and a frontier transition proved at the child's own head — none of which a carried effect
29
+ * supplies today (design §3, §7 scopes the kernel lane). Until then the direction is the RECORD and the
30
+ * SEAT; the platform's signer — now lawful on the child — stages and promotes through the ordinary
31
+ * signed lifecycle offers (`githolon model adopt <platform> --children`).
32
+ */
33
+ import { z } from "zod";
34
+ import { aggregate, instance } from "../aggregate.js";
35
+ import { directive, nomosImplementationDetail } from "../directive.js";
36
+ import { AddWins, Lww } from "../drivers.js";
37
+ import { sha256Digest, t } from "../fields.js";
38
+ import { intent } from "../intent.js";
39
+ import { addToSet, set, withMarker, type PlannedOp } from "../ops.js";
40
+ import { readFrameworkDeclaredRows } from "../read.js";
41
+ import { MODEL_LIFECYCLE_AUTHORITY } from "./domain_lifecycle.js";
42
+ import { verifiedBirthAttestation } from "./child_authentication.js";
43
+ import {
44
+ inheritedModelAuthorityEvidence,
45
+ readInheritedModelAuthority,
46
+ seatInheritedModelAuthorityOps,
47
+ } from "./model_authority_seed.js";
48
+ import { BirthAttestation } from "./receiving_group.js";
49
+ import { RelationTuple, relationTuplesByObject } from "./relations.js";
50
+
51
+ /** Wire ids — framework-internal, obscure on purpose (the 7c1f5e suffix convention). */
52
+ export const ACCEPT_PARENT_MODEL_TRANSITION_ID = "nomosInternalAcceptParentModelTransition7c1f5e";
53
+ export const DIRECT_CHILD_MODEL_TRANSITION_ID = "nomosInternalDirectChildModelTransition7c1f5e";
54
+ export const RECORD_PARENT_MODEL_TRANSITION_ID = "nomosInternalRecordParentModelTransition7c1f5e";
55
+ export const SEAT_PARENT_MODEL_AUTHORITY_ID = "nomosInternalSeatParentModelAuthority7c1f5e";
56
+ export const PARENT_MODEL_TRANSITION_AGGREGATE = "nomos_internal_ParentModelTransition_7c1f5e";
57
+ export const PARENT_MODEL_TRANSITION_PREFIX = "nomos-parent-model-transition:";
58
+
59
+ /** The transition a parent directs: which package, for which domain key, and why. The executing
60
+ * transition (stage + promote) is kernel-judged in full on the child; this names it. */
61
+ export const modelTransitionDirection = z
62
+ .object({
63
+ domain: z.string().min(1),
64
+ candidateHash: sha256Digest(),
65
+ supersedes: sha256Digest().optional(),
66
+ acceptanceReason: z.string().trim().min(1),
67
+ /** Caller-stamped (ISO-8601) — the timestamp doctrine. */
68
+ directedAt: z.string().min(1),
69
+ })
70
+ .strict();
71
+ export type ModelTransitionDirection = z.infer<typeof modelTransitionDirection>;
72
+
73
+ /** What the child accepts: the direction plus the parent's current model-lifecycle holders. Every
74
+ * member is derived by parent law from committed parent state, never supplied by a caller. */
75
+ export const parentModelTransitionEvidence = z
76
+ .object({
77
+ direction: modelTransitionDirection,
78
+ authority: inheritedModelAuthorityEvidence,
79
+ })
80
+ .strict();
81
+ export type ParentModelTransitionEvidence = z.infer<typeof parentModelTransitionEvidence>;
82
+
83
+ /** The platform's typed call: the exact child and the transition to direct. */
84
+ export const directChildModelTransitionInput = z
85
+ .object({
86
+ workspace: z.string().min(1),
87
+ domain: z.string().min(1),
88
+ candidateHash: sha256Digest(),
89
+ supersedes: sha256Digest().optional(),
90
+ acceptanceReason: z.string().trim().min(1),
91
+ directedAt: z.string().min(1),
92
+ })
93
+ .strict();
94
+ export type DirectChildModelTransitionInput = z.infer<typeof directChildModelTransitionInput>;
95
+
96
+ /** The child's in-history record of a direction: one row per (domain, candidate). */
97
+ export const ParentModelTransition = aggregate(PARENT_MODEL_TRANSITION_AGGREGATE, {
98
+ domain: t.string().merge(Lww),
99
+ candidateHash: t.sha256Digest().merge(Lww),
100
+ supersedes: t.sha256Digest().merge(Lww).optional(),
101
+ acceptanceReason: t.string().merge(Lww),
102
+ /** The verified birth parent that directed it (`workspace:<parent>`), derived from this workspace's
103
+ * own BirthAttestation — never from the payload. */
104
+ directedBy: t.string().merge(Lww),
105
+ directedAt: t.string().merge(Lww),
106
+ /** The model-lifecycle holders seated alongside the record. */
107
+ seatedHolders: t.set(t.string()).merge(AddWins),
108
+ }).public();
109
+
110
+ export function parentModelTransitionAggregateId(domain: string, candidateHash: string): string {
111
+ return `${PARENT_MODEL_TRANSITION_PREFIX}${domain}:${candidateHash}`;
112
+ }
113
+
114
+ function verifiedBirthParentId(): string {
115
+ const births = readFrameworkDeclaredRows(verifiedBirthAttestation, BirthAttestation, { verified: "true" });
116
+ if (births.length !== 1) {
117
+ throw new Error(`a parent-directed model transition requires exactly one verified BirthAttestation; found ${births.length}`);
118
+ }
119
+ const birth = births[0]!;
120
+ if (birth.verified !== "true" || !birth.parentId?.trim()) {
121
+ throw new Error("a parent-directed model transition requires a verified non-root parent");
122
+ }
123
+ return birth.parentId;
124
+ }
125
+
126
+ // ── CHILD SIDE ─────────────────────────────────────────────────────────────────────────────────
127
+
128
+ /** Record the direction under the verified birth parent's name. */
129
+ export const recordParentModelTransition = nomosImplementationDetail(
130
+ directive(RECORD_PARENT_MODEL_TRANSITION_ID)
131
+ .ensures(ParentModelTransition)
132
+ .payload(parentModelTransitionEvidence)
133
+ .plan(({ direction, authority }): PlannedOp[] => {
134
+ const row = instance(ParentModelTransition, parentModelTransitionAggregateId(direction.domain, direction.candidateHash));
135
+ return [
136
+ withMarker(set(row, "domain", direction.domain), "ensures"),
137
+ set(row, "candidateHash", direction.candidateHash),
138
+ ...(direction.supersedes === undefined ? [] : [set(row, "supersedes", direction.supersedes)]),
139
+ set(row, "acceptanceReason", direction.acceptanceReason),
140
+ set(row, "directedBy", `workspace:${verifiedBirthParentId()}`),
141
+ set(row, "directedAt", direction.directedAt),
142
+ addToSet(row, "seatedHolders", authority.holders.map((holder) => holder.principal)),
143
+ ];
144
+ })
145
+ .reads(verifiedBirthAttestation),
146
+ );
147
+
148
+ /** Seat the parent's disclosed holders — the same ops the genesis seed writes. */
149
+ export const seatParentModelAuthority = nomosImplementationDetail(
150
+ directive(SEAT_PARENT_MODEL_AUTHORITY_ID)
151
+ .ensures(RelationTuple)
152
+ .payload(parentModelTransitionEvidence)
153
+ .plan(({ authority }, ctx) => seatInheritedModelAuthorityOps(authority, ctx.principal().asAttribution())),
154
+ );
155
+
156
+ /** THE ACCEPTOR: admitted through the verified-birth-parent door; record + seat are ONE transition. */
157
+ export const acceptParentModelTransition = nomosImplementationDetail(
158
+ intent(ACCEPT_PARENT_MODEL_TRANSITION_ID)
159
+ .contract({ accepts: parentModelTransitionEvidence })
160
+ .directs(recordParentModelTransition, (evidence) => evidence)
161
+ .directs(seatParentModelAuthority, (evidence) => evidence)
162
+ .acceptsVerifiedBirthParentRecoveryEffect()
163
+ .atomically(),
164
+ );
165
+
166
+ // ── PLATFORM SIDE ──────────────────────────────────────────────────────────────────────────────
167
+
168
+ function currentParentModelTransitionEvidence(input: DirectChildModelTransitionInput): ParentModelTransitionEvidence {
169
+ const holders = readInheritedModelAuthority();
170
+ if (holders === undefined) {
171
+ throw new Error("directing a model transition requires this workspace to hold at least one active installDomain seat");
172
+ }
173
+ return parentModelTransitionEvidence.parse({
174
+ direction: modelTransitionDirection.parse({
175
+ domain: input.domain,
176
+ candidateHash: input.candidateHash,
177
+ ...(input.supersedes === undefined ? {} : { supersedes: input.supersedes }),
178
+ acceptanceReason: input.acceptanceReason,
179
+ directedAt: input.directedAt,
180
+ }),
181
+ authority: { holders, seatedAt: input.directedAt },
182
+ });
183
+ }
184
+
185
+ /** THE DIRECTION: one exact child, addressed from the typed input; the evidence comes from committed
186
+ * platform state. Gated on the platform's own model-lifecycle authority. */
187
+ export const directChildModelTransition = nomosImplementationDetail(
188
+ intent(DIRECT_CHILD_MODEL_TRANSITION_ID)
189
+ .contract({ accepts: directChildModelTransitionInput })
190
+ .reads(relationTuplesByObject)
191
+ .directsWorkspace(acceptParentModelTransition, {
192
+ workspace: ({ workspace }) => workspace,
193
+ payload: currentParentModelTransitionEvidence,
194
+ })
195
+ .requires(MODEL_LIFECYCLE_AUTHORITY, { object: "workspace:self" })
196
+ .atomically(),
197
+ );
198
+
199
+ /**
200
+ * The export map the application-home policy law composes (keys are the obscure `__nomos_*` slots;
201
+ * values are THE singletons — the law graph folds an intent's step closure by object identity).
202
+ * The two child-side consequences ride only the acceptor's step closure, as `child_authentication.ts`
203
+ * carries its gated acceptor effect.
204
+ */
205
+ export function modelTransitionExports(): Readonly<Record<string, object>> {
206
+ return {
207
+ __nomos_ParentModelTransition: ParentModelTransition,
208
+ __nomos_acceptParentModelTransition: acceptParentModelTransition,
209
+ __nomos_directChildModelTransition: directChildModelTransition,
210
+ };
211
+ }
@@ -19,7 +19,7 @@ import {
19
19
  writeWrap,
20
20
  } from "./encryption_scope.js";
21
21
  import { GenesisWarrant, seedGenesis } from "./genesis.js";
22
- import { BirthAttestation, BirthAttestationLink, seedBirthAttestation } from "./home.js";
22
+ import { BirthAttestation, BirthAttestationLink, seedBirthAttestation } from "./receiving_group.js";
23
23
  import { RelationTuple, __qualifyAggregateType, removeTuple, writeTuple } from "./relations.js";
24
24
  import { SIGNER_RELATION, enrollSigner, signerObject, identityRelations } from "./signing_identity.js";
25
25
  import { impureCapability, impureCapabilityAggregate } from "./impure_capability.js";