@githolon/dsl 0.102.4 → 0.103.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 (131) hide show
  1. package/compile_package.mjs +43 -2
  2. package/compile_proof.d.mts +47 -0
  3. package/compile_proof.mjs +343 -0
  4. package/dart/CHANGELOG.md +7 -0
  5. package/dart/lib/src/dev_cloud.dart +8 -8
  6. package/dart/lib/src/nms_generated_runtime.dart +2 -0
  7. package/dart/lib/src/runner/node-entry.mjs +5504 -1236
  8. package/dart/lib/src/runner/offline-install.mjs +4578 -528
  9. package/dart/lib/src/test_harness.dart +206 -152
  10. package/dart/lib/src/webview_bridge.dart +196 -89
  11. package/dart/pubspec.lock +1 -1
  12. package/dart/pubspec.yaml +2 -2
  13. package/dart/test/acquire_session_credentials_test.dart +4 -3
  14. package/dart/test/adv_realm_interference_test.dart +7 -6
  15. package/dart/test/cloud_bound_topology_test.dart +3 -3
  16. package/dart/test/cluster_births_test.dart +4 -3
  17. package/dart/test/cluster_device_keyed_acceptance_test.dart +10 -16
  18. package/dart/test/cluster_local_autosync_test.dart +3 -2
  19. package/dart/test/cluster_scale_test.dart +3 -2
  20. package/dart/test/dlq_session_surface_test.dart +7 -6
  21. package/dart/test/first_app_gauntlet_test.dart +14 -21
  22. package/dart/test/fixtures/wedge/fake-install.mjs +1 -1
  23. package/dart/test/four_layer_nested_topology_test.dart +4 -4
  24. package/dart/test/harness_phase_timeout_test.dart +2 -2
  25. package/dart/test/local_sync_inert_test.dart +1 -1
  26. package/dart/test/parent_signer_recovery_test.dart +2 -2
  27. package/dart/test/sealing_client_test.dart +4 -3
  28. package/dart/test/session_bound_test.dart +8 -7
  29. package/dart/test/test_harness_test.dart +13 -12
  30. package/dart/test/vo_read_typing_test.dart +4 -3
  31. package/dart/test/watch_after_offer_stall_test.dart +4 -3
  32. package/dart/test/webview_bridge_test.dart +102 -5
  33. package/dart_types/CHANGELOG.md +5 -0
  34. package/dart_types/lib/nomos_types.dart +9 -0
  35. package/dart_types/lib/src/nomos_ref.dart +20 -0
  36. package/dart_types/lib/src/optional_ref.dart +85 -0
  37. package/dart_types/lib/src/sha256_digest.dart +41 -0
  38. package/dart_types/lib/src/versioned_nomos_ref.dart +81 -0
  39. package/dart_types/pubspec.yaml +1 -1
  40. package/dart_types/test/optional_ref_test.dart +44 -0
  41. package/dart_types/test/sha256_digest_test.dart +18 -0
  42. package/package.json +9 -5
  43. package/runtime/generated-application-host.js +5365 -1105
  44. package/src/aggregate.ts +18 -0
  45. package/src/application_composition.ts +6 -32
  46. package/src/attested_core.ts +6 -3
  47. package/src/birth_meter.ts +1 -0
  48. package/src/birth_meter_ensure.ts +28 -2
  49. package/src/births.ts +1 -1
  50. package/src/build_package.ts +162 -538
  51. package/src/business_birth.ts +19 -3
  52. package/src/canonical_json.ts +21 -0
  53. package/src/check_package_main.ts +76 -35
  54. package/src/clear_directive.ts +19 -8
  55. package/src/codegen_dart.ts +305 -22
  56. package/src/codegen_dart_application.ts +844 -292
  57. package/src/codegen_dart_client.ts +1084 -407
  58. package/src/codegen_dart_scenario.ts +12 -12
  59. package/src/codegen_proof.ts +169 -39
  60. package/src/codegen_provider_dart.ts +17 -1
  61. package/src/codegen_ts.ts +298 -106
  62. package/src/compat_manifest.ts +2 -2
  63. package/src/compat_package_main.ts +8 -12
  64. package/src/compile_package_main.ts +1866 -597
  65. package/src/compose.ts +1 -1
  66. package/src/directive.ts +208 -15
  67. package/src/engine_entry.ts +165 -111
  68. package/src/evolve_preview.ts +43 -81
  69. package/src/extremum.ts +1 -1
  70. package/src/fields.ts +183 -4
  71. package/src/flow_gate.ts +75 -2
  72. package/src/framework/application_home.ts +2 -0
  73. package/src/framework/auth_provider_law.ts +2 -2
  74. package/src/framework/birth_meter.ts +7 -19
  75. package/src/framework/bootstrap.ts +0 -2
  76. package/src/framework/business_corrections.ts +9 -5
  77. package/src/framework/domain_lifecycle.ts +15 -29
  78. package/src/framework/encryption_scope.ts +2 -1
  79. package/src/framework/framework_aggregates.ts +2 -0
  80. package/src/framework/genesis.ts +16 -14
  81. package/src/framework/home.ts +20 -14
  82. package/src/framework/owned_custody.ts +9 -3
  83. package/src/framework/platform_admin.ts +3 -3
  84. package/src/framework/relations.ts +21 -13
  85. package/src/framework/signing_identity.ts +45 -40
  86. package/src/framework/workspace_invariant.ts +245 -0
  87. package/src/framework/workspaces.ts +23 -29
  88. package/src/index.ts +36 -16
  89. package/src/intent.ts +178 -6
  90. package/src/law_check.ts +32 -11
  91. package/src/law_graph.ts +2902 -0
  92. package/src/law_graph_usda.ts +1799 -0
  93. package/src/law_identity.ts +435 -0
  94. package/src/law_value_type.ts +230 -0
  95. package/src/lsp_server.ts +61 -31
  96. package/src/ops.ts +7 -0
  97. package/src/package_config.ts +141 -0
  98. package/src/package_dependencies.ts +108 -0
  99. package/src/package_dependency_usage.ts +150 -0
  100. package/src/package_source_imports.ts +71 -0
  101. package/src/plan_source_slice.ts +335 -0
  102. package/src/point_guard.ts +192 -0
  103. package/src/precondition.ts +44 -9
  104. package/src/read_projection_namespace.ts +1 -1
  105. package/src/runtime_zod.ts +44 -0
  106. package/src/secondary_ensure.ts +67 -14
  107. package/src/shape_compat.ts +1 -1
  108. package/src/stable_id_identity_bridge.ts +149 -0
  109. package/src/stable_id_lockfile.ts +278 -0
  110. package/src/stable_ids.ts +7 -2
  111. package/src/stable_ids_for_module.ts +348 -0
  112. package/src/stable_ids_types.ts +1 -1
  113. package/src/sum.ts +1 -1
  114. package/src/usd_state.ts +1 -1
  115. package/src/usda_relationship_integrity.ts +66 -0
  116. package/src/usda_text.ts +18 -0
  117. package/src/usdz.ts +78 -0
  118. package/src/value_object.ts +95 -0
  119. package/src/wire.ts +19 -0
  120. package/src/wire_encode.ts +22 -0
  121. package/src/workspace_sharding.ts +52 -36
  122. package/src/workspace_sharing.ts +28 -4
  123. package/src/zod_introspection.ts +1 -1
  124. package/dart/test/cluster_attested_test.dart +0 -201
  125. package/src/compile_engine.ts +0 -595
  126. package/src/manifest.ts +0 -1476
  127. package/src/read_projection_composition.ts +0 -117
  128. package/src/read_projection_manifest.ts +0 -115
  129. package/src/relation_composition.ts +0 -286
  130. package/src/usd.ts +0 -1967
  131. package/src/usd_layers.ts +0 -1776
