@githolon/dsl 0.107.4 → 0.108.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/dart/CHANGELOG.md +24 -0
  2. package/dart/lib/src/application_framework_calls.dart +299 -0
  3. package/dart/lib/src/generated_call.dart +96 -0
  4. package/dart/lib/src/nms_generated_runtime.dart +29 -0
  5. package/dart/lib/src/node_runner_transport.dart +77 -1
  6. package/dart/lib/src/result_usda.dart +487 -0
  7. package/dart/lib/src/runner/node-entry.mjs +10634 -6122
  8. package/dart/lib/src/runner/offline-install.mjs +4187 -2716
  9. package/dart/lib/src/runtime_v2_gateway.dart +54 -0
  10. package/dart/lib/src/runtime_v2_transport.dart +117 -0
  11. package/dart/lib/src/session_bound.dart +7 -2
  12. package/dart/lib/src/test_harness.dart +373 -282
  13. package/dart/lib/src/webview_bridge.dart +2146 -725
  14. package/dart/pubspec.lock +17 -1
  15. package/dart/pubspec.yaml +3 -2
  16. package/dart/test/acquire_session_credentials_test.dart +1 -1
  17. package/dart/test/acquire_session_test.dart +68 -14
  18. package/dart/test/adv_realm_interference_test.dart +6 -4
  19. package/dart/test/cluster_births_test.dart +11 -8
  20. package/dart/test/cluster_local_autosync_test.dart +1 -1
  21. package/dart/test/cluster_scale_test.dart +3 -2
  22. package/dart/test/dlq_session_surface_test.dart +52 -35
  23. package/dart/test/first_app_gauntlet_test.dart +1 -1
  24. package/dart/test/local_sync_inert_test.dart +23 -26
  25. package/dart/test/offer_authentication_proof_test.dart +193 -0
  26. package/dart/test/result_usda_test.dart +49 -0
  27. package/dart/test/session_bound_test.dart +8 -11
  28. package/dart/test/stale_bundle_test.dart +18 -3
  29. package/dart/test/test_harness_test.dart +14 -27
  30. package/dart/test/webview_bridge_test.dart +504 -83
  31. package/dart_types/CHANGELOG.md +17 -0
  32. package/dart_types/lib/nomos_kernel_protocol.dart +11 -0
  33. package/dart_types/lib/src/custody.dart +64 -19
  34. package/dart_types/lib/src/local_work_rejected.dart +30 -45
  35. package/dart_types/lib/src/proto/nomos/custody/v1/snapshot.pb.dart +169 -0
  36. package/dart_types/lib/src/proto/nomos/custody/v1/snapshot.pbenum.dart +11 -0
  37. package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pb.dart +17945 -0
  38. package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pbenum.dart +933 -0
  39. package/dart_types/lib/src/proto/nomos/kernel/v1/progress.pb.dart +245 -0
  40. package/dart_types/lib/src/proto/nomos/kernel/v1/progress.pbenum.dart +160 -0
  41. package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pb.dart +8664 -0
  42. package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pbenum.dart +369 -0
  43. package/dart_types/lib/src/surfaced.dart +30 -25
  44. package/dart_types/pubspec.lock +16 -0
  45. package/dart_types/pubspec.yaml +3 -1
  46. package/dart_types/test/surfaced_test.dart +2 -1
  47. package/package.json +1 -1
  48. package/runtime/generated-application-host.js +5760 -1879
  49. package/src/authoring.ts +3 -2
  50. package/src/birth_meter_ensure.ts +2 -0
  51. package/src/births.ts +21 -0
  52. package/src/build_package.ts +30 -0
  53. package/src/business_birth.ts +41 -35
  54. package/src/codegen_call_usda.ts +1111 -0
  55. package/src/codegen_dart.ts +207 -282
  56. package/src/codegen_dart_application.ts +195 -252
  57. package/src/codegen_dart_client.ts +1978 -593
  58. package/src/codegen_dart_framework_calls.ts +291 -0
  59. package/src/codegen_dart_scenario.ts +7 -0
  60. package/src/codegen_proof.ts +3 -4
  61. package/src/codegen_provider_dart.ts +21 -7
  62. package/src/codegen_query_usda.ts +214 -0
  63. package/src/codegen_result_usda.ts +685 -0
  64. package/src/codegen_ts.ts +3945 -1111
  65. package/src/compile_package_main.ts +392 -46
  66. package/src/directive.ts +19 -4
  67. package/src/engine_entry.ts +45 -4
  68. package/src/framework/application_home.ts +4 -0
  69. package/src/framework/auth_provider_law.ts +296 -20
  70. package/src/framework/birth_certificate_law.ts +24 -0
  71. package/src/framework/home.ts +83 -40
  72. package/src/framework/owned_custody.ts +25 -12
  73. package/src/framework/owned_custody_value.ts +51 -0
  74. package/src/framework/relations.ts +47 -21
  75. package/src/framework/signing_identity.ts +100 -17
  76. package/src/framework/workspaces.ts +39 -10
  77. package/src/framework_call_definitions.ts +53 -0
  78. package/src/framework_read_definitions.ts +45 -0
  79. package/src/identity_frontier.ts +58 -0
  80. package/src/index.ts +22 -1
  81. package/src/intent.ts +216 -16
  82. package/src/law_check.ts +19 -1
  83. package/src/law_graph.ts +57 -8
  84. package/src/law_graph_usda.ts +73 -5
  85. package/src/law_value_type.ts +106 -19
  86. package/src/read.ts +47 -0
  87. package/src/read_projection_namespace.ts +7 -0
  88. package/src/shape_compat.ts +44 -42
  89. package/src/stable_ids.ts +37 -2
  90. package/src/test_call_usda.ts +83 -0
  91. package/src/wire.ts +36 -2
  92. package/src/wire_encode.ts +45 -1
  93. package/src/workspace_sharing.ts +27 -10
