@githolon/dsl 0.5.0 → 0.5.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 +79 -12
- package/src/compile_package_main.ts +14 -1
- package/src/wire_encode.ts +6 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@githolon/dsl",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.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
|
@@ -188,6 +188,77 @@ export interface TsProofOptions {
|
|
|
188
188
|
readonly domainHash: string;
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
+
/** The machine-readable OFFLINE legs for ONE domain (the `@nomos-proof-legs`
|
|
192
|
+
* marker shape; the `proof-legs.json` index is a map of these by domain key). */
|
|
193
|
+
export interface ProofLegs {
|
|
194
|
+
readonly domain: string;
|
|
195
|
+
readonly directiveId: string;
|
|
196
|
+
readonly aggregateId: string;
|
|
197
|
+
readonly payload: Record<string, unknown>;
|
|
198
|
+
readonly autoStamped: readonly string[];
|
|
199
|
+
readonly mintField?: string;
|
|
200
|
+
readonly query?: { readonly id: string; readonly params: Record<string, unknown> };
|
|
201
|
+
readonly count?: { readonly id: string; readonly group: string };
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** Synthesize the offline legs for one domain module, or `null` when it has no
|
|
205
|
+
* creating write (nothing to prove). The SINGLE source of the leg-selection
|
|
206
|
+
* logic — `generateTsProof` (the .mts marker) and `proofLegsIndex` (the
|
|
207
|
+
* per-domain index) both call this, so the offline lane proves any domain the
|
|
208
|
+
* same way the generated proof proves its primary one. */
|
|
209
|
+
export function proofLegsForModule(mod: DomainModule): ProofLegs | null {
|
|
210
|
+
const createDir = (mod.directives as Directive<unknown>[]).find(
|
|
211
|
+
(d) => d?.marker === "creates" && typeof d.payloadSchema === "object",
|
|
212
|
+
);
|
|
213
|
+
if (createDir === undefined) return null;
|
|
214
|
+
const domain = mod.domain ?? mod.name;
|
|
215
|
+
const agg = (mod.aggregates as AggregateHandle[]).find((a) => a.id === createDir.aggregateId);
|
|
216
|
+
if (agg === undefined) return null;
|
|
217
|
+
const synth = synthesizePayload(createDir.payloadSchema as z.ZodTypeAny, `${domain}/${createDir.id}`);
|
|
218
|
+
const mintField = mintedCreateField(createDir, agg);
|
|
219
|
+
const baseValue: Record<string, unknown> = { ...synth.value };
|
|
220
|
+
if (mintField !== undefined) delete baseValue[mintField];
|
|
221
|
+
const query = ((mod.queries ?? []) as QueryDecl[]).find(
|
|
222
|
+
(q) => q.returns === agg.id && q.key.length > 0 && q.key.every((k) => !k.includes(".") && baseValue[k] !== undefined),
|
|
223
|
+
);
|
|
224
|
+
const count = (mod.counts ?? [])
|
|
225
|
+
.map((raw) => finishCount(raw))
|
|
226
|
+
.find((c) => c.of === agg.id && (c as { where?: unknown }).where == null && (c.by == null || baseValue[c.by] !== undefined));
|
|
227
|
+
return {
|
|
228
|
+
domain,
|
|
229
|
+
directiveId: createDir.id,
|
|
230
|
+
aggregateId: agg.id,
|
|
231
|
+
payload: baseValue,
|
|
232
|
+
autoStamped: synth.autoStamped,
|
|
233
|
+
...(mintField !== undefined ? { mintField } : {}),
|
|
234
|
+
...(query ? { query: { id: query.id, params: Object.fromEntries(query.key.map((k) => [k, baseValue[k]])) } } : {}),
|
|
235
|
+
...(count ? { count: { id: count.id, group: count.by != null ? String(baseValue[count.by]) : "" } } : {}),
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/** The per-domain legs index for `build/<name>.proof-legs.json` — every domain
|
|
240
|
+
* with a creating write, plus the default (the first, which the .mts proves).
|
|
241
|
+
* `githolon proof [--domain <key>]` runs any of these offline. */
|
|
242
|
+
export function proofLegsIndex(modules: readonly DomainModule[]): { default: string; domains: Record<string, ProofLegs> } | null {
|
|
243
|
+
const domains: Record<string, ProofLegs> = {};
|
|
244
|
+
let first: string | undefined;
|
|
245
|
+
for (const mod of modules) {
|
|
246
|
+
// FAIL SOFT per-module: a sibling domain whose payload can't be synthesized
|
|
247
|
+
// (an exotic zod shape synthesizePayload throws on) must not lose the index
|
|
248
|
+
// for the domains that DO synthesize — skip it, keep the rest.
|
|
249
|
+
let legs: ProofLegs | null;
|
|
250
|
+
try {
|
|
251
|
+
legs = proofLegsForModule(mod);
|
|
252
|
+
} catch {
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
if (legs === null) continue;
|
|
256
|
+
domains[legs.domain] = legs;
|
|
257
|
+
if (first === undefined) first = legs.domain;
|
|
258
|
+
}
|
|
259
|
+
return first === undefined ? null : { default: first, domains };
|
|
260
|
+
}
|
|
261
|
+
|
|
191
262
|
export function generateTsProof(modules: readonly DomainModule[], opts: TsProofOptions): string {
|
|
192
263
|
// The proof drives the FIRST domain that has a creating write — without one
|
|
193
264
|
// there is nothing to author, so there is nothing to prove.
|
|
@@ -203,7 +274,11 @@ export function generateTsProof(modules: readonly DomainModule[], opts: TsProofO
|
|
|
203
274
|
const factory = tsClientFactoryName(domain);
|
|
204
275
|
const hashConst = tsHashConstName(opts.packageName);
|
|
205
276
|
|
|
206
|
-
|
|
277
|
+
// SAME predicate as the mod selection above AND proofLegsForModule — so the
|
|
278
|
+
// proof body, its marker, and the index can never describe different directives.
|
|
279
|
+
const createDir = (mod.directives as Directive<unknown>[]).find(
|
|
280
|
+
(d) => d?.marker === "creates" && typeof d.payloadSchema === "object",
|
|
281
|
+
)!;
|
|
207
282
|
const agg = (mod.aggregates as AggregateHandle[]).find((a) => a.id === createDir.aggregateId);
|
|
208
283
|
if (agg === undefined) {
|
|
209
284
|
throw new Error(
|
|
@@ -260,17 +335,9 @@ export function generateTsProof(modules: readonly DomainModule[], opts: TsProofO
|
|
|
260
335
|
const listAccessor = `list${agg.id}s`;
|
|
261
336
|
|
|
262
337
|
// THE MACHINE-READABLE LEGS (parsed by `githolon`'s offline proof runner —
|
|
263
|
-
// cli/src/proof_offline.ts
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
directiveId: createDir.id,
|
|
267
|
-
aggregateId: agg.id,
|
|
268
|
-
payload: baseValue,
|
|
269
|
-
autoStamped: synth.autoStamped,
|
|
270
|
-
...(mintField !== undefined ? { mintField } : {}),
|
|
271
|
-
...(query && queryParamsObj ? { query: { id: query.id, params: queryParamsObj } } : {}),
|
|
272
|
-
...(count ? { count: { id: count.id, group: count.by != null ? String(baseValue[count.by]) : "" } } : {}),
|
|
273
|
-
});
|
|
338
|
+
// cli/src/proof_offline.ts). The ONE leg-synthesis (`proofLegsForModule`) feeds
|
|
339
|
+
// both this marker and the per-domain `proof-legs.json` index, so they never drift.
|
|
340
|
+
const legsMarker = JSON.stringify(proofLegsForModule(mod));
|
|
274
341
|
|
|
275
342
|
let step = 0;
|
|
276
343
|
const n = () => ++step;
|
|
@@ -104,7 +104,7 @@ import {
|
|
|
104
104
|
} from "./stable_ids.js";
|
|
105
105
|
import type { UsdLayer } from "./usd.js";
|
|
106
106
|
import { generateTsClient, tsClientFactoryName } from "./codegen_ts.js";
|
|
107
|
-
import { generateTsProof } from "./codegen_proof.js";
|
|
107
|
+
import { generateTsProof, proofLegsIndex } from "./codegen_proof.js";
|
|
108
108
|
|
|
109
109
|
const DSL_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
110
110
|
|
|
@@ -1287,10 +1287,20 @@ async function main(): Promise<void> {
|
|
|
1287
1287
|
// synthesizer can't sample yet still compiles — the skip names its remedy.
|
|
1288
1288
|
let proofPath: string | undefined;
|
|
1289
1289
|
let proofSkip: string | undefined;
|
|
1290
|
+
let proofDomains: string[] = [];
|
|
1290
1291
|
try {
|
|
1291
1292
|
const proofSrc = generateTsProof(domainModules, { packageName: cfg.name, domainHash });
|
|
1292
1293
|
proofPath = path.join(outDir, `${cfg.name}.proof.mts`);
|
|
1293
1294
|
writeFileSync(proofPath, proofSrc, "utf8");
|
|
1295
|
+
// THE PER-DOMAIN LEGS INDEX: every domain with a creating write, so
|
|
1296
|
+
// `githolon proof --domain <key>` proves ANY of them offline (the .mts
|
|
1297
|
+
// proves the primary one live). A multi-domain package no longer locks the
|
|
1298
|
+
// proof to whichever domain happens to be first.
|
|
1299
|
+
const legsIndex = proofLegsIndex(domainModules);
|
|
1300
|
+
if (legsIndex !== null) {
|
|
1301
|
+
writeFileSync(path.join(outDir, `${cfg.name}.proof-legs.json`), JSON.stringify(legsIndex, null, 2) + "\n", "utf8");
|
|
1302
|
+
proofDomains = Object.keys(legsIndex.domains);
|
|
1303
|
+
}
|
|
1294
1304
|
} catch (e) {
|
|
1295
1305
|
proofSkip = (e as Error).message;
|
|
1296
1306
|
}
|
|
@@ -1385,6 +1395,9 @@ async function main(): Promise<void> {
|
|
|
1385
1395
|
console.log(`prove it OFFLINE first: npx githolon proof # the generated proof's offline legs on a LOCAL holon (no cloud workspace)`);
|
|
1386
1396
|
console.log(` inner loop: npx githolon dev # watch -> recompile -> law live locally -> offline proof, on every save`);
|
|
1387
1397
|
console.log(` then the cloud loop: npx githolon proof --live # throwaway workspace, retired on exit (--keep keeps it)`);
|
|
1398
|
+
if (proofDomains.length > 1) {
|
|
1399
|
+
console.log(` this package proves ${proofDomains.length} domains (${proofDomains.join(", ")}) — default '${proofDomains[0]}'; pick another: npx githolon proof --domain <key>`);
|
|
1400
|
+
}
|
|
1388
1401
|
} else {
|
|
1389
1402
|
console.log(`prove it: npm run e2e # offline write -> sync -> admission -> cloud query, live`);
|
|
1390
1403
|
}
|
package/src/wire_encode.ts
CHANGED
|
@@ -139,9 +139,12 @@ function encodeKernelFieldOp(op: FieldOp, field: Field | undefined): WireFieldOp
|
|
|
139
139
|
* to test domain LIFECYCLE.
|
|
140
140
|
*
|
|
141
141
|
* For a KERNEL-BACKED local harness — admission through the real gate, folds,
|
|
142
|
-
* reads, the whole lifecycle on the same engine plane the cloud
|
|
143
|
-
*
|
|
144
|
-
*
|
|
142
|
+
* reads, minted ids, the whole lifecycle on the same engine plane the cloud
|
|
143
|
+
* edge runs — use the CLI, NOT this function:
|
|
144
|
+
* • `githolon dev --once` — ONE compile → law-live-locally → proof cycle, then
|
|
145
|
+
* exit (the CI/smoke lane for lifecycle + id-mint tests — a non-zero exit
|
|
146
|
+
* names the jam). `githolon dev` (no flag) is the same on a watch loop.
|
|
147
|
+
* • `githolon proof` — the generated proof's offline legs on a local holon.
|
|
145
148
|
* Those mint ids, run the gate, and fold — exactly what this function does NOT.
|
|
146
149
|
*/
|
|
147
150
|
export function executeDirectiveToIntent<P>(
|