@githolon/dsl 0.98.2 → 0.98.3

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@githolon/dsl",
3
- "version": "0.98.2",
3
+ "version": "0.98.3",
4
4
  "type": "module",
5
5
  "description": "Nomos 2 domain-authoring DSL: aggregates + directives in TS, executed and encoded to the Rust kernel's wire shapes.",
6
6
  "license": "SEE LICENSE IN LICENSE.md",
@@ -231,6 +231,30 @@ export const birthHome = directive("birthHome")
231
231
  .plan((p) => {
232
232
  const founder = p.owner; // the actor for the child's own genesis steps (its self-bound owner subject)
233
233
  const homeName = homeNameOf(p.owner); // workspace name == seeded homeName — derived from the SAME owner
234
+ // THE PARENT'S DECLARED VERIFIER (one captured read serves BOTH consumers below): the inherited
235
+ // `setAuthProvider` genesis step AND the enroll step's `verifiedVia` provenance stamp. Read it up
236
+ // front so the enroll step (which precedes the inheritance step in the chain) can see the issuer.
237
+ const apRows = p.inheritAuthProvider !== false
238
+ ? readFrameworkDeclared<Array<Record<string, unknown>>>("authProvider", { scope: "platform" })
239
+ : undefined;
240
+ const apRaw = Array.isArray(apRows) && apRows.length > 0 ? apRows[0] : undefined;
241
+ // Projected rows are `{type,id,data:{…fields}}`; folded shapes may be flat — accept both.
242
+ const ap = (apRaw && typeof apRaw === "object" && typeof (apRaw as { data?: unknown }).data === "object"
243
+ ? (apRaw as { data: Record<string, unknown> }).data
244
+ : apRaw) as Record<string, unknown> | undefined;
245
+ const apStr = (k: string): string | undefined => {
246
+ const v = ap?.[k];
247
+ return typeof v === "string" && v.length > 0 ? v : undefined;
248
+ };
249
+ // PROVENANCE (the verified-lineage thread, 2026-07-16): the kernel derives every later write's
250
+ // `principal_verified` from the ENROLL LEAF's `verifiedVia` — so a verified birth must stamp it or the
251
+ // born home's owner writes UNVERIFIED forever (and its own children are then born `verified:false`,
252
+ // whose chains refuse `verify_to_root`). The cert's `verified` IS the gate verdict post-admission
253
+ // (assemble_birth_attestation CAS-refuses a mismatch), so reading it in-plan is trustworthy — a lying
254
+ // cert never reaches this fold. An unverified birth stamps nothing (the unverified lane stays honest).
255
+ let certVerified = false;
256
+ try { certVerified = p.homeCert !== undefined && JSON.parse(p.homeCert).verified === true; } catch { /* malformed cert ⇒ unverified (the gate will refuse the birth anyway) */ }
257
+ const verifiedVia = certVerified ? apStr("issuer") : undefined;
234
258
  const genesisChain: Array<{ domain: string; directiveId: string; actor: string; payload: Record<string, unknown>; domainHash?: string; domainPackageB64?: string }> = [
235
259
  // THE ORDER-DECLARED LAW INSTALL: two layers, bytes-by-hash (empty package — the kernel resolves them
236
260
  // from the parent's custody when it folds the birth; never the host). Matches buildGenesisChain's shape.
@@ -248,22 +272,13 @@ export const birthHome = directive("birthHome")
248
272
  // ladder: every seed runs UNSIGNED on the still-warrant-free prefix; the warrant closes it). ERA-SAFE: a
249
273
  // home born earlier (pre-feature law, no such step in its recipe) replays byte-identical — the era rule
250
274
  // rides the LAW hash, not this branch.
251
- { domain: HOME_LAW_DOMAIN, directiveId: "enrollSigner", actor: founder, payload: { keyHash: p.ownerKeyHash, grantedBy: p.owner, grantedAt: 1 } },
275
+ { domain: HOME_LAW_DOMAIN, directiveId: "enrollSigner", actor: founder, payload: { keyHash: p.ownerKeyHash, grantedBy: p.owner, grantedAt: 1, ...(verifiedVia !== undefined ? { verifiedVia } : {}) } },
252
276
  ];
253
- // AUTHPROVIDER INHERITANCE (default ON — see the payload doc): read the PARENT's declared provider
254
- // (captured read, re-derived at the gate) and copy it AS DATA into the child genesis. The child owns
255
- // the copy as its own law-state; nothing is inherited-by-reference. Opt out: `inheritAuthProvider: false`.
277
+ // AUTHPROVIDER INHERITANCE (default ON — see the payload doc): copy the parent's declared provider
278
+ // (the up-front captured read above) AS DATA into the child genesis. The child owns the copy as its
279
+ // own law-state; nothing is inherited-by-reference. Opt out: `inheritAuthProvider: false`.
256
280
  if (p.inheritAuthProvider !== false) {
257
- const rows = readFrameworkDeclared<Array<Record<string, unknown>>>("authProvider", { scope: "platform" });
258
- const raw = Array.isArray(rows) && rows.length > 0 ? rows[0] : undefined;
259
- // Projected rows are `{type,id,data:{…fields}}`; folded shapes may be flat — accept both.
260
- const ap = (raw && typeof raw === "object" && typeof (raw as { data?: unknown }).data === "object"
261
- ? (raw as { data: Record<string, unknown> }).data
262
- : raw) as Record<string, unknown> | undefined;
263
- const str = (k: string): string | undefined => {
264
- const v = ap?.[k];
265
- return typeof v === "string" && v.length > 0 ? v : undefined;
266
- };
281
+ const str = apStr;
267
282
  const issuer = str("issuer");
268
283
  if (issuer !== undefined) {
269
284
  genesisChain.push({
@@ -212,6 +212,14 @@ export const enrollSigner = directive("enrollSigner")
212
212
  keyHash: sha256Hex, // sha256hex of the ed25519 device PUBLIC key
213
213
  grantedBy: z.string().min(1),
214
214
  grantedAt: z.number().int().nonnegative(), // epoch ms, caller-stamped (determinism)
215
+ /** OPTIONAL PROVENANCE — the IdP/issuer that VOUCHED for this principal at the enrolling birth.
216
+ * The kernel's `verify_captured_principal` derives `principal_verified` from THIS leaf field on
217
+ * every later write, so a genesis enroll that omits it leaves the workspace's owner permanently
218
+ * UNVERIFIED (their children are then born `verified:false` and their chains refuse
219
+ * `verify_to_root` — the 2026-07-16 estate holarchy RED). Birth recipes stamp it from the
220
+ * CAS-verified birth cert (`cert.verified` IS the gate verdict post-admission) + the inherited
221
+ * AuthProvider issuer; an unverified birth omits it (the unverified lane stays honest). */
222
+ verifiedVia: z.string().min(1).optional(),
215
223
  }),
216
224
  )
217
225
  .plan((p, ctx) => {
@@ -227,6 +235,7 @@ export const enrollSigner = directive("enrollSigner")
227
235
  subject: "key:" + p.keyHash,
228
236
  grantedBy: p.grantedBy,
229
237
  grantedAt: String(p.grantedAt),
238
+ ...(p.verifiedVia !== undefined ? { verifiedVia: p.verifiedVia } : {}),
230
239
  });
231
240
  });
232
241
 
package/src/index.ts CHANGED
@@ -416,6 +416,15 @@ export {
416
416
  type SignerEpochHandle,
417
417
  type SignerAuthority,
418
418
  } from "./framework/signing_identity.js";
419
+ // THE WORKSPACE VERIFIER is framework-owned law-state. Ordinary birth/onboarding flows compose and
420
+ // inherit it automatically; these exports exist for governance and acceptance laws that need to author
421
+ // the provider explicitly, without re-declaring the kernel's security schema in tenant code.
422
+ export {
423
+ AUTH_PROVIDER_ID,
424
+ AuthProvider,
425
+ setAuthProvider,
426
+ authProvider,
427
+ } from "./framework/auth_provider_law.js";
419
428
  // THE HOME HOLON (home_holons_and_cross_custody.md §4) — the identity-role law: the shared-with-me access
420
429
  // index + the owner lane to maintain it (the key directory is the `signer` relation above).
421
430
  export {