@@ -42,11 +42,12 @@
42
42
  * only revokes keys of its OWN identity).
43
43
  */
44
44
  import { z } from "zod";
45
- import { aggregate, instance } from "../aggregate.js";
45
+ import { birthCertificatePayload, type BirthCertificatePayload } from "./birth_certificate_law.js";
46
+ import { aggregate, instance, type BoundAggregate } from "../aggregate.js";
46
47
  import { t } from "../fields.js";
47
48
  import { Lww } from "../drivers.js";
48
49
  import { directive } from "../directive.js";
49
- import { set, withMarker, type PlannedOp } from "../ops.js";
50
+ import { set, withMarker, type FieldOp, type PlannedOp } from "../ops.js";
50
51
  import { query } from "../query.js";
51
52
  import { relationType, self, key } from "../relation_schema.js";
52
53
  import { readRef, readSet, workspaceInvariant, ref } from "./workspace_invariant.js";
@@ -57,6 +58,7 @@ import {
57
58
  RelationTuple,
58
59
  relationTupleInstanceId,
59
60
  } from "./relations.js";
61
+ import { MODEL_LIFECYCLE_AUTHORITY } from "./domain_lifecycle.js";
60
62
 
61
63
  /**
62
64
  * The framework `identity` relation schema — the `signer` relation, LEAF-ONLY
@@ -83,6 +85,9 @@ export function signerObject(principal: string): string {
83
85
  /** The `signer` relation name — the relation a device key holds on its `identity:<principal>` object. */
84
86
  export const SIGNER_RELATION = "signer";
85
87
 
88
+ /** Reserved workload principal for external admission receipts. It is never the business actor. */
89
+ export const ADMISSION_CHECKPOINT_PRINCIPAL = "workspace:admission-peer";
90
+
86
91
  const sha256Hex = z.string().regex(/^[0-9a-f]{64}$/, "expected lowercase sha256 hex (the device pubkey hash)");
87
92
 
88
93
  // ─────────────────────────────── PHASE 0 — SignerEpoch ───────────────────────────────
@@ -239,6 +244,36 @@ export const enrollSigner = directive("enrollSigner")
239
244
  });
240
245
  });
241
246
 
247
+ /**
248
+ * Enrol the runtime workload key which signs causal admission checkpoints. This is ordinary law:
249
+ * lifecycle authority chooses the public key, the relation is visible/revocable, and possession of
250
+ * the secret alone grants nothing. The key certifies that this workspace admitted an exact causal
251
+ * transition; the target directive's independent Zanzibar requirement remains business authority.
252
+ */
253
+ export const enrollAdmissionCheckpointSigner = directive(
254
+ "_nmsEffectEnrollAdmissionCheckpointSigner",
255
+ )
256
+ .ensures(RelationTuple)
257
+ .payload(
258
+ z.object({
259
+ keyHash: sha256Hex,
260
+ validFromEpoch: z.number().int().nonnegative(),
261
+ grantedAt: z.string().min(1),
262
+ }).strict(),
263
+ )
264
+ .plan((p, ctx) =>
265
+ writeTuple({
266
+ object: signerObject(ADMISSION_CHECKPOINT_PRINCIPAL),
267
+ relation: SIGNER_RELATION,
268
+ subject: `key:${p.keyHash}`,
269
+ grantedBy: ctx.principal().asAttribution(),
270
+ grantedAt: p.grantedAt,
271
+ validFromEpoch: p.validFromEpoch,
272
+ verifiedVia: "workspace-law",
273
+ }),
274
+ )
275
+ .requires(MODEL_LIFECYCLE_AUTHORITY, { object: "workspace:self" });
276
+
242
277
  /**
243
278
  * THE SELF-BIND ENROLL (VA-1 / B2). A device enrolls a key for ITS OWN verified identity — the bound
244
279
  * principal is `ctx.principal()` (the captured authoring principal), NOT a payload field, so a device can
@@ -305,8 +340,8 @@ export const enrollSignerSelfRequiresVerified = workspaceInvariant("EnrollSigner
305
340
  * DELEGATION CERT binding U's device key `P_U` to the tenant's lineage: a `BirthCert {founder: U,
306
341
  * parent_key: P_U, …}` signed by `S_P`. This singleton (keyed by U) records it in the PLATFORM's folded
307
342
  * state, so the kernel's birth offer-effect reads U's delegation by-user (trusted, not from the payload) when
308
- * it assembles U's home cert chain. The cert is OPAQUE on-chain (a JSON `BirthCert`); the kernel parses +
309
- * verifies it as one chain link (signed by S_P, whose pubkey is attested by the platform's own chain).
343
+ * it assembles U's home cert chain. Every certificate member is stored as typed USDA fields; the kernel
344
+ * reconstructs and verifies the nominal link signed by S_P, whose key is attested by the platform chain.
310
345
  *
311
346
  * SELF-BOUND / control-plane: enrolled by the tenant onboarding lane (composed into the tenant's governance
312
347
  * law, off the open session lane), so a tenant cannot forge a delegation for a user another tenant verified.
@@ -322,9 +357,21 @@ export const SignerDelegation = aggregate("SignerDelegation", {
322
357
  user: t.string().merge(Lww),
323
358
  /** The user's device PUBLIC KEY (base64) the delegation binds — `P_U`, the home_cert's signer. */
