@githolon/dsl 0.103.1 → 0.103.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/dart/CHANGELOG.md +7 -0
- package/dart/lib/src/dev_cloud.dart +5 -0
- package/dart/lib/src/runner/node-entry.mjs +1 -1
- package/dart/lib/src/runner/offline-install.mjs +1 -1
- package/dart/lib/src/test_harness.dart +33 -1
- package/dart/pubspec.lock +1 -1
- package/dart/pubspec.yaml +2 -2
- package/dart/test/first_app_gauntlet_test.dart +16 -1
- package/dart_types/CHANGELOG.md +5 -0
- package/dart_types/pubspec.yaml +1 -1
- package/package.json +1 -1
- package/src/application_home_genesis.ts +73 -0
- package/src/birth_meter.ts +7 -15
- package/src/birth_meter_ensure.ts +9 -0
- package/src/births.ts +18 -0
- package/src/business_birth.ts +44 -1
- package/src/codegen_dart_application.ts +9 -1
- package/src/codegen_dart_scenario.ts +7 -0
- package/src/codegen_proof.ts +11 -1
- package/src/compile_package_main.ts +124 -8
- package/src/directive.ts +8 -0
- package/src/framework/application_home.ts +19 -2
- package/src/framework/birth_meter.ts +4 -5
- package/src/framework/home.ts +71 -5
- package/src/framework/workspaces.ts +44 -57
- package/src/index.ts +7 -1
- package/src/law_graph.ts +23 -0
- package/src/law_graph_usda.ts +11 -1
- package/src/package_config.ts +30 -0
|
@@ -158,7 +158,7 @@ export const workspaceSelfWriteOnce = workspaceInvariant("WorkspaceSelfWriteOnce
|
|
|
158
158
|
// pre-apply folded relation tuples — refusing any author who does not HOLD the relation. The schema +
|
|
159
159
|
// the `.requires` together arm the gate (the `nomosRelations` + `nomosRelationGate` era keys); the
|
|
160
160
|
// static governance roles use the native relation gate. Creation posture is deliberately dynamic law:
|
|
161
|
-
// open
|
|
161
|
+
// open admits any proven author, invite checks `creator`, closed checks `admin`, and unset fails closed.
|
|
162
162
|
//
|
|
163
163
|
// THE CONTROL-PLANE CARVE-OUT — LEAF-ONLY (`allow: [user(), key()]`, never a userset/wildcard). A
|
|
164
164
|
// `workspace:self#admin@<group>#member` or `@<type>:*` would let a group/wildcard escalate to admin
|
|
@@ -371,8 +371,8 @@ export const CloudPolicy = aggregate("CloudPolicy", {
|
|
|
371
371
|
/**
|
|
372
372
|
* The workspace-CREATION posture dial (cloud_sovereignty.md S6) —
|
|
373
373
|
* `"open"` (anyone creates), `"invite"` (an active CreationGrant key
|
|
374
|
-
* required), or `"closed"` (admins only). OPTIONAL
|
|
375
|
-
*
|
|
374
|
+
* required), or `"closed"` (admins only). OPTIONAL in the storage schema for
|
|
375
|
+
* historical replay, but absence fails closed for new births. Merely
|
|
376
376
|
* granting somebody authority never changes the door for everybody else.
|
|
377
377
|
*/
|
|
378
378
|
creationPosture: t.string().merge(Lww).optional(),
|
|
@@ -529,13 +529,9 @@ export function buildGenesisChain(p: {
|
|
|
529
529
|
* from there. Absent ⇒ the recipe resolves an already-installed law by shape (pre-G3 / test lanes). */
|
|
530
530
|
frameworkHash?: string;
|
|
531
531
|
lawHash?: string;
|
|
532
|
-
/**
|
|
533
|
-
*
|
|
534
|
-
|
|
535
|
-
* OPT-IN: thread it only when the `lawHash` the order names carries `seedBirthPolicy` (a governance
|
|
536
|
-
* package compiled under the metered-birth DSL) — see the poolSteps note below.
|
|
537
|
-
*/
|
|
538
|
-
descendantPool?: number;
|
|
532
|
+
/** METERED BIRTH (slice A3 — the descendant budget). Required: a governance child may not be
|
|
533
|
+
* born without explicit BirthPolicy state. Zero is a legitimate declared "cannot birth" policy. */
|
|
534
|
+
descendantPool: number;
|
|
539
535
|
/** LINEAGE CONTINUITY (rebirth genesis only): the superseded incarnation's genesis oid. Threads onto the
|
|
540
536
|
* child's birthCloud record (`rebornFrom`) + the bornUnder commitment — the reborn holon testifies to its
|
|
541
537
|
* ancestry while `parent` stays the SUPERSEDED record's parent (a rebirth may never reparent). */
|
|
@@ -566,26 +562,23 @@ export function buildGenesisChain(p: {
|
|
|
566
562
|
parentHead: "",
|
|
567
563
|
...(p.rebornFrom ? { rebornFrom: p.rebornFrom } : {}),
|
|
568
564
|
});
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
//
|
|
576
|
-
//
|
|
577
|
-
//
|
|
578
|
-
const poolSteps =
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
},
|
|
587
|
-
]
|
|
588
|
-
: [];
|
|
565
|
+
if (!Number.isInteger(p.descendantPool) || p.descendantPool < 0) {
|
|
566
|
+
throw new Error(
|
|
567
|
+
"buildGenesisChain requires an explicit non-negative descendantPool; " +
|
|
568
|
+
"Nomos has no compiled birth-policy fallback",
|
|
569
|
+
);
|
|
570
|
+
}
|
|
571
|
+
// METERED BIRTH (slice A3 — THE POOL CHAINS TO ROOT): every governance child is BORN BOUNDED.
|
|
572
|
+
// Historical chains keep replaying under their historical law; this constructor authors only the
|
|
573
|
+
// current law, whose seedBirthPolicy directive is compiler-carried. Missing policy is invalid genesis.
|
|
574
|
+
const poolSteps = [
|
|
575
|
+
{
|
|
576
|
+
domain: "workspaces",
|
|
577
|
+
directiveId: "seedBirthPolicy",
|
|
578
|
+
actor: founder,
|
|
579
|
+
payload: { maxBirthsPerPrincipal: p.descendantPool, setBy: p.principal, setAt: p.bornAt },
|
|
580
|
+
},
|
|
581
|
+
];
|
|
589
582
|
return JSON.stringify([
|
|
590
583
|
...installSteps,
|
|
591
584
|
...poolSteps,
|
|
@@ -634,9 +627,6 @@ export const quotaByPrincipal = query("quotaByPrincipal")
|
|
|
634
627
|
.key("principal")
|
|
635
628
|
.returns(QuotaGrant);
|
|
636
629
|
|
|
637
|
-
/** THE DEFAULT WORKSPACE ALLOWANCE — the CLAUDE.md / CloudPolicy figure when no grant + no policy row. */
|
|
638
|
-
export const DEFAULT_MAX_WORKSPACES_PER_PRINCIPAL = 50;
|
|
639
|
-
|
|
640
630
|
/** A captured-read row as `derive_captured_read` shapes it: `{id, data:{field:value}}`. */
|
|
641
631
|
type QuotaRow = { id?: string; data?: Record<string, unknown> };
|
|
642
632
|
|
|
@@ -656,8 +646,8 @@ function countQuotaReads(principal: string): void {
|
|
|
656
646
|
* THE WORKSPACE-QUOTA VERDICT — the PURE predicate the {@link workspaceQuota} invariant runs over the
|
|
657
647
|
* COMMITTED captured reads (the same `{queryId,args,result}` the plan recorded, CAS-re-derived on every
|
|
658
648
|
* lane). Counts the principal's LIVE (non-retired/-reclaimed) CloudWorkspaces and compares against its
|
|
659
|
-
* allowance (the latest QuotaGrant.maxWorkspaces if any, else CloudPolicy.maxWorkspacesPerPrincipal
|
|
660
|
-
*
|
|
649
|
+
* allowance (the latest QuotaGrant.maxWorkspaces if any, else CloudPolicy.maxWorkspacesPerPrincipal).
|
|
650
|
+
* Missing policy is a typed refusal: quota is law, never a compiled allowance. The NEW workspace is NOT yet in the pre-apply
|
|
661
651
|
* state, so `liveCount < allowance` (strict) is the correct test: the principal may hold AT MOST
|
|
662
652
|
* `allowance`, so a fresh birth is admitted iff it already holds fewer. A principal-less call (should be
|
|
663
653
|
* impossible after S3) fails CLOSED. The verdict is a pure function of the captured reads ⇒ identical on
|
|
@@ -678,8 +668,8 @@ function quotaVerdict(
|
|
|
678
668
|
const status = (row.data?.status ?? "") as string;
|
|
679
669
|
return status !== "retired" && status !== "reclaimed";
|
|
680
670
|
}).length;
|
|
681
|
-
// ALLOWANCE: the LATEST QuotaGrant for the principal (max grantedAt) wins; else the
|
|
682
|
-
//
|
|
671
|
+
// ALLOWANCE: the LATEST QuotaGrant for the principal (max grantedAt) wins; else the explicit
|
|
672
|
+
// CloudPolicy default. `derive_captured_read` decodes t.int() as a JSON number.
|
|
683
673
|
const grants = rowsOf(quotaByPrincipal.id);
|
|
684
674
|
let allowance: number | undefined;
|
|
685
675
|
let latestGrantedAt = -Infinity;
|
|
@@ -697,7 +687,7 @@ function quotaVerdict(
|
|
|
697
687
|
const max = Number(policyRows[0]?.data?.maxWorkspacesPerPrincipal ?? NaN);
|
|
698
688
|
if (Number.isFinite(max)) allowance = max;
|
|
699
689
|
}
|
|
700
|
-
if (allowance === undefined)
|
|
690
|
+
if (allowance === undefined) return { reject: "workspace-quota-policy-not-configured" };
|
|
701
691
|
return liveCount < allowance ? { accept: true } : { reject: "workspace-quota-exceeded" };
|
|
702
692
|
}
|
|
703
693
|
|
|
@@ -1213,7 +1203,7 @@ export const rebirthConsentByWorkspace = query("rebirthConsentByWorkspace")
|
|
|
1213
1203
|
// ─────────────────────────── birthChild — THE ONE BIRTH DIRECTIVE (the `kind`-collapse) ───────────────
|
|
1214
1204
|
// "There are only workspaces, all equal until a domain is installed." birthChild is the SINGLE directive
|
|
1215
1205
|
// that births any child — a plain leaf OR a platform; the difference is the GENESIS DATA the payload carries,
|
|
1216
|
-
// never a node-class. The same creation posture governs leaf and platform births: open
|
|
1206
|
+
// never a node-class. The same creation posture governs leaf and platform births: open admits any
|
|
1217
1207
|
// proven author, invite requires `#creator`, and closed requires `#admin`. The prior `#platformCreator`
|
|
1218
1208
|
// second tier is retired.
|
|
1219
1209
|
// • genesis ABSENT → a plain lineage record (no foundingAdminHash); boot-on-touch, never drained.
|
|
@@ -1245,8 +1235,9 @@ export const birthChild = directive("birthChild")
|
|
|
1245
1235
|
/** GENESIS (optional): present ⇒ this child is born running the governance law (a platform). The
|
|
1246
1236
|
* sha256 of the founding-admin key the requester presented — the provider grants admin to the hash. */
|
|
1247
1237
|
foundingAdminHash: sha256Hex.optional(),
|
|
1248
|
-
/** PLATFORM POOL: how many live children the born platform may parent.
|
|
1249
|
-
|
|
1238
|
+
/** PLATFORM POOL: explicit law-state for how many live children the born platform may parent.
|
|
1239
|
+
* Required with genesis. There is no framework default. Zero deliberately disables births. */
|
|
1240
|
+
pool: z.number().int().nonnegative().optional(),
|
|
1250
1241
|
/** GENESIS birth time as an ISO string (caller-stamped — the timestamp doctrine). Arms the warrant
|
|
1251
1242
|
* in the law-authored genesis chain; required for (and only used by) a genesis birth. */
|
|
1252
1243
|
bornAt: z.string().optional(),
|
|
@@ -1264,11 +1255,6 @@ export const birthChild = directive("birthChild")
|
|
|
1264
1255
|
* LAST into the child's genesis. REQUIRED for a genesis birth to complete — a birth without a
|
|
1265
1256
|
* valid cert is refused atomically (no unwarranted platform lane survives era 0). */
|
|
1266
1257
|
platformCert: z.string().optional(),
|
|
1267
|
-
/** METERED BIRTH (slice A3): the child's own descendant budget — when present, the genesis
|
|
1268
|
-
* recipe seeds the child's BirthPolicy (`seedBirthPolicy`) so it is BORN BOUNDED. OPT-IN:
|
|
1269
|
-
* only pass it when the `lawHash` the order names carries `seedBirthPolicy` (a governance
|
|
1270
|
-
* package compiled under the metered-birth DSL). Only meaningful with a genesis. */
|
|
1271
|
-
descendantPool: z.number().int().positive().optional(),
|
|
1272
1258
|
/** GOVERNANCE POSTURE (governance_postures.md) — the born child's declared posture; default
|
|
1273
1259
|
* `managed`. Mirrored onto its lineage record so root's bailiff can consult it on the hot path
|
|
1274
1260
|
* (the tenant's own {@link GovernancePosture} singleton is authoritative). Additive/era-safe. */
|
|
@@ -1276,22 +1262,22 @@ export const birthChild = directive("birthChild")
|
|
|
1276
1262
|
})
|
|
1277
1263
|
// A genesis birth (a platform) must carry a principal AND a bornAt — it owns a subtree, a lineage
|
|
1278
1264
|
// anchor, and a law-authored genesis chain whose warrant is stamped at bornAt.
|
|
1279
|
-
.refine((d) => !d.foundingAdminHash || (d.principal.length > 0 && !!d.bornAt), {
|
|
1280
|
-
message: "a genesis birth (foundingAdminHash present) requires a non-empty principal
|
|
1281
|
-
path: ["
|
|
1265
|
+
.refine((d) => !d.foundingAdminHash || (d.principal.length > 0 && !!d.bornAt && d.pool !== undefined), {
|
|
1266
|
+
message: "a genesis birth (foundingAdminHash present) requires a non-empty principal, bornAt (ISO), and explicit pool",
|
|
1267
|
+
path: ["pool"],
|
|
1282
1268
|
}),
|
|
1283
1269
|
)
|
|
1284
1270
|
.plan((p) => {
|
|
1285
1271
|
// THE WORKSPACE-QUOTA CAPTURED READS (#58 / S2) — same unconditional capture as createWorkspace, so the
|
|
1286
1272
|
// WorkspaceQuota invariant counts this principal's live workspaces against its allowance on every lane.
|
|
1287
1273
|
countQuotaReads(p.principal);
|
|
1288
|
-
const rec = planBirthRecord(p, p.foundingAdminHash ? { foundingAdminHash: p.foundingAdminHash, pool: p.pool } : undefined);
|
|
1274
|
+
const rec = planBirthRecord(p, p.foundingAdminHash ? { foundingAdminHash: p.foundingAdminHash, pool: p.pool as number } : undefined);
|
|
1289
1275
|
// LAW AUTHORS THE GENESIS RECIPE (P1): a genesis birth carries its child's [installDomain×2 →]
|
|
1290
1276
|
// seedGenesis→grantAdmin→birthCloud chain. (refine guarantees principal + bornAt here.)
|
|
1291
1277
|
if (p.foundingAdminHash) {
|
|
1292
1278
|
// ERA 0 — every governance/platform birth is WARRANTED (no compat hatch to thread; buildGenesisChain
|
|
1293
1279
|
// always records the real self-id).
|
|
1294
|
-
const genesisChain = buildGenesisChain({ name: p.name, principal: p.principal, parent: p.parent, tier: p.tier, foundingAdminHash: p.foundingAdminHash, bornAt: p.bornAt as string, requestedAt: p.requestedAt,
|
|
1280
|
+
const genesisChain = buildGenesisChain({ name: p.name, principal: p.principal, parent: p.parent, tier: p.tier, foundingAdminHash: p.foundingAdminHash, bornAt: p.bornAt as string, requestedAt: p.requestedAt, descendantPool: p.pool as number, ...(p.frameworkHash ? { frameworkHash: p.frameworkHash } : {}), ...(p.lawHash ? { lawHash: p.lawHash } : {}) });
|
|
1295
1281
|
// THE GENESIS RECIPE IS ALSO A LINEAGE/AUDIT FACT on the parent's chain (the parent records what it
|
|
1296
1282
|
// ORDERED — law naming law, legitimate). The kernel does NOT read this field to detect the birth.
|
|
1297
1283
|
rec.set("genesisChain", genesisChain);
|
|
@@ -1642,7 +1628,7 @@ export const revokeAdmin = directive("revokeAdmin")
|
|
|
1642
1628
|
*/
|
|
1643
1629
|
// grantCreation — creation authority IS the self-relative `#creator` tuple the CreationGate reads.
|
|
1644
1630
|
// Writes `workspace:self#creator@key:<keyHash>` (no CreationGrant aggregate). Under posture invite/closed
|
|
1645
|
-
// the gate admits only holders of an active #creator subject; under open
|
|
1631
|
+
// the gate admits only holders of an active #creator subject; under explicit open it admits anyone.
|
|
1646
1632
|
// #creator is ONE relation over ONE principal graph; a subject is `key:<hash>` (proof by holding a secret —
|
|
1647
1633
|
// a Bearer) OR `user:<uid>` (proof of identity — an auth-provider token). The relation allows BOTH
|
|
1648
1634
|
// (allow:[user(),key()]); these are not two authorities, just two ways a principal authenticates. So
|
|
@@ -1755,7 +1741,7 @@ export { RelationTuple };
|
|
|
1755
1741
|
// Static governance requirements use the full-native relation gate: a directive carrying
|
|
1756
1742
|
// `.requires("<relation>")` is checked by the ONE wasm gate over PRE-APPLY tuples on every door (author /
|
|
1757
1743
|
// edge admission / verify_chain replay). Workspace creation is the intentional exception because it is a
|
|
1758
|
-
// three-posture policy, not one static role: the invariant below admits a proven author under open
|
|
1744
|
+
// three-posture policy, not one static role: the invariant below admits a proven author under explicit open,
|
|
1759
1745
|
// checks `#creator` under invite, and checks `#admin` under closed. The captured author principal is pinned
|
|
1760
1746
|
// to the sealed Attribution.actor on every peer — so "who may grant or create" is LAW, never a host pre-check. The
|
|
1761
1747
|
// pre-apply roster means `grantAdmin(@key:self)` cannot self-grant (the not-yet-written subject is absent
|
|
@@ -1858,7 +1844,7 @@ export const reclaimRequiresRetired = workspaceInvariant("ReclaimRequiresRetired
|
|
|
1858
1844
|
|
|
1859
1845
|
// ── THE WORKSPACE-QUOTA GATE (S2 — THE QUOTA LAW, ENFORCED) ────────────────────────────────────────────
|
|
1860
1846
|
// The native `.requires("creator")` replacement accidentally collapsed a THREE-POSTURE law into one
|
|
1861
|
-
// permanently invite-only door. Creation is not a static role check: open
|
|
1847
|
+
// permanently invite-only door. Creation is not a static role check: open admits any PROVEN author;
|
|
1862
1848
|
// invite admits #creator; closed admits #admin. Keep that policy in an invariant over the committed prefix,
|
|
1863
1849
|
// while the native relation evaluator remains the one meaning of "holds #creator/#admin" everywhere else.
|
|
1864
1850
|
//
|
|
@@ -1894,8 +1880,9 @@ function creationPostureVerdict(
|
|
|
1894
1880
|
if (actor === "" || claimed === "" || requestedBy === "" || claimed !== proven || requestedBy !== proven) {
|
|
1895
1881
|
return { reject: "creation.identity-mismatch" };
|
|
1896
1882
|
}
|
|
1897
|
-
const posture = String((snapshots.policy as { creationPosture?: string } | undefined)?.creationPosture ?? "
|
|
1898
|
-
if (posture === "
|
|
1883
|
+
const posture = String((snapshots.policy as { creationPosture?: string } | undefined)?.creationPosture ?? "");
|
|
1884
|
+
if (posture === "") return { reject: "creation.policy-not-configured" };
|
|
1885
|
+
if (posture === "open") return { accept: true };
|
|
1899
1886
|
if (posture === "invite") {
|
|
1900
1887
|
return activeRelationSubject(snapshots.creators, actor)
|
|
1901
1888
|
? { accept: true }
|
|
@@ -1915,7 +1902,7 @@ const creationPostureReads = readSet(
|
|
|
1915
1902
|
readRef("admins", RelationTuple).at(ADMIN_TUPLE_ID),
|
|
1916
1903
|
);
|
|
1917
1904
|
|
|
1918
|
-
/** Compatibility create: open
|
|
1905
|
+
/** Compatibility create: open ⇒ proven author; invite ⇒ creator; closed ⇒ admin; unset ⇒ refuse. */
|
|
1919
1906
|
export const creationPostureCreate = workspaceInvariant("CreationPostureCreate")
|
|
1920
1907
|
.on("createWorkspace")
|
|
1921
1908
|
.reads(creationPostureReads)
|
package/src/index.ts
CHANGED
|
@@ -16,6 +16,13 @@ export {
|
|
|
16
16
|
type NomosPackageDefinition,
|
|
17
17
|
type NomosPackageDomainConfig,
|
|
18
18
|
} from "./package_config.js";
|
|
19
|
+
export {
|
|
20
|
+
applicationHomeGenesis,
|
|
21
|
+
offerAtHomeGenesis,
|
|
22
|
+
type ApplicationHomeGenesis,
|
|
23
|
+
type ApplicationHomeGenesisFacts,
|
|
24
|
+
type ApplicationHomeGenesisStep,
|
|
25
|
+
} from "./application_home_genesis.js";
|
|
19
26
|
export type { RuntimePackageDependency } from "./package_dependencies.js";
|
|
20
27
|
export {
|
|
21
28
|
aggregate,
|
|
@@ -538,7 +545,6 @@ export {
|
|
|
538
545
|
childLifecyclesByStatus,
|
|
539
546
|
birthPolicy,
|
|
540
547
|
birthGrantByPrincipal,
|
|
541
|
-
DEFAULT_MAX_BIRTHS_PER_PRINCIPAL,
|
|
542
548
|
birthQuotaVerdict,
|
|
543
549
|
birthQuotaInvariantId,
|
|
544
550
|
setBirthPolicy,
|
package/src/law_graph.ts
CHANGED
|
@@ -545,6 +545,13 @@ export interface LawIntentNode {
|
|
|
545
545
|
readonly births: boolean;
|
|
546
546
|
readonly birthRecord?: LawRef<"aggregate">;
|
|
547
547
|
readonly birthPrefix?: string;
|
|
548
|
+
/** The law-declared genesis verb that establishes this workspace's birth policy. This is a
|
|
549
|
+
* relationship to executable law, never a compiler/runtime allowance value: the kernel uses it
|
|
550
|
+
* only to require an explicit matching step in child genesis before custody can be created. */
|
|
551
|
+
readonly birthPolicySeed?: LawRef<"intent">;
|
|
552
|
+
/** Additional law verbs which this birth requires the child genesis to offer. Cross-domain
|
|
553
|
+
* targets remain typed closure references and are resolved to USDA paths during composition. */
|
|
554
|
+
readonly birthGenesisRequires: readonly LawTargetRef<"intent">[];
|
|
548
555
|
readonly attestation?: {
|
|
549
556
|
readonly ownerObject: string;
|
|
550
557
|
readonly ownerField: string;
|
|
@@ -1362,6 +1369,22 @@ export function discoverLawGraph(
|
|
|
1362
1369
|
birthRecord: ref(aggregateByLabel.get("NomosBirthRecord")!.node.entity),
|
|
1363
1370
|
birthPrefix: "nomos-birth-record:",
|
|
1364
1371
|
}),
|
|
1372
|
+
...(intent.birthsChild !== true || intentEntities.get("seedBirthPolicy") === undefined ? {} : {
|
|
1373
|
+
birthPolicySeed: ref(intentEntities.get("seedBirthPolicy")!),
|
|
1374
|
+
}),
|
|
1375
|
+
birthGenesisRequires: (intent.birthGenesisRequirements ?? []).map((requirement) => {
|
|
1376
|
+
const local = requirement.domain === module.name
|
|
1377
|
+
? intentEntities.get(requirement.directiveId)
|
|
1378
|
+
: undefined;
|
|
1379
|
+
return local === undefined
|
|
1380
|
+
? {
|
|
1381
|
+
kind: "dependency-export" as const,
|
|
1382
|
+
entityKind: "intent" as const,
|
|
1383
|
+
label: requirement.directiveId,
|
|
1384
|
+
domain: requirement.domain,
|
|
1385
|
+
}
|
|
1386
|
+
: ref(local);
|
|
1387
|
+
}),
|
|
1365
1388
|
...(intent.attestationAuthorizedGate === undefined ? {} : {
|
|
1366
1389
|
attestation: {
|
|
1367
1390
|
ownerObject: intent.attestationAuthorizedGate.ownerObject,
|
package/src/law_graph_usda.ts
CHANGED
|
@@ -971,6 +971,16 @@ function emitIntent(
|
|
|
971
971
|
`${pad}custom uniform string nomos:birthPrefix = ${quote(intent.birthPrefix ?? "")}`,
|
|
972
972
|
);
|
|
973
973
|
}
|
|
974
|
+
if (intent.birthPolicySeed !== undefined) {
|
|
975
|
+
body.push(
|
|
976
|
+
`${pad}custom rel nomos:birthPolicySeed = <${requiredPath(intent.birthPolicySeed.id, paths)}>`,
|
|
977
|
+
);
|
|
978
|
+
}
|
|
979
|
+
if (intent.birthGenesisRequires.length > 0) {
|
|
980
|
+
body.push(
|
|
981
|
+
`${pad}custom rel nomos:birthGenesisRequires = ${targets(intent.birthGenesisRequires, paths, resolveDependency)}`,
|
|
982
|
+
);
|
|
983
|
+
}
|
|
974
984
|
if (intent.attestation !== undefined) {
|
|
975
985
|
body.push(
|
|
976
986
|
`${pad}custom uniform string nomos:attestationOwnerObject = ${quote(intent.attestation.ownerObject)}`,
|
|
@@ -1756,7 +1766,7 @@ function emitContainer<T extends { readonly entity: { readonly id: string } }>(
|
|
|
1756
1766
|
}
|
|
1757
1767
|
|
|
1758
1768
|
function targets(
|
|
1759
|
-
refs: readonly LawTargetRef<"aggregate" | "contract" | "relation" | "policy" | "read">[],
|
|
1769
|
+
refs: readonly LawTargetRef<"aggregate" | "contract" | "relation" | "policy" | "read" | "intent">[],
|
|
1760
1770
|
paths: ReadonlyMap<string, string>,
|
|
1761
1771
|
resolveDependency: ResolveDependency,
|
|
1762
1772
|
): string {
|
package/src/package_config.ts
CHANGED
|
@@ -4,6 +4,10 @@ import {
|
|
|
4
4
|
normalizeRuntimePackageDependencies,
|
|
5
5
|
type RuntimePackageDependency,
|
|
6
6
|
} from "./package_dependencies.js";
|
|
7
|
+
import {
|
|
8
|
+
isApplicationHomeGenesis,
|
|
9
|
+
type ApplicationHomeGenesis,
|
|
10
|
+
} from "./application_home_genesis.js";
|
|
7
11
|
|
|
8
12
|
/** The source modules which compose one domain exported by a Nomos package. */
|
|
9
13
|
export interface NomosPackageDomainConfig {
|
|
@@ -21,6 +25,14 @@ export interface NomosPackageDomainConfig {
|
|
|
21
25
|
export interface NomosPackageConfig {
|
|
22
26
|
readonly name: string;
|
|
23
27
|
readonly domains: readonly NomosPackageDomainConfig[];
|
|
28
|
+
/** Application-root policy compiled into the private receiving-group law.
|
|
29
|
+
* Required for a published application: Nomos never invents a child-workspace allowance. */
|
|
30
|
+
readonly application?: {
|
|
31
|
+
readonly maxChildWorkspacesPerUser: number;
|
|
32
|
+
/** Tenant law which must hold from the application's first usable home state. Every entry is
|
|
33
|
+
* an ordinary offer executed through the child's gate; omission declares no tenant ceremony. */
|
|
34
|
+
readonly homeGenesis?: ApplicationHomeGenesis;
|
|
35
|
+
};
|
|
24
36
|
/** Separately installed law required at runtime; USDA composition arcs do not belong here. */
|
|
25
37
|
readonly dependencies?: readonly RuntimePackageDependency[];
|
|
26
38
|
}
|
|
@@ -95,6 +107,24 @@ export function validateNomosPackageConfig(value: unknown): {
|
|
|
95
107
|
if (config.dependencies !== undefined && !Array.isArray(config.dependencies)) {
|
|
96
108
|
throw new Error("package dependencies must be an array");
|
|
97
109
|
}
|
|
110
|
+
if (config.application !== undefined) {
|
|
111
|
+
const max = config.application.maxChildWorkspacesPerUser;
|
|
112
|
+
if (!Number.isInteger(max) || max < 0) {
|
|
113
|
+
throw new Error(
|
|
114
|
+
"application.maxChildWorkspacesPerUser must be a non-negative integer; " +
|
|
115
|
+
"Nomos has no compiled birth-policy fallback",
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
if (
|
|
119
|
+
config.application.homeGenesis !== undefined &&
|
|
120
|
+
!isApplicationHomeGenesis(config.application.homeGenesis)
|
|
121
|
+
) {
|
|
122
|
+
throw new Error(
|
|
123
|
+
"application.homeGenesis must be declared with applicationHomeGenesis(...); " +
|
|
124
|
+
"Nomos will not reinterpret an untyped genesis recipe",
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
98
128
|
const runtimeDependencies = normalizeRuntimePackageDependencies(
|
|
99
129
|
config.name,
|
|
100
130
|
config.dependencies ?? [],
|