@githolon/dsl 0.108.4 → 0.108.7

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 (44) hide show
  1. package/dart/CHANGELOG.md +5 -0
  2. package/dart/lib/src/application_framework_calls.dart +21 -0
  3. package/dart/lib/src/dev_cloud.dart +67 -0
  4. package/dart/lib/src/nms_test_environment.dart +1 -1
  5. package/dart/lib/src/runner/node-entry.mjs +354 -104
  6. package/dart/lib/src/runner/offline-install.mjs +64 -8
  7. package/dart/lib/src/session_bound.dart +58 -30
  8. package/dart/lib/src/test_harness.dart +60 -98
  9. package/dart/lib/src/webview_bridge.dart +212 -32
  10. package/dart/pubspec.lock +1 -1
  11. package/dart/pubspec.yaml +2 -2
  12. package/dart/test/node_runner_transport_test.dart +5 -5
  13. package/dart/test/webview_bridge_test.dart +6 -0
  14. package/dart_types/CHANGELOG.md +4 -0
  15. package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pb.dart +428 -2
  16. package/dart_types/pubspec.yaml +1 -1
  17. package/package.json +1 -1
  18. package/runtime/generated-application-host.js +293 -79
  19. package/src/application_topology.ts +120 -28
  20. package/src/births.ts +27 -0
  21. package/src/codegen_call_usda.ts +9 -4
  22. package/src/codegen_dart_application.ts +146 -37
  23. package/src/codegen_dart_client.ts +225 -160
  24. package/src/codegen_dart_framework_calls.ts +89 -4
  25. package/src/codegen_ts.ts +135 -60
  26. package/src/compile_package_main.ts +3598 -1484
  27. package/src/directive.ts +320 -118
  28. package/src/fields.ts +2 -3
  29. package/src/framework/application_home.ts +3 -0
  30. package/src/framework/auth_provider_law.ts +20 -28
  31. package/src/framework/genesis.ts +32 -1
  32. package/src/framework/home.ts +45 -8
  33. package/src/framework/signing_identity.ts +78 -0
  34. package/src/framework/workspaces.ts +9 -1
  35. package/src/framework_call_dart_enums.ts +33 -0
  36. package/src/framework_call_definitions.ts +11 -2
  37. package/src/index.ts +12 -0
  38. package/src/intent.ts +525 -194
  39. package/src/law_graph.ts +32 -4
  40. package/src/law_graph_usda.ts +3 -0
  41. package/src/package_config.ts +16 -1
  42. package/src/read.ts +33 -11
  43. package/src/wire.ts +1 -0
  44. package/src/wire_encode.ts +3 -3
package/src/fields.ts CHANGED
@@ -1079,9 +1079,8 @@ export const t = {
1079
1079
  { timestamp: true },
1080
1080
  ) as TimestampField<number>;
1081
1081
  },
1082
- /** A boolean flag (Lww). Stored as the kernel scalar `"true"`/`"false"` and decoded back to a real
1083
- * JSON boolean on read — so a flag is `t.bool()`, not a 2-value `t.enum`. Counts/filters key on the
1084
- * same string form. (Not encryptable — only Lww-class scalars are, and bool already is.) */
1082
+ /** A first-class USDA boolean flag (Lww). It remains a boolean through authored law, kernel state,
1083
+ * canonical custody and generated reads; it is never lowered through a string or JSON value. */
1085
1084
  bool(): Field<boolean, "bool"> {
1086
1085
  return makeField("bool", z.boolean(), FirstWriterWins);
1087
1086
  },
@@ -10,6 +10,7 @@
10
10
 
11
11
  import type { AggregateHandle } from "../aggregate.js";
12
12
  import type { ApplicationHomeGenesis } from "../application_home_genesis.js";
13
+ import type { WorkspaceRole } from "../births.js";
13
14
  import type { Directive } from "../directive.js";
14
15
  import type { QueryDecl } from "../query.js";
15
16
  import { APPLICATION_HOME_DOMAIN } from "./application_home_domain.js";