324
359
  deviceKey: t.string().merge(Lww),
325
- /** THE DELEGATION CERT (JSON `executor::birth_cert::BirthCert`), signed by the tenant's `S_P`. Opaque
326
- * on-chain; the kernel parses + verifies it as the `links[1]` delegation in U's travelling chain. */
327
- certJson: t.string().merge(Lww),
360
+ /** Legacy replay slot for histories authored before the typed certificate fields below. */
361
+ certJson: t.string().merge(Lww).optional(),
362
+ certificateChild: t.string().merge(Lww).optional(),
363
+ certificateFounder: t.string().merge(Lww).optional(),
364
+ certificateVerified: t.bool().merge(Lww).optional(),
365
+ certificateParentKey: t.string().merge(Lww).optional(),
366
+ certificateParentId: t.string().merge(Lww).optional(),
367
+ certificateEpoch: t.int().merge(Lww).optional(),
368
+ certificateSignature: t.string().merge(Lww).optional(),
369
+ certificateVerifiedVia: t.string().merge(Lww).optional(),
370
+ certificateIdpToken: t.string().merge(Lww).optional(),
371
+ certificateCapturedClock: t.int().merge(Lww).optional(),
372
+ certificateAuthProviderIssuer: t.string().merge(Lww).optional(),
373
+ certificateAuthProviderJwks: t.string().merge(Lww).optional(),
374
+ certificateAuthProviderAudience: t.string().merge(Lww).optional(),
328
375
  /** ISO-8601, caller-stamped (determinism — no clock in the plan). */
329
376
  enrolledAt: t.string().merge(Lww),
330
377
  }).public();
@@ -335,6 +382,29 @@ export function signerDelegationInstanceId(user: string): string {
335
382
  return SIGNER_DELEGATION_PREFIX + user;
336
383
  }
337
384
 
385
+ function writeDelegationCertificate(
386
+ delegation: BoundAggregate<typeof SignerDelegation.id, typeof SignerDelegation.fields>,
387
+ certificate: BirthCertificatePayload,
388
+ marker?: "ensures",
389
+ ): PlannedOp[] {
390
+ const marked = (operation: FieldOp) => marker ? withMarker(operation, marker) : operation;
391
+ return [
392
+ marked(set(delegation, "certificateChild", certificate.child)),
393
+ marked(set(delegation, "certificateFounder", certificate.founder)),
394
+ marked(set(delegation, "certificateVerified", certificate.verified)),
395
+ marked(set(delegation, "certificateParentKey", certificate.parentKey)),
396
+ marked(set(delegation, "certificateParentId", certificate.parentId)),
397
+ marked(set(delegation, "certificateEpoch", certificate.epoch)),
398
+ marked(set(delegation, "certificateSignature", certificate.signature)),
399
+ ...(certificate.verifiedVia ? [marked(set(delegation, "certificateVerifiedVia", certificate.verifiedVia))] : []),
400
+ ...(certificate.idpToken ? [marked(set(delegation, "certificateIdpToken", certificate.idpToken))] : []),
401
+ ...(certificate.capturedClock === undefined ? [] : [marked(set(delegation, "certificateCapturedClock", certificate.capturedClock))]),
402
+ ...(certificate.authProviderIssuer ? [marked(set(delegation, "certificateAuthProviderIssuer", certificate.authProviderIssuer))] : []),
403
+ ...(certificate.authProviderJwks ? [marked(set(delegation, "certificateAuthProviderJwks", certificate.authProviderJwks))] : []),
404
+ ...(certificate.authProviderAudience ? [marked(set(delegation, "certificateAuthProviderAudience", certificate.authProviderAudience))] : []),
405
+ ];
406
+ }
407
+
338
408
  /**
339
409
  * `enrollFirstDevice` (architecture/keyless_verified_onboard.md) — THE KEYLESS VERIFIED FIRST-DEVICE
340
410
  * self-onboard. A brand-new principal (an IdP-verified user with NO enrolled signer key) bootstraps its
@@ -369,8 +439,11 @@ export const enrollFirstDevice = directive("enrollFirstDevice")
369
439
  /** THE CAPTURED PREMISE: the IdP's signed identity assertion (JWT), re-verified on every lane against
370
440
  * the on-chain AuthProvider keys. */
