@githolon/dsl 0.2.2 → 0.3.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/package.json +4 -1
- package/src/build_package.ts +124 -3
- package/src/codegen_dart.ts +15 -0
- package/src/codegen_ts.ts +235 -7
- package/src/compile_package_main.ts +342 -6
- package/src/engine_entry.ts +124 -4
- package/src/framework/workspace_invariant.ts +7 -0
- package/src/index.ts +6 -0
- package/src/manifest.ts +56 -7
- package/src/usd.ts +37 -0
- package/src/workspace_routing.ts +585 -0
- package/src/workspace_sharding.ts +1179 -0
- package/src/workspace_type.ts +609 -0
package/src/manifest.ts
CHANGED
|
@@ -43,6 +43,11 @@ import type { DerivedDecl } from "./derived.js";
|
|
|
43
43
|
import type { CombinedDecl } from "./combined.js";
|
|
44
44
|
import type { CertifiedReadDecl } from "./certified_read.js";
|
|
45
45
|
import type { RelationDecl } from "./relation.js";
|
|
46
|
+
import { type CanonicalWorkspaceType } from "./workspace_type.js";
|
|
47
|
+
import {
|
|
48
|
+
canonicalTaxonomyFragment,
|
|
49
|
+
type CanonicalDirectiveRoute,
|
|
50
|
+
} from "./workspace_routing.js";
|
|
46
51
|
|
|
47
52
|
/** One captured `[fieldName, zodKind]` payload field, with optionality. */
|
|
48
53
|
export interface CanonicalPayloadField {
|
|
@@ -221,6 +226,13 @@ export interface CanonicalCount {
|
|
|
221
226
|
readonly where?: CanonicalPred;
|
|
222
227
|
/** The group-by field, in DECLARED form. OMITTED for a grand-total count. */
|
|
223
228
|
readonly by?: string;
|
|
229
|
+
/**
|
|
230
|
+
* THE ESTATE SCOPE (sharding §5, slice 3): the workspace-type id this read is
|
|
231
|
+
* lifted to via `scoped(read, Ws)` — its per-shard values ride the §5.2 delta
|
|
232
|
+
* lane as gate-recomputed coordinator subtotals. OMITTED for home-scope reads
|
|
233
|
+
* (every pre-slice-3 count is byte-identical — the `cap(n)` discipline).
|
|
234
|
+
*/
|
|
235
|
+
readonly scope?: string;
|
|
224
236
|
}
|
|
225
237
|
|
|
226
238
|
/**
|
|
@@ -263,6 +275,8 @@ export interface CanonicalSum {
|
|
|
263
275
|
readonly where?: CanonicalPred;
|
|
264
276
|
/** The group-by field. OMITTED for a grand-total sum. */
|
|
265
277
|
readonly by?: string;
|
|
278
|
+
/** THE ESTATE SCOPE (sharding §5, slice 3) — see {@link CanonicalCount.scope}. */
|
|
279
|
+
readonly scope?: string;
|
|
266
280
|
}
|
|
267
281
|
|
|
268
282
|
/**
|
|
@@ -428,6 +442,29 @@ export interface CanonicalManifest {
|
|
|
428
442
|
* (non-optional at both TS and manifest levels), optional predicate, and `limit`.
|
|
429
443
|
*/
|
|
430
444
|
readonly orderedReads?: CanonicalOrderedRead[];
|
|
445
|
+
/**
|
|
446
|
+
* The domain's FIRST-CLASS WORKSPACE TYPES (sharding §10 RATIFIED, slice 1), SORTED
|
|
447
|
+
* by id. OMITTED ENTIRELY when the domain declares none — so a taxonomy-free domain
|
|
448
|
+
* is byte-identical to before this key existed (pinned golden hashes UNCHANGED; the
|
|
449
|
+
* `cap(n)` discipline). The taxonomy IS law: a type's root/mode/children/globals/
|
|
450
|
+
* pool/cap all move the domain hash (per-type optional keys omitted-when-absent).
|
|
451
|
+
*/
|
|
452
|
+
readonly workspaceTypes?: CanonicalWorkspaceType[];
|
|
453
|
+
/**
|
|
454
|
+
* The DERIVED HOMING TABLE (aggregate wire id → workspace-type id) — present iff
|
|
455
|
+
* {@link workspaceTypes} is. Derived (never hand-written) by the fail-closed homing
|
|
456
|
+
* walk over the aggregates' `t.ref` chains, and HASH-BEARING: a homing move is a
|
|
457
|
+
* law change (placement of FACTS is custody, but which chain a fact is BORN into
|
|
458
|
+
* is law — the shard gate's `wrong-home` invariant pins to this table).
|
|
459
|
+
*/
|
|
460
|
+
readonly homes?: Record<string, string>;
|
|
461
|
+
/**
|
|
462
|
+
* THE DERIVED DIRECTIVE ROUTING TABLE (sharding slice 2) — present only when the
|
|
463
|
+
* domain declares a taxonomy with at least one packed-homed directive, SORTED by
|
|
464
|
+
* directive id, HASH-BEARING (the client routes by it; the shard gate's typed
|
|
465
|
+
* `wrong-home` refusal pins to it). OMITTED ENTIRELY otherwise (hash-stable).
|
|
466
|
+
*/
|
|
467
|
+
readonly routes?: CanonicalDirectiveRoute[];
|
|
431
468
|
}
|
|
432
469
|
|
|
433
470
|
/** Minimal structural view of Zod 4 schema internals we read deterministically. */
|
|
@@ -690,15 +727,16 @@ function canonicalCounts(
|
|
|
690
727
|
): { counts?: CanonicalCount[] } {
|
|
691
728
|
if (declared === undefined || declared.length === 0) return {};
|
|
692
729
|
const counts: CanonicalCount[] = [...declared]
|
|
693
|
-
.map(finishCount)
|
|
694
|
-
.map((c) => ({
|
|
730
|
+
.map((raw) => ({ finished: finishCount(raw), scope: (raw as { scope?: unknown }).scope }))
|
|
731
|
+
.map(({ finished: c, scope }) => ({
|
|
695
732
|
id: c.id,
|
|
696
733
|
of: c.of,
|
|
697
|
-
// OMIT-WHEN-ABSENT: `where` and `
|
|
698
|
-
// predicate-free
|
|
699
|
-
// (hash-stable — the same discipline as every other optional
|
|
734
|
+
// OMIT-WHEN-ABSENT: `where`, `by` and `scope` are omitted when not declared so
|
|
735
|
+
// a predicate-free / grand-total / home-scope count is byte-identical to the
|
|
736
|
+
// legacy form (hash-stable — the same discipline as every other optional key).
|
|
700
737
|
...(c.where !== undefined ? { where: c.where } : {}),
|
|
701
738
|
...(c.by !== undefined ? { by: c.by } : {}),
|
|
739
|
+
...(typeof scope === "string" ? { scope } : {}),
|
|
702
740
|
}))
|
|
703
741
|
.sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
|
|
704
742
|
return { counts };
|
|
@@ -733,13 +771,14 @@ function canonicalSpatials(
|
|
|
733
771
|
function canonicalSums(declared: AnySum[] | undefined): { sums?: CanonicalSum[] } {
|
|
734
772
|
if (declared === undefined || declared.length === 0) return {};
|
|
735
773
|
const sums: CanonicalSum[] = [...declared]
|
|
736
|
-
.map(finishSum)
|
|
737
|
-
.map((s) => ({
|
|
774
|
+
.map((raw) => ({ finished: finishSum(raw), scope: (raw as { scope?: unknown }).scope }))
|
|
775
|
+
.map(({ finished: s, scope }) => ({
|
|
738
776
|
id: s.id,
|
|
739
777
|
of: s.of,
|
|
740
778
|
sumField: s.sumField,
|
|
741
779
|
...(s.where !== undefined ? { where: s.where } : {}),
|
|
742
780
|
...(s.by !== undefined ? { by: s.by } : {}),
|
|
781
|
+
...(typeof scope === "string" ? { scope } : {}),
|
|
743
782
|
}))
|
|
744
783
|
.sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
|
|
745
784
|
return { sums };
|
|
@@ -901,6 +940,16 @@ export function domainManifest(mod: DomainModule): CanonicalManifest {
|
|
|
901
940
|
...(canonicalExtrema(mod.mins, "mins") as { mins?: CanonicalExtremum[] }),
|
|
902
941
|
...(canonicalExtrema(mod.maxes, "maxes") as { maxes?: CanonicalExtremum[] }),
|
|
903
942
|
...canonicalOrderedReads(mod.orderedReads),
|
|
943
|
+
// Omit-when-empty: a taxonomy-free domain contributes NO taxonomy key (hash-
|
|
944
|
+
// stable). When declared, this RUNS the fail-closed homing walk AND the slice-2
|
|
945
|
+
// route derivation — an unhomeable or unroutable taxonomy never produces an
|
|
946
|
+
// identity (workspace_type.ts + workspace_routing.ts).
|
|
947
|
+
...canonicalTaxonomyFragment({
|
|
948
|
+
name: mod.name,
|
|
949
|
+
aggregates: mod.aggregates,
|
|
950
|
+
directives: mod.directives,
|
|
951
|
+
...(mod.workspaceTypes !== undefined ? { workspaceTypes: mod.workspaceTypes } : {}),
|
|
952
|
+
}),
|
|
904
953
|
};
|
|
905
954
|
}
|
|
906
955
|
|
package/src/usd.ts
CHANGED
|
@@ -170,6 +170,24 @@ export interface UsdLayer {
|
|
|
170
170
|
* same discipline as `queries`/`references`/`reads`/`emits`).
|
|
171
171
|
*/
|
|
172
172
|
readonly variantSets?: Record<string, Record<string, UsdPrim[]>>;
|
|
173
|
+
/**
|
|
174
|
+
* THE INVARIANT-GATE DECLARATION (#41 — "the law is the era"). Present IFF the layer's
|
|
175
|
+
* module declares ≥1 invariant (aggregate or workspace): the law's EXPLICIT opt-in to
|
|
176
|
+
* invariant EXECUTION at the one gate. The wasm gate runs the engine-backed invariant
|
|
177
|
+
* oracles for an intent only when the law resolved for that intent carries this key —
|
|
178
|
+
* every bundle compiled before #41 (whose declared invariants the gate held as hashed-
|
|
179
|
+
* but-inert law) lacks it, so chains sealed under the inert gate replay green forever.
|
|
180
|
+
* OMITTED (`undefined`) for invariant-free law — byte-identical hash, same discipline
|
|
181
|
+
* as `queries`/`references`. Hand-adding it to a foreign bundle only opts IN to
|
|
182
|
+
* stricter checking; removing it makes new law, for that law's own chains (status quo).
|
|
183
|
+
*/
|
|
184
|
+
readonly nomosInvariantGate?: {
|
|
185
|
+
readonly v: 1;
|
|
186
|
+
/** Aggregate types whose declared `invariant` bodies the gate executes, sorted. */
|
|
187
|
+
readonly aggregates?: string[];
|
|
188
|
+
/** Declared workspace invariants `{id, on}` the gate executes, sorted by id. */
|
|
189
|
+
readonly workspaceInvariants?: { id: string; on: string }[];
|
|
190
|
+
};
|
|
173
191
|
}
|
|
174
192
|
|
|
175
193
|
/** The reserved variant name declaring a set's DEFAULT (USD has a default variant). */
|
|
@@ -239,12 +257,31 @@ export function emitUsd(
|
|
|
239
257
|
// which already applies omit-when-empty: `queries` is present here ONLY when the
|
|
240
258
|
// module declared them, so a query-free layer is byte-identical to before.
|
|
241
259
|
const manifest = domainManifest(l.module);
|
|
260
|
+
// THE INVARIANT-GATE DECLARATION (#41): presence-only, derived from the SAME module
|
|
261
|
+
// the lump's executable bodies come from — sorted, omit-when-empty (hash-stable for
|
|
262
|
+
// invariant-free law; see the `UsdLayer.nomosInvariantGate` banner for the era rule).
|
|
263
|
+
const invariantAggregates = l.module.aggregates
|
|
264
|
+
.filter((a) => a.hasInvariant === true)
|
|
265
|
+
.map((a) => a.id)
|
|
266
|
+
.sort();
|
|
267
|
+
const wsInvariants = [...(l.module.workspaceInvariants ?? [])]
|
|
268
|
+
.map((w) => ({ id: w.id, on: w.on }))
|
|
269
|
+
.sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
|
|
242
270
|
return {
|
|
243
271
|
path: l.path,
|
|
244
272
|
prims: encodeModuleToPrims(l.path, l.module),
|
|
245
273
|
...(manifest.queries !== undefined ? { queries: manifest.queries } : {}),
|
|
246
274
|
...(manifest.deriveds !== undefined ? { deriveds: manifest.deriveds } : {}),
|
|
247
275
|
...(manifest.combineds !== undefined ? { combineds: manifest.combineds } : {}),
|
|
276
|
+
...(invariantAggregates.length > 0 || wsInvariants.length > 0
|
|
277
|
+
? {
|
|
278
|
+
nomosInvariantGate: {
|
|
279
|
+
v: 1 as const,
|
|
280
|
+
...(invariantAggregates.length > 0 ? { aggregates: invariantAggregates } : {}),
|
|
281
|
+
...(wsInvariants.length > 0 ? { workspaceInvariants: wsInvariants } : {}),
|
|
282
|
+
},
|
|
283
|
+
}
|
|
284
|
+
: {}),
|
|
248
285
|
};
|
|
249
286
|
})
|
|
250
287
|
.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));
|