@githolon/dsl 0.29.0 → 0.29.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.
- package/package.json +1 -1
- package/src/codegen_proof.ts +116 -27
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@githolon/dsl",
|
|
3
|
-
"version": "0.29.
|
|
3
|
+
"version": "0.29.1",
|
|
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",
|
package/src/codegen_proof.ts
CHANGED
|
@@ -696,13 +696,17 @@ export function resolveGrantableBaseRelations(
|
|
|
696
696
|
export function discoverRelationBootstrapLeg(mod: DomainModule): RelationBootstrapLeg | undefined {
|
|
697
697
|
const domain = mod.domain ?? mod.name;
|
|
698
698
|
const directives = mod.directives as Directive<unknown>[];
|
|
699
|
-
const
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
)
|
|
699
|
+
const isGatedProvable = (d: Directive<unknown> | undefined): boolean =>
|
|
700
|
+
d?.requiresRelationGate !== undefined &&
|
|
701
|
+
typeof d.payloadSchema === "object" &&
|
|
702
|
+
d.birthsChild !== true &&
|
|
703
|
+
d.attestationAuthorizedGate === undefined;
|
|
704
|
+
// PREFER a gated `.creates` as the bootstrap target: a gated create is exactly the shape excluded from the
|
|
705
|
+
// naive standalone-create leg (isStandaloneCreate), so the bootstrap leg is its ONLY positive proof — seed
|
|
706
|
+
// authority, then prove the CREATE is admitted. When no gated create exists, fall back to any gated write
|
|
707
|
+
// (a gated `.mutates`/`.ensures`), so an un-created gated law is still proven.
|
|
708
|
+
const gated = directives.find((d) => isGatedProvable(d) && d.marker === "creates")
|
|
709
|
+
?? directives.find((d) => isGatedProvable(d));
|
|
706
710
|
if (gated === undefined) return undefined;
|
|
707
711
|
const relation = gated.requiresRelationGate!.relation;
|
|
708
712
|
|
|
@@ -1185,13 +1189,17 @@ export interface ProofLegs {
|
|
|
1185
1189
|
* The SINGLE source of the create-leg selection — `generateTsProof` (the .mts marker) and
|
|
1186
1190
|
* `proofLegsIndex` (the per-domain index) both call this, so the offline lane proves any domain the
|
|
1187
1191
|
* same way the generated proof proves its primary one. */
|
|
1188
|
-
/** A `.creates` directive the proof can DRIVE from a synthesized sample offline
|
|
1189
|
-
* is the child-birth lane), not ATTESTATION-AUTHORIZED (needs a signed §3 quote no
|
|
1190
|
-
* e.g. the home law's `recordShare`)
|
|
1191
|
-
*
|
|
1192
|
+
/** A `.creates` directive the proof can DRIVE from a synthesized sample offline WITH NO SEEDED AUTHORITY: not
|
|
1193
|
+
* a `.births()` (a birth is the child-birth lane), not ATTESTATION-AUTHORIZED (needs a signed §3 quote no
|
|
1194
|
+
* synthesizer can produce — e.g. the home law's `recordShare`), and NOT AUTHZ-GATED (`.requires(R)` — a
|
|
1195
|
+
* gated create dispatched with no seeded authority is REFUSED at the gate; its metadata already says it
|
|
1196
|
+
* needs authority, so the naive standalone leg must not touch it — it is proven POSITIVELY by the
|
|
1197
|
+
* relation-bootstrap leg / the born-child genesis instead). Those are NOT standalone-provable offline; the
|
|
1198
|
+
* domain proves via its bootstrap / child-birth / compile-valid legs instead. */
|
|
1192
1199
|
function isStandaloneCreate(d: Directive<unknown> | undefined): boolean {
|
|
1193
1200
|
return d?.marker === "creates" && typeof d.payloadSchema === "object"
|
|
1194
|
-
&& d.birthsChild !== true && d.attestationAuthorizedGate === undefined
|
|
1201
|
+
&& d.birthsChild !== true && d.attestationAuthorizedGate === undefined
|
|
1202
|
+
&& d.requiresRelationGate === undefined;
|
|
1195
1203
|
}
|
|
1196
1204
|
|
|
1197
1205
|
export function proofLegsForModule(mod: DomainModule): ProofLegs | null {
|
|
@@ -1545,19 +1553,94 @@ function generateBirthOnlyProof(
|
|
|
1545
1553
|
return out.join("\n");
|
|
1546
1554
|
}
|
|
1547
1555
|
|
|
1556
|
+
/**
|
|
1557
|
+
* THE BOOTSTRAP-ONLY PROOF (gated-create isolation): a package whose ONLY creating write is AUTHZ-GATED
|
|
1558
|
+
* (`.creates(...).requires(R)` — co2's estate `createSite`). It has no ungated standalone create to dispatch
|
|
1559
|
+
* naively (that would be REFUSED at the gate with no seeded authority) and no `.births()` genesis. So the
|
|
1560
|
+
* proof deploys the law, connects, and drives the RELATION-BOOTSTRAP leg as its primary write: seed authority
|
|
1561
|
+
* (layers 1-3), THEN prove the gated create is ADMITTED — the ordering (seed BEFORE the gated dispatch) is
|
|
1562
|
+
* correct by construction. If authority genuinely can't be seeded, the leg emits the loud diagnostic (never a
|
|
1563
|
+
* false green). The offline runner proves the same leg locally (`githolon proof`); this `.mts` is `--live`.
|
|
1564
|
+
*/
|
|
1565
|
+
function generateBootstrapOnlyProof(
|
|
1566
|
+
mod: DomainModule,
|
|
1567
|
+
opts: TsProofOptions,
|
|
1568
|
+
primaryLegs: ProofLegs,
|
|
1569
|
+
): string {
|
|
1570
|
+
const domain = mod.domain ?? mod.name;
|
|
1571
|
+
const factory = tsClientFactoryName(domain);
|
|
1572
|
+
const hashConst = tsHashConstName(opts.packageName);
|
|
1573
|
+
const rb = primaryLegs.relationBootstrap;
|
|
1574
|
+
if (rb === undefined) {
|
|
1575
|
+
// Only reached defensively — the caller gates on relationBootstrap !== undefined.
|
|
1576
|
+
throw new Error(`domain '${domain}' has a gated create but no relation-bootstrap leg to prove it (no seedable authority)`);
|
|
1577
|
+
}
|
|
1578
|
+
const slug =
|
|
1579
|
+
opts.packageName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 24) || "domain";
|
|
1580
|
+
const legsMarker = JSON.stringify(primaryLegs);
|
|
1581
|
+
let step = 0;
|
|
1582
|
+
const n = () => ++step;
|
|
1583
|
+
const out: string[] = [];
|
|
1584
|
+
out.push(
|
|
1585
|
+
`// AUTO-GENERATED by nomos-compile — the RUNNABLE PROOF for package "${opts.packageName}",`,
|
|
1586
|
+
`// synthesized from the domain's OWN law. This package's ONLY creating write is AUTHZ-GATED`,
|
|
1587
|
+
`// (\`${domain}/${rb.gatedDirectiveId}\` .requires("${rb.relation}")), so the proof SEEDS authority first,`,
|
|
1588
|
+
`// then proves the gated create is admitted — never a naive dispatch the gate would refuse. Reshape the`,
|
|
1589
|
+
`// law, recompile, and this proof reshapes itself — no test rewriting. Run it:`,
|
|
1590
|
+
`//`,
|
|
1591
|
+
`// npx githolon proof (offline legs on a local holon)`,
|
|
1592
|
+
`// npx githolon proof --live (or: npx tsx build/${opts.packageName}.proof.mts — the full cloud loop)`,
|
|
1593
|
+
`//`,
|
|
1594
|
+
`// Regenerated on every compile; do not edit.`,
|
|
1595
|
+
`// @nomos-proof-legs ${legsMarker}`,
|
|
1596
|
+
`import { readFileSync } from "node:fs";`,
|
|
1597
|
+
`import { connect, encodeIntentOfferBytes } from "@githolon/client";`,
|
|
1598
|
+
`import { ${factory}, ${hashConst} } from "./${opts.packageName}.client.ts";`,
|
|
1599
|
+
`void connect; void encodeIntentOfferBytes; void ${factory};`,
|
|
1600
|
+
``,
|
|
1601
|
+
`const CLOUD = (process.env.NOMOS_CLOUD || "https://nomos.captainapp.co.uk").replace(/\\/+$/, "");`,
|
|
1602
|
+
`const WS = process.env.NOMOS_WS || ${JSON.stringify(slug + "-proof-")} + Math.random().toString(36).slice(2, 8);`,
|
|
1603
|
+
``,
|
|
1604
|
+
...v2IdentityAndCleanupPreamble(opts, hashConst, n),
|
|
1605
|
+
``,
|
|
1606
|
+
`// ${n()}. connect + bind the GENERATED typed client (the relation-bootstrap leg drives it with an actor)`,
|
|
1607
|
+
`const holon = await connect({ cloud: CLOUD, workspace: WS, clientId: "proof-1" });`,
|
|
1608
|
+
`ok(\`web client connected — ${factory} bound (replica \${holon.replica.slice(0, 6)}…)\`);`,
|
|
1609
|
+
``,
|
|
1610
|
+
// The SAME relation-bootstrap emitter the standalone proof uses — seed authority, then prove the GATED
|
|
1611
|
+
// CREATE is admitted (layers 1-3; a speculative seed-path degrades to a diagnostic, never a false green).
|
|
1612
|
+
...relationSeedLegLines(rb, factory, n),
|
|
1613
|
+
`console.log(\`\\nALL GREEN — generated proof for "${opts.packageName}": deploy → seed authority → gated create ${rb.gatedDirectiveId} admitted (\${WS})\`);`,
|
|
1614
|
+
``,
|
|
1615
|
+
...v2CatchFinally(),
|
|
1616
|
+
``,
|
|
1617
|
+
);
|
|
1618
|
+
return out.join("\n");
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1548
1621
|
export function generateTsProof(modules: readonly DomainModule[], opts: TsProofOptions): string {
|
|
1549
|
-
// PRIMARY-DOMAIN SELECTION: the live `.mts` drives a STANDALONE create when the package has one
|
|
1550
|
-
// deploy → write → query → sync → cloud loop).
|
|
1551
|
-
//
|
|
1552
|
-
//
|
|
1553
|
-
//
|
|
1622
|
+
// PRIMARY-DOMAIN SELECTION: the live `.mts` drives a STANDALONE (ungated) create when the package has one
|
|
1623
|
+
// (the full deploy → write → query → sync → cloud loop). Else a BIRTH package (`.births()`) drives the
|
|
1624
|
+
// birth. Else a GATED-CREATE package — whose only creating write `.requires(R)` (co2's estate `createSite`)
|
|
1625
|
+
// — drives the RELATION-BOOTSTRAP leg as its primary write: seed authority, THEN the gated create is
|
|
1626
|
+
// admitted (never a naive first dispatch that the gate would refuse). Either way, the marker = the primary
|
|
1627
|
+
// domain's FULL legs (so the offline runner + the index never describe different directives).
|
|
1554
1628
|
const hasStandaloneCreate = (m: DomainModule): boolean =>
|
|
1555
1629
|
(m.directives as Directive<unknown>[]).some((d) => isStandaloneCreate(d));
|
|
1556
1630
|
const hasBirth = (m: DomainModule): boolean => birthDirectiveOf(m) !== undefined;
|
|
1557
|
-
const
|
|
1631
|
+
const isBootstrapProvable = (m: DomainModule): boolean => {
|
|
1632
|
+
try { return discoverRelationBootstrapLeg(m) !== undefined; } catch { return false; }
|
|
1633
|
+
};
|
|
1634
|
+
const mod = modules.find(hasStandaloneCreate) ?? modules.find(hasBirth) ?? modules.find(isBootstrapProvable);
|
|
1558
1635
|
if (mod === undefined) {
|
|
1636
|
+
// No provable creating write anywhere. If a GATED create exists but its authority can't be seeded, surface
|
|
1637
|
+
// the loud bootstrap diagnostic (never a false green); else the generic "add a .creates" remedy.
|
|
1638
|
+
const gapMod = modules.find((m) => diagnoseRelationBootstrapGap(m) !== undefined);
|
|
1639
|
+
const gap = gapMod !== undefined ? diagnoseRelationBootstrapGap(gapMod) : undefined;
|
|
1559
1640
|
throw new Error(
|
|
1560
|
-
|
|
1641
|
+
gap !== undefined
|
|
1642
|
+
? `no proof could be synthesized: ${gap}`
|
|
1643
|
+
: `no .creates directive in any domain — a generated proof needs one creating write (or a .births() birth directive); add a directive(...).creates(...) (test/e2e.mts remains the hand-authored lane)`,
|
|
1561
1644
|
);
|
|
1562
1645
|
}
|
|
1563
1646
|
const domain = mod.domain ?? mod.name;
|
|
@@ -1565,18 +1648,24 @@ export function generateTsProof(modules: readonly DomainModule[], opts: TsProofO
|
|
|
1565
1648
|
const hashConst = tsHashConstName(opts.packageName);
|
|
1566
1649
|
// THE MARKER (since 0.5.0) + the per-domain index are ONE synthesis (`legsForDomain`) — the proof body, its
|
|
1567
1650
|
// marker, and the index can never describe different directives. The primary domain's legs carry whichever
|
|
1568
|
-
// of standalone / child-birth it has.
|
|
1651
|
+
// of standalone / child-birth / relation-bootstrap it has.
|
|
1569
1652
|
const primaryLegs = legsForDomain(mod, modules);
|
|
1570
1653
|
const childBirth = primaryLegs.childBirth;
|
|
1571
1654
|
|
|
1572
|
-
// The standalone-create lane
|
|
1573
|
-
//
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
);
|
|
1655
|
+
// The standalone-create lane needs an UNGATED create (isStandaloneCreate — never a gated/birth/attestation
|
|
1656
|
+
// create, which the gate would refuse dispatched with no seeded authority). Absent one, the primary write
|
|
1657
|
+
// is the birth leg (a `.births()` domain) or the relation-bootstrap leg (a gated-create domain).
|
|
1658
|
+
const createDir = (mod.directives as Directive<unknown>[]).find((d) => isStandaloneCreate(d));
|
|
1577
1659
|
if (createDir === undefined) {
|
|
1578
|
-
// BIRTH-ONLY PRIMARY: emit a birth-shaped proof (
|
|
1579
|
-
|
|
1660
|
+
// BIRTH-ONLY PRIMARY: emit a birth-shaped proof (the birth replays genesis, seating authority, then the
|
|
1661
|
+
// born child self-validates — a gated child-domain create is proven INSIDE the born child context).
|
|
1662
|
+
if (primaryLegs.childBirth !== undefined) return generateBirthOnlyProof(mod, modules, opts, primaryLegs);
|
|
1663
|
+
// BOOTSTRAP-ONLY PRIMARY: the only creating write is GATED — deploy, then seed authority + prove the
|
|
1664
|
+
// gated create is admitted (the relation-bootstrap leg is its ONLY positive proof).
|
|
1665
|
+
if (primaryLegs.relationBootstrap !== undefined) return generateBootstrapOnlyProof(mod, opts, primaryLegs);
|
|
1666
|
+
// A gated create with no seedable authority: loud diagnostic (compile skips the proof, law still ships).
|
|
1667
|
+
const gap = diagnoseRelationBootstrapGap(mod);
|
|
1668
|
+
throw new Error(gap !== undefined ? `no proof could be synthesized for '${domain}': ${gap}` : `domain '${domain}' has no provable creating write`);
|
|
1580
1669
|
}
|
|
1581
1670
|
const agg = (mod.aggregates as AggregateHandle[]).find((a) => a.id === createDir.aggregateId);
|
|
1582
1671
|
if (agg === undefined) {
|