371
441
  idpToken: z.string().min(1),
372
- /** THE KEYLESS DELEGATION CERT (JSON `executor::birth_cert::BirthCert`) — the self-serve sibling of
373
- * `enrollDelegation.certJson`. Built CLIENT-SIDE via the `cert_sign` op: DEVICE-self-signed by this
442
+ /** Legacy replay input for callers predating `delegationCertificate`. New callers must provide the
443
+ * typed certificate below. */
444
+ delegationCert: z.string().min(1).optional(),
445
+ /** THE KEYLESS DELEGATION CERT — the self-serve sibling of `enrollDelegation.certificate`. Built
446
+ * CLIENT-SIDE via the typed kernel sign operation: DEVICE-self-signed by this
374
447
  * same device key `P_U` (parent_key == P_U), founder == `user:<uid>`, carrying `verifiedVia` +
375
448
  * `idpToken` + `capturedClock`. There is NO tenant `S_P` in the loop — the kernel's home-birth chain
376
449
  * walk (`verify_to_root`, keyless branch) RE-VERIFIES the token against the platform-attested
@@ -380,7 +453,7 @@ export const enrollFirstDevice = directive("enrollFirstDevice")
380
453
  * OPTIONAL — an enroll-only flow (seat the signer, no imminent home birth) omits it and seeds no
381
454
  * delegation (backward-compatible with every pre-B `enrollFirstDevice` caller). The keyless home-birth
382
455
  * ceremony ALWAYS supplies it (that is what seeds the delegation the chain needs). */
383
- delegationCert: z.string().min(1).optional(),
456
+ delegationCertificate: birthCertificatePayload.optional(),
384
457
  }),
385
458
  )
386
459
  .plan((p, ctx) => {
@@ -404,14 +477,24 @@ export const enrollFirstDevice = directive("enrollFirstDevice")
404
477
  // The delegation is keyed by the AUTHENTICATED principal — EXACTLY the `founder` the kernel's birth
405
478
  // offer-effect reads it back by (`read_signer_delegation(state, &founder)`, founder == captured principal
406
479
  // == this `rawPrincipal`, already in `user:<uid>` form). Do NOT re-prefix.
407
- // Absent delegationCert ⇒ enroll-only (no delegation seeded), byte-identical to a pre-B enroll.
408
- if (!p.delegationCert) return tupleOps;
480
+ // Absent certificate ⇒ enroll-only (no delegation seeded), byte-identical to a pre-B enroll.
481
+ if (!p.delegationCert && !p.delegationCertificate) return tupleOps;
409
482
  const d = instance(SignerDelegation, signerDelegationInstanceId(rawPrincipal));
410
483
  const delegationOps: PlannedOp[] = [
411
484
  withMarker(set(d, "user", rawPrincipal), "ensures"),
412
485
  withMarker(set(d, "deviceKey", "key:" + p.keyHash), "ensures"),
413
- withMarker(set(d, "certJson", p.delegationCert), "ensures"),
414
- withMarker(set(d, "enrolledAt", p.grantedAt), "ensures"),
486
+ ...(p.delegationCertificate
487
+ ? [
488
+ withMarker(set(d, "enrolledAt", p.grantedAt), "ensures"),
489
+ ...writeDelegationCertificate(d, p.delegationCertificate, "ensures"),
490
+ ]
491
+ : [
492
+ // Exact legacy event order is replay identity, even though Lww folding would commute these
493
+ // two writes. Historical enrollFirstDevice intents wrote certJson before enrolledAt; retain
494
+ // that byte-level outcome when re-authoring an old payload under a candidate law.
495
+ withMarker(set(d, "certJson", p.delegationCert!), "ensures"),
496
+ withMarker(set(d, "enrolledAt", p.grantedAt), "ensures"),
497
+ ]),
415
498
  ];
416
499
  return [...tupleOps, ...delegationOps];
417
500
  })