@@ -79,6 +80,7 @@ export function applicationHomePolicyLaw(
79
80
  maxChildWorkspacesPerUser: number,
80
81
  birthPolicyDomains: readonly string[],
81
82
  homeGenesis?: ApplicationHomeGenesis,
83
+ parentWorkspaceRoles: readonly WorkspaceRole[] = [],
82
84
  ) {
83
85
  return {
84
86
  __nomos_birthReceivingGroup: directive(
@@ -87,6 +89,7 @@ export function applicationHomePolicyLaw(
87
89
  maxChildWorkspacesPerUser,
88
90
  birthPolicyDomains,
89
91
  homeGenesis,
92
+ parentWorkspaceRoles,
90
93
  ),
91
94
  ),
92
95
  };
@@ -196,30 +196,7 @@ export type AuthProviderVerifyingConfiguration = Omit<
196
196
  /** Read the current provider through its three declared O(1) indexes and reconstruct the one nominal
197
197
  * configuration value used by child genesis and provider-epoch effects. */
198
198
  function readCurrentAuthProviderRows() {
199
- try {
200
- return readFrameworkDeclaredRows(authProvider, AuthProvider, { scope: "platform" });
201
- } catch (error) {
202
- // Law plans execute in the deterministic VM, not in the compiler's Node
203
- // realm. Imported class identity therefore cannot be used as an
204
- // `instanceof` discriminator here: the compiler may carry the property
205
- // path without carrying a constructible host class. Zod's issue list is
206
- // already the nominal failure disclosure we need; inspect that bounded
207
- // shape without depending on host-realm prototype identity.
208
- const issues = error !== null && typeof error === "object" &&
209
- "issues" in error && Array.isArray(error.issues)
210
- ? error.issues
211
- : [];
212
- if (issues.some((issue: unknown) =>
213
- issue !== null && typeof issue === "object" &&
214
- "code" in issue && issue.code === "unrecognized_keys" &&
215
- "keys" in issue && Array.isArray(issue.keys) && issue.keys.includes("keys")
216
- )) {
217
- throw new Error(
218
- "the AuthProvider still uses the historical serialized key field; migrate it to a typed keySet first",
219
- );
220
- }
221
- throw error;
222
- }
199
+ return readFrameworkDeclaredRows(authProvider, AuthProvider, { scope: "platform" });
223
200
  }
224
201
 
225
202
  type CurrentAuthProviderRow = ReturnType<typeof readCurrentAuthProviderRows>[number];
@@ -265,6 +242,9 @@ function readCurrentAuthProviderValue(): {
265
242
  )
266
243
  .map((certificate) => certificate.derBase64),
267
244
  }));
