@githolon/dsl 0.102.4 → 0.103.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/compile_package.mjs +43 -2
- package/compile_proof.d.mts +47 -0
- package/compile_proof.mjs +343 -0
- package/dart/CHANGELOG.md +7 -0
- package/dart/lib/src/dev_cloud.dart +8 -8
- package/dart/lib/src/nms_generated_runtime.dart +2 -0
- package/dart/lib/src/runner/node-entry.mjs +5504 -1236
- package/dart/lib/src/runner/offline-install.mjs +4578 -528
- package/dart/lib/src/test_harness.dart +206 -152
- package/dart/lib/src/webview_bridge.dart +196 -89
- package/dart/pubspec.lock +1 -1
- package/dart/pubspec.yaml +2 -2
- package/dart/test/acquire_session_credentials_test.dart +4 -3
- package/dart/test/adv_realm_interference_test.dart +7 -6
- package/dart/test/cloud_bound_topology_test.dart +3 -3
- package/dart/test/cluster_births_test.dart +4 -3
- package/dart/test/cluster_device_keyed_acceptance_test.dart +10 -16
- package/dart/test/cluster_local_autosync_test.dart +3 -2
- package/dart/test/cluster_scale_test.dart +3 -2
- package/dart/test/dlq_session_surface_test.dart +7 -6
- package/dart/test/first_app_gauntlet_test.dart +14 -21
- package/dart/test/fixtures/wedge/fake-install.mjs +1 -1
- package/dart/test/four_layer_nested_topology_test.dart +4 -4
- package/dart/test/harness_phase_timeout_test.dart +2 -2
- package/dart/test/local_sync_inert_test.dart +1 -1
- package/dart/test/parent_signer_recovery_test.dart +2 -2
- package/dart/test/sealing_client_test.dart +4 -3
- package/dart/test/session_bound_test.dart +8 -7
- package/dart/test/test_harness_test.dart +13 -12
- package/dart/test/vo_read_typing_test.dart +4 -3
- package/dart/test/watch_after_offer_stall_test.dart +4 -3
- package/dart/test/webview_bridge_test.dart +102 -5
- package/dart_types/CHANGELOG.md +5 -0
- package/dart_types/lib/nomos_types.dart +9 -0
- package/dart_types/lib/src/nomos_ref.dart +20 -0
- package/dart_types/lib/src/optional_ref.dart +85 -0
- package/dart_types/lib/src/sha256_digest.dart +41 -0
- package/dart_types/lib/src/versioned_nomos_ref.dart +81 -0
- package/dart_types/pubspec.yaml +1 -1
- package/dart_types/test/optional_ref_test.dart +44 -0
- package/dart_types/test/sha256_digest_test.dart +18 -0
- package/package.json +9 -5
- package/runtime/generated-application-host.js +5365 -1105
- package/src/aggregate.ts +18 -0
- package/src/application_composition.ts +6 -32
- package/src/attested_core.ts +6 -3
- package/src/birth_meter.ts +1 -0
- package/src/birth_meter_ensure.ts +28 -2
- package/src/births.ts +1 -1
- package/src/build_package.ts +162 -538
- package/src/business_birth.ts +19 -3
- package/src/canonical_json.ts +21 -0
- package/src/check_package_main.ts +76 -35
- package/src/clear_directive.ts +19 -8
- package/src/codegen_dart.ts +305 -22
- package/src/codegen_dart_application.ts +844 -292
- package/src/codegen_dart_client.ts +1084 -407
- package/src/codegen_dart_scenario.ts +12 -12
- package/src/codegen_proof.ts +169 -39
- package/src/codegen_provider_dart.ts +17 -1
- package/src/codegen_ts.ts +298 -106
- package/src/compat_manifest.ts +2 -2
- package/src/compat_package_main.ts +8 -12
- package/src/compile_package_main.ts +1866 -597
- package/src/compose.ts +1 -1
- package/src/directive.ts +208 -15
- package/src/engine_entry.ts +165 -111
- package/src/evolve_preview.ts +43 -81
- package/src/extremum.ts +1 -1
- package/src/fields.ts +183 -4
- package/src/flow_gate.ts +75 -2
- package/src/framework/application_home.ts +2 -0
- package/src/framework/auth_provider_law.ts +2 -2
- package/src/framework/birth_meter.ts +7 -19
- package/src/framework/bootstrap.ts +0 -2
- package/src/framework/business_corrections.ts +9 -5
- package/src/framework/domain_lifecycle.ts +15 -29
- package/src/framework/encryption_scope.ts +2 -1
- package/src/framework/framework_aggregates.ts +2 -0
- package/src/framework/genesis.ts +16 -14
- package/src/framework/home.ts +20 -14
- package/src/framework/owned_custody.ts +9 -3
- package/src/framework/platform_admin.ts +3 -3
- package/src/framework/relations.ts +21 -13
- package/src/framework/signing_identity.ts +45 -40
- package/src/framework/workspace_invariant.ts +245 -0
- package/src/framework/workspaces.ts +23 -29
- package/src/index.ts +36 -16
- package/src/intent.ts +178 -6
- package/src/law_check.ts +32 -11
- package/src/law_graph.ts +2902 -0
- package/src/law_graph_usda.ts +1799 -0
- package/src/law_identity.ts +435 -0
- package/src/law_value_type.ts +230 -0
- package/src/lsp_server.ts +61 -31
- package/src/ops.ts +7 -0
- package/src/package_config.ts +141 -0
- package/src/package_dependencies.ts +108 -0
- package/src/package_dependency_usage.ts +150 -0
- package/src/package_source_imports.ts +71 -0
- package/src/plan_source_slice.ts +335 -0
- package/src/point_guard.ts +192 -0
- package/src/precondition.ts +44 -9
- package/src/read_projection_namespace.ts +1 -1
- package/src/runtime_zod.ts +44 -0
- package/src/secondary_ensure.ts +67 -14
- package/src/shape_compat.ts +1 -1
- package/src/stable_id_identity_bridge.ts +149 -0
- package/src/stable_id_lockfile.ts +278 -0
- package/src/stable_ids.ts +7 -2
- package/src/stable_ids_for_module.ts +348 -0
- package/src/stable_ids_types.ts +1 -1
- package/src/sum.ts +1 -1
- package/src/usd_state.ts +1 -1
- package/src/usda_relationship_integrity.ts +66 -0
- package/src/usda_text.ts +18 -0
- package/src/usdz.ts +78 -0
- package/src/value_object.ts +95 -0
- package/src/wire.ts +19 -0
- package/src/wire_encode.ts +22 -0
- package/src/workspace_sharding.ts +52 -36
- package/src/workspace_sharing.ts +28 -4
- package/src/zod_introspection.ts +1 -1
- package/dart/test/cluster_attested_test.dart +0 -201
- package/src/compile_engine.ts +0 -595
- package/src/manifest.ts +0 -1476
- package/src/read_projection_composition.ts +0 -117
- package/src/read_projection_manifest.ts +0 -115
- package/src/relation_composition.ts +0 -286
- package/src/usd.ts +0 -1967
- package/src/usd_layers.ts +0 -1776
package/src/engine_entry.ts
CHANGED
|
@@ -63,13 +63,7 @@ import { synthesizeBirthQuotaInvariants } from "./birth_meter.js";
|
|
|
63
63
|
import { withBirthMeterExports } from "./birth_meter_ensure.js";
|
|
64
64
|
import { expandRoleExports } from "./role.js";
|
|
65
65
|
import { withAttestedReadExports } from "./attested.js";
|
|
66
|
-
import {
|
|
67
|
-
import type { QueryDecl } from "./query.js";
|
|
68
|
-
import type { AnyCount } from "./count.js";
|
|
69
|
-
import type { AnySum } from "./sum.js";
|
|
70
|
-
import type { AnyExtremum } from "./extremum.js";
|
|
71
|
-
import type { SpatialDecl } from "./spatial.js";
|
|
72
|
-
import type { DomainModule } from "./codegen_dart.js";
|
|
66
|
+
import type { OpenApiDoc } from "./codegen_openapi.js";
|
|
73
67
|
import type { Directive } from "./directive.js";
|
|
74
68
|
import type { AggregateHandle, AggregateInvariantFn, AggregateInvariantVerdict } from "./aggregate.js";
|
|
75
69
|
import type { Ports } from "./ctx.js";
|
|
@@ -84,6 +78,7 @@ import { expandBusinessBirthExports, isBusinessBirthDirective } from "./business
|
|
|
84
78
|
import { withOwnedCustodyExports } from "./framework/owned_custody.js";
|
|
85
79
|
import { withBusinessCorrectionExports } from "./framework/business_corrections.js";
|
|
86
80
|
import { withClearDirectives } from "./clear_directive.js";
|
|
81
|
+
import { withWorkspaceSharingInvitationExports } from "./workspace_sharing.js";
|
|
87
82
|
import {
|
|
88
83
|
applicationLanguageOf,
|
|
89
84
|
assertApplicationLanguageCoversAuthoredDirectives,
|
|
@@ -123,6 +118,19 @@ export interface EngineRouting {
|
|
|
123
118
|
readonly relationOf?: Record<string, readonly string[]>;
|
|
124
119
|
/** workspace-invariant id → declaring domain keys (#266 — the gate's reads/assert dispatches). */
|
|
125
120
|
readonly workspaceInvariantOf?: Record<string, readonly string[]>;
|
|
121
|
+
/**
|
|
122
|
+
* Dispatch-domain label → canonical USDA domain identity (`d_<sid>`). Tuple object types use this
|
|
123
|
+
* durable namespace so a domain rename cannot rewrite Zanzibar identity.
|
|
124
|
+
*/
|
|
125
|
+
readonly relationNamespaceOf?: Record<string, string>;
|
|
126
|
+
/**
|
|
127
|
+
* Domain key → every non-global aggregate type in the complete compiled domain. A selectively
|
|
128
|
+
* sliced plan may retain a secondary aggregate only inside a closure, so reconstructing this set
|
|
129
|
+
* from the slice's exported declarations can silently lose the type's namespace.
|
|
130
|
+
*/
|
|
131
|
+
readonly namespacedAggregatesOf?: Record<string, readonly string[]>;
|
|
132
|
+
/** Domain key → every local relation shape in the complete compiled domain, for the same reason. */
|
|
133
|
+
readonly qualifiableRelationsOf?: Record<string, readonly string[]>;
|
|
126
134
|
}
|
|
127
135
|
|
|
128
136
|
/** The one declarative input: dispatch key → ORDERED module list (later wins). */
|
|
@@ -133,6 +141,19 @@ export interface EngineEntryConfig {
|
|
|
133
141
|
* Values may be thunks (lazy boot — see the module header).
|
|
134
142
|
*/
|
|
135
143
|
readonly domains: Record<string, readonly DomainModuleSource[]>;
|
|
144
|
+
/**
|
|
145
|
+
* Compiler-authenticated exact routes may share one domain-agnostic framework plan. When the
|
|
146
|
+
* requested dispatch domain is absent from `domains`, prepare and execute this sole registry while
|
|
147
|
+
* retaining the requested domain for relation namespacing. Never authored by tenant code.
|
|
148
|
+
*/
|
|
149
|
+
readonly routedDomainFallback?: string;
|
|
150
|
+
/**
|
|
151
|
+
* Domain-local dependency initializers emitted by the compiler. They run one per
|
|
152
|
+
* `prepareDomain()` call before the domain's composable sources and their exports are discarded.
|
|
153
|
+
* This turns a tenant module's cross-domain ES import closure into bounded maintenance quanta
|
|
154
|
+
* without registering the imported domain's declarations in the caller's slice.
|
|
155
|
+
*/
|
|
156
|
+
readonly preloads?: Record<string, readonly (() => unknown)[]>;
|
|
136
157
|
/** Optional report registry: `reportId` → a factory `(actor) => Report`. */
|
|
137
158
|
readonly reports?: Record<string, (actor: string) => EngineReport>;
|
|
138
159
|
/** REQUIRED when any domain module is a thunk; ignored otherwise. */
|
|
@@ -147,16 +168,11 @@ export interface EngineEntryConfig {
|
|
|
147
168
|
*/
|
|
148
169
|
readonly seeds?: readonly unknown[];
|
|
149
170
|
/**
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
* already auto-discovered + named-resolved them when it composed each DomainModule). The
|
|
154
|
-
* directives + aggregates ARE discovered from the modules; these ride alongside so the
|
|
155
|
-
* lump's `globalThis.describe` reproduces the EXACT `<name>.openapi.json` the compiler wrote
|
|
156
|
-
* (byte-identity, no Rust re-implementation, no drift). Keyed by domain dispatch key, in the
|
|
157
|
-
* same declaration order as `domains`. Omitted ⇒ describe still emits offers from directives.
|
|
171
|
+
* Compiler-derived self-description. It is a presentation projection held inside the separately
|
|
172
|
+
* routed `describe` plan, never executable law IR. Ordinary offer/read plans omit it completely,
|
|
173
|
+
* so OpenAPI/JSON-Schema generation cannot sit on their parse or readiness flame path.
|
|
158
174
|
*/
|
|
159
|
-
readonly
|
|
175
|
+
readonly openapiDocument?: OpenApiDoc;
|
|
160
176
|
/**
|
|
161
177
|
* The package's OpenAPI document title (the compiler's `"<name> (nomos package)"`). Baked into
|
|
162
178
|
* the lump so `describe` reproduces the compiler's `<name>.openapi.json` byte-for-byte without
|
|
@@ -165,17 +181,6 @@ export interface EngineEntryConfig {
|
|
|
165
181
|
readonly packageTitle?: string;
|
|
166
182
|
}
|
|
167
183
|
|
|
168
|
-
/** The openapi-relevant decls one domain contributes beyond its directives/aggregates. */
|
|
169
|
-
export interface OpenApiDomainDecls {
|
|
170
|
-
readonly queries?: readonly QueryDecl[];
|
|
171
|
-
readonly counts?: readonly AnyCount[];
|
|
172
|
-
readonly sums?: readonly AnySum[];
|
|
173
|
-
readonly mins?: readonly AnyExtremum[];
|
|
174
|
-
readonly maxes?: readonly AnyExtremum[];
|
|
175
|
-
readonly spatials?: readonly SpatialDecl[];
|
|
176
|
-
readonly workspaceInvariants?: readonly WorkspaceInvariantDecl[];
|
|
177
|
-
}
|
|
178
|
-
|
|
179
184
|
interface RegistryEntry {
|
|
180
185
|
directive: Directive<unknown>;
|
|
181
186
|
agg: AggregateHandle;
|
|
@@ -264,6 +269,7 @@ function mergeModules(mods: readonly DomainModuleExports[], domain: string): Dom
|
|
|
264
269
|
[...directivesOf(merged).values()],
|
|
265
270
|
domain,
|
|
266
271
|
);
|
|
272
|
+
merged = withWorkspaceSharingInvitationExports(merged, applicationLanguage.workspaceSharing);
|
|
267
273
|
}
|
|
268
274
|
merged = expandBusinessBirthExports(merged, domain);
|
|
269
275
|
merged = withOwnedCustodyExports(merged);
|
|
@@ -327,6 +333,20 @@ function buildDomainSlice(mod: DomainModuleExports, domain: string): DomainSlice
|
|
|
327
333
|
? discoveredDirectives
|
|
328
334
|
: executableDirectivesForLanguage(applicationLanguage, discoveredDirectives, domain);
|
|
329
335
|
const dirs = new Map(executableDirectives.map((directive) => [directive.id, directive]));
|
|
336
|
+
// A directive already owns the typed aggregate handle it targets. Retain that
|
|
337
|
+
// link unconditionally in the EXECUTABLE slice instead of requiring a second
|
|
338
|
+
// aggregate re-export. For a cross-workspace birth this does not copy child
|
|
339
|
+
// schema into the parent's canonical law: it only gives this selected runtime
|
|
340
|
+
// plan enough structure to register and validate its declared offer. Canonical
|
|
341
|
+
// package composition keeps its separate child-law dependency rule.
|
|
342
|
+
for (const directive of discoveredDirectives) {
|
|
343
|
+
if (directive.aggregate !== undefined) {
|
|
344
|
+
aggs.set(directive.aggregate.id, directive.aggregate);
|
|
345
|
+
}
|
|
346
|
+
for (const output of directive.secondaryOutputs ?? []) {
|
|
347
|
+
if (output.aggregate !== undefined) aggs.set(output.aggregate.id, output.aggregate);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
330
350
|
// RELATIONS AUTO-ENSURE (mirror of composeDomainModule): a relate-family directive `.ensures(RelationTuple)`
|
|
331
351
|
// needs the framework aggregate registered for DISPATCH too — without it the directive is silently dropped
|
|
332
352
|
// below. Inject iff a directive targets it and the dev didn't already export the handle.
|
|
@@ -496,12 +516,16 @@ export function collectEngineRouting(
|
|
|
496
516
|
const aggregateInvariantOf: Record<string, string[]> = {};
|
|
497
517
|
const relationOf: Record<string, string[]> = {};
|
|
498
518
|
const workspaceInvariantOf: Record<string, string[]> = {};
|
|
519
|
+
const namespacedAggregatesOf: Record<string, string[]> = {};
|
|
520
|
+
const qualifiableRelationsOf: Record<string, string[]> = {};
|
|
499
521
|
const add = (map: Record<string, string[]>, key: string, domainName: string) => {
|
|
500
522
|
const list = map[key] ?? (map[key] = []);
|
|
501
523
|
if (!list.includes(domainName)) list.push(domainName);
|
|
502
524
|
};
|
|
503
525
|
for (const [domainName, mods] of Object.entries(domains)) {
|
|
504
526
|
const slice = buildDomainSlice(mergeModules(mods, domainName), domainName);
|
|
527
|
+
namespacedAggregatesOf[domainName] = [...slice.qualifiableAggregates].sort();
|
|
528
|
+
qualifiableRelationsOf[domainName] = [...slice.qualifiableRelations].sort();
|
|
505
529
|
// Type-keyed dispatches arrive with the ROW's type — QUALIFIED for a namespaced aggregate (the
|
|
506
530
|
// runtime `__type` stamp), bare for a global one / a pre-namespacing row. Route BOTH keys so
|
|
507
531
|
// either era resolves to the declaring domain (the slice lookup strips the qualifier back off).
|
|
@@ -513,7 +537,15 @@ export function collectEngineRouting(
|
|
|
513
537
|
for (const relationId of slice.invariants.keys()) add(relationOf, relationId, domainName);
|
|
514
538
|
for (const wsInvariantId of slice.wsInvariants.keys()) add(workspaceInvariantOf, wsInvariantId, domainName);
|
|
515
539
|
}
|
|
516
|
-
return {
|
|
540
|
+
return {
|
|
541
|
+
derivedOf,
|
|
542
|
+
combinedOf,
|
|
543
|
+
aggregateInvariantOf,
|
|
544
|
+
relationOf,
|
|
545
|
+
workspaceInvariantOf,
|
|
546
|
+
namespacedAggregatesOf,
|
|
547
|
+
qualifiableRelationsOf,
|
|
548
|
+
};
|
|
517
549
|
}
|
|
518
550
|
|
|
519
551
|
/**
|
|
@@ -551,6 +583,10 @@ function portsFromHost(principalRaw = ""): Ports {
|
|
|
551
583
|
export interface RegisteredEngine {
|
|
552
584
|
plan(job: unknown): WireEvent[] | { events: WireEvent[]; strikes?: string[]; endorse?: { sink: string; facet: string; reason: string | null }[] };
|
|
553
585
|
planReport(job: unknown): string;
|
|
586
|
+
/** Initialize at most one lazy dependency/module, or compose an initialized domain slice. */
|
|
587
|
+
prepareDomain(domain: string): { complete: boolean; initialized: number; total: number };
|
|
588
|
+
/** Compiler/tooling probe: force one domain and prove an exact routed offer is registered. */
|
|
589
|
+
hasDirective(domain: string, directiveId: string): boolean;
|
|
554
590
|
/** The G1 self-describe verb: the lump's own merged OpenAPI, derived from its modules. */
|
|
555
591
|
describe(opts?: { lawHash?: string; title?: string }): OpenApiDoc;
|
|
556
592
|
}
|
|
@@ -565,6 +601,8 @@ export interface RegisteredEngine {
|
|
|
565
601
|
*/
|
|
566
602
|
export function registerEngine(config: EngineEntryConfig): RegisteredEngine {
|
|
567
603
|
const domainNames = Object.keys(config.domains);
|
|
604
|
+
const sourceDomainFor = (requested: string): string =>
|
|
605
|
+
config.domains[requested] !== undefined ? requested : (config.routedDomainFallback ?? requested);
|
|
568
606
|
const lazy = Object.values(config.domains).some((mods) =>
|
|
569
607
|
mods.some((m) => typeof m === "function"),
|
|
570
608
|
);
|
|
@@ -581,15 +619,61 @@ export function registerEngine(config: EngineEntryConfig): RegisteredEngine {
|
|
|
581
619
|
|
|
582
620
|
// ── domain key → its slice (forced once per sandbox; eager boot forces ALL now) ──
|
|
583
621
|
const sliceCache = new Map<string, DomainSlice>();
|
|
622
|
+
const initializedPreloads = new Map<string, number>();
|
|
623
|
+
const initializedSources = new Map<string, DomainModuleExports[]>();
|
|
624
|
+
function prepareDomain(domainName: string): { complete: boolean; initialized: number; total: number } {
|
|
625
|
+
domainName = sourceDomainFor(domainName);
|
|
626
|
+
const sources = config.domains[domainName];
|
|
627
|
+
if (sources === undefined) return { complete: true, initialized: 0, total: 0 };
|
|
628
|
+
const preloads = config.preloads?.[domainName] ?? [];
|
|
629
|
+
const total = preloads.length + sources.length;
|
|
630
|
+
if (sliceCache.has(domainName)) {
|
|
631
|
+
return { complete: true, initialized: total, total };
|
|
632
|
+
}
|
|
633
|
+
const preloaded = initializedPreloads.get(domainName) ?? 0;
|
|
634
|
+
if (preloaded < preloads.length) {
|
|
635
|
+
preloads[preloaded]!();
|
|
636
|
+
initializedPreloads.set(domainName, preloaded + 1);
|
|
637
|
+
return { complete: false, initialized: preloaded + 1, total };
|
|
638
|
+
}
|
|
639
|
+
let initialized = initializedSources.get(domainName);
|
|
640
|
+
if (initialized === undefined) {
|
|
641
|
+
initialized = [];
|
|
642
|
+
initializedSources.set(domainName, initialized);
|
|
643
|
+
}
|
|
644
|
+
if (initialized.length < sources.length) {
|
|
645
|
+
const source = sources[initialized.length]!;
|
|
646
|
+
initialized.push(typeof source === "function" ? source() : source);
|
|
647
|
+
return { complete: false, initialized: preloads.length + initialized.length, total };
|
|
648
|
+
}
|
|
649
|
+
const slice = buildDomainSlice(mergeModules(initialized, domainName), domainName);
|
|
650
|
+
// The compiler computes these classifications from the complete domain before plan slicing.
|
|
651
|
+
// Prefer that authenticated inventory over the reduced export bag: a closure-retained secondary
|
|
652
|
+
// aggregate/relation is executable law even when tree-shaking removes its top-level export.
|
|
653
|
+
const compiledAggregates = routing.namespacedAggregatesOf?.[domainName];
|
|
654
|
+
if (compiledAggregates !== undefined) {
|
|
655
|
+
slice.qualifiableAggregates = new Set(compiledAggregates);
|
|
656
|
+
}
|
|
657
|
+
const compiledRelations = routing.qualifiableRelationsOf?.[domainName];
|
|
658
|
+
if (compiledRelations !== undefined) {
|
|
659
|
+
slice.qualifiableRelations = new Set(compiledRelations);
|
|
660
|
+
}
|
|
661
|
+
sliceCache.set(domainName, slice);
|
|
662
|
+
initializedSources.delete(domainName);
|
|
663
|
+
initializedPreloads.delete(domainName);
|
|
664
|
+
return { complete: true, initialized: total, total };
|
|
665
|
+
}
|
|
584
666
|
function sliceOf(domainName: string): DomainSlice | undefined {
|
|
667
|
+
domainName = sourceDomainFor(domainName);
|
|
585
668
|
const cached = sliceCache.get(domainName);
|
|
586
669
|
if (cached !== undefined) return cached;
|
|
587
670
|
const sources = config.domains[domainName];
|
|
588
671
|
if (sources === undefined) return undefined;
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
672
|
+
while (!prepareDomain(domainName).complete) { /* synchronous compatibility lane */ }
|
|
673
|
+
return sliceCache.get(domainName);
|
|
674
|
+
}
|
|
675
|
+
function hasDirective(domainName: string, directiveId: string): boolean {
|
|
676
|
+
return sliceOf(domainName)?.registry.has(directiveId) === true;
|
|
593
677
|
}
|
|
594
678
|
if (!lazy) for (const domainName of domainNames) sliceOf(domainName);
|
|
595
679
|
|
|
@@ -698,23 +782,9 @@ export function registerEngine(config: EngineEntryConfig): RegisteredEngine {
|
|
|
698
782
|
return found;
|
|
699
783
|
}
|
|
700
784
|
|
|
701
|
-
//
|
|
702
|
-
//
|
|
703
|
-
|
|
704
|
-
/** `{workspaceInvariantList:{}}` → the DECLARED set `[{id,on},…]` sorted by id (discovery). */
|
|
705
|
-
function planWorkspaceInvariantList(): string {
|
|
706
|
-
const declared = new Map<string, { id: string; on: string }>();
|
|
707
|
-
const domains =
|
|
708
|
-
routing.workspaceInvariantOf !== undefined
|
|
709
|
-
? [...new Set(Object.values(routing.workspaceInvariantOf).flat())]
|
|
710
|
-
: domainNames;
|
|
711
|
-
for (const domainName of domains) {
|
|
712
|
-
const slice = sliceOf(domainName);
|
|
713
|
-
if (slice === undefined) continue;
|
|
714
|
-
for (const w of slice.wsInvariants.values()) declared.set(w.id, { id: w.id, on: w.on });
|
|
715
|
-
}
|
|
716
|
-
return JSON.stringify([...declared.values()].sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0)));
|
|
717
|
-
}
|
|
785
|
+
// Workspace-invariant read selection uses typed USDA interpreted by Rust whenever the
|
|
786
|
+
// compiler can describe it. This dispatch remains the deterministic JavaScript fallback
|
|
787
|
+
// for tenant selectors that deliberately exceed that bounded read algebra.
|
|
718
788
|
|
|
719
789
|
/** `{workspaceInvariantReads:{id}, payload}` → the bounded ref-set `[{name,aggregate,id},…]`. */
|
|
720
790
|
function planWorkspaceInvariantReads(job: {
|
|
@@ -732,11 +802,7 @@ export function registerEngine(config: EngineEntryConfig): RegisteredEngine {
|
|
|
732
802
|
throw new Error(`engine workspaceInvariantReads: no workspace invariant registered for "${id}"`);
|
|
733
803
|
}
|
|
734
804
|
const intent = (job.intent?.payload ?? {}) as Record<string, unknown>;
|
|
735
|
-
// LAW-GATED AUTHZ: the captured author identity (a top-level sibling of `intent`, set by the wasm
|
|
736
|
-
// author leg + replayed verbatim) — the governance invariant reads it to gate by the AUTHOR.
|
|
737
805
|
const principal = (job.capturedPorts?.principal ?? "") as string;
|
|
738
|
-
// VA-core (Phase 3): the kernel-DERIVED author-verified flag (`captured_ports.principal_verified`),
|
|
739
|
-
// threaded the same way as `principal`, so an invariant may gate on a VERIFIED author (e.g. enrollSignerSelf).
|
|
740
806
|
const principalVerified = job.capturedPorts?.principal_verified === true;
|
|
741
807
|
return JSON.stringify(decl.reads({ intent, principal, principalVerified }));
|
|
742
808
|
}
|
|
@@ -848,20 +914,16 @@ export function registerEngine(config: EngineEntryConfig): RegisteredEngine {
|
|
|
848
914
|
queryRows?: unknown[];
|
|
849
915
|
priorState?: Record<string, unknown>;
|
|
850
916
|
}): string {
|
|
851
|
-
// Branch order mirrors emit_engine.ts: workspace-invariant
|
|
917
|
+
// Branch order mirrors emit_engine.ts: workspace-invariant bodies → aggregateInvariant →
|
|
852
918
|
// invariant → derive → combine → report (the gate's most recent dispatch key wins).
|
|
853
919
|
const wsJob = job as {
|
|
854
920
|
intent?: {
|
|
855
|
-
workspaceInvariantList?: unknown;
|
|
856
921
|
workspaceInvariantReads?: { id?: string };
|
|
857
922
|
workspaceInvariant?: { id?: string };
|
|
858
923
|
payload?: unknown;
|
|
859
924
|
};
|
|
860
925
|
priorState?: Record<string, unknown>;
|
|
861
926
|
};
|
|
862
|
-
if (wsJob.intent?.workspaceInvariantList !== undefined) {
|
|
863
|
-
return planWorkspaceInvariantList();
|
|
864
|
-
}
|
|
865
927
|
if (wsJob.intent?.workspaceInvariantReads !== undefined) {
|
|
866
928
|
return planWorkspaceInvariantReads(wsJob);
|
|
867
929
|
}
|
|
@@ -934,7 +996,12 @@ export function registerEngine(config: EngineEntryConfig): RegisteredEngine {
|
|
|
934
996
|
// token qualifies explicitly. (`module.domain` === `intent.domain`.) Synchronous plan execution ⇒
|
|
935
997
|
// cleared in the `finally`.
|
|
936
998
|
const slice = sliceOf(domain)!;
|
|
937
|
-
__setDispatchContext({
|
|
999
|
+
__setDispatchContext({
|
|
1000
|
+
domain,
|
|
1001
|
+
relationNamespace: routing.relationNamespaceOf?.[domain] ?? domain,
|
|
1002
|
+
qualifiable: slice.qualifiableRelations,
|
|
1003
|
+
qualifiableAggregates: slice.qualifiableAggregates,
|
|
1004
|
+
});
|
|
938
1005
|
let wire: ReturnType<typeof executeDirectiveToIntent>;
|
|
939
1006
|
try {
|
|
940
1007
|
wire = executeDirectiveToIntent(entry.directive, entry.agg, intent.payload as never, ctx);
|
|
@@ -952,6 +1019,28 @@ export function registerEngine(config: EngineEntryConfig): RegisteredEngine {
|
|
|
952
1019
|
// `captured_ports.births` and folds it after admit; decode_plan_output ignores it for the byte-compare),
|
|
953
1020
|
// so a birth-free intent still emits the bare event array, byte-identical (the era rule).
|
|
954
1021
|
const births = wire.births;
|
|
1022
|
+
// CURRENT KERNELS expose a Rust-owned plan sink inside the sealed engine. Hand the completed
|
|
1023
|
+
// typed wire values to it while they are still native QuickJS objects, so the kernel can build
|
|
1024
|
+
// and meter `Event`s directly instead of walking a second returned object graph. This is an
|
|
1025
|
+
// execution ABI, not authority: the same values still pass the ordinary kernel gates, and old
|
|
1026
|
+
// kernels/packages retain the returned-value lane below for era replay.
|
|
1027
|
+
const submitNativePlan = (globalThis as unknown as {
|
|
1028
|
+
nomos?: {
|
|
1029
|
+
__submitPlan?: (
|
|
1030
|
+
events: WireEvent[],
|
|
1031
|
+
strikes: string[],
|
|
1032
|
+
endorse: { sink: string; facet: string; reason: string | null }[],
|
|
1033
|
+
births: { workspace: string; genesisChain: unknown }[],
|
|
1034
|
+
) => void;
|
|
1035
|
+
};
|
|
1036
|
+
}).nomos?.__submitPlan;
|
|
1037
|
+
if (typeof submitNativePlan === "function") {
|
|
1038
|
+
submitNativePlan(wire.events, wire.strikes, endorse ?? [], births ?? []);
|
|
1039
|
+
// The Rust sink now owns the result. Return the smallest lawful sentinel; the kernel ignores
|
|
1040
|
+
// it when a native submission is present and reconstructs compatibility bytes from its typed
|
|
1041
|
+
// events. This avoids retaining and re-traversing the large event graph at the ABI boundary.
|
|
1042
|
+
return [];
|
|
1043
|
+
}
|
|
955
1044
|
if (!wire.strikes.length && !(endorse && endorse.length) && !(births && births.length)) return wire.events;
|
|
956
1045
|
return {
|
|
957
1046
|
events: wire.events,
|
|
@@ -972,58 +1061,21 @@ export function registerEngine(config: EngineEntryConfig): RegisteredEngine {
|
|
|
972
1061
|
* package title), matching the compiler's `domainHash`/`"<name> (nomos package)"`.
|
|
973
1062
|
*/
|
|
974
1063
|
function describe(opts?: { lawHash?: string; title?: string }): OpenApiDoc {
|
|
975
|
-
const
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
const sources = config.domains[domainName];
|
|
979
|
-
if (sources === undefined) continue;
|
|
980
|
-
const merged = mergeModules(sources.map((m) => (typeof m === "function" ? m() : m)), domainName);
|
|
981
|
-
// Aggregates dedup by wire id + RelationTuple auto-ensure (the compose contract) — openapi
|
|
982
|
-
// reads aggregates only for the hasMany inverse indexes, so this matches composeDomainModule.
|
|
983
|
-
const byId = aggregatesOf(merged);
|
|
984
|
-
const discoveredDirectives = [...directivesOf(merged).values()];
|
|
985
|
-
const applicationLanguage = applicationLanguageOf([merged], domainName);
|
|
986
|
-
const directives = applicationLanguage === undefined
|
|
987
|
-
? discoveredDirectives
|
|
988
|
-
: executableDirectivesForLanguage(applicationLanguage, discoveredDirectives, domainName);
|
|
989
|
-
const applicationIntents = applicationLanguage === undefined
|
|
990
|
-
? undefined
|
|
991
|
-
: [
|
|
992
|
-
...applicationLanguage.intents,
|
|
993
|
-
...directives.filter((directive) =>
|
|
994
|
-
isBusinessBirthDirective(directive) &&
|
|
995
|
-
!applicationLanguage.intents.some((intent) => intent.id === directive.id)),
|
|
996
|
-
];
|
|
997
|
-
if (!byId.has(RelationTuple.id) && directives.some((d) => d.aggregateId === RelationTuple.id)) {
|
|
998
|
-
byId.set(RelationTuple.id, RelationTuple);
|
|
999
|
-
}
|
|
1000
|
-
const decls = config.openapiDecls?.[domainName] ?? {};
|
|
1001
|
-
const module = {
|
|
1002
|
-
name: domainName,
|
|
1003
|
-
domain: domainName,
|
|
1004
|
-
aggregates: [...byId.values()],
|
|
1005
|
-
directives,
|
|
1006
|
-
...(applicationIntents === undefined ? {} : { applicationIntents }),
|
|
1007
|
-
...(decls.queries && decls.queries.length > 0 ? { queries: [...decls.queries] } : {}),
|
|
1008
|
-
...(decls.counts && decls.counts.length > 0 ? { counts: [...decls.counts] } : {}),
|
|
1009
|
-
...(decls.sums && decls.sums.length > 0 ? { sums: [...decls.sums] } : {}),
|
|
1010
|
-
...(decls.mins && decls.mins.length > 0 ? { mins: [...decls.mins] } : {}),
|
|
1011
|
-
...(decls.maxes && decls.maxes.length > 0 ? { maxes: [...decls.maxes] } : {}),
|
|
1012
|
-
...(decls.spatials && decls.spatials.length > 0 ? { spatials: [...decls.spatials] } : {}),
|
|
1013
|
-
...(decls.workspaceInvariants && decls.workspaceInvariants.length > 0
|
|
1014
|
-
? { workspaceInvariants: [...decls.workspaceInvariants] }
|
|
1015
|
-
: {}),
|
|
1016
|
-
} as unknown as DomainModule;
|
|
1017
|
-
fragments.push(generateOpenApiFragment(module, {
|
|
1018
|
-
...(lawHash !== undefined ? { lawHash } : {}),
|
|
1019
|
-
includeFrameworkRoutes: true,
|
|
1020
|
-
}));
|
|
1064
|
+
const document = config.openapiDocument;
|
|
1065
|
+
if (document === undefined) {
|
|
1066
|
+
throw new Error("engine describe: selected plan has no compiled OpenAPI projection");
|
|
1021
1067
|
}
|
|
1022
|
-
const
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1068
|
+
const lawHash = opts?.lawHash;
|
|
1069
|
+
const title = opts?.title ?? config.packageTitle ?? document.info["title"];
|
|
1070
|
+
const priorInfo = document.info;
|
|
1071
|
+
const info: Record<string, unknown> = {
|
|
1072
|
+
...priorInfo,
|
|
1073
|
+
...(title === undefined ? {} : { title }),
|
|
1074
|
+
version: lawHash === undefined ? (priorInfo["version"] ?? "0") : lawHash.slice(0, 12),
|
|
1075
|
+
};
|
|
1076
|
+
if (lawHash === undefined) delete info["x-nomos-law-hash"];
|
|
1077
|
+
else info["x-nomos-law-hash"] = lawHash;
|
|
1078
|
+
return { ...document, info };
|
|
1027
1079
|
}
|
|
1028
1080
|
|
|
1029
1081
|
// The engine evals the bundle as a classic script and FREEZES globalThis before
|
|
@@ -1031,7 +1083,9 @@ export function registerEngine(config: EngineEntryConfig): RegisteredEngine {
|
|
|
1031
1083
|
// describe verb (the kernel `describe` run mode evals `globalThis.describe(opts)`).
|
|
1032
1084
|
(globalThis as { plan?: unknown }).plan = plan;
|
|
1033
1085
|
(globalThis as { planReport?: unknown }).planReport = planReport;
|
|
1086
|
+
(globalThis as { __nomosPrepareDomain?: unknown }).__nomosPrepareDomain = prepareDomain;
|
|
1087
|
+
(globalThis as { __nomosHasDirective?: unknown }).__nomosHasDirective = hasDirective;
|
|
1034
1088
|
(globalThis as { describe?: unknown }).describe = describe;
|
|
1035
1089
|
|
|
1036
|
-
return { plan, planReport, describe } as RegisteredEngine;
|
|
1090
|
+
return { plan, planReport, prepareDomain, hasDirective, describe } as RegisteredEngine;
|
|
1037
1091
|
}
|