@@ -466,7 +549,7 @@ export const revokeSigner = directive("revokeSigner")
466
549
  * offer-effect can read U's delegation when it assembles U's home chain. `.ensures` (a deterministic-keyed
467
550
  * singleton — upsert-by-user). A CONTROL-PLANE write composed into the tenant's onboarding governance law
468
551
  * (off the open session lane) — only the tenant (whose `S_P` the platform chain attests) may enroll a
469
- * delegation. The `certJson` is verified by the kernel at home birth (signed by S_P, founder == U); a forged
552
+ * delegation. The typed certificate is verified by the kernel at home birth (signed by S_P, founder == U); a forged
470
553
  * delegation simply fails the chain walk / founder-binding at the child's gate.
471
554
  */
472
555
  export const enrollDelegation = directive("enrollDelegation")
@@ -475,7 +558,7 @@ export const enrollDelegation = directive("enrollDelegation")
475
558
  z.object({
476
559
  user: z.string().min(1), // the user:<uid> the delegation enrolls
477
560
  deviceKey: z.string().min(1), // base64 P_U — the user's device public key
478
- certJson: z.string().min(1), // JSON BirthCert, signed by the tenant's S_P
561
+ certificate: birthCertificatePayload,
479
562
  enrolledAt: z.string().min(1), // ISO-8601, caller-stamped
480
563
  }),
481
564
  )
@@ -484,8 +567,8 @@ export const enrollDelegation = directive("enrollDelegation")
484
567
  return [
485
568
  set(d, "user", p.user),
486
569
  set(d, "deviceKey", p.deviceKey),
487
- set(d, "certJson", p.certJson),
488
570
  set(d, "enrolledAt", p.enrolledAt),
571
+ ...writeDelegationCertificate(d, p.certificate),
489
572
  ];
490
573
  });
491
574
 
@@ -106,7 +106,14 @@ export { enrollFirstDevice, revokeSigner } from "./signing_identity.js";
106
106
  // `[platform_cert]` chain would fail `verify_to_root` (>=2 links), so its own verify doors must stay inert
107
107
  // while it still carries the cert for its children. Fully additive (new aggregate + directive, no era key ⇒
108
108
  // pre-existing chains replay byte-identical). See architecture/verified_auth_from_genesis.md.
109
- export { BIRTH_ATTESTATION_ID, BirthAttestation, birthAttestation, seedBirthAttestation } from "./home.js";
109
+ export {
110
+ BIRTH_ATTESTATION_ID,
111
+ BIRTH_ATTESTATION_LINK_PREFIX,
112
+ BirthAttestation,
113
+ BirthAttestationLink,
114
+ birthAttestation,
115
+ seedBirthAttestation,
116
+ } from "./home.js";
110
117
  // THE ENROLL-ONCE DELEGATION LANE — a platform records each tenant's device-key delegation (signed by its
111
118
  // onboarding signer S_P) so the kernel reads it at `signer-delegation:<user>` when assembling a home's chain.
112
119
  export { SignerDelegation, enrollDelegation, signerDelegationByUser } from "./signing_identity.js";
@@ -1390,16 +1397,37 @@ export const setPlatformPool = directive("setPlatformPool")
1390
1397
  // here verbatim — the public surface and the law bytes are unchanged.
1391
1398
  export {
1392
1399
  AUTH_PROVIDER_ID,
1400
+ AUTH_PROVIDER_KEY_ID_PREFIX,
1401
+ AUTH_PROVIDER_CERTIFICATE_ID_PREFIX,
1393
1402
  AuthProvider,
1403
+ AuthProviderKey,
1404
+ AuthProviderCertificate,
1405
+ authProviderPublicKey,
1406
+ authProviderKeySet,
1407
+ authProviderConfiguration,
1408
+ type AuthProviderConfiguration,
1409
+ writeAuthProviderConfiguration,
1410
+ writeAuthProviderKeySet,
1394
1411
  seedAuthProvider,
1395
1412
  authProviderSeedBeforeWarrant,
1396
1413
  setAuthProvider,
1397
1414
  authProvider,
1415
+ authProviderKeys,
1416
+ authProviderCertificates,
1417
+ } from "./auth_provider_law.js";
1418
+ import {
1419
+ AUTH_PROVIDER_ID,
1420
+ AuthProvider,
1421
+ AuthProviderCertificate,
1422
+ AuthProviderKey,
1423
+ authProvider,
1424
+ authProviderKeySet,
1425
+ setAuthProvider,
1426
+ writeAuthProviderKeySet,
1398
1427
  } from "./auth_provider_law.js";
1399
- import { AUTH_PROVIDER_ID, AuthProvider, setAuthProvider, authProvider } from "./auth_provider_law.js";
1400
1428
 