245
+ if (keyEpoch === undefined || keys.length === 0) {
246
+ throw new Error("the current AuthProvider has no typed verifying-key epoch");
247
+ }
268
248
  return {
269
249
  provider,
270
250
  verifying: {
@@ -373,10 +353,13 @@ export function writeAuthProviderKeySet(keySet: z.infer<typeof authProviderKeySe
373
353
  return ops;
374
354
  }
375
355
 
376
- export function writeAuthProviderConfiguration(p: AuthProviderConfiguration): PlannedOp[] {
356
+ function writeAuthProviderConfigurationWithMarker(
357
+ p: AuthProviderConfiguration,
358
+ marker: "ensures" | "mutates",
359
+ ): PlannedOp[] {
377
360
  const ap = instance(AuthProvider, AUTH_PROVIDER_ID);
378
361
  return [
379
- withMarker(set(ap, "scope", "platform"), "ensures"),
362
+ withMarker(set(ap, "scope", "platform"), marker),
380
363
  set(ap, "issuer", p.issuer),
381
364
  set(ap, "jwksUrl", p.jwksUrl),
382
365
  ...(p.audience ? [set(ap, "audience", p.audience)] : []),
@@ -400,10 +383,19 @@ export function writeAuthProviderConfiguration(p: AuthProviderConfiguration): Pl
400
383
  ];
401
384
  }
402
385
 
386
+ /** Birth creates the singleton; maintenance requires the existing singleton. */
387
+ export function writeAuthProviderConfiguration(p: AuthProviderConfiguration): PlannedOp[] {
388
+ return writeAuthProviderConfigurationWithMarker(p, "ensures");
389
+ }
390
+
391
+ export function updateAuthProviderConfiguration(p: AuthProviderConfiguration): PlannedOp[] {
392
+ return writeAuthProviderConfigurationWithMarker(p, "mutates");
393
+ }
394
+
403
395
  export const setAuthProvider = directive("setAuthProvider")
404
- .ensures(AuthProvider)
396
+ .mutates(AuthProvider)
405
397
  .payload(authProviderConfiguration)
406
- .plan(writeAuthProviderConfiguration)
398
+ .plan(updateAuthProviderConfiguration)
407
399
  .alsoEnsuresMany(AuthProviderKey)
408
400
  .alsoEnsuresMany(AuthProviderCertificate)
409
401
  .requires("admin");
@@ -35,6 +35,11 @@ import { directive } from "../directive.js";
35
35
  import { set, type PlannedOp } from "../ops.js";
36
36
  import { RelationTuple, writeTuple } from "./relations.js";
37
37
  import { MODEL_LIFECYCLE_AUTHORITY } from "./domain_lifecycle.js";
38
+ import {
39
+ ADMISSION_CHECKPOINT_PRINCIPAL,
40
+ SIGNER_RELATION,
41
+ signerObject,
42
+ } from "./signing_identity.js";
38
43
 
39
44
  /**
40
45
  * Deterministic singleton id of the founding warrant — MUST equal
@@ -60,12 +65,31 @@ export const GenesisWarrant = aggregate("GenesisWarrant", {
60
65
  export type GenesisWarrantHandle = typeof GenesisWarrant;
61
66
 
62
67
  /** The framework PRIMITIVE plan: record the founding warrant (singleton). */
63
- export function writeGenesisWarrant(p: { principal: string; workspaceId: string; bornAt: string }): PlannedOp[] {
68
+ export function writeGenesisWarrant(p: {
69
+ principal: string;
70
+ workspaceId: string;
71
+ bornAt: string;
72
+ admissionCheckpointSigners?: readonly {
73
+ keyHash: string;
74
+ validFromEpoch: number;
75
+ }[] | undefined;
76
+ }): PlannedOp[] {
64
77
  const w = instance(GenesisWarrant, GENESIS_WARRANT_ID);
65
78
  return [
66
79
  set(w, "principal", p.principal),
67
80
  set(w, "workspaceId", p.workspaceId),
68
81
  set(w, "bornAt", p.bornAt),
82
+ ...(p.admissionCheckpointSigners ?? []).flatMap((signer) =>
83
+ writeTuple({
84
+ object: signerObject(ADMISSION_CHECKPOINT_PRINCIPAL),
85
+ relation: SIGNER_RELATION,
86
+ subject: `key:${signer.keyHash}`,
87
+ grantedBy: p.principal,
88
+ grantedAt: p.bornAt,
89
+ validFromEpoch: signer.validFromEpoch,
90
+ verifiedVia: "workspace-genesis",
91
+ })
92
+ ),
69
93
  ];
70
94
  }
71
95
 
@@ -95,6 +119,13 @@ export const seedGenesis = directive("seedGenesis")
95
119
  // here; this directive just writes the warrant it is given. Era: the regime is per-workspace, at genesis.
96
120
  workspaceId: z.string(),
97
121
  bornAt: z.string().min(1),
122
+ /** Public workload identities already enrolled by the verified parent. The kernel derives this
123
+ * list from folded parent law-state while assembling a child warrant; neither host nor tenant
124
+ * payload can nominate a key, and the corresponding secret never enters custody. */
125
+ admissionCheckpointSigners: z.array(z.object({
126
+ keyHash: z.string().regex(/^[0-9a-f]{64}$/),
127
+ validFromEpoch: z.number().int().nonnegative(),
128
+ }).strict()).optional(),
98
129
  }),
99
130
  )
100
131
  .plan((p) => [
@@ -33,7 +33,7 @@ import { directive } from "../directive.js";
33
33
  import { ensure } from "../authoring.js";
34
34
  import { set, withMarker, type PlannedOp } from "../ops.js";
35
35
  import { query } from "../query.js";
36
- import { birth } from "../births.js";
36
+ import { birth, type WorkspaceRole } from "../births.js";
37
37
  import {
38
38
  authProvider as authProviderQuery,
39
39
  authProviderCertificates as authProviderCertificatesQuery,
@@ -42,8 +42,13 @@ import {
42
42
  seedAuthProvider,
43
43
  } from "./auth_provider_law.js";
44
44
  import { readRef, readSet, workspaceInvariant, refAs } from "./workspace_invariant.js";
45
- import { identityRelations } from "./signing_identity.js";
46
- import { RelationTuple, writeTuple } from "./relations.js";
45
+ import {
46
+ identityRelations,
47
+ } from "./signing_identity.js";
48
+ import {
49
+ RelationTuple,
50
+ writeTuple,
51
+ } from "./relations.js";
47
52
  import { relationType, self, user, selfObject } from "../relation_schema.js";
48
53
  import { requireParentAttestedBirth, type ParentAttestedBirthMarker } from "../births.js";
49
54
  import { GenesisWarrant, seedGenesis } from "./genesis.js";
@@ -123,12 +128,26 @@ export const DEFAULT_RECEIVING_GROUP_POLICY = {
123
128
  guardianQuorum: 1,
124
129
  } as const;
125
130
 
126
- function writeReceivingGroupPolicy(p: { setAt: string }): PlannedOp[] {
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[] {
127
146
  const policy = instance(ReceivingGroupPolicy, RECEIVING_GROUP_POLICY_ID);
128
147
  return [
129
148
  set(policy, "additionalDevice", DEFAULT_RECEIVING_GROUP_POLICY.additionalDevice),
130
149
  set(policy, "revocation", DEFAULT_RECEIVING_GROUP_POLICY.revocation),
131
- set(policy, "recovery", DEFAULT_RECEIVING_GROUP_POLICY.recovery),
150
+ set(policy, "recovery", p.recovery ?? DEFAULT_RECEIVING_GROUP_POLICY.recovery),
132
151
  set(policy, "guardianQuorum", DEFAULT_RECEIVING_GROUP_POLICY.guardianQuorum),
133
152
  set(policy, "setAt", p.setAt),
134
153
  ];
@@ -137,7 +156,10 @@ function writeReceivingGroupPolicy(p: { setAt: string }): PlannedOp[] {
137
156
  /** Genesis-only default policy. Policy changes become a separate, guardian-aware ceremony. */
138
157
  export const seedReceivingGroupPolicy = directive("nomosInternalSeedReceivingGroupPolicy7c1f5e")
139
158
  .ensures(ReceivingGroupPolicy)
140
- .payload(z.object({ setAt: z.string().min(1) }))
159
+ .payload(z.object({
160
+ setAt: z.string().min(1),
161
+ recovery: receivingGroupRecoveryPolicy.optional(),
162
+ }))
141
163
  .plan((p) => writeReceivingGroupPolicy(p));
142
164
 
143
165
  /**
@@ -306,6 +328,7 @@ export function birthReceivingGroupForDomain(
306
328
  maxChildWorkspacesPerUser: number,
307
329
  birthPolicyDomains: readonly string[],
308
330
  homeGenesis?: ApplicationHomeGenesis,
331
+ parentWorkspaceRoles: readonly WorkspaceRole[] = [],
309
332
  ) {
310
333
  if (groupLawDomain.length === 0) {
311
334
  throw new Error("birthReceivingGroupForDomain requires a non-empty receiving-group law domain");
@@ -438,12 +461,26 @@ export function birthReceivingGroupForDomain(
438
461
  // THE DECLARED BIRTH EFFECT (the unix model): the recipe rides the committed intent as a declared output
439
462
  // (captured_ports.births). The kernel — reading the `.births()` declaration off the law manifest — takes
440
463
  // the recipe and spawns + self-validates the child through the child's OWN gate (each step self-verifies).
441
- birth({ workspace: groupName, genesisChain });
442
- return [];
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
+ });
443
479
  })
444
480
  .reads(authProviderQuery) // the parent-side AuthProvider capture the inheritance copies (the #58 lane)
445
481
  .reads(authProviderKeysQuery)
446
482
  .reads(authProviderCertificatesQuery)
483
+ .alsoEnsures(RelationTuple)
447
484
  .births(); // BIRTH IS A DECLARED KERNEL PRIMITIVE — emits the `nomosBirthGate` era key; the kernel folds the recipe
448
485
  return {
449
486
  ...birthDirective,
@@ -59,6 +59,7 @@ import {
59
59
  relationTupleInstanceId,
60
60
  } from "./relations.js";
61
61
  import { MODEL_LIFECYCLE_AUTHORITY } from "./domain_lifecycle.js";
62
+ import { readFrameworkDeclaredRows } from "../read.js";
62
63
 
63
64
  /**
64
65
  * The framework `identity` relation schema — the `signer` relation, LEAF-ONLY
@@ -377,6 +378,19 @@ export const SignerDelegation = aggregate("SignerDelegation", {
377
378
  }).public();
378
379
  export type SignerDelegationHandle = typeof SignerDelegation;
379
380
 
381
+ /** The bounded, typed disclosure a parent workspace may carry when its law recovers a child device.
382
+ * It deliberately excludes the historical certJson slot: current cross-workspace law consumes only
383
+ * the nominal certificate fields and the exact signer key subject admitted by the parent. */
384
+ export const signerDelegationRecoveryEvidence = z.object({
385
+ user: z.string().min(1),
386
+ deviceKeySubject: z.string().regex(/^key:[0-9a-f]{64}$/),
387
+ enrolledAt: z.string().min(1),
388
+ certificate: birthCertificatePayload,
389
+ }).strict();
390
+ export type SignerDelegationRecoveryEvidence = z.infer<
391
+ typeof signerDelegationRecoveryEvidence
392
+ >;
393
+
380
394
  /** The deterministic singleton id of a user's signer delegation (the kernel reads THIS id by-user). */
381
395
  export function signerDelegationInstanceId(user: string): string {
382
396
  return SIGNER_DELEGATION_PREFIX + user;
@@ -405,6 +419,25 @@ function writeDelegationCertificate(
405
419
  ];
406
420
  }
407
421
 
422
+ /** Materialise the exact typed delegation disclosed by a parent during device
423
+ * recovery. Keeping this beside the canonical SignerDelegation definition and
424
+ * certificate writer gives application law one compositional write primitive;
425
+ * it does not need to mirror the certificate fields or serialize a document. */
426
+ export function writeSignerDelegationRecoveryEvidence(
427
+ evidence: SignerDelegationRecoveryEvidence,
428
+ ): PlannedOp[] {
429
+ const delegation = instance(
430
+ SignerDelegation,
431
+ signerDelegationInstanceId(evidence.user),
432
+ );
433
+ return [
434
+ set(delegation, "user", evidence.user),
435
+ set(delegation, "deviceKey", evidence.deviceKeySubject),
436
+ set(delegation, "enrolledAt", evidence.enrolledAt),
437
+ ...writeDelegationCertificate(delegation, evidence.certificate),
438
+ ];
439
+ }
440
+
408
441
  /**
409
442
  * `enrollFirstDevice` (architecture/keyless_verified_onboard.md) — THE KEYLESS VERIFIED FIRST-DEVICE
410
443
  * self-onboard. A brand-new principal (an IdP-verified user with NO enrolled signer key) bootstraps its
@@ -575,6 +608,51 @@ export const enrollDelegation = directive("enrollDelegation")
575
608
  /** Audit: a user's signer delegation (the enroll-once cert binding their device to the tenant lineage). */
576
609
  export const signerDelegationByUser = query("signerDelegationByUser").key("user").returns(SignerDelegation);
577
610
 
611
+ /** Read exactly one current typed delegation through its declared O(1) index. Missing or incomplete
612
+ * typed certificate members fail closed; no legacy document is parsed or carried. */
613
+ export function readSignerDelegationRecoveryEvidence(
614
+ user: string,
615
+ ): SignerDelegationRecoveryEvidence | undefined {
616
+ const rows = readFrameworkDeclaredRows(
617
+ signerDelegationByUser,
618
+ SignerDelegation,
619
+ { user },
620
+ );
621
+ if (rows.length === 0) return undefined;
622
+ if (rows.length !== 1) {
623
+ throw new Error(
624
+ `signerDelegationByUser('${user}') returned ${rows.length} rows; expected exactly one`,
625
+ );
626
+ }
627
+ const row = rows[0]!;
628
+ return signerDelegationRecoveryEvidence.parse({
629
+ user: row.user,
630
+ deviceKeySubject: row.deviceKey,
631
+ enrolledAt: row.enrolledAt,
632
+ certificate: {
633
+ child: row.certificateChild,
634
+ founder: row.certificateFounder,
635
+ verified: row.certificateVerified,
636
+ parentKey: row.certificateParentKey,
637
+ parentId: row.certificateParentId,
638
+ epoch: row.certificateEpoch,
639
+ signature: row.certificateSignature,
640
+ verifiedVia: row.certificateVerifiedVia,
641
+ idpToken: row.certificateIdpToken,
642
+ capturedClock: row.certificateCapturedClock,
643
+ ...(row.certificateAuthProviderIssuer === undefined
644
+ ? {}
645
+ : { authProviderIssuer: row.certificateAuthProviderIssuer }),
646
+ ...(row.certificateAuthProviderJwks === undefined
647
+ ? {}
648
+ : { authProviderJwks: row.certificateAuthProviderJwks }),
649
+ ...(row.certificateAuthProviderAudience === undefined
650
+ ? {}
651
+ : { authProviderAudience: row.certificateAuthProviderAudience }),
652
+ },
653
+ });
654
+ }
655
+
578
656
  /** Audit: the signer tuples for an identity (the raw relation aggregate). */
579
657
  export const signerTuplesByObject = query("signerTuplesByObject")
580
658
  .key("object")
@@ -76,7 +76,7 @@ import { query } from "../query.js";
76
76
  import { read } from "../read.js";
77
77
  import { readRef, readSet, workspaceInvariant, refAs, type WorkspaceInvariantVerdict } from "./workspace_invariant.js";
78
78
  import { writeTuple, removeTuple, RelationTuple, relationTupleInstanceId } from "./relations.js";
79
- import { relationType, self, user, key } from "../relation_schema.js";
79
+ import { relationType, self, user, key, object } from "../relation_schema.js";
80
80
  import { WORKSPACE_ADMIN_RELATION } from "./governance_relations.js";
81
81
  import { GENESIS_WARRANT_ID } from "./genesis.js";
82
82
  import { idOf } from "../value_object.js";
@@ -121,6 +121,8 @@ export { SignerDelegation, enrollDelegation, signerDelegationByUser } from "./si
121
121
  /** Canonical governance-law namespace. Genesis routes refer to this declaration, never a repeated
122
122
  * string literal, so renaming the module cannot silently strand part of the founding ceremony. */
123
123
  export const WORKSPACES_DOMAIN = "workspaces" as const;
124
+ /** A workspace born directly by this workspace. The canonical birth plan seats this relation atomically. */
125
+ export const WORKSPACE_CHILD_RELATION = "child" as const;
124
126
 
125
127
  // ── WORKSPACE SELF-IDENTITY (the law reads its OWN install-context) ──────────────────────────────────
126
128
  // The governance bundle runs on root AND every born platform. A workspace knows its ROLE via this
@@ -203,6 +205,12 @@ export const workspaceRelations = relationType("workspace")
203
205
  .relation("creator", { rewrite: self(), allow: [user(), key()] })
204
206
  .relation("platformCreator", { rewrite: self(), allow: [user(), key()] });
205
207
 
208
+ /** Global holarchy edge kept separate so application packages can compose child authority without
209
+ * re-exporting the governance admin/creator surface into a tenant domain. */
210
+ export const workspaceChildRelations = relationType("workspace")
211
+ .asGlobal()
212
+ .relation(WORKSPACE_CHILD_RELATION, { rewrite: self(), allow: [object("workspace")] });
213
+
206
214
  // --- vocabulary ----------------------------------------------------------------
207
215
 
208
216
  /** Where a workspace's holon runs: an edge DO or the dedicated 12GiB container. */
@@ -0,0 +1,33 @@
1
+ import type { Directive } from "./directive.js";
2
+ import { collectDartEnums } from "./codegen_dart.js";
3
+ import { fixedFrameworkCallDefinitions } from "./framework_call_definitions.js";
4
+
5
+ /**
6
+ * The Dart types for enums carried by pre-bind framework calls.
7
+ *
8
+ * The authored fixed-call directives remain the one schema authority. This
9
+ * registry only gives their enum vocabularies stable Dart names and emits the
10
+ * corresponding declarations into the stable framework-call contract. The
11
+ * per-application implementation consumes the same registry, so it can never
12
+ * invent an undeclared field-local fallback such as `RecoveryEnum`.
13
+ */
14
+ export function collectFixedFrameworkDartEnums(): {
15
+ readonly dartTypes: Map<string, string>;
16
+ readonly decls: string[];
17
+ } {
18
+ // Naming enums after the stable framework call kind keeps public Dart names
19
+ // independent of the directive's opaque wire id. Only payload schemas are
20
+ // inspected from these aliases; no executable directive behaviour is copied.
21
+ const directives = fixedFrameworkCallDefinitions
22
+ .filter((definition) => definition.dartBirth === true)
23
+ .map((definition) => ({
24
+ ...definition.directive,
25
+ id: definition.kind,
26
+ // collectDartEnums uses aggregateId as the semantic owner when present.
27
+ // This compile-only alias deliberately names that owner after the stable
28
+ // framework call rather than the directive's internal storage aggregate.
29
+ aggregateId: definition.kind,
30
+ })) as Directive<any>[];
31
+
32
+ return collectDartEnums([], directives, "NmsFramework");
33
+ }
@@ -7,7 +7,7 @@
7
7
 
8
8
  import type { Directive } from "./directive.js";
9
9
  import { APPLICATION_HOME_DOMAIN } from "./framework/application_home_domain.js";
10
- import { setAuthProvider } from "./framework/auth_provider_law.js";
10
+ import { seedAuthProvider, setAuthProvider } from "./framework/auth_provider_law.js";
11
11
  import { seedBirthPolicy } from "./framework/birth_meter.js";
12
12
  import { installDomain, promoteDomain, rollbackDomain, stageDomain } from "./framework/domain_lifecycle.js";
13
13
  import { seedGenesis } from "./framework/genesis.js";
@@ -17,13 +17,20 @@ import {
17
17
  seedReceivingGroup,
18
18
  seedReceivingGroupPolicy,
19
19
  } from "./framework/home.js";
20
- import { enrollDelegation, enrollFirstDevice, enrollSigner } from "./framework/signing_identity.js";
20
+ import {
21
+ enrollAdmissionCheckpointSigner,
22
+ enrollDelegation,
23
+ enrollFirstDevice,
24
+ enrollSigner,
25
+ } from "./framework/signing_identity.js";
21
26
  import { grantAdmin } from "./framework/workspaces.js";
22
27
 
23
28
  export interface FixedFrameworkCallDefinition {
24
29
  readonly group: "identity" | "governance" | "lifecycle" | "birth";
25
30
  readonly kind: string;
26
31
  readonly directive: Directive<any>;
32
+ /** Public command route when a framework effect is wrapped by a stable typed intent. */
33
+ readonly routeId?: string;
27
34
  /** Needed by the pre-bind Dart birth ceremony before an application exists. */
28
35
  readonly dartBirth?: true;
29
36
  /** A composed application-home law must contain this operation. */
@@ -39,6 +46,7 @@ const receivingGroupBirth = birthReceivingGroupForDomain(
39
46
  export const fixedFrameworkCallDefinitions: readonly FixedFrameworkCallDefinition[] = [
40
47
  { group: "identity", kind: "enrollFirstDevice", directive: enrollFirstDevice, dartBirth: true, requiredApplicationHome: true },
41
48
  { group: "identity", kind: "enrollSigner", directive: enrollSigner, dartBirth: true, requiredApplicationHome: true },
49
+ { group: "identity", kind: "enrollAdmissionCheckpointSigner", directive: enrollAdmissionCheckpointSigner, routeId: "enrollAdmissionCheckpointSigner", requiredApplicationHome: true },
42
50
  { group: "identity", kind: "setAuthProvider", directive: setAuthProvider, requiredApplicationHome: true },
43
51
  { group: "identity", kind: "birthReceivingGroup", directive: receivingGroupBirth, dartBirth: true, requiredApplicationHome: true },
44
52
  { group: "governance", kind: "grantAdmin", directive: grantAdmin },
@@ -47,6 +55,7 @@ export const fixedFrameworkCallDefinitions: readonly FixedFrameworkCallDefinitio
47
55
  { group: "lifecycle", kind: "promoteDomain", directive: promoteDomain },
48
56
  { group: "lifecycle", kind: "rollbackDomain", directive: rollbackDomain },
49
57
  { group: "birth", kind: "seedBirthPolicy", directive: seedBirthPolicy, dartBirth: true },
58
+ { group: "birth", kind: "seedAuthProvider", directive: seedAuthProvider, requiredApplicationHome: true },
50
59
  { group: "birth", kind: "enrollDelegation", directive: enrollDelegation, dartBirth: true },
51
60
  { group: "birth", kind: "seedBirthAttestation", directive: seedBirthAttestation, dartBirth: true },
52
61
  { group: "birth", kind: "seedGenesis", directive: seedGenesis, dartBirth: true },
package/src/index.ts CHANGED
@@ -175,6 +175,9 @@ export {
175
175
  language,
176
176
  isBusinessIntent,
177
177
  isApplicationLanguage,
178
+ authenticatesWithEnrolledDevice,
179
+ repairsChildAuthenticationFor,
180
+ childAuthenticationRecoveryAggregateId,
178
181
  applicationLanguageOf,
179
182
  executableDirectivesForLanguage,
180
183
  assertApplicationLanguageCoversAuthoredDirectives,
@@ -320,6 +323,7 @@ export {
320
323
  export {
321
324
  birth,
322
325
  workspaceRole,
326
+ parentWorkspaceRoleRelations,
323
327
  workspaceNameForKey,
324
328
  WORKSPACE_NAME_SEP,
325
329
  birthKeyed,
@@ -526,10 +530,14 @@ export {
526
530
  // THE ENROLL-ONCE DELEGATION (the peer-sovereign root-of-trust) — the per-user tenant-signed cert the
527
531
  // kernel reads to assemble U's home cert chain at birth.
528
532
  SignerDelegation,
533
+ signerDelegationRecoveryEvidence,
529
534
  SIGNER_DELEGATION_PREFIX,
530
535
  signerDelegationInstanceId,
531
536
  enrollDelegation,
532
537
  signerDelegationByUser,
538
+ readSignerDelegationRecoveryEvidence,
539
+ writeSignerDelegationRecoveryEvidence,
540
+ type SignerDelegationRecoveryEvidence,
533
541
  type SignerDelegationHandle,
534
542
  type SignerEpochHandle,
535
543
  type SignerAuthority,
@@ -574,6 +582,10 @@ export {
574
582
  RECEIVING_GROUP_NAME_HASH_LEN,
575
583
  RECEIVING_GROUP_POLICY_ID,
576
584
  DEFAULT_RECEIVING_GROUP_POLICY,
585
+ RECEIVING_GROUP_RECOVERY_POLICIES,
586
+ receivingGroupRecoveryPolicy,
587
+ PLATFORM_IDENTITY_PROVIDER_RECOVERY,
588
+ type ReceivingGroupRecoveryPolicy,
577
589
  seedReceivingGroup,
578
590
  seedReceivingGroupPolicy,
579
591
  writeReceivingGroup,