@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
@@ -4,738 +4,9 @@
4
4
  // If a file isn't this / hosting this / authoring for this / proving this — it's gone.
5
5
 
6
6
  /**
7
- * framework/home.ts — THE HOME HOLON (the identity role; `architecture/home_holons_and_cross_custody.md`
8
- * §4). One holon, three roles — "workspace," "platform," "home" are the SAME githolon wearing the role
9
- * its installed LAW gives it. A HOME holon runs THIS law: an identity's subject-side root.
10
- *
11
- * It holds only PUBLIC material + signed facts (private keys never leave the client, so the cloud hosting
12
- * it stays operator-blind):
13
- * - KEY DIRECTORY — the identity's public device keys: the `signer` relation
14
- * (`identity:<principal>#signer@key:<hash>`, `framework/signing_identity.ts`). Re-exported here so a
15
- * home holon's law carries it: "wrap the scope key to U's device" becomes "read U's home key roster."
16
- * - SHARED-WITH-ME index (§5) — one record per verified cross-custody attestation delivered here, so
17
- * "show me everything shared with me" is a LOCAL query, no fan-out.
18
- * - INBOX — grants/invites/notifications/dead-letters addressed to the identity.
19
- *
20
- * THE FORWARD-CHECK DOCTRINE (§5): the index is a DISCOVERY HINT, not the authority. When the identity
21
- * actually opens the asserting workspace, THAT workspace's gate does the live `Check` — so a stale share
22
- * (the asserter revoked it) is fail-safe: the identity sees a workspace it can no longer open, the forward
23
- * check denies, the hint is pruned. (The cross-custody ATTESTATION that proves a delivered share is signed
24
- * + verifiable is §3; the host DELIVERY lane that fills the index is §5. This file is the law that holds
25
- * the result, and the owner-authored lane to maintain it.)
7
+ * @deprecated `framework/home.ts` is the OLD NAME of `framework/receiving_group.ts` (the receiving
8
+ * group is the framework concept; "home" is a tenant's word for the business law it composes into
9
+ * that anchor — `architecture/receiving_group_lifecycle.md`). This shim re-exports the same
10
+ * declarations, byte-identical, for ONE release; import `./receiving_group.js` instead.
26
11
  */