1401
1429
  /**
1402
- * rotateKeys — TRUSTLESS key rotation. Replace {@link AuthProvider.keys} with a new JWKS whose every key
1430
+ * rotateKeys — TRUSTLESS key rotation. Replace the typed key epoch with public keys whose every key
1403
1431
  * carries an `x5c` cert chain. DELIBERATELY UNGATED at the relation level — the KERNEL is the authority: it
1404
1432
  * admits this ONLY if each key's x5c chain validates (RFC 5280) to the law-pinned {@link AuthProvider.rootCert}
1405
1433
  * and each key matches its CA-vouched leaf cert (the bind). So a bailiff (host on a cron, or anyone) may
@@ -1410,17 +1438,18 @@ export const rotateKeys = directive("rotateKeys")
1410
1438
  .ensures(AuthProvider)
1411
1439
  .payload(
1412
1440
  z.object({
1413
- /** The new JWKS JSON; EACH key MUST carry an `x5c` the kernel validates to {@link AuthProvider.rootCert}. */
1414
- keys: z.string().min(1),
1441
+ /** The new typed keys; EACH key MUST carry an `x5c` the kernel validates to the pinned root. */
1442
+ keySet: authProviderKeySet,
1415
1443
  rotatedAt: epochMs,
1416
- }),
1444
+ }).strict(),
1417
1445
  )
1418
1446
  .plan((p) => {
1419
1447
  const ap = instance(AuthProvider, AUTH_PROVIDER_ID);
1420
- // The kernel's x5c admission gate authorizes this (validate_rotate_keys); the plan just stores the
1421
- // CA-vouched JWKS. The `ensures` marker upserts onto the existing AuthProvider singleton.
1422
- return [withMarker(set(ap, "keys", p.keys), "ensures"), set(ap, "setAt", p.rotatedAt)];
1423
- });
1448
+ // The kernel's x5c admission gate authorizes this; the plan stores the CA-vouched typed key epoch.
1449
+ return [withMarker(set(ap, "keyEpoch", p.keySet.epoch), "ensures"), ...writeAuthProviderKeySet(p.keySet), set(ap, "setAt", p.rotatedAt)];
1450
+ })
1451
+ .alsoEnsuresMany(AuthProviderKey)
1452
+ .alsoEnsuresMany(AuthProviderCertificate);
1424
1453
 