@@ -13,7 +13,7 @@ import { Lww } from "../drivers.js";
13
13
  import { set, withMarker } from "../ops.js";
14
14
  import { query } from "../query.js";
15
15
  import { GENESIS_WARRANT_ID } from "./genesis.js";
16
- import { refAs, workspaceInvariant } from "./workspace_invariant.js";
16
+ import { readRef, readSet, refAs, workspaceInvariant } from "./workspace_invariant.js";
17
17
 
18
18
  const epochMs = z.number().int().nonnegative();
19
19
 
@@ -135,7 +135,7 @@ export const seedAuthProvider = directive("seedAuthProvider")
135
135
 
136
136
  export const authProviderSeedBeforeWarrant = workspaceInvariant("AuthProviderSeedBeforeWarrant")
137
137
  .on("seedAuthProvider")
138
- .reads(() => [refAs("warrant", "GenesisWarrant", GENESIS_WARRANT_ID)])
138
+ .reads(readSet(readRef("warrant", "GenesisWarrant").at(GENESIS_WARRANT_ID)))
139
139
  .assert(({ warrant }) => {
140
140
  // Missing invariant refs are represented as an empty snapshot by the executor, not necessarily null.
141
141
  const principal = (warrant as { principal?: unknown } | null | undefined)?.principal;
@@ -27,7 +27,7 @@ import { z } from "zod";
27
27
  import { instance } from "../aggregate.js";
28
28
  import { directive } from "../directive.js";
29
29
  import { set, type PlannedOp } from "../ops.js";
30
- import { refAs, workspaceInvariant } from "./workspace_invariant.js";
30
+ import { readRef, readSet, refAs, workspaceInvariant } from "./workspace_invariant.js";
31
31
  import {
32
32
  BirthPolicy,
33
33
  BirthGrant,
@@ -149,9 +149,7 @@ export const reclaimChildAsAdmin = directive("reclaimChildAsAdmin")
149
149
  /** Reclaim is two-phase; a child must first be explicitly withdrawn. */
150
150
  export const reclaimChildRequiresRetired = workspaceInvariant("ReclaimChildRequiresRetired")
151
151
  .on("reclaimChild")
152
- .reads((ctx) => [
153
- refAs("record", "NomosChildLifecycle", "pre:" + childLifecycleId(String(ctx.intent.child ?? ""))),
154
- ])
152
+ .reads(readSet(readRef("record", NomosChildLifecycle).pre().fromPayload("child", { prefix: "nomos-child-lifecycle:" })))
155
153
  .assert(({ record }, ctx) =>
156
154
  (record as { status?: string; principal?: string } | undefined)?.status === "retired"
157
155
  && sameLifecyclePrincipal((record as { principal?: string }).principal, ctx?.principal)
@@ -162,9 +160,7 @@ export const reclaimChildRequiresRetired = workspaceInvariant("ReclaimChildRequi
162
160
  /** Operator recovery has the same two-phase law, without depending on the broken creator credential. */
163
161
  export const reclaimChildAsAdminRequiresRetired = workspaceInvariant("ReclaimChildAsAdminRequiresRetired")
164
162
  .on("reclaimChildAsAdmin")
165
- .reads((ctx) => [
166
- refAs("record", "NomosChildLifecycle", "pre:" + childLifecycleId(String(ctx.intent.child ?? ""))),
167
- ])
163
+ .reads(readSet(readRef("record", NomosChildLifecycle).pre().fromPayload("child", { prefix: "nomos-child-lifecycle:" })))
168
164
  .assert(({ record }) =>
169
165
  (record as { status?: string } | undefined)?.status === "retired"
170
166
  ? { accept: true }
@@ -174,9 +170,7 @@ export const reclaimChildAsAdminRequiresRetired = workspaceInvariant("ReclaimChi
174
170
  /** Reclaimed is permanent: retirement cannot move a child back out of the terminal state. */
175
171
  export const retireChildNotReclaimed = workspaceInvariant("RetireChildNotReclaimed")
176
172
  .on("retireChild")
177
- .reads((ctx) => [
178
- refAs("record", "NomosChildLifecycle", "pre:" + childLifecycleId(String(ctx.intent.child ?? ""))),
179
- ])
173
+ .reads(readSet(readRef("record", NomosChildLifecycle).pre().fromPayload("child", { prefix: "nomos-child-lifecycle:" })))
180
174
  .assert(({ record }) =>
181
175
  (record as { status?: string } | undefined)?.status === "reclaimed"
182
176
  ? { reject: "reclaimed-child-is-terminal" }
@@ -186,9 +180,7 @@ export const retireChildNotReclaimed = workspaceInvariant("RetireChildNotReclaim
186
180
  /** Reclaimed is terminal for operator recovery too. */
187
181
  export const retireChildAsAdminNotReclaimed = workspaceInvariant("RetireChildAsAdminNotReclaimed")
188
182
  .on("retireChildAsAdmin")
189
- .reads((ctx) => [
190
- refAs("record", "NomosChildLifecycle", "pre:" + childLifecycleId(String(ctx.intent.child ?? ""))),
191
- ])
183
+ .reads(readSet(readRef("record", NomosChildLifecycle).pre().fromPayload("child", { prefix: "nomos-child-lifecycle:" })))
192
184
  .assert(({ record }) =>
193
185
  (record as { status?: string } | undefined)?.status === "reclaimed"
194
186
  ? { reject: "reclaimed-child-is-terminal" }
@@ -198,9 +190,7 @@ export const retireChildAsAdminNotReclaimed = workspaceInvariant("RetireChildAsA
198
190
  /** A lifecycle cannot mint authority for arbitrary custody: retirement must name its exact birth witness. */
199
191
  export const retireChildRequiresBirth = workspaceInvariant("RetireChildRequiresBirth")
200
192
  .on("retireChild")
201
- .reads((ctx) => [
202
- refAs("birth", "NomosBirthRecord", "pre:" + birthRecordId(String(ctx.intent.child ?? ""))),
203
- ])
193
+ .reads(readSet(readRef("birth", NomosBirthRecord).pre().fromPayload("child", { prefix: "nomos-birth-record:" })))
204
194
  .assert(({ birth }, ctx) => {
205
195
  const record = birth as { child?: string; principal?: string } | undefined;
206
196
  const intent = ctx?.intent as { child?: string; principal?: string } | undefined;
@@ -214,9 +204,7 @@ export const retireChildRequiresBirth = workspaceInvariant("RetireChildRequiresB
214
204
  /** Admin recovery may act for the recorded creator, but still cannot invent or retarget custody. */
215
205
  export const retireChildAsAdminRequiresBirth = workspaceInvariant("RetireChildAsAdminRequiresBirth")
216
206
  .on("retireChildAsAdmin")
217
- .reads((ctx) => [
218
- refAs("birth", "NomosBirthRecord", "pre:" + birthRecordId(String(ctx.intent.child ?? ""))),
219
- ])
207
+ .reads(readSet(readRef("birth", NomosBirthRecord).pre().fromPayload("child", { prefix: "nomos-birth-record:" })))
220
208
  .assert(({ birth }, ctx) => {
221
209
  const record = birth as { child?: string; principal?: string } | undefined;
222
210
  const intent = ctx?.intent as { child?: string; principal?: string } | undefined;
@@ -16,7 +16,5 @@
16
16
 
17
17
  export {
18
18
  DomainInstallation,
19
- PolicyBundle,
20
19
  installDomain,
21
- policyAggregateId,
22
20
  } from "./domain_lifecycle.js";
@@ -22,8 +22,16 @@ const correctionRecord = aggregate(BUSINESS_CORRECTION_AGGREGATE, {
22
22
  correctedAt: t.string().merge(Lww),
23
23
  }).public();
24
24
 
25
+ export const businessCorrectionRecord = {
26
+ ...correctionRecord,
27
+ businessBirthInternal: true as const,
28
+ };
29
+
25
30
  const correction = directive(BUSINESS_CORRECTION_DIRECTIVE)
26
- .ensures(correctionRecord)
31
+ // The directive's typed aggregate handle is followed by composeDomainModule. It must be the same
32
+ // framework-private singleton that is exported below; pointing at the unbranded construction
33
+ // intermediate lets that handle overwrite the branded one during typed target closure.
34
+ .ensures(businessCorrectionRecord)
27
35
  .payload(z.object({
28
36
  recordId: z.string().min(1),
29
37
  target: z.string().min(1),
@@ -45,10 +53,6 @@ const correction = directive(BUSINESS_CORRECTION_DIRECTIVE)
45
53
  ];
46
54
  });
47
55
 
48
- export const businessCorrectionRecord = {
49
- ...correctionRecord,
50
- businessBirthInternal: true as const,
51
- };
52
56
  export const recordBusinessCorrection = {
53
57
  ...correction,
54
58
  businessBirthInternal: true as const,
@@ -9,10 +9,10 @@
9
9
  * The `nomos` lifecycle/controller surface.
10
10
  *
11
11
  * This is the Kubernetes CRD/API-server split in Nomos terms:
12
- * * `PolicyBundle` is the content-addressed package object (`policy:{hash}.bundle`);
13
- * * `DomainInstallation` is the workspace resource with spec/status/phase;
14
- * * `installDomain` writes BOTH in one intent and declares the `installDomain`
15
- * capability. `stageDomain` writes the same content as Pending without serving it;
12
+ * * the kernel-custodied USDA closure is the content-addressed law object;
13
+ * * `DomainInstallation` is the small workspace resource with spec/status/phase;
14
+ * * `installDomain` writes that reference in one intent and declares the `installDomain`
15
+ * capability. `stageDomain` records the same closure as Pending without serving it;
16
16
  * `promoteDomain` and `rollbackDomain` are phase changes whose admission is judged
17
17
  * against the staged package. This is the richer controller API; bootstrap exposes
18
18
  * a thinner install-only intent for stage-zero.
@@ -43,16 +43,12 @@ export const DOMAIN_INSTALLATION_PHASES = [
43
43
  ] as const;
44
44
  export type DomainInstallationPhase = (typeof DOMAIN_INSTALLATION_PHASES)[number];
45
45
 
46
- export const PolicyBundle = aggregate("PolicyBundle", {
47
- bundle: t.string().merge(Lww),
48
- }).public();
49
-
50
46
  export const DomainInstallation = aggregate("DomainInstallation", {
51
47
  "spec.domainHash": t.string().merge(Lww),
52
48
  "spec.packageHash": t.string().merge(Lww),
53
- "spec.policyAggregate": t.string().merge(Lww),
54
49
  "spec.authorityScope": t.string().merge(Lww),
55
50
  "spec.installedBy": t.string().merge(Lww),
51
+ "spec.lawClosureIdentity": t.string().merge(Lww),
56
52
  "spec.dependencies": t.set(t.string()),
57
53
  "spec.supersedes": t.string().merge(Lww).optional(),
58
54
  "spec.finalizers": t.set(t.string()),
@@ -95,18 +91,10 @@ export const ReleaseReceipt = aggregate(RELEASE_RECEIPT_AGGREGATE, {
95
91
  acceptedAt: t.int().merge(Lww),
96
92
  }).public();
97
93
 
98
- export function policyAggregateId(domainHash: string): string {
99
- return `policy:${domainHash}`;
100
- }
101
-
102
94
  export function domainInstallationAggregateId(domainHash: string): string {
103
95
  return `domain-installation:${domainHash}`;
104
96
  }
105
97
 
106
- function policyBundleInstance(domainHash: string) {
107
- return instance(PolicyBundle, policyAggregateId(domainHash));
108
- }
109
-
110
98
  function domainInstallationInstance(domainHash: string) {
111
99
  return instance(DomainInstallation, domainInstallationAggregateId(domainHash));
112
100
  }
@@ -157,13 +145,15 @@ const preflightReceipt = z.object({
157
145
  });
158
146
 
159
147
  const packagePayload = {
160
- domainHash: z.string(),
161
- packageUsda: z.string(),
148
+ domainHash: lowerHex64,
162
149
  installedBy: z.string(),
150
+ lawClosureIdentity: lowerHex64,
163
151
  authorityScope: z.string().default("workspace/root"),
164
- dependencies: z.array(z.string()).default([]),
152
+ // Omission means the empty set; keep that in the plan instead of encoding a composite default
153
+ // into canonical USDA merely to save `?? []` at runtime.
154
+ dependencies: z.array(z.string()).optional(),
165
155
  supersedes: z.string().optional(),
166
- finalizers: z.array(z.string()).default([]),
156
+ finalizers: z.array(z.string()).optional(),
167
157
  };
168
158
 
169
159
  export const installDomain = directive("installDomain")
@@ -185,15 +175,13 @@ export const installDomain = directive("installDomain")
185
175
  }),
186
176
  )
187
177
  .plan((p): PlannedOp[] => {
188
- const policy = policyBundleInstance(p.domainHash);
189
178
  const install = domainInstallationInstance(p.domainHash);
190
179
  const ops: PlannedOp[] = [
191
- withMarker(set(policy, "bundle", p.packageUsda), "ensures"),
192
- set(install, "spec.domainHash", p.domainHash),
180
+ withMarker(set(install, "spec.domainHash", p.domainHash), "ensures"),
193
181
  set(install, "spec.packageHash", p.domainHash),
194
- set(install, "spec.policyAggregate", policyAggregateId(p.domainHash)),
195
182
  set(install, "spec.authorityScope", p.authorityScope),
196
183
  set(install, "spec.installedBy", p.installedBy),
184
+ set(install, "spec.lawClosureIdentity", p.lawClosureIdentity),
197
185
  set(install, "metadata.generation", 1),
198
186
  set(install, "status.phase", "Active"),
199
187
  set(install, "status.observedGeneration", 1),
@@ -231,15 +219,13 @@ export const stageDomain = directive("stageDomain")
231
219
  { message: "a staged domain package cannot supersede itself", path: ["supersedes"] },
232
220
  ))
233
221
  .plan((p): PlannedOp[] => {
234
- const policy = policyBundleInstance(p.domainHash);
235
222
  const install = domainInstallationInstance(p.domainHash);
236
223
  const ops: PlannedOp[] = [
237
- withMarker(set(policy, "bundle", p.packageUsda), "ensures"),
238
- set(install, "spec.domainHash", p.domainHash),
224
+ withMarker(set(install, "spec.domainHash", p.domainHash), "ensures"),
239
225
  set(install, "spec.packageHash", p.domainHash),
240
- set(install, "spec.policyAggregate", policyAggregateId(p.domainHash)),
241
226
  set(install, "spec.authorityScope", p.authorityScope),
242
227
  set(install, "spec.installedBy", p.installedBy),
228
+ set(install, "spec.lawClosureIdentity", p.lawClosureIdentity),
243
229
  set(install, "metadata.generation", 1),
244
230
  set(install, "status.phase", "Pending"),
245
231
  set(install, "status.observedGeneration", 0),
@@ -146,7 +146,8 @@ export const advanceKeyEpoch = directive("advanceKeyEpoch")
146
146
  wraps: z.array(wrapEntrySchema),
147
147
  }),
148
148
  )
149
- .plan((p) => writeKeyEpoch(p.scope, p.epoch, p.openedAt, p.wraps));
149
+ .plan((p) => writeKeyEpoch(p.scope, p.epoch, p.openedAt, p.wraps))
150
+ .alsoEnsuresMany(WrappedKey);
150
151
 
151
152
  /**
152
153
  * `wrapKey` — write ONE wrap (the single-member handoff). Beyond its use as a primitive,
@@ -36,6 +36,7 @@ import { nomosSourceFrontierEnsure } from "../attested.js";
36
36
  import * as birthMeter from "../birth_meter.js";
37
37
  import * as birthMeterEnsure from "../birth_meter_ensure.js";
38
38
  import * as birthMeterFramework from "./birth_meter.js";
39
+ import * as businessCorrections from "./business_corrections.js";
39
40
  import * as authProviderLaw from "./auth_provider_law.js";
40
41
  import * as disclosure from "./disclosure.js";
41
42
  import * as domainLifecycle from "./domain_lifecycle.js";
@@ -59,6 +60,7 @@ const FRAMEWORK_NAMESPACES: ReadonlyArray<Record<string, unknown>> = [
59
60
  birthMeter,
60
61
  birthMeterEnsure,
61
62
  birthMeterFramework,
63
+ businessCorrections,
62
64
  authProviderLaw,
63
65
  disclosure,
64
66
  domainLifecycle,
@@ -9,18 +9,19 @@
9
9
  *
10
10
  * THE BOOTSTRAP PARADOX: the relation gate refuses a founding control-plane grant
11
11
  * on a VIRGIN chain (an empty `#admin`/`#creator`/… roster) — there is no admin yet
12
- * to gate the first admin. Resolved LAWFULLY (not by a host bypass): at birth the
13
- * host verifies the `x-nomos-auth` token ONCE and records the verified principal as
14
- * an in-history fact — this `GenesisWarrant`. The gate's GENESIS CLAUSE
12
+ * to gate the first admin. Resolved LAWFULLY (not by a host bypass): the root
13
+ * `seedGenesis` is signed by the self-authenticating key principal it installs; a
14
+ * child receives its warrant only from the kernel's already-admitted parent-birth
15
+ * effect and the carried birth certificate rooted at K_root. The gate's GENESIS CLAUSE
15
16
  * (`executor::genesis_admits`) then admits a founding grant on a virgin object IFF
16
17
  * the warrant binds the chain to the captured principal. Strictly additive (only an
17
18
  * otherwise-`Unauthorized` virgin grant), so every sealed chain replays unchanged.
18
19
  *
19
- * CONTROL-PLANE: `seedGenesis` is authored by the BIRTH DOOR (the host, after the
20
- * one-time token verification), NOT by the open session lane — the session lane
21
- * structurally refuses control-plane intents, so a tenant cannot forge a warrant for
22
- * a principal it does not own. The warrant is the host's recorded verification, not
23
- * a host authority decision: every replaying peer re-reads the chain fact.
20
+ * CONTROL-PLANE: `seedGenesis` is never a host assertion. At the root it carries an
21
+ * author block whose public key derives the claimed `key:<sha256>` principal and whose
22
+ * signature binds the exact workspace id. For descendants it is emitted only by the
23
+ * kernel after verifying the parent's admitted birth and K_root-rooted certificate.
24
+ * Every replaying peer re-verifies those cryptographic facts from custody.
24
25
  *
25
26
  * SINGLETON per chain: one founding principal per home/workspace, so the warrant is
26
27
  * a singleton keyed `genesis-warrant:self`. `seedGenesis` is create-once — a second
@@ -32,7 +33,7 @@ import { t } from "../fields.js";
32
33
  import { Lww } from "../drivers.js";
33
34
  import { directive } from "../directive.js";
34
35
  import { set, type PlannedOp } from "../ops.js";
35
- import { writeTuple } from "./relations.js";
36
+ import { RelationTuple, writeTuple } from "./relations.js";
36
37
 
37
38
  /**
38
39
  * Deterministic singleton id of the founding warrant — MUST equal
@@ -42,16 +43,16 @@ export const GENESIS_WARRANT_ID = "genesis-warrant:self";
42
43
 
43
44
  /**
44
45
  * The founding-warrant record. It does THREE jobs at once:
45
- * - `principal` — the x-nomos-auth-verified OWNER (the genesis clause binds the founding grant to it);
46
+ * - `principal` — the cryptographically proven founder (the genesis clause binds the founding grant to it);
46
47
  * - `workspaceId` — this workspace's UNIQUE SELF-ID (the source binding the author signature covers,
47
48
  * re-derived locally by the gate — NOT the shared/deterministic genesis commit, which is identical
48
49
  * across all workspaces and so bound nothing);
49
50
  * - its mere PRESENCE — the SIGNED-AUTHOR REGIME signal (the "era"): a workspace with a warrant
50
- * REQUIRES a verified author block (forge closed); one without falls back to the legacy
51
- * host-stamped principal (pre-feature chains replay green, per-position).
51
+ * REQUIRES a verified author block (forge closed). A root seed proves itself against
52
+ * its own workspace-bound key; descendants additionally carry their parent-attested lineage.
52
53
  */
53
54
  export const GenesisWarrant = aggregate("GenesisWarrant", {
54
- principal: t.string().merge(Lww), // the x-nomos-auth-verified owner, recorded at birth
55
+ principal: t.string().merge(Lww), // the cryptographically proven founder, recorded at birth
55
56
  workspaceId: t.string().merge(Lww), // this workspace's unique self-id (the author-signature source binding)
56
57
  bornAt: t.string().merge(Lww), // ISO-8601, caller-stamped (determinism)
57
58
  }).public();
@@ -104,4 +105,5 @@ export const seedGenesis = directive("seedGenesis")
104
105
  grantedBy: p.principal,
105
106
  grantedAt: p.bornAt,
106
107
  }),
107
- ]);
108
+ ])
109
+ .alsoEnsures(RelationTuple);
@@ -37,9 +37,9 @@ import { query } from "../query.js";
37
37
  import { birth } from "../births.js";
38
38
  import { readFrameworkDeclared } from "../read.js";
39
39
  import { authProvider as authProviderQuery, seedAuthProvider } from "./auth_provider_law.js";
40
- import { workspaceInvariant, refAs } from "./workspace_invariant.js";
40
+ import { readRef, readSet, workspaceInvariant, refAs } from "./workspace_invariant.js";
41
41
  import { identityRelations } from "./signing_identity.js";
42
- import { writeTuple } from "./relations.js";
42
+ import { RelationTuple, writeTuple } from "./relations.js";
43
43
  import { relationType, self, user, selfObject } from "../relation_schema.js";
44
44
  import { requireParentAttestedBirth, type ParentAttestedBirthMarker } from "../births.js";
45
45
  import { GenesisWarrant, seedGenesis } from "./genesis.js";
@@ -168,7 +168,8 @@ export function writeReceivingGroup(p: { principal: string; workspaceName: strin
168
168
  export const seedReceivingGroup = directive("nomosInternalSeedReceivingGroup7c1f5e")
169
169
  .ensures(ReceivingGroup)
170
170
  .payload(z.object({ principal: z.string().min(1), workspaceName: z.string().min(1), bornAt: z.string().min(1) }))
171
- .plan((p) => writeReceivingGroup(p));
171
+ .plan((p) => writeReceivingGroup(p))
172
+ .alsoEnsures(RelationTuple);
172
173
 
173
174
  /**
174
175
  * THE SQUAT INVARIANT (home_holons §5) — a home holon's self-committed `homeName` MUST be the hash of its
@@ -180,7 +181,7 @@ export const seedReceivingGroup = directive("nomosInternalSeedReceivingGroup7c1f
180
181
  */
181
182
  export const receivingGroupNameBindsPrincipal = workspaceInvariant("ReceivingGroupNameBindsPrincipal")
182
183
  .on("nomosInternalSeedReceivingGroup7c1f5e")
183
- .reads(() => [refAs("group", "NomosInternalReceivingGroup7c1f5e", RECEIVING_GROUP_ID)])
184
+ .reads(readSet(readRef("group", ReceivingGroup).at(RECEIVING_GROUP_ID)))
184
185
  .declassify("the receiving-group address is a public hash of its stable principal; refusing a mismatch reveals no private field")
185
186
  .assert(({ group }) => {
186
187
  const g = (group ?? {}) as { principal?: string; workspaceName?: string };
@@ -191,10 +192,10 @@ export const receivingGroupNameBindsPrincipal = workspaceInvariant("ReceivingGro
191
192
  : { reject: "a receiving group's workspace name must hash its stable principal" };
192
193
  });
193
194
 
194
- const receivingGroupPolicyRefs = () => [
195
- refAs("group", "NomosInternalReceivingGroup7c1f5e", RECEIVING_GROUP_ID),
196
- refAs("policy", "NomosInternalReceivingGroupPolicy7c1f5e", RECEIVING_GROUP_POLICY_ID),
197
- ];
195
+ const receivingGroupPolicyRefs = readSet(
196
+ readRef("group", ReceivingGroup).at(RECEIVING_GROUP_ID),
197
+ readRef("policy", ReceivingGroupPolicy).at(RECEIVING_GROUP_POLICY_ID),
198
+ );
198
199
 
199
200
  /** An IdP token may bootstrap the parent before the group exists; it may never bypass an existing group's
200
201
  * device policy. A new group device must be approved by a current device or, later, guardian evidence. */
@@ -259,7 +260,7 @@ export function receivingGroupNameOf(principal: string): string {
259
260
  * (no anonymous home birth); the offer principal IS the auth boundary (the tenant's setAuthProvider).
260
261
  *
261
262
  * The genesis chain it authors (reusing the order-declares-the-law install shape — bytes resolved by hash
262
- * from the parent's custody, `domainPackageB64: ""`):
263
+ * from the parent's typed USDA closure custody):
263
264
  * [ bootstrap/installDomain(frameworkHash), nomos/home installDomain(lawHash), seedHomeOwner(owner, …) ]
264
265
  * `frameworkHash` (the bootstrap controller hash) + `lawHash` (the HOME law package domainHash) are
265
266
  * tenant-PINNED at their governance compile (mirroring `birthChild`) — the end-user app supplies neither;
@@ -352,11 +353,11 @@ export function birthReceivingGroupForDomain(groupLawDomain: string) {
352
353
  let certVerified = false;
353
354
  try { certVerified = p.homeCert !== undefined && JSON.parse(p.homeCert).verified === true; } catch { /* malformed cert ⇒ unverified (the gate will refuse the birth anyway) */ }
354
355
  const verifiedVia = certVerified ? apStr("issuer") : undefined;
355
- const genesisChain: Array<{ domain: string; directiveId: string; actor: string; payload: Record<string, unknown>; domainHash?: string; domainPackageB64?: string }> = [
356
- // THE ORDER-DECLARED LAW INSTALL: two layers, bytes-by-hash (empty package — the kernel resolves them
357
- // from the parent's custody when it folds the birth; never the host). Matches buildGenesisChain's shape.
358
- { domain: "bootstrap", directiveId: "installDomain", actor: founder, payload: { domainHash: p.frameworkHash }, domainHash: p.frameworkHash, domainPackageB64: "" },
359
- { domain: "nomos", directiveId: "installDomain", actor: founder, payload: { domainHash: p.lawHash }, domainHash: p.lawHash, domainPackageB64: "" },
356
+ const genesisChain: Array<{ domain: string; directiveId: string; actor: string; payload: Record<string, unknown>; domainHash?: string }> = [
357
+ // THE ORDER-DECLARED LAW INSTALL: two typed closure identities. The kernel resolves each
358
+ // closure from the parent's custody when it folds the birth; law bytes never ride the intent.
359
+ { domain: "bootstrap", directiveId: "installDomain", actor: founder, payload: { domainHash: p.frameworkHash }, domainHash: p.frameworkHash },
360
+ { domain: "nomos", directiveId: "installDomain", actor: founder, payload: { domainHash: p.lawHash }, domainHash: p.lawHash },
360
361
  {
361
362
  domain: groupLawDomain,
362
363
  directiveId: "nomosInternalSeedReceivingGroupPolicy7c1f5e",
@@ -509,6 +510,11 @@ export const pruneShare = directive("pruneShare")
509
510
  /** "Show me everything <asserter> shared with me" — an indexed probe over the local access list. */
510
511
  export const sharedByWorkspace = query("sharedByWorkspace").key("asserterWorkspace").returns(SharedWithMe);
511
512
 
513
+ /** "Show me every share for this protected object" — the indexed access-list probe used by generated
514
+ * application discovery. A home commonly has a very large installed law, so discovery must never fall back
515
+ * to the generic `aggregatesByType(SharedWithMe)` scan merely to find whole-workspace shares. */
516
+ export const sharedByObject = query("sharedByObject").key("object").returns(SharedWithMe);
517
+
512
518
  // ─────────────────── THE PEER-SOVEREIGN ROOT-OF-TRUST (the BirthAttestation cert chain) ───────────────────
513
519
 
514
520
  /**
@@ -288,7 +288,8 @@ function ownedRecordActionDirectives(aggregate: AggregateHandle) {
288
288
  grantedAt: p.sharedAt,
289
289
  }),
290
290
  ...p.wraps.flatMap((entry) => writeWrap(recordScope(aggregate, p.recordId), entry.epoch, entry)),
291
- ]),
291
+ ])
292
+ .alsoEnsures(RelationTuple),
292
293
  { businessBirthInternal: true as const },
293
294
  );
294
295
 
@@ -313,7 +314,9 @@ function ownedRecordActionDirectives(aggregate: AggregateHandle) {
313
314
  revokedAt: p.changedAt,
314
315
  }),
315
316
  ...writeKeyEpoch(recordScope(aggregate, p.recordId), p.epoch, p.changedAt, p.wraps),
316
- ]),
317
+ ])
318
+ .alsoEnsures(RelationTuple)
319
+ .alsoEnsuresMany(WrappedKey),
317
320
  { businessBirthInternal: true as const },
318
321
  );
319
322
 
@@ -354,7 +357,10 @@ function ownedRecordActionDirectives(aggregate: AggregateHandle) {
354
357
  ops.push(...writeKeyEpoch(scope, p.epoch, p.changedAt, []));
355
358
  for (const entry of p.historicWraps) ops.push(...writeWrap(scope, entry.epoch, entry));
356
359
  return ops;
357
- }),
360
+ })
361
+ .alsoEnsuresMany(RelationTuple)
362
+ .alsoMutates(aggregate)
363
+ .alsoEnsuresMany(WrappedKey),
358
364
  { businessBirthInternal: true as const },
359
365
  );
360
366
 
@@ -102,7 +102,7 @@ import { directive, type RequirableDirective } from "../directive.js";
102
102
  import { set } from "../ops.js";
103
103
  import { query, type QueryDecl } from "../query.js";
104
104
  import { writeTuple, RelationTuple } from "./relations.js";
105
- import { workspaceInvariant, refAs, type WorkspaceInvariantDecl } from "./workspace_invariant.js";
105
+ import { readRef, readSet, workspaceInvariant, refAs, type WorkspaceInvariantDecl } from "./workspace_invariant.js";
106
106
 
107
107
  /** The founder singleton's stable instance id — one founder per platform workspace (`workspace:self`). */
108
108
  export const PLATFORM_FOUNDER_ID = "platform-founder:self";
@@ -215,7 +215,7 @@ export function seedPlatformAdmin(opts: SeedPlatformAdminOptions): PlatformAdmin
215
215
  */
216
216
  const platformFounderWriteOnce = workspaceInvariant(writeOnceInvariantId)
217
217
  .on(founderDirectiveId)
218
- .reads(() => [refAs("prior", founderAggregateId, "pre:" + PLATFORM_FOUNDER_ID)])
218
+ .reads(readSet(readRef("prior", founderAggregateId).pre().at(PLATFORM_FOUNDER_ID)))
219
219
  .assert(({ prior }, ctx) => {
220
220
  const seated = (prior ?? {}) as { principal?: string };
221
221
  // WRITE-ONCE: a founder already recorded ⇒ refuse a re-seat (the seat is immutable after genesis).
@@ -260,7 +260,7 @@ export function seedPlatformAdmin(opts: SeedPlatformAdminOptions): PlatformAdmin
260
260
  */
261
261
  const platformAdminBindsFounder = workspaceInvariant(bindsInvariantId)
262
262
  .on(seatDirectiveId)
263
- .reads(() => [refAs("founder", founderAggregateId, PLATFORM_FOUNDER_ID)])
263
+ .reads(readSet(readRef("founder", founderAggregateId).at(PLATFORM_FOUNDER_ID)))
264
264
  .assert(({ founder }, ctx) => {
265
265
  const rec = (founder ?? {}) as { principal?: string };
266
266
  const intent = (ctx?.intent ?? {}) as { founder?: string };
@@ -15,7 +15,7 @@
15
15
  * ── The aggregate (object-keyed) ─────────────────────────────────────────────
16
16
  * `RelationTuple` is keyed `reltuple-<object>-<relation>` — ONE aggregate per
17
17
  * (object, relation) pair — carrying a `subjects: MapOf(Lww)` map of `subject → leaf`,
18
- * where each leaf is a JSON `{ status }` ("active" | "revoked"). The projection folds an
18
+ * where each leaf is a typed `RelationshipSubject` (`active` | `revoked`). The projection folds an
19
19
  * ACTIVE subject into a `relations(object, relation, subject)` row; a revoked subject
20
20
  * yields no row (Check fails closed).
21
21
  *
@@ -41,7 +41,7 @@
41
41
  */
42
42
  import { z } from "zod";
43
43
  import { aggregate, instance } from "../aggregate.js";
44
- import { t } from "../fields.js";
44
+ import { t, type JsonValue } from "../fields.js";
45
45
  import { Lww, MapOf } from "../drivers.js";
46
46
  import { directive } from "../directive.js";
47
47
  import { set, setEntry, withMarker, type PlannedOp } from "../ops.js";
@@ -70,6 +70,11 @@ import { qualifyReadProjectionType } from "../read_projection_namespace.js";
70
70
  interface DispatchContext {
71
71
  /** The dispatching domain key — the qualifier (`module.domain === intent.domain`). */
72
72
  readonly domain: string;
73
+ /**
74
+ * The durable Zanzibar namespace for this domain. Canonical USDA uses the domain's stable identity
75
+ * (`d_<sid>`), not its mutable dispatch label. Older/test engines may omit this and retain the label.
76
+ */
77
+ readonly relationNamespace?: string;
73
78
  /** `<type>#<relation>` for every LOCAL non-global authored relation of this domain — the qualify set. */
74
79
  readonly qualifiable: ReadonlySet<string>;
75
80
  /**
@@ -122,14 +127,14 @@ function resolveTupleObject(object: string | RelationObjectToken, relation: stri
122
127
  "qualify by). Tokens (selfWorkspace()/selfObject()) resolve only inside a directive plan.",
123
128
  );
124
129
  }
125
- return `${qualifyRelationType(_ctx.domain, object.type)}:${object.id}`;
130
+ return `${qualifyRelationType(_ctx.relationNamespace ?? _ctx.domain, object.type)}:${object.id}`;
126
131
  }
127
132
  // A PLAIN STRING is classified by `(type, relation)` against the dispatching domain's schema.
128
133
  const colon = object.indexOf(":");
129
134
  if (colon < 0 || _ctx === undefined) return object; // malformed / no context ⇒ verbatim
130
135
  const type = object.slice(0, colon);
131
136
  if (_ctx.qualifiable.has(`${type}#${relation}`)) {
132
- return `${qualifyRelationType(_ctx.domain, type)}${object.slice(colon)}`;
137
+ return `${qualifyRelationType(_ctx.relationNamespace ?? _ctx.domain, type)}${object.slice(colon)}`;
133
138
  }
134
139
  return object; // global / unknown / per-record ⇒ BARE
135
140
  }
@@ -185,7 +190,7 @@ export function relationTupleInstanceId(object: string, relation: string): strin
185
190
  *
186
191
  * - object Lww (the address, materialised on first relate so the aggregate exists)
187
192
  * - relation Lww (the edge label)
188
- * - subjects MapOf(Lww) — subject → JSON `{status}` leaf (active drops to a tuple row)
193
+ * - subjects MapOf(Lww) — subject → typed `RelationshipSubject` runtime leaf
189
194
  */
190
195
  export const RelationTuple = aggregate("RelationTuple", {
191
196
  object: t.string().merge(Lww),
@@ -194,7 +199,7 @@ export const RelationTuple = aggregate("RelationTuple", {
194
199
  }).public();
195
200
  export type RelationTupleHandle = typeof RelationTuple;
196
201
 
197
- /** The per-subject leaf the `subjects` map stores (JSON-encoded). Frozen wire shape. */
202
+ /** The per-subject leaf the `subjects` map stores as a typed kernel value. */
198
203
  export interface RelationSubjectLeaf {
199
204
  status: RelationStatus;
200
205
  grantedBy: string;
@@ -222,11 +227,11 @@ export interface RelationSubjectLeaf {
222
227
  ownedCustody?: string;
223
228
  }
224
229
 
225
- /** Strip undefined keys so the JSON leaf is byte-stable (no dropped-slot `"k":undefined`). */
226
- function compact(obj: Record<string, unknown>): RelationSubjectLeaf {
230
+ /** Strip undefined keys so the typed leaf has one stable optional-field shape. */
231
+ function compact(obj: Record<string, unknown>): RelationSubjectLeaf & Record<string, JsonValue> {
227
232
  const out: Record<string, unknown> = {};
228
233
  for (const [k, v] of Object.entries(obj)) if (v !== undefined) out[k] = v;
229
- return out as unknown as RelationSubjectLeaf;
234
+ return out as RelationSubjectLeaf & Record<string, JsonValue>;
230
235
  }
231
236
 
232
237
  interface WriteTupleInput {
@@ -277,9 +282,9 @@ function lowerTuple(
277
282
  // subject's endorsement is recorded on the setEntry op so the discovery harvest lifts it into
278
283
  // nomosFlowGate.endorse; grantedBy is free attribution (materialised, not gated).
279
284
  //
280
- // The captured authoring principal IS already a wire-form subject (`user:<uid>` / `key:<hash>`, the
281
- // host-stamped actor — the SAME form the write gate parses via `Subject::parse`), so an endorsed
282
- // authority subject lowers to that leaf verbatim and the gate's `engine.check` matches it.
285
+ // The captured authoring principal IS already a kernel-proven wire-form subject (`user:<uid>` /
286
+ // `key:<hash>` — the SAME form the write gate parses via `Subject::parse`), so an endorsed authority
287
+ // subject lowers to that leaf verbatim and the gate's `engine.check` matches it.
283
288
  const subjectE = endorsementOf(p.subject);
284
289
  const subjectRaw = subjectE
285
290
  ? subjectE.principal
@@ -300,7 +305,10 @@ function lowerTuple(
300
305
  verifiedVia: p.verifiedVia,
301
306
  ownedCustody: p.ownedCustody,
302
307
  });
303
- const subjectEntry = setEntry(rt, "subjects", subjectRaw, JSON.stringify(leaf));
308
+ const subjectEntry = {
309
+ ...setEntry(rt, "subjects", subjectRaw, leaf),
310
+ kernelValue: { RelationshipSubject: leaf },
311
+ };
304
312
  return [
305
313
  // upsert the aggregate head (first relate creates it); without this the referential
306
314
  // gate would reject a setEntry on an absent id.