27
- import { z } from "zod";
28
- import type { ApplicationHomeGenesis } from "../application_home_genesis.js";
29
- import { aggregate, instance, OWNED_READ_RELATION } from "../aggregate.js";
30
- import { sha256Digest, t } from "../fields.js";
31
- import { Lww } from "../drivers.js";
32
- import { directive } from "../directive.js";
33
- import { ensure } from "../authoring.js";
34
- import { set, withMarker, type PlannedOp } from "../ops.js";
35
- import { query } from "../query.js";
36
- import { birth, type WorkspaceRole } from "../births.js";
37
- import {
38
- authProvider as authProviderQuery,
39
- authProviderCertificates as authProviderCertificatesQuery,
40
- authProviderKeys as authProviderKeysQuery,
41
- readAuthProviderVerifyingConfiguration,
42
- seedAuthProvider,
43
- } from "./auth_provider_law.js";
44
- import { readRef, readSet, workspaceInvariant, refAs } from "./workspace_invariant.js";
45
- import {
46
- identityRelations,
47
- } from "./signing_identity.js";
48
- import {
49
- RelationTuple,
50
- writeTuple,
51
- } from "./relations.js";
52
- import { relationType, self, user, selfObject } from "../relation_schema.js";
53
- import { requireParentAttestedBirth, type ParentAttestedBirthMarker } from "../births.js";
54
- import { GenesisWarrant, seedGenesis } from "./genesis.js";
55
- import { idOf } from "../value_object.js";
56
- import {
57
- DomainInstallExecutor,
58
- domainInstallGenesisOffer,
59
- } from "./domain_lifecycle.js";
60
- import { birthCertificatePayload } from "./birth_certificate_law.js";
61
-
62
- // `nomos.sha256` — the TRUSTLESS, pure hash computed IN the githolon (Rust sha2 bound in the sealed engine;
63
- // see deterministic-rquickjs). Available as a global to plans + invariant predicates (like `nomos.mint`); it
64
- // lets the home law re-derive `home-<hash(owner)>` itself, so the SQUAT invariant runs in-law on every peer.
65
- declare const nomos: { sha256(input: string): string };
66
-
67
- /** The KEY DIRECTORY is the `signer` relation — re-exported so a home holon's law composes it (the
68
- * identity's public device keys, enrolled via `enrollSigner`, checked by the gate). */
69
- export { identityRelations };
70
-
71
- /** THE GENESIS WARRANT primitives — re-exported so a HOME law carries them in the `home` domain key. The
72
- * birthHome genesis chain runs `home/seedGenesis` to record the home's unique self-id (== homeName), so
73
- * `workspace_self_id` resolves on the home and BOTH the signed-author regime + the parent-attested-birth
74
- * cert door FIRE on every home (BREAK 1). Without this the home is unwarranted and both doors are inert. */
75
- export { GenesisWarrant, seedGenesis };
76
-
77
- /**
78
- * THE RECEIVING GROUP — one sovereign framework identity whose enrolled devices clone this same holon.
79
- * It is not a tenant Person, an IdP account or a host-owned account. The native global
80
- * `identity:<principal>#signer@key:<hash>` relation is its device roster; this singleton binds the group's
81
- * stable principal to the workspace that carries that roster and its access manifest.
82
- *
83
- * The wire identifiers are deliberately obscure framework names. Tenant business packages may model their
84
- * own `ReceivingGroup`, `home` or `group` concepts without silently colliding with this implementation.
85
- */
86
- export const RECEIVING_GROUP_ID = "nomos-internal-receiving-group-7c1f5e:self";
87
- /** A receiving group's self-committed workspace-name prefix. */
88
- export const RECEIVING_GROUP_NAME_PREFIX = "nomos-rg-";
89
- export const RECEIVING_GROUP_NAME_HASH_LEN = 40;
90
- export const RECEIVING_GROUP_POLICY_ID = "nomos-internal-receiving-group-policy-7c1f5e:self";
91
- export const ReceivingGroup = aggregate("NomosInternalReceivingGroup7c1f5e", {
92
- /** The stable Zanzibar principal represented by this group. Credentials may locate it but do not own it. */
93
- principal: t.string().merge(Lww),
94
- /** The group's self-committed workspace name, deterministically bound to its stable principal. */
95
- workspaceName: t.string().merge(Lww),
96
- /** ISO-8601, caller-stamped (determinism — no clock in the plan). */
97
- bornAt: t.string().merge(Lww),
98
- // The group's genesis seats its controller in OWNED_READ_RELATION below. Declaring that same capability
99
- // here makes the law's coarse pack gate recognise the seat, so a newly enrolled device can clone its own
100
- // receiving group before any tenant records or tenant-authored grants exist. This remains ordinary,
101
- // replayable Zanzibar state: revocation removes the seat; there is no kernel-level founder bypass.
102
- }, { cap: 1 }).readableBy(OWNED_READ_RELATION);
103
-
104
- /**
105
- * The framework-owned device lifecycle policy for one receiving group. This is deliberately data, not a
106
- * client-side branch: every peer replays the same rule. The first supported posture is intentionally small
107
- * and secure: a live, verified device may add or revoke another device; keyless IdP enrolment is only the
108
- * pre-group bootstrap lane.
109
- *
110
- * ALL-DEVICE-LOSS RECOVERY — CO2 already recovers through its platform AuthProvider, but the implementation
111
- * reaches that result by repeating birth after this home's direct enrollment policy refuses. The corrected
112
- * design (`architecture/guardian_device_recovery.md`, reconciled 2026-08-10) makes recovery authority an
113
- * explicit tenant-selected policy: platform identity provider or guardian quorum. The missing work is to
114
- * evaluate that choice at the existing child's frontier and delete the client-side birth-repeat bypass.
115
- */
116
- export const ReceivingGroupPolicy = aggregate("NomosInternalReceivingGroupPolicy7c1f5e", {
117
- additionalDevice: t.string().merge(Lww),
118
- revocation: t.string().merge(Lww),
119
- recovery: t.string().merge(Lww),
120
- guardianQuorum: t.int().merge(Lww),
121
- setAt: t.string().merge(Lww),
122
- }, { cap: 1 }).public();
123
-
124
- export const DEFAULT_RECEIVING_GROUP_POLICY = {
125
- additionalDevice: "current-device",
126
- revocation: "current-device",
127
- recovery: "guardian-quorum",
128
- guardianQuorum: 1,
129
- } as const;
130
-
131
- /** The recovery authorities a receiving group may explicitly select. The default remains guardian
132
- * quorum; an application must deliberately choose its attested parent identity provider. */
133
- export const RECEIVING_GROUP_RECOVERY_POLICIES = [
134
- "guardian-quorum",
135
- "platform-identity-provider",
136
- ] as const;
137
- export const receivingGroupRecoveryPolicy = z.enum(RECEIVING_GROUP_RECOVERY_POLICIES);
138
- export type ReceivingGroupRecoveryPolicy = z.infer<typeof receivingGroupRecoveryPolicy>;
139
- export const PLATFORM_IDENTITY_PROVIDER_RECOVERY: ReceivingGroupRecoveryPolicy =
140
- "platform-identity-provider";
141
-
142
- function writeReceivingGroupPolicy(p: {
143
- setAt: string;
144
- recovery?: ReceivingGroupRecoveryPolicy | undefined;
145
- }): PlannedOp[] {
146
- const policy = instance(ReceivingGroupPolicy, RECEIVING_GROUP_POLICY_ID);
147
- return [
148
- set(policy, "additionalDevice", DEFAULT_RECEIVING_GROUP_POLICY.additionalDevice),
149
- set(policy, "revocation", DEFAULT_RECEIVING_GROUP_POLICY.revocation),
150
- set(policy, "recovery", p.recovery ?? DEFAULT_RECEIVING_GROUP_POLICY.recovery),
151
- set(policy, "guardianQuorum", DEFAULT_RECEIVING_GROUP_POLICY.guardianQuorum),
152
- set(policy, "setAt", p.setAt),
153
- ];
154
- }
155
-
156
- /** Genesis-only default policy. Policy changes become a separate, guardian-aware ceremony. */
157
- export const seedReceivingGroupPolicy = directive("nomosInternalSeedReceivingGroupPolicy7c1f5e")
158
- .ensures(ReceivingGroupPolicy)
159
- .payload(z.object({
160
- setAt: z.string().min(1),
161
- recovery: receivingGroupRecoveryPolicy.optional(),
162
- }))
163
- .plan((p) => writeReceivingGroupPolicy(p));
164
-
165
- /**
166
- * The group's controller relation binds its stable principal inside the same genesis. Business representation
167
- * remains separate Zanzibar edges; this relation only establishes who controls this receiving-group holon.
168
- */
169
- export const receivingGroupRelations = relationType("nomos.internal.receiving-group.7c1f5e").relation("controller", {
170
- rewrite: self(),
171
- allow: [user()],
172
- });
173
-
174
- /** Stamp the receiving group and atomically seat its controller relation. */
175
- export function writeReceivingGroup(p: { principal: string; workspaceName: string; bornAt: string }): PlannedOp[] {
176
- const h = instance(ReceivingGroup, RECEIVING_GROUP_ID);
177
- return [
178
- set(h, "principal", p.principal),
179
- set(h, "workspaceName", p.workspaceName),
180
- set(h, "bornAt", p.bornAt),
181
- ...writeTuple({
182
- object: selfObject(receivingGroupRelations),
183
- relation: "controller",
184
- subject: p.principal,
185
- grantedBy: p.principal,
186
- grantedAt: p.bornAt,
187
- }),
188
- // A device clones the encrypted workspace before record-level ownership can be evaluated locally.
189
- // Seat the group's controller for that ciphertext transport in the same genesis; individual owned
190
- // records still require their own per-record reader edge before they decrypt or appear in reads.
191
- ...writeTuple({
192
- object: "workspace:self",
193
- relation: OWNED_READ_RELATION,
194
- subject: p.principal,
195
- grantedBy: p.principal,
196
- grantedAt: p.bornAt,
197
- }),
198
- ];
199
- }
200
-
201
- /**
202
- * Genesis-only receiving-group stamp. The name is caller-supplied but the invariant below re-derives it.
203
- */
204
- export const seedReceivingGroup = directive("nomosInternalSeedReceivingGroup7c1f5e")
205
- .ensures(ReceivingGroup)
206
- .payload(z.object({ principal: z.string().min(1), workspaceName: z.string().min(1), bornAt: z.string().min(1) }))
207
- .plan((p) => writeReceivingGroup(p))
208
- .alsoEnsures(RelationTuple);
209
-
210
- /**
211
- * THE SQUAT INVARIANT (home_holons §5) — a home holon's self-committed `homeName` MUST be the hash of its
212
- * owner: `homeName == home-<sha256(principal)>`. Declared by the home law, it EXECUTES at the one gate — and
213
- * crucially at `verify_chain` (the bailiff's upload-birth): a squatter's chain (claiming `home-<hash(bob)>`
214
- * but owned by `mallory`) FAILS the home law's OWN gate during adoption — refused IN THE GITHOLON, BY THE LAW,
215
- * never by a host check. The host only routes the chain to the name it commits to (custody). `nomos.sha256`
216
- * re-derives the hash in-law on every peer, so the verdict is identical everywhere.
217
- */
218
- export const receivingGroupNameBindsPrincipal = workspaceInvariant("ReceivingGroupNameBindsPrincipal")
219
- .on("nomosInternalSeedReceivingGroup7c1f5e")
220
- .reads(readSet(readRef("group", ReceivingGroup).at(RECEIVING_GROUP_ID)))
221
- .declassify("the receiving-group address is a public hash of its stable principal; refusing a mismatch reveals no private field")
222
- .assert(({ group }) => {
223
- const g = (group ?? {}) as { principal?: string; workspaceName?: string };
224
- const expected = RECEIVING_GROUP_NAME_PREFIX
225
- + nomos.sha256(String(g.principal ?? "")).slice(0, RECEIVING_GROUP_NAME_HASH_LEN);
226
- return g.workspaceName === expected
227
- ? { accept: true }
228
- : { reject: "a receiving group's workspace name must hash its stable principal" };
229
- });
230
-
231
- const receivingGroupPolicyRefs = readSet(
232
- readRef("group", ReceivingGroup).at(RECEIVING_GROUP_ID),
233
- readRef("policy", ReceivingGroupPolicy).at(RECEIVING_GROUP_POLICY_ID),
234
- );
235
-
236
- /** An IdP token may bootstrap the parent before the group exists; it may never bypass an existing group's
237
- * device policy. An existing group chooses whether recovery is delegated to its platform AuthProvider or to
238
- * guardians; the current default below says guardian, while CO2's current product behaviour is platform IdP.
239
- *
240
- * KNOWN GAP (`architecture/guardian_device_recovery.md`): this invariant is declared `.on("enrollFirstDevice")`
241
- * and only fires when that directive targets THIS home directly. It is NOT re-applied when the birth
242
- * offer-effect (`run_birth_effect`, repeating `nomosInternalBirthReceivingGroup` against an ALREADY-founded
243
- * home) folds a signer seat via the SAME underlying mechanism. That is how CO2 recovery works today, but its
244
- * home frontier still says `guardian-quorum`. The fix is not to ban platform recovery: add the explicit
245
- * platform-identity-provider policy, make CO2 choose it, and have the child gate verify the chosen evidence. */
246
- export const receivingGroupRejectsKeylessAdditionalDevice = workspaceInvariant("ReceivingGroupRejectsKeylessAdditionalDevice")
247
- .on("enrollFirstDevice")
248
- .reads(receivingGroupPolicyRefs)
249
- .declassify("device enrollment deliberately reveals that this receiving group has already completed first-device bootstrap")
250
- .assert(({ group }) => typeof group?.principal !== "string" || group.principal.length === 0
251
- ? { accept: true }
252
- : { reject: "receiving-group-additional-device-requires-current-device-or-guardian" });
253
-
254
- /** The shipped additional-device policy: an already enrolled, verified device signs the self-bound enrol. */
255
- export const receivingGroupAdditionalDeviceFollowsPolicy = workspaceInvariant("ReceivingGroupAdditionalDeviceFollowsPolicy")
256
- .on("enrollSignerSelf")
257
- .reads(receivingGroupPolicyRefs)
258
- .declassify("device lifecycle policy intentionally branches on principal_verified")
259
- .assert(({ group, policy }, ctx) => {
260
- if (typeof group?.principal !== "string" || group.principal.length === 0) return { accept: true };
261
- const p = policy as { additionalDevice?: string } | undefined;
262
- return p?.additionalDevice === "current-device" && ctx?.principalVerified === true
263
- ? { accept: true }
264
- : { reject: "receiving-group-additional-device-policy-refused" };
265
- });
266
-
267
- /** The shipped revocation policy: a live verified group device authors the remove-wins signer change. */
268
- export const receivingGroupRevocationFollowsPolicy = workspaceInvariant("ReceivingGroupRevocationFollowsPolicy")
269
- .on("revokeSigner")
270
- .reads(receivingGroupPolicyRefs)
271
- .declassify("device lifecycle policy intentionally branches on principal_verified")
272
- .assert(({ group, policy }, ctx) => {
273
- if (typeof group?.principal !== "string" || group.principal.length === 0) return { accept: true };
274
- const p = policy as { revocation?: string } | undefined;
275
- return p?.revocation === "current-device" && ctx?.principalVerified === true
276
- ? { accept: true }
277
- : { reject: "receiving-group-revocation-policy-refused" };
278
- });
279
-
280
- /** Re-derive a receiving group's workspace name in-law. */
281
- export function receivingGroupNameOf(principal: string): string {
282
- return RECEIVING_GROUP_NAME_PREFIX
283
- + nomos.sha256(String(principal)).slice(0, RECEIVING_GROUP_NAME_HASH_LEN);
284
- }
285
-
286
- /**
287
- * `birthHome` — THE FRAMEWORK BIRTH PRIMITIVE for a home holon. This is the MECHANICS (OURS) so a tenant
288
- * never hand-builds a home genesis: the parent (the cloud/platform whose governance includes this directive)
289
- * ORDERS the birth of an identity's home holon, and the kernel's offer-effect spawns it + self-validates it
290
- * through the child's OWN gate from intent 0 (the `.births()` declared consequence; `architecture/
291
- * home_holons_and_cross_custody.md` + `sovereign_adapter.md` "birth is a kernel offer-effect").
292
- *
293
- * SELF-BOUND — squatting is structurally impossible (no separate grant needed; the policy gate is the
294
- * tenant's `setAuthProvider` auth scoping, which decides whether the offering principal is verified at all):
295
- * 1. The home OWNER rides the payload (`owner`, a `user:<uid>` subject). `ctx.principal()` is opaque
296
- * PrincipalEvidence — it CANNOT be read as a raw string in-plan to compute the slot name — so the owner
297
- * is payload-carried, but the binding below makes it sound.
298
- * 2. The workspace name + the seeded `homeName` are BOTH derived from THE SAME payload `owner` via
299
- * {@link homeNameOf} — they cannot diverge in this plan.
300
- * 3. The child's genesis includes `seedHomeOwner(owner, homeNameOf(owner), bornAt)`, and the home law's
301
- * {@link homeNameBindsOwner} invariant RE-DERIVES `home-<sha256(owner)>` at the child's gate (author AND
302
- * verify_chain). So a chain that claims `home-<hash(alice)>` but seeds owner `bob` FAILS the child's own
303
- * law — refused in the githolon, by the law, never by a host. A verified principal is required upstream
304
- * (no anonymous home birth); the offer principal IS the auth boundary (the tenant's setAuthProvider).
305
- *
306
- * The genesis chain it authors (reusing the order-declares-the-law install shape — bytes resolved by hash
307
- * from the parent's typed USDA closure custody):
308
- * [ bootstrap/installDomain(frameworkHash), nomos/home installDomain(lawHash), seedHomeOwner(owner, …) ]
309
- * `frameworkHash` (the bootstrap controller hash) + `lawHash` (the HOME law package domainHash) are
310
- * tenant-PINNED at their governance compile (mirroring `birthChild`) — the end-user app supplies neither;
311
- * the tenant's HomeBirth.viaCoordinator buildBody / their governance fills them. `seedHomeOwner` is INCLUDED
312
- * so HomeOwner is seeded and `homeNameBindsOwner` passes (a birth without it would be an invalid, un-owned
313
- * home).
314
- */
315
- // Standalone framework law explicitly declares `home`; compiler-composed business applications explicitly
316
- // declare the obscure APPLICATION_HOME_DOMAIN. The kernel refuses law with no attestation-seed registrar.
317
- export const RECEIVING_GROUP_LAW_DOMAIN = "home";
318
- /**
319
- * Build the private home-birth primitive for the domain key that carries the home law.
320
- *
321
- * Most framework-authored laws still use the historic public `home` key through
322
- * {@link birthHome}. Business packages use an obscure compiler-owned key instead, so a
323
- * tenant remains free to model a business concept called "home". The key is closed over
324
- * here and written into every child-genesis step; it is never a tenant payload field.
325
- */
326
- export function birthReceivingGroupForDomain(
327
- groupLawDomain: string,
328
- maxChildWorkspacesPerUser: number,
329
- birthPolicyDomains: readonly string[],
330
- homeGenesis?: ApplicationHomeGenesis,
331
- parentWorkspaceRoles: readonly WorkspaceRole[] = [],
332
- ) {
333
- if (groupLawDomain.length === 0) {
334
- throw new Error("birthReceivingGroupForDomain requires a non-empty receiving-group law domain");
335
- }
336
- if (!Number.isInteger(maxChildWorkspacesPerUser) || maxChildWorkspacesPerUser < 0) {
337
- throw new Error(
338
- "birthReceivingGroupForDomain requires an explicit non-negative maxChildWorkspacesPerUser; " +
339
- "Nomos has no compiled birth-policy fallback",
340
- );
341
- }
342
- const policyDomains = [...new Set(birthPolicyDomains)];
343
- if (
344
- policyDomains.length === 0 ||
345
- policyDomains.some((domain) => domain.trim().length === 0) ||
346
- !policyDomains.includes(groupLawDomain)
347
- ) {
348
- throw new Error(
349
- "birthReceivingGroupForDomain requires every co-resident birth-capable law domain, " +
350
- "including its own domain; Nomos will not birth partially configured law",
351
- );
352
- }
353
- const birthDirective = directive("nomosInternalBirthReceivingGroup7c1f5e")
354
- .creates(ReceivingGroup)
355
- .payload(
356
- z.object({
357
- /** The identity this home belongs to (a `user:<uid>` subject). The workspace name + seeded homeName are
358
- * both `home-<sha256(owner)>` — self-bound, so you can only birth YOUR OWN home slot. */
359
- owner: z.string().min(1),
360
- /** The bootstrap framework controller content hash — tenant-pinned at governance compile (the child
361
- * installs it IN-CHAIN as intent 0; the kernel resolves the bytes by hash from the parent's custody). */
362
- frameworkHash: sha256Digest(),
363
- /** The HOME law package domainHash — tenant-pinned at governance compile (the child's second install). */
364
- lawHash: sha256Digest(),
365
- /** ISO-8601 birth time, caller-stamped (the timestamp doctrine — the plan reads no clock). */
366
- bornAt: z.string().min(1),
367
- /** AUTHPROVIDER INHERITANCE — DEFAULT ON, opt out with `false`. Verification is PER-WORKSPACE (the
368
- * kernel never walks up to the parent), so a PRIVATE child born without its own AuthProvider cannot
369
- * verify any token — its own owner is locked out of verified reads (the co2 phase-6 wall). By
370
- * default the birth READS the parent's `authProvider` row (the #58 captured-read lane — live at
371
- * author, CAS-re-derived at the gate) and, when one is declared, COPIES it AS DATA into the child's
372
- * genesis (a `setAuthProvider` step) — the child still OWNS its verifier as its own law-state; the
373
- * parent's later rotations do NOT propagate (re-set on the child to rotate). Requirements the
374
- * refusals name: the parent law must compose the `authProvider` query and the child law the
375
- * `setAuthProvider` directive (both ride the framework export set). Pass `false` for a child that
376
- * must NOT trust the parent's IdP (it then seeds its own or stays bare-principal). */
377
- inheritAuthProvider: z.boolean().optional(),
378
- }),
379
- )
380
- .plan((p) => {
381
- const founder = p.owner; // the actor for the child's own genesis steps (its self-bound owner subject)
382
- const groupName = receivingGroupNameOf(p.owner);
383
- // THE PARENT'S DECLARED VERIFIER. This captured read supplies the inherited provider seed.
384
- // Birth-certificate verification and founding-signer enrollment belong to the kernel-owned
385
- // attestation step, so neither fact is duplicated in this tenant plan or payload.
386
- const inheritedProvider = p.inheritAuthProvider === false
387
- ? undefined
388
- : readAuthProviderVerifyingConfiguration();
389
- const genesisChain: Array<{ domain: string; directiveId: string; actor: string; payload: Record<string, unknown>; domainHash?: string }> = [
390
- // THE ORDER-DECLARED LAW INSTALL: two typed closure identities. The kernel resolves each
391
- // closure from the parent's custody when it folds the birth; law bytes never ride the intent.
392
- domainInstallGenesisOffer(
393
- DomainInstallExecutor.StageZero,
394
- p.frameworkHash,
395
- founder,
396
- ),
397
- domainInstallGenesisOffer(
398
- DomainInstallExecutor.LifecycleController,
399
- p.lawHash,
400
- founder,
401
- ),
402
- {
403
- domain: groupLawDomain,
404
- directiveId: "nomosInternalSeedReceivingGroupPolicy7c1f5e",
405
- actor: founder,
406
- payload: { setAt: p.bornAt },
407
- },
408
- // SEED THE OWNER — the home is born OWNED; the homeNameBindsOwner invariant in the child's law proves
409
- // homeName == home-<sha256(owner)> at the child's own gate, so the slot can ONLY be its rightful owner's.
410
- {
411
- domain: groupLawDomain,
412
- directiveId: "nomosInternalSeedReceivingGroup7c1f5e",
413
- actor: founder,
414
- payload: { principal: p.owner, workspaceName: groupName, bornAt: p.bornAt },
415
- },
416
- // The receiving group is born with its child-workspace allowance as explicit law-state. The
417
- // value is closed over by the package's application policy, so neither the host nor the end
418
- // user can substitute it in the offer payload.
419
- ...policyDomains.map((domain) => ({
420
- domain,
421
- directiveId: "seedBirthPolicy",
422
- actor: founder,
423
- payload: {
424
- maxBirthsPerPrincipal: maxChildWorkspacesPerUser,
425
- setBy: p.owner,
426
- setAt: p.bornAt,
427
- },
428
- })),
429
- // Tenant founding law is an ordered list of ordinary offers. Values derive solely from the
430
- // canonical home facts; every payload is parsed by the target directive before it reaches
431
- // the child's author gate. There is no host append point and no framework-selected fallback.
432
- ...(homeGenesis?.steps ?? []).map((step) => ({
433
- domain: step.domain,
434
- directiveId: step.directive.id,
435
- actor: founder,
436
- payload: step.directive.payloadSchema.parse(step.payload({
437
- owner: p.owner,
438
- workspaceName: groupName,
439
- bornAt: p.bornAt,
440
- })),
441
- })),
442
- ];
443
- // AUTHPROVIDER INHERITANCE (default ON — see the payload doc): copy the parent's declared provider
444
- // (the up-front captured read above) AS DATA into the child genesis. The child owns the copy as its
445
- // own law-state; nothing is inherited-by-reference. Opt out: `inheritAuthProvider: false`.
446
- if (p.inheritAuthProvider !== false) {
447
- if (inheritedProvider !== undefined) {
448
- genesisChain.push({
449
- domain: groupLawDomain,
450
- directiveId: "seedAuthProvider",
451
- actor: founder,
452
- payload: {
453
- ...inheritedProvider,
454
- label: "inherited-from-parent",
455
- setBy: p.owner,
456
- setAt: 1, // genesis position — deterministic, like enrollSigner's grantedAt
457
- },
458
- });
459
- }
460
- }
461
- // THE DECLARED BIRTH EFFECT (the unix model): the recipe rides the committed intent as a declared output
462
- // (captured_ports.births). The kernel — reading the `.births()` declaration off the law manifest — takes
463
- // the recipe and spawns + self-validates the child through the child's OWN gate (each step self-verifies).
464
- birth({
465
- workspace: groupName,
466
- genesisChain,
467
- ...(parentWorkspaceRoles.length > 0 ? { parentWorkspaceRoles } : {}),
468
- });
469
- // Parent/child lineage is an ordinary global Zanzibar relation in parent custody. The exact child
470
- // address comes from the same plan which births it, so neither the host nor the caller can redirect
471
- // this seat. Application law can then authorize upward workspace effects with the ordinary relation.
472
- return writeTuple({
473
- object: "workspace:self",
474
- relation: "child",
475
- subject: `workspace:${groupName}`,
476
- grantedBy: p.owner,
477
- grantedAt: p.bornAt,
478
- });
479
- })
480
- .reads(authProviderQuery) // the parent-side AuthProvider capture the inheritance copies (the #58 lane)
481
- .reads(authProviderKeysQuery)
482
- .reads(authProviderCertificatesQuery)
483
- .alsoEnsures(RelationTuple)
484
- .births(); // BIRTH IS A DECLARED KERNEL PRIMITIVE — emits the `nomosBirthGate` era key; the kernel folds the recipe
485
- return {
486
- ...birthDirective,
487
- ...(homeGenesis === undefined || homeGenesis.steps.length === 0
488
- ? {}
489
- : {
490
- birthGenesisRequirements: homeGenesis.steps.map((step) => ({
491
- domain: step.domain,
492
- directiveId: step.directive.id,
493
- })),
494
- }),
495
- };
496
- }
497
-
498
- /** Build the standalone framework receiving-group law with an explicit allowance. */
499
- export const birthReceivingGroup = (maxChildWorkspacesPerUser: number) =>
500
- birthReceivingGroupForDomain(
501
- RECEIVING_GROUP_LAW_DOMAIN,
502
- maxChildWorkspacesPerUser,
503
- [RECEIVING_GROUP_LAW_DOMAIN],
504
- );
505
-
506
- /**
507
- * THE SHARED-WITH-ME INDEX (§5) — one record per cross-custody attestation delivered to this home holon:
508
- * a signed edge `<asserterWorkspace> : <object> # <relation> @ this-identity`, indexed LOCALLY so the
509
- * access list is a local query (no fan-out across every resource holon). A DISCOVERY HINT — the live authz
510
- * stays the forward `Check` on the asserting holon when the identity opens it.
511
- */
512
- export const SharedWithMe = aggregate("SharedWithMe", {
513
- /** The holon that signed + delivered this edge — WHERE the live forward `Check` runs when opened. */
514
- asserterWorkspace: t.string().merge(Lww),
515
- /** The shared OBJECT — the whole workspace (`workspace:self`) or a specific record (`Entry:<id>`). */
516
- object: t.string().merge(Lww),
517
- /** The relation granted (`reader` / `editor` / a read cap). */
518
- relation: t.string().merge(Lww),
519
- /** The asserter's OWNER principal — whose key signed the attestation (verified at §3 admission). */
520
- asserterPrincipal: t.string().merge(Lww),
521
- /** ISO-8601, caller-stamped (determinism — no clock in the plan). */
522
- attestedAt: t.string().merge(Lww),
523
- /** PRUNED (forward-check fail-safe): set when the live `Check` on the asserter denies — the hint is
524
- * dropped from the list but the audit row stays. `""` = live. */
525
- prunedAt: t.string().merge(Lww),
526
- }).public();
527
-
528
- /** One idempotent access-manifest row per source edge in this home. Delivery is at-least-once: a retry,
529
- * reconnect or source outbox replay must update the same bookmark rather than manufacture another thing the
530
- * recipient appears to have access to. The home itself scopes the recipient, so the edge coordinate is the
531
- * source workspace + protected object + granted relation. */
532
- export function sharedWithMeId(asserterWorkspace: string, object: string, relation: string): string {
533
- const coordinate = JSON.stringify([asserterWorkspace, object, relation]);
534
- return `SharedWithMe_${nomos.sha256(coordinate)}`;
535
- }
536
-
537
- /**
538
- * `recordShare` — index a cross-custody share into the home holon's access list. AUTHORED on the home
539
- * holon (the identity's own subject-side root). The payload carries the §3 CROSS-CUSTODY ATTESTATION — a
540
- * SIGNED QUOTE: the asserter's device `publicKey` + a `signature` over the edge
541
- * `<asserterWorkspace>:<object>#<relation>@<this-home-owner>`. The home holon's OWN gate verifies it
542
- * (`executor::record_share_attestation_violation`, bound to the warrant owner), so the BAILIFF can deliver
543
- * it HOST-FREE (the host carries bytes, vouches nothing — the gate vouches). The owner lane authors the
544
- * SAME shape (the owner holds the quote the asserter gave it). The signature is a verification input, not
545
- * stored — only the edge facts fold into the index. The live authority stays the forward `Check` on the
546
- * asserter when the identity opens it (§5 fail-safe); a stale/forged quote can't enter the list at all.
547
- */
548
- export const recordShare = directive("recordShare")
549
- .ensures(SharedWithMe)
550
- .payload(
551
- z.object({
552
- asserterWorkspace: z.string().min(1),
553
- object: z.string().min(1),
554
- relation: z.string().min(1),
555
- asserterPrincipal: z.string().min(1),
556
- attestedAt: z.string().min(1),
557
- /** The asserter's device PUBLIC KEY (base64) — what the §3 gate verifies the quote against. */
558
- publicKey: z.string().min(1),
559
- /** The asserter's SIGNATURE (base64) over the edge bytes, subject = this home's owner. */
560
- signature: z.string().min(1),
561
- }),
562
- )
563
- .plan((p) => {
564
- // ENSURE, never CREATE: signed delivery is retryable and therefore at-least-once. Re-delivery (including
565
- // a later re-grant after prune) refreshes this exact access edge and makes it live again.
566
- ensure(SharedWithMe, sharedWithMeId(p.asserterWorkspace, p.object, p.relation))
567
- .set("asserterWorkspace", p.asserterWorkspace)
568
- .set("object", p.object)
569
- .set("relation", p.relation)
570
- .set("asserterPrincipal", p.asserterPrincipal)
571
- .set("attestedAt", p.attestedAt)
572
- .set("prunedAt", "");
573
- return [];
574
- })
575
- // CROSS-CUSTODY ATTESTATION-AUTHORIZED (§3/§5): the payload's signed quote IS the authorization (lowered
576
- // into the `nomosAttestationGate` era key) — the one gate verifies it against the home's owner (the
577
- // LAW-DECLARED owner-source below, NOT a kernel-hardcoded id) + pins the principal to the attestation key,
578
- // so the bailiff delivers it host-free to an OFFLINE subject (no device key, no author block).
579
- .attestationAuthorized({ ownerObject: RECEIVING_GROUP_ID, ownerField: "principal" });
580
-
581
- /**
582
- * `pruneShare` — fail-safe drop of a hint whose forward `Check` denied (the asserter revoked it). The row
583
- * stays for audit; `prunedAt` removes it from the live list. (The forward check itself is the resource
584
- * holon's job — this records the verdict locally.)
585
- */
586
- export const pruneShare = directive("pruneShare")
587
- .mutates(SharedWithMe)
588
- .payload(z.object({ shareId: idOf(SharedWithMe), prunedAt: z.string().min(1) }))
589
- .plan((p) => [set(instance(SharedWithMe, p.shareId), "prunedAt", p.prunedAt)]);
590
-
591
- /** "Show me everything <asserter> shared with me" — an indexed probe over the local access list. */
592
- export const sharedByWorkspace = query("sharedByWorkspace").key("asserterWorkspace").returns(SharedWithMe);
593
-
594
- /** "Show me every share for this protected object" — the indexed access-list probe used by generated
595
- * application discovery. A home commonly has a very large installed law, so discovery must never fall back
596
- * to the generic `aggregatesByType(SharedWithMe)` scan merely to find whole-workspace shares. */
597
- export const sharedByObject = query("sharedByObject").key("object").returns(SharedWithMe);
598
-
599
- // ─────────────────── THE PEER-SOVEREIGN ROOT-OF-TRUST (the BirthAttestation cert chain) ───────────────────
600
-
601
- /**
602
- * THE BIRTH ATTESTATION (the cert, on-chain for AUDIT). When a parent P births this home via the offer-
603
- * effect, the kernel seeds a SIGNED [executor::birth_cert::BirthCert] {child, founder, verified, parentKey,
604
- * parentId, epoch} into the home's genesis (it travels with the home's `GenesisWarrant.bornUnder` so a peer
605
- * verifies it OFFLINE), AND folds this singleton record so the home's projection surfaces "who attested my
606
- * birth, and was my founder verified". `verified` + `founder` are the parent's GATE verdict (captured-port,
607
- * CAS-as-law), never the offer payload. A peer's TRUST decision uses the travelling signed chain (the kernel
608
- * verify doors); this aggregate is the human-readable mirror.
609
- */
610
- export const BIRTH_ATTESTATION_ID = "birth-attestation:self";
611
- export const BIRTH_ATTESTATION_LINK_PREFIX = "birth-attestation-link:";
612
- export const BirthAttestation = aggregate("BirthAttestation", {
613
- /** This home's self-id (`home-<sha256(founder)>`) — the cert's `child`. */
614
- child: t.string().merge(Lww),
615
- /** The founding principal the parent attested (== {@link HomeOwner} `principal`). */
616
- founder: t.string().merge(Lww),
617
- /** THE PARENT'S GATE VERDICT: was `founder` VERIFIED at the parent's offer gate (an IdP vouched)? */
618
- verified: t.string().merge(Lww), // "true"/"false" (string for the Lww scalar projection)
619
- /** The parent's workspace self-id (lineage). */
620
- parentId: t.string().merge(Lww),
621
- /** The parent's enrolled signer PUBLIC KEY (base64) — `K_P`, the cert's signer. */
622
- parentKey: t.string().merge(Lww),
623
- /** The parent's SignerEpoch at the attestation (informational; the cert is judged at birth-time validity). */
624
- epoch: t.int().merge(Lww),
625
- /** Legacy replay slot for histories authored before `BirthAttestationLink`. New histories write the
626
- * travelling chain only as ordered, typed link records below. */
627
- certChain: t.string().merge(Lww).optional(),
628
- }).public();
629
-
630
- /** One exact link in the travelling certificate chain. The zero-padded index is custody order; every
631
- * certificate member is a separate typed USDA property. `certChain` above remains only as a replay fallback
632
- * for histories authored before this aggregate existed. */
633
- export const BirthAttestationLink = aggregate("BirthAttestationLink", {
634
- index: t.int().merge(Lww),
635
- child: t.string().merge(Lww),
636
- founder: t.string().merge(Lww),
637
- verified: t.bool().merge(Lww),
638
- parentKey: t.string().merge(Lww),
639
- parentId: t.string().merge(Lww),
640
- epoch: t.int().merge(Lww),
641
- signature: t.string().merge(Lww),
642
- verifiedVia: t.string().merge(Lww).optional(),
643
- idpToken: t.string().merge(Lww).optional(),
644
- capturedClock: t.int().merge(Lww).optional(),
645
- authProviderIssuer: t.string().merge(Lww).optional(),
646
- authProviderJwks: t.string().merge(Lww).optional(),
647
- authProviderAudience: t.string().merge(Lww).optional(),
648
- }).public();
649
-
650
- /** Audit read: this home's birth attestation (who attested it + the verified verdict). */
651
- export const birthAttestation = query("birthAttestation").key("child").returns(BirthAttestation);
652
-
653
- /**
654
- * `seedBirthAttestation` — THE GENESIS-DOOR step the parent's offer-effect INJECTS into the home's genesis
655
- * chain (the kernel appends it in `run_birth_effect` carrying the assembled + signed cert chain). It folds
656
- * the [`BirthAttestation`] singleton so the home's own state carries its travelling cert. A CONTROL-PLANE
657
- * write seeded once at birth (the open session lane structurally refuses it by directive id). The values
658
- * are the parent's GATE VERDICT (`founder`/`verified` lowered from the captured port — CAS-as-law, never
659
- * the offer payload) + the typed signed links; the home's verify doors re-derive trust from the chain.
660
- */
661
- export const seedBirthAttestation = directive("seedBirthAttestation")
662
- .ensures(BirthAttestation)
663
- .payload(
664
- z.object({
665
- child: z.string().min(1),
666
- founder: z.string().min(1),
667
- verified: z.string().min(1), // "true"/"false"
668
- /** The parent's workspace self-id (lineage). EMPTY for a root-DIRECT birth (root carries no self-id
669
- * binding in the unwarranted lane) — the cert's terminal link is then signed by K_root directly. */
670
- parentId: z.string(),
671
- parentKey: z.string().min(1), // base64 K_P
672
- epoch: z.number().int().nonnegative(),
673
- links: z.array(birthCertificatePayload).min(1),
674
- /** Law-declared target roles for the verified immediate parent workspace. The kernel injects this
675
- * value from the admitted birth recipe and supplies `parentId`; no host chooses either fact. */
676
- parentWorkspaceRoles: z.array(z.string().regex(/^[A-Za-z][A-Za-z0-9_-]*$/)).optional(),
677
- }).superRefine((payload, ctx) => {
678
- if ((payload.parentWorkspaceRoles?.length ?? 0) > 0 && payload.parentId.length === 0) {
679
- ctx.addIssue({ code: "custom", message: "parent workspace roles require a verified non-root parentId" });
680
- }
681
- }),
682
- )
683
- .plan((p) => {
684
- const h = instance(BirthAttestation, BIRTH_ATTESTATION_ID);
685
- const header = [
686
- set(h, "child", p.child),
687
- set(h, "founder", p.founder),
688
- set(h, "verified", p.verified),
689
- set(h, "parentId", p.parentId),
690
- set(h, "parentKey", p.parentKey),
691
- set(h, "epoch", p.epoch),
692
- ];
693
- const links = p.links.flatMap((certificate, index) => {
694
- const link = instance(BirthAttestationLink, `${BIRTH_ATTESTATION_LINK_PREFIX}${String(index).padStart(8, "0")}`);
695
- return [
696
- withMarker(set(link, "index", index), "ensures"),
697
- withMarker(set(link, "child", certificate.child), "ensures"),
698
- withMarker(set(link, "founder", certificate.founder), "ensures"),
699
- withMarker(set(link, "verified", certificate.verified), "ensures"),
700
- withMarker(set(link, "parentKey", certificate.parentKey), "ensures"),
701
- withMarker(set(link, "parentId", certificate.parentId), "ensures"),
702
- withMarker(set(link, "epoch", certificate.epoch), "ensures"),
703
- withMarker(set(link, "signature", certificate.signature), "ensures"),
704
- ...(certificate.verifiedVia ? [withMarker(set(link, "verifiedVia", certificate.verifiedVia), "ensures")] : []),
705
- ...(certificate.idpToken ? [withMarker(set(link, "idpToken", certificate.idpToken), "ensures")] : []),
706
- ...(certificate.capturedClock === undefined ? [] : [withMarker(set(link, "capturedClock", certificate.capturedClock), "ensures")]),
707
- ...(certificate.authProviderIssuer ? [withMarker(set(link, "authProviderIssuer", certificate.authProviderIssuer), "ensures")] : []),
708
- ...(certificate.authProviderJwks ? [withMarker(set(link, "authProviderJwks", certificate.authProviderJwks), "ensures")] : []),
709
- ...(certificate.authProviderAudience ? [withMarker(set(link, "authProviderAudience", certificate.authProviderAudience), "ensures")] : []),
710
- ];
711
- });
712
- const parentAuthority = (p.parentWorkspaceRoles ?? []).flatMap((relation) => writeTuple({
713
- object: "workspace:self",
714
- relation,
715
- subject: `workspace:${p.parentId}`,
716
- grantedBy: `workspace:${p.parentId}`,
717
- grantedAt: String(p.epoch),
718
- }));
719
- return [...header, ...links, ...parentAuthority];
720
- })
721
- .alsoEnsures(BirthAttestationLink)
722
- .alsoEnsures(RelationTuple);
723
-
724
- /**
725
- * THE ERA DECLARATION (the `nomosParentAttestedBirth` USD key). Exporting this sentinel from the home law
726
- * tells the kernel's verify doors to VERIFY THE TRAVELLING CERT CHAIN to the pinned `K_root` on every lane
727
- * (author / receive / verify_chain) — so a warranted home that self-asserts a verified founder WITHOUT a
728
- * parent-signed chain rooting at root is refused (`ParentDidNotAttest` / `CertChainBroken` /
729
- * `NotRootedAtRoot`). Era-ruled: a home law that does NOT export this carries no key and replays byte-
730
- * identical (the squat-only `homeNameBindsOwner` check still runs; the cert check is simply inert).
731
- */
732
- export const parentAttestedBirth: ParentAttestedBirthMarker = {
733
- ...requireParentAttestedBirth,
734
- // DECLARE the owner + cert locators so the KERNEL reads them (it names neither): the home owner lives at
735
- // the `HomeOwner` singleton's `principal`. `certObject`/`certField` retain the legacy chain locator for
736
- // old histories; current histories are discovered through the typed `BirthAttestationLink` aggregate.
737
- ownerObject: RECEIVING_GROUP_ID,
738
- ownerField: "principal",
739
- certObject: BIRTH_ATTESTATION_ID,
740
- certField: "certChain",
741
- };
12
+ export * from "./receiving_group.js";