1425
1454
  /**
1426
1455
  * HostnameClaim — a CUSTOM HOSTNAME bound to a platform: `api.acme.com` serving
@@ -0,0 +1,53 @@
1
+ // Stable framework operation names, bound to their authored directive schemas.
2
+ //
3
+ // This is deliberately metadata, not a second schema language. Every payload
4
+ // type and encoder is derived from the Directive object carried here. Both the
5
+ // TypeScript and Dart compilers consume this same list, so adding or changing a
6
+ // framework field cannot leave a handwritten host mirror behind.
7
+
8
+ import type { Directive } from "./directive.js";
9
+ import { APPLICATION_HOME_DOMAIN } from "./framework/application_home_domain.js";
10
+ import { setAuthProvider } from "./framework/auth_provider_law.js";
11
+ import { seedBirthPolicy } from "./framework/birth_meter.js";
12
+ import { installDomain, promoteDomain, rollbackDomain, stageDomain } from "./framework/domain_lifecycle.js";
13
+ import { seedGenesis } from "./framework/genesis.js";
14
+ import {
15
+ birthReceivingGroupForDomain,
16
+ seedBirthAttestation,
17
+ seedReceivingGroup,
18
+ seedReceivingGroupPolicy,
19
+ } from "./framework/home.js";
20
+ import { enrollDelegation, enrollFirstDevice, enrollSigner } from "./framework/signing_identity.js";
21
+
22
+ export interface FixedFrameworkCallDefinition {
23
+ readonly group: "identity" | "lifecycle" | "birth";
24
+ readonly kind: string;
25
+ readonly directive: Directive<any>;
26
+ /** Needed by the pre-bind Dart birth ceremony before an application exists. */
27
+ readonly dartBirth?: true;
28
+ /** A composed application-home law must contain this operation. */
29
+ readonly requiredApplicationHome?: true;
30
+ }
31
+
32
+ const receivingGroupBirth = birthReceivingGroupForDomain(
33
+ APPLICATION_HOME_DOMAIN,
34
+ 0,
35
+ [APPLICATION_HOME_DOMAIN],
36
+ );
37
+
38
+ export const fixedFrameworkCallDefinitions: readonly FixedFrameworkCallDefinition[] = [
39
+ { group: "identity", kind: "enrollFirstDevice", directive: enrollFirstDevice, dartBirth: true, requiredApplicationHome: true },
40
+ { group: "identity", kind: "enrollSigner", directive: enrollSigner, dartBirth: true, requiredApplicationHome: true },
41
+ { group: "identity", kind: "setAuthProvider", directive: setAuthProvider, requiredApplicationHome: true },
42
+ { group: "identity", kind: "birthReceivingGroup", directive: receivingGroupBirth, dartBirth: true, requiredApplicationHome: true },
43
+ { group: "lifecycle", kind: "installDomain", directive: installDomain },
44
+ { group: "lifecycle", kind: "stageDomain", directive: stageDomain },
45
+ { group: "lifecycle", kind: "promoteDomain", directive: promoteDomain },
46
+ { group: "lifecycle", kind: "rollbackDomain", directive: rollbackDomain },
47
+ { group: "birth", kind: "seedBirthPolicy", directive: seedBirthPolicy, dartBirth: true },
48
+ { group: "birth", kind: "enrollDelegation", directive: enrollDelegation, dartBirth: true },
49
+ { group: "birth", kind: "seedBirthAttestation", directive: seedBirthAttestation, dartBirth: true },
50
+ { group: "birth", kind: "seedGenesis", directive: seedGenesis, dartBirth: true },
51
+ { group: "birth", kind: "seedReceivingGroupPolicy", directive: seedReceivingGroupPolicy, dartBirth: true },
52
+ { group: "birth", kind: "seedReceivingGroup", directive: seedReceivingGroup, dartBirth: true },
53
+ ];
@@ -0,0 +1,45 @@
1
+ // Stable framework reads bound to their authored aggregate/query declarations.
2
+ //
3
+ // This is metadata, not another schema language. The compiler consumes the
4
+ // AggregateHandle/QueryDecl objects directly, so the public host contract,
5
+ // canonical query USDA and result decoder all change together with the DSL.
6
+
7
+ import type { AggregateHandle } from "./aggregate.js";
8
+ import type { QueryDecl } from "./query.js";
9
+ import { EncKey, encKeyByPrincipal } from "./framework/encryption_identity.js";
10
+ import {
11
+ KeyScope,
12
+ WrappedKey,
13
+ keyScopeByScope,
14
+ wrappedKeysByRecipient,
15
+ } from "./framework/encryption_scope.js";
16
+ import {
17
+ OwnedRecoveryOrder,
18
+ OwnedRecoveryPolicy,
19
+ ownedRecoveryOrdersByRecoveryPrincipal,
20
+ } from "./framework/owned_custody.js";
21
+ import { RelationTuple, relationTuplesByObject } from "./framework/relations.js";
22
+ import { SignerEpoch } from "./framework/signing_identity.js";
23
+
24
+ export interface FixedFrameworkReadDefinition {
25
+ readonly kind:
26
+ | "encKey"
27
+ | "keyScope"
28
+ | "ownedRecoveryOrder"
29
+ | "ownedRecoveryPolicy"
30
+ | "relationTuple"
31
+ | "signerEpoch"
32
+ | "wrappedKey";
33
+ readonly aggregate: AggregateHandle;
34
+ readonly query?: QueryDecl;
35
+ }
36
+
37
+ export const fixedFrameworkReadDefinitions: readonly FixedFrameworkReadDefinition[] = [
38
+ { kind: "encKey", aggregate: EncKey, query: encKeyByPrincipal },
39
+ { kind: "keyScope", aggregate: KeyScope, query: keyScopeByScope },
40
+ { kind: "ownedRecoveryOrder", aggregate: OwnedRecoveryOrder, query: ownedRecoveryOrdersByRecoveryPrincipal },
41
+ { kind: "ownedRecoveryPolicy", aggregate: OwnedRecoveryPolicy },
42
+ { kind: "relationTuple", aggregate: RelationTuple, query: relationTuplesByObject },
43
+ { kind: "signerEpoch", aggregate: SignerEpoch },
44
+ { kind: "wrappedKey", aggregate: WrappedKey, query: wrappedKeysByRecipient },
45
+ ];
@@ -0,0 +1,58 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import { existsSync, readFileSync, realpathSync } from "node:fs";
3
+ import path from "node:path";
4
+
5
+ export type IdentityFrontierSource = Readonly<{
6
+ source: string;
7
+ custody: "git-head" | "working-file";
8
+ }>;
9
+
10
+ /**
11
+ * Read the identity frontier which is already part of custody.
12
+ *
13
+ * The working identity layer is candidate output: it may contain identities minted
14
+ * by an earlier successful local compile which have never been committed or shipped.
15
+ * Git HEAD is therefore the historical evolution frontier whenever the package is in
16
+ * Git custody. Outside Git, the checked-in/working file remains the portable fallback.
17
+ */
18
+ export function readHistoricalIdentityFrontier(
19
+ lockPath: string,
20
+ ): IdentityFrontierSource | undefined {
21
+ const directory = path.dirname(lockPath);
22
+ let repositoryRoot: string;
23
+ try {
24
+ repositoryRoot = realpathSync(execFileSync("git", ["rev-parse", "--show-toplevel"], {
25
+ cwd: directory,
26
+ encoding: "utf8",
27
+ stdio: ["ignore", "pipe", "ignore"],
28
+ }).trim());
29
+ } catch {
30
+ return existsSync(lockPath)
31
+ ? { source: readFileSync(lockPath, "utf8"), custody: "working-file" }
32
+ : undefined;
33
+ }
34
+
35
+ const canonicalLockPath = path.join(realpathSync(directory), path.basename(lockPath));
36
+ const relative = path.relative(repositoryRoot, canonicalLockPath);
37
+ if (relative === "" || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {
38
+ return existsSync(lockPath)
39
+ ? { source: readFileSync(lockPath, "utf8"), custody: "working-file" }
40
+ : undefined;
41
+ }
42
+
43
+ try {
44
+ return {
45
+ source: execFileSync("git", ["show", `HEAD:${relative.split(path.sep).join("/")}`], {
46
+ cwd: repositoryRoot,
47
+ encoding: "utf8",
48
+ stdio: ["ignore", "pipe", "ignore"],
49
+ }),
50
+ custody: "git-head",
51
+ };
52
+ } catch {
53
+ // A repository with no committed identity has no historical frontier. Treating
54
+ // an untracked or candidate-only file as history would make local experimentation
55
+ // irreversible before it ever entered custody.
56
+ return undefined;
57
+ }
58
+ }
package/src/index.ts CHANGED
@@ -254,7 +254,7 @@ export { repair, repairsOf, isRepairDecl, type RepairDecl, type RepairMatcher, t
254
254
  // NOT YET DEPLOYABLE (#57): the sealed wasm engine does not provide `nomos.read` yet, so
255
255
  // `nomos-compile` REFUSES law that references read() (a named compile error, never a runtime halt).
256
256
  // The captured-reads wave (task #58) wires the capability in and lifts the refusal.
257
- export { read } from "./read.js";
257
+ export { read, readFrameworkDeclaredRows } from "./read.js";
258
258
  // RELEASE COHERENCE — standard OSGi Contract Namespace requirements derived from law shape.
259
259
  export {
260
260
  requiredKernelContracts,
@@ -319,12 +319,14 @@ export {
319
319
  // `nomosBirthGate` era key, never domain state) — spawns + self-validates the child after the offer admits.
320
320
  export {
321
321
  birth,
322
+ workspaceRole,
322
323
  workspaceNameForKey,
323
324
  WORKSPACE_NAME_SEP,
324
325
  birthKeyed,
325
326
  birthSingleton,
326
327
  birthInstance,
327
328
  type BirthRecipe,
329
+ type WorkspaceRole,
328
330
  type GenesisChainOrBuilder,
329
331
  type BusinessBirthDecl,
330
332
  type BusinessBirthSpec,
@@ -505,6 +507,8 @@ export {
505
507
  identityRelations,
506
508
  signerObject,
507
509
  SIGNER_RELATION,
510
+ ADMISSION_CHECKPOINT_PRINCIPAL,
511
+ enrollAdmissionCheckpointSigner,
508
512
  enrollSigner,
509
513
  // VA-core — SignerEpoch + self-bind enroll/revoke + the strict-increment & verified-enroll gates.
510
514
  SignerEpoch,
@@ -535,11 +539,26 @@ export {
535
539
  // the provider explicitly, without re-declaring the kernel's security schema in tenant code.
536
540
  export {
537
541
  AUTH_PROVIDER_ID,
542
+ AUTH_PROVIDER_KEY_ID_PREFIX,
543
+ AUTH_PROVIDER_CERTIFICATE_ID_PREFIX,
538
544
  AuthProvider,
545
+ AuthProviderKey,
546
+ AuthProviderCertificate,
547
+ authProviderPublicKey,
548
+ authProviderKeySet,
549
+ authProviderConfiguration,
550
+ type AuthProviderConfiguration,
551
+ type AuthProviderVerifyingConfiguration,
552
+ readAuthProviderConfiguration,
553
+ readAuthProviderVerifyingConfiguration,
554
+ writeAuthProviderConfiguration,
555
+ writeAuthProviderKeySet,
539
556
  seedAuthProvider,
540
557
  authProviderSeedBeforeWarrant,
541
558
  setAuthProvider,
542
559
  authProvider,
560
+ authProviderKeys,
561
+ authProviderCertificates,
543
562
  } from "./framework/auth_provider_law.js";
544
563
  // THE RECEIVING-GROUP HOLON — the framework-private shared signer roster + access manifest.
545
564
  export {
@@ -566,7 +585,9 @@ export {
566
585
  birthReceivingGroup,
567
586
  // THE PEER-SOVEREIGN ROOT-OF-TRUST (the BirthAttestation cert chain).
568
587
  BirthAttestation,
588
+ BirthAttestationLink,
569
589
  BIRTH_ATTESTATION_ID,
590
+ BIRTH_ATTESTATION_LINK_PREFIX,
570
591
  seedBirthAttestation,
571
592
  birthAttestation,
572
593
  parentAttestedBirth,