@githolon/dsl 0.16.3 → 0.18.0
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 +5 -0
- package/dart/lib/nomos_client.dart +5 -0
- package/dart/lib/src/errors.dart +79 -0
- package/dart/lib/src/home.dart +20 -0
- package/dart/lib/src/webview_bridge.dart +68 -0
- package/dart/lib/src/wire.dart +117 -0
- package/dart/pubspec.lock +1 -1
- package/dart/pubspec.yaml +2 -1
- package/dart/test/home_parity_test.dart +9 -0
- package/dart/test/wire_test.dart +48 -0
- package/package.json +1 -1
- package/src/births.ts +82 -0
- package/src/build_package.ts +23 -27
- package/src/codegen_dart.ts +10 -0
- package/src/codegen_ts.ts +12 -8
- package/src/compile_package_main.ts +61 -109
- package/src/decl_shapes.ts +122 -0
- package/src/directive.ts +30 -0
- package/src/engine_entry.ts +109 -8
- package/src/framework/home.ts +179 -0
- package/src/framework/impure_capability.ts +8 -4
- package/src/framework/relations.ts +22 -0
- package/src/framework/signing_identity.ts +291 -2
- package/src/framework/workspace_invariant.ts +17 -2
- package/src/framework/workspaces.ts +392 -153
- package/src/index.ts +42 -0
- package/src/usd.ts +44 -0
- package/src/usd_layers.ts +41 -0
- package/src/wire.ts +13 -0
- package/src/wire_encode.ts +14 -2
package/src/codegen_ts.ts
CHANGED
|
@@ -534,7 +534,7 @@ export function generateTsClient(modules: readonly DomainModule[], opts: TsClien
|
|
|
534
534
|
// the obligation the birth provider materializes. parentWs = "root" for a top-level platform,
|
|
535
535
|
// else the parent holon's own name. timestamps ride IN the payload (the determinism doctrine);
|
|
536
536
|
// a platform's foundingAdminHash = sha256(your chosen platformAdminKey) — the host never mints it.
|
|
537
|
-
const emit = (name: string, doc: string, params: string[], lane: { kind: "boot" } | { kind: "offer"; parentWs: string; directiveId: "createWorkspace" | "
|
|
537
|
+
const emit = (name: string, doc: string, params: string[], lane: { kind: "boot" } | { kind: "offer"; parentWs: string; directiveId: "createWorkspace" | "birthChild" }) => {
|
|
538
538
|
if (emittedBirths.has(name)) return;
|
|
539
539
|
emittedBirths.add(name);
|
|
540
540
|
const sig = `opts: NomosBirthAuth & { cloud: string; ${params.join("; ")} }`;
|
|
@@ -547,14 +547,18 @@ export function generateTsClient(modules: readonly DomainModule[], opts: TsClien
|
|
|
547
547
|
);
|
|
548
548
|
return;
|
|
549
549
|
}
|
|
550
|
-
|
|
550
|
+
// A platform birth is birthChild WITH genesis (the tier collapsed onto #creator; birthPlatform is
|
|
551
|
+
// gone). The genesis stamps ride IN the payload (the determinism doctrine): foundingAdminHash =
|
|
552
|
+
// sha256(your chosen platformAdminKey), bornAt = the ISO birth time. The host replays the
|
|
553
|
+
// law-authored chain — it mints no genesis.
|
|
554
|
+
const isPlatformOffer = lane.directiveId === "birthChild";
|
|
551
555
|
const bodyFields = [
|
|
552
556
|
`name: opts.name`,
|
|
553
557
|
`parent: ${lane.parentWs}`,
|
|
554
558
|
`principal: opts.principal ?? ""`,
|
|
555
559
|
`requestedBy: opts.principal ?? ""`,
|
|
556
560
|
`requestedAt: Date.now()`,
|
|
557
|
-
...(isPlatformOffer ? [`foundingAdminHash: await nomosKeyHash(opts.platformAdminKey)`] : []),
|
|
561
|
+
...(isPlatformOffer ? [`foundingAdminHash: await nomosKeyHash(opts.platformAdminKey)`, `bornAt: new Date().toISOString()`] : []),
|
|
558
562
|
];
|
|
559
563
|
out.push(
|
|
560
564
|
`/** ${doc} */`,
|
|
@@ -570,13 +574,13 @@ export function generateTsClient(modules: readonly DomainModule[], opts: TsClien
|
|
|
570
574
|
const isPlatform = t.childIds.length > 0;
|
|
571
575
|
if (!childIds.has(t.id)) {
|
|
572
576
|
// A TOP-LEVEL type: a workspace births on the boot lane; a platform-kind
|
|
573
|
-
// coordinator births via the root holon's
|
|
577
|
+
// coordinator births via the root holon's birthChild offer (with genesis).
|
|
574
578
|
emit(
|
|
575
579
|
fnName(t.id),
|
|
576
|
-
`Birth a '${t.id}' workspace${isPlatform ? " (a platform-kind coordinator: hosts its own subtree; PRESENT your chosen platformAdminKey) via root's
|
|
580
|
+
`Birth a '${t.id}' workspace${isPlatform ? " (a platform-kind coordinator: hosts its own subtree; PRESENT your chosen platformAdminKey) via root's birthChild offer" : " on the boot lane (the one-time secret comes back)"} — derived from the taxonomy. Placement is automatic (measured shape) — no tier to pick.`,
|
|
577
581
|
isPlatform ? [`name: string`, `platformAdminKey: string`] : [`name: string`],
|
|
578
582
|
isPlatform
|
|
579
|
-
? { kind: "offer", parentWs: `"root"`, directiveId: "
|
|
583
|
+
? { kind: "offer", parentWs: `"root"`, directiveId: "birthChild" }
|
|
580
584
|
: { kind: "boot" },
|
|
581
585
|
);
|
|
582
586
|
}
|
|
@@ -587,11 +591,11 @@ export function generateTsClient(modules: readonly DomainModule[], opts: TsClien
|
|
|
587
591
|
const childIsPlatform = child.childIds.length > 0;
|
|
588
592
|
emit(
|
|
589
593
|
fnName(child.id),
|
|
590
|
-
`Birth a '${child.id}' under a '${t.id}' — the taxonomy's hasMany edge, a governance offer on the parent holon (POST /v2/workspaces/<${parentParam}>/${childIsPlatform ? "
|
|
594
|
+
`Birth a '${child.id}' under a '${t.id}' — the taxonomy's hasMany edge, a governance offer on the parent holon (POST /v2/workspaces/<${parentParam}>/${childIsPlatform ? "birthChild" : "createWorkspace"}; lineage + pool enforced by the parent's law).${childIsPlatform ? " PRESENT your chosen platformAdminKey." : ""} Placement is automatic (measured shape).`,
|
|
591
595
|
childIsPlatform
|
|
592
596
|
? [`${parentParam}: string`, `name: string`, `platformAdminKey: string`]
|
|
593
597
|
: [`${parentParam}: string`, `name: string`],
|
|
594
|
-
{ kind: "offer", parentWs: `opts.${parentParam}`, directiveId: childIsPlatform ? "
|
|
598
|
+
{ kind: "offer", parentWs: `opts.${parentParam}`, directiveId: childIsPlatform ? "birthChild" : "createWorkspace" },
|
|
595
599
|
);
|
|
596
600
|
}
|
|
597
601
|
}
|
|
@@ -61,30 +61,37 @@ import {
|
|
|
61
61
|
type PermissionVocabulary,
|
|
62
62
|
} from "./codegen_dart.js";
|
|
63
63
|
import { generateDartBridgeClient } from "./codegen_dart_client.js";
|
|
64
|
-
import type
|
|
64
|
+
import { finishCount, type AnyCount } from "./count.js";
|
|
65
65
|
import type { QueryDecl } from "./query.js";
|
|
66
66
|
import type { SpatialDecl } from "./spatial.js";
|
|
67
|
-
import type
|
|
67
|
+
import { finishSum, type AnySum } from "./sum.js";
|
|
68
68
|
import type { DerivedDecl } from "./derived.js";
|
|
69
69
|
import type { CombinedDecl } from "./combined.js";
|
|
70
70
|
import type { ImpureCapabilityDecl } from "./codegen_provider_dart.js";
|
|
71
71
|
import {
|
|
72
72
|
aggregatesOf,
|
|
73
73
|
buildIdentity,
|
|
74
|
-
buildReadManifest,
|
|
75
74
|
composeDomainModule,
|
|
76
75
|
directivesOf,
|
|
77
76
|
emitUsdJsonForModules,
|
|
78
77
|
packageUsda,
|
|
79
78
|
sha256HexUtf8,
|
|
80
|
-
writeIdentity,
|
|
81
79
|
type Mod,
|
|
82
80
|
} from "./build_package.js";
|
|
83
81
|
import { collectEngineRouting } from "./engine_entry.js";
|
|
82
|
+
import {
|
|
83
|
+
discover,
|
|
84
|
+
isCountDecl,
|
|
85
|
+
isQueryDecl,
|
|
86
|
+
isSpatialDecl,
|
|
87
|
+
isSumDecl,
|
|
88
|
+
isWorkspaceInvariantDecl,
|
|
89
|
+
type DeclBag,
|
|
90
|
+
} from "./decl_shapes.js";
|
|
84
91
|
import { resolveWorkspaceTypes, type WorkspaceTypeDecl } from "./workspace_type.js";
|
|
85
92
|
import { canonicalTaxonomyFragment, validateWorkspaceTaxonomyAndRoutes } from "./workspace_routing.js";
|
|
86
93
|
import { shardingLawModule, type ShardingLawSpec } from "./workspace_sharding.js";
|
|
87
|
-
import type
|
|
94
|
+
import { finishExtremum, type AnyExtremum } from "./extremum.js";
|
|
88
95
|
import type { WorkspaceInvariantDecl } from "./framework/workspace_invariant.js";
|
|
89
96
|
import { type RelationTypeDecl, isRelationTypeDecl, validateRelationType } from "./relation_schema.js";
|
|
90
97
|
import {
|
|
@@ -97,7 +104,6 @@ import { domainManifest } from "./manifest.js";
|
|
|
97
104
|
import type { WireSchema } from "./wire.js";
|
|
98
105
|
import {
|
|
99
106
|
deriveStableIdContinuity,
|
|
100
|
-
stableIdsFromManifestJson,
|
|
101
107
|
type InferredRename,
|
|
102
108
|
type StableIds,
|
|
103
109
|
} from "./stable_ids.js";
|
|
@@ -192,37 +198,9 @@ function fail(msg: string): never {
|
|
|
192
198
|
}
|
|
193
199
|
|
|
194
200
|
// ── decl auto-discovery (by SHAPE, mirroring the engine entry's duck-types) ───────
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
!!v &&
|
|
199
|
-
typeof v === "object" &&
|
|
200
|
-
typeof (v as { id?: unknown }).id === "string" &&
|
|
201
|
-
Array.isArray((v as { key?: unknown }).key) &&
|
|
202
|
-
((v as { key: unknown[] }).key as unknown[]).every((k) => typeof k === "string") &&
|
|
203
|
-
typeof (v as { returns?: unknown }).returns === "string" &&
|
|
204
|
-
typeof (v as { fn?: unknown }).fn !== "function"
|
|
205
|
-
);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
function isWorkspaceInvariantDecl(v: unknown): v is WorkspaceInvariantDecl {
|
|
209
|
-
return (
|
|
210
|
-
!!v &&
|
|
211
|
-
typeof v === "object" &&
|
|
212
|
-
(v as { __isWorkspaceInvariant?: unknown }).__isWorkspaceInvariant === true
|
|
213
|
-
);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
function isSpatialDecl(v: unknown): v is SpatialDecl {
|
|
217
|
-
return (
|
|
218
|
-
!!v &&
|
|
219
|
-
typeof v === "object" &&
|
|
220
|
-
typeof (v as { id?: unknown }).id === "string" &&
|
|
221
|
-
typeof (v as { of?: unknown }).of === "string" &&
|
|
222
|
-
typeof (v as { on?: unknown }).on === "string" &&
|
|
223
|
-
typeof (v as { fn?: unknown }).fn !== "function"
|
|
224
|
-
);
|
|
225
|
-
}
|
|
201
|
+
// The query/workspace-invariant/spatial/sum/count predicates + `discover` live in the SHARED
|
|
202
|
+
// bundle-safe `decl_shapes.ts` (imported above) — the lump's self-describe verb discovers by the
|
|
203
|
+
// EXACT same shape so the kernel-served OpenAPI matches the compiled `<name>.openapi.json`.
|
|
226
204
|
|
|
227
205
|
function isDerivedDecl(v: unknown): v is DerivedDecl {
|
|
228
206
|
return (
|
|
@@ -250,35 +228,6 @@ function isCombinedDecl(v: unknown): v is CombinedDecl {
|
|
|
250
228
|
);
|
|
251
229
|
}
|
|
252
230
|
|
|
253
|
-
/** A sum decl/builder — the `{id, of, sumField}` mark (counts/extremums never carry `sumField`). */
|
|
254
|
-
function isSumDecl(v: unknown): v is AnySum {
|
|
255
|
-
if (!v || typeof v !== "object") return false;
|
|
256
|
-
const o = v as Record<string, unknown>;
|
|
257
|
-
return typeof o.id === "string" && typeof o.of === "string" && typeof o.sumField === "string";
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
/** A count decl/builder — `{id, of}` with NONE of the other decl families' marks. */
|
|
261
|
-
function isCountDecl(v: unknown): v is AnyCount {
|
|
262
|
-
if (!v || typeof v !== "object") return false;
|
|
263
|
-
const o = v as Record<string, unknown>;
|
|
264
|
-
return (
|
|
265
|
-
typeof o.id === "string" &&
|
|
266
|
-
typeof o.of === "string" &&
|
|
267
|
-
typeof o.on !== "string" && // spatial
|
|
268
|
-
typeof o.fn !== "function" && // derived/combined
|
|
269
|
-
!Array.isArray(o.key) && // query
|
|
270
|
-
!("field" in o) && // extremum (wire-descriptor shape)
|
|
271
|
-
!("valueField" in o) && // extremum (the ExtremumDecl/Extremum-builder mark — never a count)
|
|
272
|
-
!("sumField" in o) && // sum (the SumDecl/Sum-builder mark — never a count)
|
|
273
|
-
!("orderBy" in o) && // ordered read
|
|
274
|
-
!("_existsMarker" in o) && // exists
|
|
275
|
-
typeof o.refField !== "string" && // combined
|
|
276
|
-
o.__isAggregateHandle !== true && // aggregate
|
|
277
|
-
typeof o.aggregateId !== "string" && // directive
|
|
278
|
-
typeof o.plan !== "function"
|
|
279
|
-
);
|
|
280
|
-
}
|
|
281
|
-
|
|
282
231
|
/**
|
|
283
232
|
* Scan merged exports for `workspaceType(...)` decls (sharding §10 slice 1) by the
|
|
284
233
|
* `__isWorkspaceType` brand — individual exports AND exported arrays. Dedupe is BY
|
|
@@ -301,24 +250,6 @@ function discoverWorkspaceTypes(merged: Mod): WorkspaceTypeDecl[] {
|
|
|
301
250
|
return out;
|
|
302
251
|
}
|
|
303
252
|
|
|
304
|
-
/** Scan merged exports for decls matching `match`: individual exports AND exported arrays. */
|
|
305
|
-
function discover<T>(merged: Mod, match: (v: unknown) => v is T): T[] {
|
|
306
|
-
const seen = new Set<string>();
|
|
307
|
-
const out: T[] = [];
|
|
308
|
-
const push = (v: T) => {
|
|
309
|
-
const key = JSON.stringify(v, (_k, val) => (typeof val === "function" ? "<fn>" : val));
|
|
310
|
-
if (!seen.has(key)) {
|
|
311
|
-
seen.add(key);
|
|
312
|
-
out.push(v);
|
|
313
|
-
}
|
|
314
|
-
};
|
|
315
|
-
for (const v of Object.values(merged)) {
|
|
316
|
-
if (match(v)) push(v);
|
|
317
|
-
else if (Array.isArray(v)) for (const el of v) if (match(el)) push(el);
|
|
318
|
-
}
|
|
319
|
-
return out;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
253
|
/** Validate the LITERAL dart-codegen import hints (config data, not module exports). */
|
|
323
254
|
function checkDartImports(domainKey: string, imports: readonly DartImport[] | undefined): void {
|
|
324
255
|
for (const imp of imports ?? []) {
|
|
@@ -532,6 +463,12 @@ async function main(): Promise<void> {
|
|
|
532
463
|
const entryMintInstalls: string[] = []; // route-tagged in-plan mints (taxonomy packages only)
|
|
533
464
|
const routingInput: Record<string, Mod[]> = {};
|
|
534
465
|
const domainModules: DomainModule[] = [];
|
|
466
|
+
// THE SELF-DESCRIBE DECLS (G1): per domain key, the FINISHED plain read/maintenance decls the
|
|
467
|
+
// lump's `globalThis.describe` needs that it cannot rediscover by shape alone (mins/maxes are
|
|
468
|
+
// config-named; sharding sums are framework-appended). Plain JSON (finishCount/Sum/Extremum
|
|
469
|
+
// pass finished decls through), serialized into the generated entry as `openapiDecls`, so the
|
|
470
|
+
// kernel-run describe reproduces THIS compile's `<name>.openapi.json` byte-for-byte.
|
|
471
|
+
const openapiDeclsByDomain: Record<string, unknown> = {};
|
|
535
472
|
const layered = layeredFlag || cfg.layered === true;
|
|
536
473
|
const layeredDomains: { key: string; inputs: LayeredModuleInput[] }[] = [];
|
|
537
474
|
let importSeq = 0;
|
|
@@ -831,6 +768,24 @@ async function main(): Promise<void> {
|
|
|
831
768
|
// no-path / ambiguous / cross-home / unroutable law is a NAMED COMPILE
|
|
832
769
|
// ERROR here — never a domain silently recorded as identity-excluded.
|
|
833
770
|
const composed = domainModules[domainModules.length - 1]!;
|
|
771
|
+
|
|
772
|
+
// ── THE SELF-DESCRIBE DECLS (G1): the FINISHED plain read/maintenance decls the lump's
|
|
773
|
+
// `describe` reconstructs the openapi fragment from. Directives + aggregates are read from
|
|
774
|
+
// the live module exports IN the lump; these ride alongside (mins/maxes are config-named +
|
|
775
|
+
// sharding sums are framework-appended — not shape-rediscoverable). Omit-when-empty so a
|
|
776
|
+
// decl-free domain contributes nothing (and offers still derive from its directives).
|
|
777
|
+
{
|
|
778
|
+
const declsForDomain: Record<string, unknown[]> = {};
|
|
779
|
+
if (queries.length > 0) declsForDomain.queries = queries.map((q) => ({ id: q.id, key: [...q.key], returns: q.returns }));
|
|
780
|
+
if (counts.length > 0) declsForDomain.counts = counts.map((c) => finishCount(c));
|
|
781
|
+
if (sums.length > 0) declsForDomain.sums = sums.map((s) => finishSum(s));
|
|
782
|
+
if (mins.length > 0) declsForDomain.mins = mins.map((e) => finishExtremum(e));
|
|
783
|
+
if (maxes.length > 0) declsForDomain.maxes = maxes.map((e) => finishExtremum(e));
|
|
784
|
+
if (spatials.length > 0) declsForDomain.spatials = spatials.map((s) => ({ id: s.id, of: s.of, on: s.on }));
|
|
785
|
+
if (workspaceInvariants.length > 0) declsForDomain.workspaceInvariants = workspaceInvariants.map((w) => ({ id: w.id, on: w.on }));
|
|
786
|
+
if (Object.keys(declsForDomain).length > 0) openapiDeclsByDomain[d.key] = declsForDomain;
|
|
787
|
+
}
|
|
788
|
+
|
|
834
789
|
if (composed.workspaceTypes !== undefined && composed.workspaceTypes.length > 0) {
|
|
835
790
|
try {
|
|
836
791
|
validateWorkspaceTaxonomyAndRoutes(composed);
|
|
@@ -948,10 +903,6 @@ async function main(): Promise<void> {
|
|
|
948
903
|
const priorLock: StableIdLock | undefined = existsSync(lockPath)
|
|
949
904
|
? (JSON.parse(readFileSync(lockPath, "utf8")) as StableIdLock)
|
|
950
905
|
: undefined;
|
|
951
|
-
const priorBuildManifestsPath = path.join(outDir, "domain_identity_manifests.json");
|
|
952
|
-
const priorBuildManifests: Record<string, string> | undefined = existsSync(priorBuildManifestsPath)
|
|
953
|
-
? (JSON.parse(readFileSync(priorBuildManifestsPath, "utf8")) as Record<string, string>)
|
|
954
|
-
: undefined;
|
|
955
906
|
const inferredRenames: { domain: string; renames: InferredRename[] }[] = [];
|
|
956
907
|
const nextLock: StableIdLock = { v: 1, domains: {} };
|
|
957
908
|
for (const mod of domainModules) {
|
|
@@ -977,23 +928,14 @@ async function main(): Promise<void> {
|
|
|
977
928
|
// it carries no stable ids either.
|
|
978
929
|
continue;
|
|
979
930
|
}
|
|
980
|
-
// Continuity source: the lockfile
|
|
931
|
+
// Continuity source: the committed nomos.stable-ids.json lockfile (the canonical identity ledger).
|
|
932
|
+
// (The old "else the prior build's domain_identity_manifests.json" fallback is gone with that sidecar.)
|
|
981
933
|
let prior: StableIds | undefined;
|
|
982
934
|
let priorSchemas: Record<string, WireSchema> | undefined;
|
|
983
935
|
const locked = priorLock?.domains[identityName];
|
|
984
936
|
if (locked !== undefined) {
|
|
985
937
|
prior = locked.stableIds;
|
|
986
938
|
priorSchemas = locked.schemas;
|
|
987
|
-
} else if (priorBuildManifests?.[identityName] !== undefined) {
|
|
988
|
-
prior = stableIdsFromManifestJson(priorBuildManifests[identityName]!);
|
|
989
|
-
try {
|
|
990
|
-
const parsed = JSON.parse(priorBuildManifests[identityName]!) as {
|
|
991
|
-
aggregates?: { id: string; schema: WireSchema }[];
|
|
992
|
-
};
|
|
993
|
-
priorSchemas = Object.fromEntries((parsed.aggregates ?? []).map((a) => [a.id, a.schema]));
|
|
994
|
-
} catch {
|
|
995
|
-
priorSchemas = undefined;
|
|
996
|
-
}
|
|
997
939
|
}
|
|
998
940
|
const { continuity, inferred } = deriveStableIdContinuity(
|
|
999
941
|
identityName,
|
|
@@ -1132,6 +1074,14 @@ async function main(): Promise<void> {
|
|
|
1132
1074
|
...(entryReports.length > 0 ? [` reports: {`, ...entryReports, ` },`] : []),
|
|
1133
1075
|
...(eagerLump ? [] : [` routing: ${JSON.stringify(routing)},`]),
|
|
1134
1076
|
...(zodSeedNames.length > 0 ? [` seeds: [${zodSeedNames.join(", ")}],`] : []),
|
|
1077
|
+
// THE SELF-DESCRIBE INPUTS (G1): the finished read/maintenance decls + the package title, baked
|
|
1078
|
+
// into the lump so `globalThis.describe` reproduces this compile's `<name>.openapi.json` over the
|
|
1079
|
+
// FOLDED LAW — the kernel serves the spec, the host stages nothing. Omit-when-empty (decl-free
|
|
1080
|
+
// packages: offers still derive from directives; the title default is the workspace-level title).
|
|
1081
|
+
...(Object.keys(openapiDeclsByDomain).length > 0
|
|
1082
|
+
? [` openapiDecls: ${JSON.stringify(openapiDeclsByDomain)},`]
|
|
1083
|
+
: []),
|
|
1084
|
+
` packageTitle: ${JSON.stringify(`${cfg.name} (nomos package)`)},`,
|
|
1135
1085
|
`});`,
|
|
1136
1086
|
// ROUTE-TAGGED IN-PLAN MINTS (sharding §4, slice 3): wraps globalThis.plan +
|
|
1137
1087
|
// globalThis.nomos.mint at top-level eval — pre-freeze, after registerEngine's
|
|
@@ -1321,15 +1271,13 @@ async function main(): Promise<void> {
|
|
|
1321
1271
|
layeredFileCount = relPaths.length;
|
|
1322
1272
|
}
|
|
1323
1273
|
|
|
1324
|
-
// ── 3. the
|
|
1325
|
-
//
|
|
1326
|
-
//
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1274
|
+
// ── 3. the IDENTITY emit (for the summary's per-domain identityHash) ──
|
|
1275
|
+
// The admission identity is carried INSIDE the package USD IR (emitUsd) + the committed
|
|
1276
|
+
// nomos.stable-ids.json lockfile; the deploy/cloud/runtime contract uses neither a read-manifest nor an
|
|
1277
|
+
// identity-manifest sidecar. The old domain_manifests.json / domain_identity_*.json build files were
|
|
1278
|
+
// local diagnostics the contract ignored — REMOVED (they only confused /build consumers). We still
|
|
1279
|
+
// compute the identity to surface its per-domain hash in the summary below.
|
|
1331
1280
|
const identity = buildIdentity(domainModules);
|
|
1332
|
-
const { manifestsPath } = writeIdentity(identity, outDir);
|
|
1333
1281
|
|
|
1334
1282
|
// ── 3b. the OpenAPI spec — THE PACKAGE'S SELF-DESCRIPTION (the host's runtime routing table;
|
|
1335
1283
|
// architecture/githolon_host_contract.md "The Self-Describing API"). Each domain emits its fragment
|
|
@@ -1463,8 +1411,12 @@ async function main(): Promise<void> {
|
|
|
1463
1411
|
` layered ${rel(layeredRootPath)} (${layeredFileCount} module layer(s) in build/layers/ — flatten-verified byte-identical to the canonical IR)`,
|
|
1464
1412
|
);
|
|
1465
1413
|
}
|
|
1466
|
-
|
|
1467
|
-
|
|
1414
|
+
{
|
|
1415
|
+
const sum = (pick: (m: (typeof domainModules)[number]) => readonly unknown[] | undefined) =>
|
|
1416
|
+
domainModules.reduce((n, m) => n + (pick(m)?.length ?? 0), 0);
|
|
1417
|
+
console.log(` reads ${sum((m) => m.queries)} quer(y/ies), ${sum((m) => m.counts)} count(s), ${sum((m) => m.sums)} sum(s) — declared (routed via the openapi)`);
|
|
1418
|
+
}
|
|
1419
|
+
console.log(` identity ${Object.keys(identity.manifests).length} domain(s) (carried in the package IR + nomos.stable-ids.json; no sidecar files)${identity.excluded.length ? ` — ${identity.excluded.length} EXCLUDED (palette gap)` : ""}`);
|
|
1468
1420
|
for (const [dom, h] of Object.entries(identity.hashes)) console.log(` ${dom.padEnd(20)} ${h}`);
|
|
1469
1421
|
for (const ex of identity.excluded) console.log(` EXCLUDED ${ex.domain}: ${ex.reason}`);
|
|
1470
1422
|
// STABLE IDS (#58): the minted/carried identity surface + every INFERRED rename —
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// NOMOS — Nomos Sovereign: participants act · verify · remember LOCALLY; hosted remotes are
|
|
2
|
+
// replaceable custody/transport, not truth. ⇒ ONE Nomos GitHolon wasm32-wasip1 artifact.
|
|
3
|
+
// If a file isn't this / hosting this / authoring for this / proving this — it's gone.
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* decl_shapes.ts — THE DUCK-TYPE PREDICATES for the read/maintenance decl families, hoisted
|
|
7
|
+
* into ONE bundle-safe module so the COMPILER (`compile_package_main.ts`) and the LUMP's own
|
|
8
|
+
* self-describe verb (`engine_entry.ts` `describe`) discover decls by the EXACT same shape.
|
|
9
|
+
*
|
|
10
|
+
* Why shared: the kernel-served OpenAPI (G1 — openapi residue removal) is produced by the lump
|
|
11
|
+
* running `generateOpenApiFragment` over the SAME modules it dispatches; if the lump discovered
|
|
12
|
+
* queries/counts/sums/spatials by a DIFFERENT shape than the compiler did when it wrote
|
|
13
|
+
* `<name>.openapi.json`, the kernel-served spec would drift from the compiled one. One predicate
|
|
14
|
+
* set ⇒ one shape ⇒ byte-identity.
|
|
15
|
+
*
|
|
16
|
+
* ENGINE-BUNDLE-SAFE: imports NO node builtin (only DSL types) — it bundles under esbuild
|
|
17
|
+
* `--platform=neutral` into the sealed QuickJS lump.
|
|
18
|
+
*/
|
|
19
|
+
import type { QueryDecl } from "./query.js";
|
|
20
|
+
import type { SpatialDecl } from "./spatial.js";
|
|
21
|
+
import type { AnySum } from "./sum.js";
|
|
22
|
+
import type { AnyCount } from "./count.js";
|
|
23
|
+
import type { WorkspaceInvariantDecl } from "./framework/workspace_invariant.js";
|
|
24
|
+
|
|
25
|
+
/** A merged domain-module exports bag (scanned by shape). */
|
|
26
|
+
export type DeclBag = Record<string, unknown>;
|
|
27
|
+
|
|
28
|
+
/** A declared query — `{id, key:string[], returns}` with no projection `fn` (that marks derived/combined). */
|
|
29
|
+
export function isQueryDecl(v: unknown): v is QueryDecl {
|
|
30
|
+
return (
|
|
31
|
+
!!v &&
|
|
32
|
+
typeof v === "object" &&
|
|
33
|
+
typeof (v as { id?: unknown }).id === "string" &&
|
|
34
|
+
Array.isArray((v as { key?: unknown }).key) &&
|
|
35
|
+
((v as { key: unknown[] }).key as unknown[]).every((k) => typeof k === "string") &&
|
|
36
|
+
typeof (v as { returns?: unknown }).returns === "string" &&
|
|
37
|
+
typeof (v as { fn?: unknown }).fn !== "function"
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** A workspace invariant — branded `__isWorkspaceInvariant`. */
|
|
42
|
+
export function isWorkspaceInvariantDecl(v: unknown): v is WorkspaceInvariantDecl {
|
|
43
|
+
return (
|
|
44
|
+
!!v &&
|
|
45
|
+
typeof v === "object" &&
|
|
46
|
+
(v as { __isWorkspaceInvariant?: unknown }).__isWorkspaceInvariant === true
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** A spatial index — `{id, of, on}` with no projection `fn`. */
|
|
51
|
+
export function isSpatialDecl(v: unknown): v is SpatialDecl {
|
|
52
|
+
return (
|
|
53
|
+
!!v &&
|
|
54
|
+
typeof v === "object" &&
|
|
55
|
+
typeof (v as { id?: unknown }).id === "string" &&
|
|
56
|
+
typeof (v as { of?: unknown }).of === "string" &&
|
|
57
|
+
typeof (v as { on?: unknown }).on === "string" &&
|
|
58
|
+
typeof (v as { fn?: unknown }).fn !== "function"
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** A sum decl/builder — the `{id, of, sumField}` mark (counts/extremums never carry `sumField`). */
|
|
63
|
+
export function isSumDecl(v: unknown): v is AnySum {
|
|
64
|
+
if (!v || typeof v !== "object") return false;
|
|
65
|
+
const o = v as Record<string, unknown>;
|
|
66
|
+
return typeof o.id === "string" && typeof o.of === "string" && typeof o.sumField === "string";
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** A count decl/builder — `{id, of}` with NONE of the other decl families' marks. */
|
|
70
|
+
export function isCountDecl(v: unknown): v is AnyCount {
|
|
71
|
+
if (!v || typeof v !== "object") return false;
|
|
72
|
+
const o = v as Record<string, unknown>;
|
|
73
|
+
return (
|
|
74
|
+
typeof o.id === "string" &&
|
|
75
|
+
typeof o.of === "string" &&
|
|
76
|
+
typeof o.on !== "string" && // spatial
|
|
77
|
+
typeof o.fn !== "function" && // derived/combined
|
|
78
|
+
!Array.isArray(o.key) && // query
|
|
79
|
+
!("field" in o) && // extremum (wire-descriptor shape)
|
|
80
|
+
!("valueField" in o) && // extremum (the ExtremumDecl/Extremum-builder mark — never a count)
|
|
81
|
+
!("sumField" in o) && // sum (the SumDecl/Sum-builder mark — never a count)
|
|
82
|
+
!("orderBy" in o) && // ordered read
|
|
83
|
+
!("_existsMarker" in o) && // exists
|
|
84
|
+
typeof o.refField !== "string" && // combined
|
|
85
|
+
o.__isAggregateHandle !== true && // aggregate
|
|
86
|
+
typeof o.aggregateId !== "string" && // directive
|
|
87
|
+
typeof o.plan !== "function"
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/** An extremum decl/builder — `{id, of, valueField}` with `{kind:"min"|"max"}` (the #47 read). */
|
|
92
|
+
export function isExtremumDecl(v: unknown): boolean {
|
|
93
|
+
if (!v || typeof v !== "object") return false;
|
|
94
|
+
const o = v as Record<string, unknown>;
|
|
95
|
+
return (
|
|
96
|
+
typeof o.id === "string" &&
|
|
97
|
+
typeof o.of === "string" &&
|
|
98
|
+
typeof o.valueField === "string" &&
|
|
99
|
+
(o.kind === "min" || o.kind === "max")
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Scan merged exports for decls matching `match`: individual exports AND exported arrays, deduped
|
|
105
|
+
* by a function-blind JSON key (the SAME dedup `compile_package_main.ts` `discover` uses).
|
|
106
|
+
*/
|
|
107
|
+
export function discover<T>(merged: DeclBag, match: (v: unknown) => v is T): T[] {
|
|
108
|
+
const seen = new Set<string>();
|
|
109
|
+
const out: T[] = [];
|
|
110
|
+
const push = (v: T) => {
|
|
111
|
+
const key = JSON.stringify(v, (_k, val) => (typeof val === "function" ? "<fn>" : val));
|
|
112
|
+
if (!seen.has(key)) {
|
|
113
|
+
seen.add(key);
|
|
114
|
+
out.push(v);
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
for (const v of Object.values(merged)) {
|
|
118
|
+
if (match(v)) push(v);
|
|
119
|
+
else if (Array.isArray(v)) for (const el of v) if (match(el)) push(el);
|
|
120
|
+
}
|
|
121
|
+
return out;
|
|
122
|
+
}
|
package/src/directive.ts
CHANGED
|
@@ -141,6 +141,20 @@ export interface Directive<P = unknown> {
|
|
|
141
141
|
* relation-free directive's canonical manifest is byte-identical to before this existed.
|
|
142
142
|
*/
|
|
143
143
|
readonly declaredRelations: RelationDecl[];
|
|
144
|
+
/**
|
|
145
|
+
* BIRTH IS AN EXPLICIT, DECLARED KERNEL PRIMITIVE (G3 — the unix model). When `true`, this directive
|
|
146
|
+
* BIRTHS a child workspace as the defined CONSEQUENCE of its offer: its `plan` produces the child's
|
|
147
|
+
* genesis recipe (`birth(recipe)`) onto the intent's birth effect, and the kernel — reading THIS
|
|
148
|
+
* declaration off the law manifest (the `nomosBirthGate` era key, the SAME way it reads `.reads`/
|
|
149
|
+
* `.creates`/invariants — NOT domain state) — spawns the child's custody and self-validates its whole
|
|
150
|
+
* genesis through the child's OWN gate after this offer admits. The kernel NEVER scans a tenant/governance
|
|
151
|
+
* aggregate to detect a birth (a circular dependency, forbidden): the birth is declared, like a syscall.
|
|
152
|
+
* Lowered into the `nomosBirthGate` USD era key (emitted iff a package declares ≥1 birth directive), so
|
|
153
|
+
* pre-feature chains carry no key and replay byte-green (the era rule). `false` ⇒ a non-birthing directive.
|
|
154
|
+
* (FIELD `birthsChild` vs the chainable method `.births()` — the `requiresRelationGate`/`.requires()` and
|
|
155
|
+
* `attestationAuthorizedGate`/`.attestationAuthorized()` naming convention; the declaration is the noun.)
|
|
156
|
+
*/
|
|
157
|
+
readonly birthsChild?: boolean;
|
|
144
158
|
/**
|
|
145
159
|
* The directive's DECLARED required HOST CAPABILITIES — the capability PORTS the HOST must
|
|
146
160
|
* PROVIDE for this directive to run (`OFFER_KERNEL_ARCHITECTURE.dot` cluster_ports / `OFFER_FLOW.dot`
|
|
@@ -243,6 +257,16 @@ export interface RequirableDirective<P> extends Directive<P> {
|
|
|
243
257
|
* Returns a NEW requirable directive.
|
|
244
258
|
*/
|
|
245
259
|
requiresHostCapability(...portIds: string[]): RequirableDirective<P>;
|
|
260
|
+
/**
|
|
261
|
+
* Declare this directive a BIRTH primitive (G3 — the unix model): birthing a child workspace is the
|
|
262
|
+
* defined CONSEQUENCE of its offer. The `plan` must record the child's genesis recipe (`birth(recipe)`,
|
|
263
|
+
* reusing `buildGenesisChain`) onto the intent's birth effect; the kernel reads THIS declaration off the
|
|
264
|
+
* law manifest (the `nomosBirthGate` era key — NOT domain state) and, after the offer admits, spawns the
|
|
265
|
+
* child's custody + self-validates its genesis through the child's OWN gate. Purely additive +
|
|
266
|
+
* non-destructive — a directive that never calls this is NOT a birth primitive and is byte-identical in
|
|
267
|
+
* the canonical manifest to before this existed (the era rule). Returns a NEW requirable directive.
|
|
268
|
+
*/
|
|
269
|
+
births(): RequirableDirective<P>;
|
|
246
270
|
}
|
|
247
271
|
|
|
248
272
|
/** Stage 1: id + a referential marker (which fixes the target aggregate). */
|
|
@@ -409,6 +433,12 @@ function makeRequirable<P>(base: Directive<P>): RequirableDirective<P> {
|
|
|
409
433
|
const merged = [...new Set([...base.declaredHostCapabilities, ...portIds])].sort();
|
|
410
434
|
return makeRequirable({ ...base, declaredHostCapabilities: merged });
|
|
411
435
|
},
|
|
436
|
+
births(): RequirableDirective<P> {
|
|
437
|
+
// BIRTH AS A DECLARED KERNEL PRIMITIVE (G3): mark this directive a birth — its plan's `birth(recipe)`
|
|
438
|
+
// rides the intent, and the kernel (reading the `nomosBirthGate` era key, not domain state) executes
|
|
439
|
+
// the birth after admit. Era-ruled: a non-birthing directive omits the flag and is byte-identical.
|
|
440
|
+
return makeRequirable({ ...base, birthsChild: true });
|
|
441
|
+
},
|
|
412
442
|
};
|
|
413
443
|
}
|
|
414
444
|
|