@githolon/dsl 0.100.6 → 0.101.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 +6 -0
- package/dart/lib/src/dev_cloud.dart +46 -15
- package/dart/lib/src/test_harness.dart +78 -16
- package/dart/lib/src/webview_bridge.dart +640 -126
- package/dart/pubspec.lock +1 -1
- package/dart/pubspec.yaml +2 -2
- package/dart/test/bundle_version_pairing_test.dart +11 -22
- package/dart/test/co2_product_gauntlet_test.dart +228 -0
- package/dart/test/errors_test.dart +63 -12
- package/dart/test/first_app_gauntlet_test.dart +29 -3
- package/dart/test/webview_bridge_test.dart +274 -0
- package/dart_types/CHANGELOG.md +6 -0
- package/dart_types/lib/src/errors.dart +136 -30
- package/dart_types/lib/src/surfaced.dart +48 -2
- package/dart_types/lib/src/wire.dart +3 -1
- package/dart_types/pubspec.yaml +1 -1
- package/dart_types/test/surfaced_test.dart +19 -0
- package/package.json +1 -1
- package/src/activity.ts +43 -4
- package/src/aggregate.ts +132 -22
- package/src/attested_core.ts +1 -1
- package/src/authoring.ts +119 -6
- package/src/birth_meter.ts +4 -4
- package/src/birth_meter_ensure.ts +9 -1
- package/src/births.ts +53 -22
- package/src/build_package.ts +55 -14
- package/src/business_birth.ts +48 -7
- package/src/codegen_dart.ts +267 -37
- package/src/codegen_dart_client.ts +921 -82
- package/src/codegen_openapi.ts +28 -5
- package/src/codegen_proof.ts +107 -11
- package/src/codegen_ts.ts +961 -135
- package/src/compile_package_main.ts +155 -45
- package/src/conflicts.ts +252 -0
- package/src/describe_model.ts +448 -0
- package/src/directive.ts +5 -38
- package/src/drivers.ts +12 -4
- package/src/engine_entry.ts +4 -0
- package/src/evolve_preview.ts +72 -11
- package/src/fields.ts +201 -55
- package/src/framework/application_home.ts +103 -0
- package/src/framework/application_home_domain.ts +2 -0
- package/src/framework/attested_receipts.ts +2 -2
- package/src/framework/auth_provider_law.ts +51 -24
- package/src/framework/business_corrections.ts +170 -0
- package/src/framework/disclosure.ts +1 -1
- package/src/framework/domain_lifecycle.ts +250 -16
- package/src/framework/encryption_identity.ts +1 -1
- package/src/framework/encryption_scope.ts +21 -13
- package/src/framework/era_certification.ts +1 -1
- package/src/framework/framework_aggregates.ts +2 -0
- package/src/framework/genesis.ts +1 -1
- package/src/framework/home.ts +22 -9
- package/src/framework/identity.ts +5 -5
- package/src/framework/impure_capability.ts +2 -2
- package/src/framework/owned_custody.ts +561 -0
- package/src/framework/platform_admin.ts +1 -1
- package/src/framework/relations.ts +9 -1
- package/src/framework/repair.ts +1 -1
- package/src/framework/signing_identity.ts +2 -2
- package/src/framework/source_roster.ts +1 -1
- package/src/framework/workspaces.ts +17 -10
- package/src/generated_client_names.ts +39 -0
- package/src/index.ts +20 -15
- package/src/kernel_capabilities.ts +25 -1
- package/src/law_check.ts +4 -1
- package/src/manifest.ts +356 -63
- package/src/read_projection_manifest.ts +8 -0
- package/src/read_projection_namespace.ts +4 -0
- package/src/relation.ts +1 -1
- package/src/shape_compat.ts +47 -2
- package/src/stable_ids.ts +38 -6
- package/src/stable_ids_types.ts +30 -0
- package/src/surfaced_lint.ts +0 -0
- package/src/usd.ts +62 -11
- package/src/usd_layers.ts +54 -3
- package/src/value_object.ts +23 -19
- package/src/wire.ts +1 -0
- package/src/wire_encode.ts +48 -4
- package/src/workspace_routing.ts +57 -0
- package/src/workspace_sharding.ts +9 -9
- package/src/certified_read.ts +0 -313
|
@@ -67,12 +67,14 @@ import {
|
|
|
67
67
|
} from "./codegen_dart.js";
|
|
68
68
|
import type { ContractHandle } from "./contract.js";
|
|
69
69
|
import { generateDartBridgeClient } from "./codegen_dart_client.js";
|
|
70
|
+
import { buildNomosDescribeModel } from "./describe_model.js";
|
|
70
71
|
import {
|
|
71
72
|
isFrameworkAggregate,
|
|
72
73
|
isFrameworkDirective,
|
|
73
74
|
isFrameworkQuery,
|
|
74
75
|
} from "./framework/framework_aggregates.js";
|
|
75
76
|
import { RelationTuple, relationTuplesByObject } from "./framework/relations.js";
|
|
77
|
+
import { isNamespacedAggregate } from "./read_projection_namespace.js";
|
|
76
78
|
import { finishCount, type AnyCount } from "./count.js";
|
|
77
79
|
import type { QueryDecl } from "./query.js";
|
|
78
80
|
import type { SpatialDecl } from "./spatial.js";
|
|
@@ -94,6 +96,7 @@ import { synthesizePreconditionInvariants } from "./precondition.js";
|
|
|
94
96
|
import { BIRTH_FRAMEWORK_QUERIES, synthesizeBirthQuotaInvariants } from "./birth_meter.js";
|
|
95
97
|
import { withBirthMeterExports } from "./birth_meter_ensure.js";
|
|
96
98
|
import { expandBusinessBirthExports } from "./business_birth.js";
|
|
99
|
+
import { withOwnedCustodyExports } from "./framework/owned_custody.js";
|
|
97
100
|
import { expandRoleExports, rolesOf } from "./role.js";
|
|
98
101
|
import { collectEngineRouting } from "./engine_entry.js";
|
|
99
102
|
import {
|
|
@@ -134,6 +137,7 @@ import { generateTsProof, proofLegsIndex } from "./codegen_proof.js";
|
|
|
134
137
|
import { checkDomainModules, formatFindings, hasRefusal } from "./law_check.js";
|
|
135
138
|
import type { NomosCompat } from "./compat_manifest.js";
|
|
136
139
|
import { requiredKernelFeatures, type FeatureProbeModule } from "./kernel_capabilities.js";
|
|
140
|
+
import { APPLICATION_HOME_DOMAIN } from "./framework/application_home_domain.js";
|
|
137
141
|
|
|
138
142
|
const DSL_DIR = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
139
143
|
|
|
@@ -494,8 +498,8 @@ const FRAMEWORK_FILE = "nomos_framework";
|
|
|
494
498
|
/** The shared basename of the domain-contracts DTO file emitted once per package (domain_contracts.md). */
|
|
495
499
|
const CONTRACTS_FILE = "contracts";
|
|
496
500
|
|
|
497
|
-
/** The shared basename of the ACTIVITY REGISTRY
|
|
498
|
-
*
|
|
501
|
+
/** The shared basename of the ACCOUNTABLE ACTIVITY REGISTRY emitted once per package when it carries at
|
|
502
|
+
* least one public business directive. `.activity(...)` enriches the generated baseline; it does not gate it. */
|
|
499
503
|
const ACTIVITY_FILE = "activity_registry";
|
|
500
504
|
|
|
501
505
|
/** Collect every domain contract across the package's modules, deduped by id (later-wins). Sorted by id.
|
|
@@ -783,6 +787,7 @@ function emitDart(
|
|
|
783
787
|
barrelName = "nomos_domains",
|
|
784
788
|
compat?: NomosCompat,
|
|
785
789
|
names?: Readonly<Record<string, string>>,
|
|
790
|
+
describePackageName = barrelName,
|
|
786
791
|
): string[] {
|
|
787
792
|
const domainSources: string[] = []; // for flat-mode alias validation (dart.names)
|
|
788
793
|
const sourceByFile = new Map<string, string>(); // fileBase → src, for precise alias-import selection
|
|
@@ -889,14 +894,14 @@ function emitDart(
|
|
|
889
894
|
aggregateIdClassNames: packageAggregateIdClassNames(modules),
|
|
890
895
|
}));
|
|
891
896
|
}
|
|
892
|
-
// 2a-ter. the shared ACTIVITY REGISTRY (`activity_registry.dart`) —
|
|
893
|
-
//
|
|
894
|
-
// (
|
|
897
|
+
// 2a-ter. the shared ACCOUNTABLE ACTIVITY + DESCRIPTION REGISTRY (`activity_registry.dart`) — emitted
|
|
898
|
+
// ONCE for every package. A read-only package has an empty activity registry but still exposes
|
|
899
|
+
// describe(model/current/rules/history/decisions/evidence).
|
|
900
|
+
// Pure (nomos_types), so the client folds typed rows from the intent log with no runtime import.
|
|
895
901
|
const packageActivity = collectActivityDescriptors(modules);
|
|
896
|
-
const
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
}
|
|
902
|
+
const describeModel = buildNomosDescribeModel(modules, describePackageName);
|
|
903
|
+
const activityImportUri = `${ACTIVITY_FILE}.dart`;
|
|
904
|
+
writeGenerated(ACTIVITY_FILE, generateDartActivityRegistry(packageActivity));
|
|
900
905
|
// CROSS-DOMAIN `t.foreignRef` (auto import). A foreignRef field typed `ForeignRef<CatalogueListing>` +
|
|
901
906
|
// `CatalogueListing.fromJson` needs the TARGET aggregate's Dart class — which lives in the target DOMAIN's
|
|
902
907
|
// generated file. Within ONE package the compiler knows which domain owns each aggregate, so we auto-emit
|
|
@@ -972,7 +977,9 @@ function emitDart(
|
|
|
972
977
|
...(compat !== undefined ? { compat } : {}),
|
|
973
978
|
supportImport,
|
|
974
979
|
...(domainFrameworkImport !== undefined ? { frameworkImportUri: domainFrameworkImport } : {}),
|
|
975
|
-
|
|
980
|
+
emitActivity: true,
|
|
981
|
+
activityImportUri,
|
|
982
|
+
describeModel,
|
|
976
983
|
packageAggregateDomains,
|
|
977
984
|
});
|
|
978
985
|
const cp = path.join(genDir, `${mod.name}.client.dart`);
|
|
@@ -1051,11 +1058,11 @@ const DART_TYPES_IMPORT = `import 'package:nomos_types/nomos_types.dart';`;
|
|
|
1051
1058
|
* just the floor generated code needs — a lagging pin forces tenants into dependency_overrides. */
|
|
1052
1059
|
// 0.3.0: SurfacedValue<T>/SurfacedObservation/PendingConflictRow — generated Surfaced-field typing +
|
|
1053
1060
|
// the pendingConflicts read rows.
|
|
1054
|
-
const NOMOS_TYPES_DEP = "^0.
|
|
1061
|
+
const NOMOS_TYPES_DEP = "^0.7.0";
|
|
1055
1062
|
// 0.48.x: session-bound clients (XClient.bind/NomosClientInterface/DomainClientSessionMismatch/
|
|
1056
1063
|
// DomainNotInstalledForSession, engine.follow, pendingConflicts lanes) — the generated client
|
|
1057
1064
|
// REQUIRES this surface. 0.48.1 fixes NomosSession.watchPendingConflicts delegation.
|
|
1058
|
-
const NOMOS_CLIENT_DEP = "^0.
|
|
1065
|
+
const NOMOS_CLIENT_DEP = "^0.63.0";
|
|
1059
1066
|
// DRIFT TRIPWIRE: pubspec_pins.test.ts asserts these equal the CURRENT versions in dsl/dart/pubspec.yaml
|
|
1060
1067
|
// and dsl/dart_types/pubspec.yaml — a Dart release without this bump fails the suite, so tenants never
|
|
1061
1068
|
// land back in dependency_overrides (the exact co2 report this closes, third occurrence).
|
|
@@ -1145,6 +1152,7 @@ function emitDartPackages(
|
|
|
1145
1152
|
packages: { readonly types: string; readonly client: string; readonly test?: string; readonly compat?: string; readonly barrelExports?: "all" | "explicit" },
|
|
1146
1153
|
names: Readonly<Record<string, string>> | undefined,
|
|
1147
1154
|
compat?: NomosCompat,
|
|
1155
|
+
describePackageName = packages.client,
|
|
1148
1156
|
): { written: string[]; cursed: string[] } {
|
|
1149
1157
|
for (const [role, name] of Object.entries(packages)) {
|
|
1150
1158
|
if (typeof name !== "string" || !isPubPackageName(name)) {
|
|
@@ -1160,6 +1168,7 @@ function emitDartPackages(
|
|
|
1160
1168
|
if (new Set(roleNames).size !== roleNames.length) fail(`dart.packages: types/client/test/compat names must be distinct`);
|
|
1161
1169
|
|
|
1162
1170
|
const packageContracts = collectPackageContracts(modules);
|
|
1171
|
+
const describeModel = buildNomosDescribeModel(modules, describePackageName);
|
|
1163
1172
|
const shared = collectDartSharedSymbols(modules, packageContracts);
|
|
1164
1173
|
const written: string[] = [];
|
|
1165
1174
|
const genRel = DART_GENERATED_SUBDIR.split(path.sep).join("/");
|
|
@@ -1222,10 +1231,9 @@ function emitDartPackages(
|
|
|
1222
1231
|
aggregateIdClassNames: packageAggregateIdClassNames(modules),
|
|
1223
1232
|
}));
|
|
1224
1233
|
}
|
|
1225
|
-
// ACTIVITY REGISTRY (layered):
|
|
1226
|
-
// client resolves it through the types-package barrel (which re-exports every types file). Opt-in only.
|
|
1234
|
+
// ACTIVITY + DESCRIPTION REGISTRY (layered): universal, including packages with empty history.
|
|
1227
1235
|
const packageActivity = collectActivityDescriptors(modules);
|
|
1228
|
-
|
|
1236
|
+
writeTypes(ACTIVITY_FILE, generateDartActivityRegistry(packageActivity));
|
|
1229
1237
|
// CROSS-DOMAIN foreignRef (layered): map aggregate id → its domain's type file, so a foreignRef field's
|
|
1230
1238
|
// target class resolves via a sibling import (the purity gate now permits sibling type files).
|
|
1231
1239
|
const aggIdToTypeFile = new Map<string, string>();
|
|
@@ -1357,7 +1365,8 @@ function emitDartPackages(
|
|
|
1357
1365
|
...(compat !== undefined ? { compat } : {}),
|
|
1358
1366
|
supportImport: "package",
|
|
1359
1367
|
typesImportUri,
|
|
1360
|
-
|
|
1368
|
+
emitActivity: true,
|
|
1369
|
+
describeModel,
|
|
1361
1370
|
packageAggregateDomains: buildPackageAggregateDomains(modules),
|
|
1362
1371
|
// Under 'explicit' the types barrel withholds per-domain classes — import every domain's TYPES
|
|
1363
1372
|
// file directly so the client's read-model/payload/ref/typed-id references resolve. (The no-dup-
|
|
@@ -1552,6 +1561,20 @@ async function main(): Promise<void> {
|
|
|
1552
1561
|
fail(`package name '${cfg.name}' is not a safe basename (letters, digits, spaces, '.', '-', '_')`);
|
|
1553
1562
|
}
|
|
1554
1563
|
|
|
1564
|
+
// ONE BUSINESS BIRTH IS A COMPLETE PRODUCT ENTRYPOINT. The compiler privately appends the
|
|
1565
|
+
// application/home law which turns a signed-in identity into its home workspace; that home can then
|
|
1566
|
+
// call the generated business birth. Tenant config never names this domain. The deliberately obscure
|
|
1567
|
+
// key reduces collision likelihood, but collision handling is still fail-closed: never reinterpret a
|
|
1568
|
+
// tenant's same-named concept as framework machinery.
|
|
1569
|
+
if (cfg.domains.some((d) => d.key === APPLICATION_HOME_DOMAIN)) {
|
|
1570
|
+
fail(
|
|
1571
|
+
`domain key '${APPLICATION_HOME_DOMAIN}' is reserved by Nomos for the private application/home law; ` +
|
|
1572
|
+
`rename the tenant domain (Nomos will not silently overwrite or reroute it)`,
|
|
1573
|
+
);
|
|
1574
|
+
}
|
|
1575
|
+
const domainsToCompile: DomainConfig[] = [...cfg.domains];
|
|
1576
|
+
let applicationHomeInjected = false;
|
|
1577
|
+
|
|
1555
1578
|
const outDir = path.resolve(cfgDir, cfg.outDir ?? "build");
|
|
1556
1579
|
mkdirSync(outDir, { recursive: true });
|
|
1557
1580
|
|
|
@@ -1599,7 +1622,7 @@ async function main(): Promise<void> {
|
|
|
1599
1622
|
tasksQueryId: string | null;
|
|
1600
1623
|
}[] = [];
|
|
1601
1624
|
|
|
1602
|
-
for (const d of
|
|
1625
|
+
for (const d of domainsToCompile) {
|
|
1603
1626
|
if (typeof d.key !== "string" || !Array.isArray(d.modules) || d.modules.length === 0) {
|
|
1604
1627
|
fail(`each domain needs { key, modules: [path, ...] }; got ${JSON.stringify(d)}`);
|
|
1605
1628
|
}
|
|
@@ -1620,7 +1643,21 @@ async function main(): Promise<void> {
|
|
|
1620
1643
|
}
|
|
1621
1644
|
let merged: Mod = {};
|
|
1622
1645
|
for (const m of mods) merged = { ...merged, ...m };
|
|
1646
|
+
const declaresBusinessBirth = Object.values(merged).some(
|
|
1647
|
+
(value) =>
|
|
1648
|
+
value !== null &&
|
|
1649
|
+
typeof value === "object" &&
|
|
1650
|
+
(value as { __isBusinessBirth?: unknown }).__isBusinessBirth === true,
|
|
1651
|
+
);
|
|
1652
|
+
if (declaresBusinessBirth && !applicationHomeInjected) {
|
|
1653
|
+
applicationHomeInjected = true;
|
|
1654
|
+
domainsToCompile.push({
|
|
1655
|
+
key: APPLICATION_HOME_DOMAIN,
|
|
1656
|
+
modules: [path.join(DSL_DIR, "src", "framework", "application_home.ts")],
|
|
1657
|
+
});
|
|
1658
|
+
}
|
|
1623
1659
|
merged = expandBusinessBirthExports(merged, d.key);
|
|
1660
|
+
merged = withOwnedCustodyExports(merged);
|
|
1624
1661
|
// `capability()` bundles expand into discoverable entries (the CLI plane's
|
|
1625
1662
|
// merge point) — queries/sums/sid-minting/manifests all see the pieces.
|
|
1626
1663
|
merged = expandCapabilityExports(merged);
|
|
@@ -1756,7 +1793,7 @@ async function main(): Promise<void> {
|
|
|
1756
1793
|
// taxonomy-free packages emit NOTHING here (the slice-1 byte-stability law).
|
|
1757
1794
|
if (shardingModForDomain !== undefined && shardingLazyExpr !== undefined && !eagerLump) {
|
|
1758
1795
|
const auxKey = `${d.key}/nomos-sharding`;
|
|
1759
|
-
if (
|
|
1796
|
+
if (domainsToCompile.some((x) => x.key === auxKey) || routingInput[auxKey] !== undefined) {
|
|
1760
1797
|
fail(
|
|
1761
1798
|
`domain key '${auxKey}' is reserved for the derived sharding law's invariant routing — rename the domain`,
|
|
1762
1799
|
);
|
|
@@ -1911,7 +1948,7 @@ async function main(): Promise<void> {
|
|
|
1911
1948
|
? { dartImports: d.dartImports }
|
|
1912
1949
|
: {}),
|
|
1913
1950
|
...(d.dartRefImports !== undefined && d.dartRefImports.length > 0
|
|
1914
|
-
? { dartRefImports: d.dartRefImports }
|
|
1951
|
+
? { dartRefImports: [...d.dartRefImports] }
|
|
1915
1952
|
: {}),
|
|
1916
1953
|
...(permissionVocabulary !== undefined ? { permissionVocabulary } : {}),
|
|
1917
1954
|
}),
|
|
@@ -2042,6 +2079,13 @@ async function main(): Promise<void> {
|
|
|
2042
2079
|
}
|
|
2043
2080
|
}
|
|
2044
2081
|
|
|
2082
|
+
// Presentation is a separate concern from executable law. The private application/home domain remains
|
|
2083
|
+
// in `domainModules` for hashing, routing, self-description, replay and static checking, but generated
|
|
2084
|
+
// tenant clients/proofs/interfaces contain business vocabulary only.
|
|
2085
|
+
const presentationDomainModules = domainModules.filter(
|
|
2086
|
+
(mod) => (mod.domain ?? mod.name) !== APPLICATION_HOME_DOMAIN,
|
|
2087
|
+
);
|
|
2088
|
+
|
|
2045
2089
|
// ── STABLE-ID CONTINUITY (#58 — names are labels, identity is minted) ──
|
|
2046
2090
|
// Derive each composed domain's stable ids from the PRIOR compile: the committed
|
|
2047
2091
|
// `nomos.stable-ids.json` lockfile beside the config (the durable source — survives
|
|
@@ -2065,12 +2109,23 @@ async function main(): Promise<void> {
|
|
|
2065
2109
|
const identityName = mod.name;
|
|
2066
2110
|
// The CURRENT canonical aggregate schemas (a pre-continuity manifest pass —
|
|
2067
2111
|
// aggregates/schemas do not depend on continuity).
|
|
2068
|
-
let currentAggs: {
|
|
2112
|
+
let currentAggs: {
|
|
2113
|
+
id: string;
|
|
2114
|
+
schema: WireSchema;
|
|
2115
|
+
kinds?: Record<string, string>;
|
|
2116
|
+
global?: boolean;
|
|
2117
|
+
}[];
|
|
2069
2118
|
try {
|
|
2070
2119
|
const preManifest = domainManifest(mod);
|
|
2071
2120
|
currentAggs = preManifest.aggregates.map((a) => ({
|
|
2072
2121
|
id: a.id,
|
|
2073
2122
|
schema: a.schema,
|
|
2123
|
+
// One framework aggregate may be composed into many independently compiled
|
|
2124
|
+
// domain packages. Give that shared row one global stable-id scope so the
|
|
2125
|
+
// installed read manifest sees the same field contract from every package.
|
|
2126
|
+
global: mod.aggregates.some(
|
|
2127
|
+
(candidate) => candidate.id === a.id && !isNamespacedAggregate(candidate),
|
|
2128
|
+
),
|
|
2074
2129
|
// The CURRENT field kinds (off the pre-continuity stableIds emission) — the
|
|
2075
2130
|
// pair rule's kind axis ("rename + add a field" in one release still infers).
|
|
2076
2131
|
kinds: Object.fromEntries(
|
|
@@ -2154,7 +2209,7 @@ async function main(): Promise<void> {
|
|
|
2154
2209
|
// `connect()` negotiates compatibility by SHAPE (stable-id subtyping), not by law hash.
|
|
2155
2210
|
// architecture/shape_compatibility.md. Multiple modules sharing a domain key merge.
|
|
2156
2211
|
const packageInterface: Record<string, DomainInterface> = {};
|
|
2157
|
-
for (const mod of
|
|
2212
|
+
for (const mod of presentationDomainModules) {
|
|
2158
2213
|
const key = mod.domain ?? mod.name;
|
|
2159
2214
|
const di = domainInterface(mod, nextLock.domains[mod.name]?.stableIds);
|
|
2160
2215
|
const prior = packageInterface[key];
|
|
@@ -2176,7 +2231,7 @@ async function main(): Promise<void> {
|
|
|
2176
2231
|
// supported: each codegen layer mints a named recursive type for it (TS `type <Name>`, Dart
|
|
2177
2232
|
// recursive class). Surfaced here so the tenant sees which fields became which named types.
|
|
2178
2233
|
const recursiveNotes: string[] = [];
|
|
2179
|
-
for (const mod of
|
|
2234
|
+
for (const mod of presentationDomainModules) {
|
|
2180
2235
|
for (const d of (mod.directives ?? []) as Array<{ id?: unknown; payloadSchema?: unknown }>) {
|
|
2181
2236
|
if (!d || typeof d.id !== "string" || !d.payloadSchema || typeof d.payloadSchema !== "object") continue;
|
|
2182
2237
|
for (const { path, name } of recursiveLazyTypes(d.payloadSchema as Parameters<typeof recursiveLazyTypes>[0], d.id)) {
|
|
@@ -2311,6 +2366,24 @@ async function main(): Promise<void> {
|
|
|
2311
2366
|
// JS shim with the platform-native binary, which only an exec can run.
|
|
2312
2367
|
const esbuildBin = path.join(path.dirname(esbuildPkgJson), esbuildBinRel ?? "bin/esbuild");
|
|
2313
2368
|
|
|
2369
|
+
const canonicalizeEngineJavascript = (source: string): string => {
|
|
2370
|
+
// esbuild includes module labels derived from the package's install topology in
|
|
2371
|
+
// non-minified bundles. The same law therefore used to hash differently when the
|
|
2372
|
+
// DSL was reached through this monorepo (../../dsl/src/...) and through a packed
|
|
2373
|
+
// dependency (node_modules/@githolon/dsl/src/...). Canonicalise only esbuild's
|
|
2374
|
+
// generated comment/function labels: tenant strings and executable imports are
|
|
2375
|
+
// deliberately outside these narrow replacements.
|
|
2376
|
+
const body = source
|
|
2377
|
+
.replace(/^\s*"use strict";\s*$/gm, "")
|
|
2378
|
+
.replace(/^(\s*\/\/ )(?:(?:\.\.\/)+dsl\/src\/|node_modules\/@githolon\/dsl\/src\/)/gm, "$1@githolon/dsl/src/")
|
|
2379
|
+
.replace(/"(?:(?:\.\.\/)+dsl\/src\/|node_modules\/@githolon\/dsl\/src\/)([^"]+)"\(\) \{/g, '"@githolon/dsl/src/$1"() {')
|
|
2380
|
+
.replace(/^(\s*\/\/ )(?:(?:\.\.\/)+node_modules\/zod\/|node_modules\/zod\/)/gm, "$1zod/")
|
|
2381
|
+
.replace(/"(?:(?:\.\.\/)+node_modules\/zod\/|node_modules\/zod\/)([^"]+)"\(\) \{/g, '"zod/$1"() {')
|
|
2382
|
+
.replace(/\n[ \t]*\n/g, "\n")
|
|
2383
|
+
.trimEnd();
|
|
2384
|
+
return `"use strict";\n${body}\n`;
|
|
2385
|
+
};
|
|
2386
|
+
|
|
2314
2387
|
const compact = compactFlag || cfg.compact === true;
|
|
2315
2388
|
let javascript: string;
|
|
2316
2389
|
if (compact) {
|
|
@@ -2349,6 +2422,7 @@ async function main(): Promise<void> {
|
|
|
2349
2422
|
{ encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], cwd: cfgDir, maxBuffer: 256 * 1024 * 1024 },
|
|
2350
2423
|
).trimEnd() + "\n";
|
|
2351
2424
|
}
|
|
2425
|
+
javascript = canonicalizeEngineJavascript(javascript);
|
|
2352
2426
|
if (!/globalThis\.plan\s*=/.test(javascript) && !/globalThis\["plan"\]\s*=/.test(javascript)) {
|
|
2353
2427
|
fail(`bundled engine entry does not assign globalThis.plan — refusing to package`);
|
|
2354
2428
|
}
|
|
@@ -2442,7 +2516,7 @@ async function main(): Promise<void> {
|
|
|
2442
2516
|
"utf8",
|
|
2443
2517
|
);
|
|
2444
2518
|
try {
|
|
2445
|
-
execFileSync(process.execPath, [probePath, lumpPath, JSON.stringify(
|
|
2519
|
+
execFileSync(process.execPath, [probePath, lumpPath, JSON.stringify(domainsToCompile.map((d) => d.key))], {
|
|
2446
2520
|
encoding: "utf8",
|
|
2447
2521
|
stdio: ["ignore", "ignore", "pipe"],
|
|
2448
2522
|
});
|
|
@@ -2555,7 +2629,7 @@ async function main(): Promise<void> {
|
|
|
2555
2629
|
}
|
|
2556
2630
|
})();
|
|
2557
2631
|
const compatDomains: NomosCompat["domains"] = {};
|
|
2558
|
-
for (const m of
|
|
2632
|
+
for (const m of presentationDomainModules) {
|
|
2559
2633
|
const key = m.domain ?? m.name;
|
|
2560
2634
|
const identityHash = identity.hashes[key];
|
|
2561
2635
|
compatDomains[key] = identityHash === undefined ? {} : { identityHash };
|
|
@@ -2564,7 +2638,11 @@ async function main(): Promise<void> {
|
|
|
2564
2638
|
// era-key features). Baked into the client so connect() can check it against the target
|
|
2565
2639
|
// kernel's advertised capabilities BEFORE the law folds (kernel_capabilities.ts).
|
|
2566
2640
|
const requiresKernel = ((): string[] => {
|
|
2567
|
-
const probes: FeatureProbeModule[] = domainModules.map((m) => (
|
|
2641
|
+
const probes: FeatureProbeModule[] = domainModules.map((m) => ({
|
|
2642
|
+
...(m.queries ? { queries: m.queries } : {}),
|
|
2643
|
+
...(m.surfacedResolvers ? { surfacedResolvers: m.surfacedResolvers } : {}),
|
|
2644
|
+
...(m.aggregates ? { aggregates: m.aggregates } : {}),
|
|
2645
|
+
}));
|
|
2568
2646
|
try {
|
|
2569
2647
|
const parsed = JSON.parse(usdJson) as { layers?: Record<string, unknown>[] };
|
|
2570
2648
|
for (const layer of parsed.layers ?? []) probes.push({ layer });
|
|
@@ -2607,7 +2685,7 @@ async function main(): Promise<void> {
|
|
|
2607
2685
|
const summary = {
|
|
2608
2686
|
package: cfg.name,
|
|
2609
2687
|
domainHash,
|
|
2610
|
-
domains:
|
|
2688
|
+
domains: presentationDomainModules.map((m) => ({
|
|
2611
2689
|
domain: m.domain ?? m.name,
|
|
2612
2690
|
aggregates: m.aggregates.map((a) => a.id),
|
|
2613
2691
|
directives: m.directives.map((d) => d.id),
|
|
@@ -2647,14 +2725,14 @@ async function main(): Promise<void> {
|
|
|
2647
2725
|
let birthWarnings: string[] = [];
|
|
2648
2726
|
let proofNotes: string[] = [];
|
|
2649
2727
|
try {
|
|
2650
|
-
const proofSrc = generateTsProof(
|
|
2728
|
+
const proofSrc = generateTsProof(presentationDomainModules, { packageName: cfg.name, domainHash, interface: packageInterface });
|
|
2651
2729
|
proofPath = path.join(outDir, `${cfg.name}.proof.mts`);
|
|
2652
2730
|
writeFileSync(proofPath, proofSrc, "utf8");
|
|
2653
2731
|
// THE PER-DOMAIN LEGS INDEX: every domain with a creating write, so
|
|
2654
2732
|
// `githolon proof --domain <key>` proves ANY of them offline (the .mts
|
|
2655
2733
|
// proves the primary one live). A multi-domain package no longer locks the
|
|
2656
2734
|
// proof to whichever domain happens to be first.
|
|
2657
|
-
const legsIndex = proofLegsIndex(
|
|
2735
|
+
const legsIndex = proofLegsIndex(presentationDomainModules, packageInterface);
|
|
2658
2736
|
if (legsIndex !== null) {
|
|
2659
2737
|
writeFileSync(path.join(outDir, `${cfg.name}.proof-legs.json`), JSON.stringify(legsIndex, null, 2) + "\n", "utf8");
|
|
2660
2738
|
proofDomains = Object.keys(legsIndex.domains);
|
|
@@ -2671,7 +2749,7 @@ async function main(): Promise<void> {
|
|
|
2671
2749
|
// itself failed, still derive the per-domain diagnostics (best-effort).
|
|
2672
2750
|
if (proofSkip !== undefined && birthWarnings.length === 0) {
|
|
2673
2751
|
try {
|
|
2674
|
-
const idx = proofLegsIndex(
|
|
2752
|
+
const idx = proofLegsIndex(presentationDomainModules, packageInterface);
|
|
2675
2753
|
if (idx !== null) {
|
|
2676
2754
|
birthWarnings = Object.values(idx.domains).flatMap((l) => l.birthDiagnostics ?? []);
|
|
2677
2755
|
proofNotes = Object.values(idx.domains).flatMap((l) => l.proofDiagnostics ?? []);
|
|
@@ -2689,7 +2767,7 @@ async function main(): Promise<void> {
|
|
|
2689
2767
|
` queries: ${d.queries.join(", ") || "—"} counts: ${d.counts.join(", ") || "—"} sums: ${d.sums.join(", ") || "—"}`,
|
|
2690
2768
|
]),
|
|
2691
2769
|
`deploy: POST ${cfg.name}.deploy.json to /v2/workspaces/<ws>/domains (or: githolon deploy <ws>)`,
|
|
2692
|
-
`typed client: ${cfg.name}.client.ts — ${tsClientFactoryName(
|
|
2770
|
+
`typed client: ${cfg.name}.client.ts — ${tsClientFactoryName(presentationDomainModules[0]?.domain ?? presentationDomainModules[0]?.name ?? cfg.name)}(holon), law hash baked in`,
|
|
2693
2771
|
proofPath !== undefined
|
|
2694
2772
|
? `generated proof: ${cfg.name}.proof.mts — run: githolon proof (live; ends ALL GREEN or names the jam)`
|
|
2695
2773
|
: `generated proof: SKIPPED — ${proofSkip}`,
|
|
@@ -2700,7 +2778,7 @@ async function main(): Promise<void> {
|
|
|
2700
2778
|
// ── 5. the typed TS client (#10 — the web sibling of codegen_dart), with the
|
|
2701
2779
|
// deployed law's content hash baked in (emitted AFTER the package is hashed) ──
|
|
2702
2780
|
const clientPath = path.join(outDir, `${cfg.name}.client.ts`);
|
|
2703
|
-
writeFileSync(clientPath, generateTsClient(
|
|
2781
|
+
writeFileSync(clientPath, generateTsClient(presentationDomainModules, { packageName: cfg.name, domainHash, interface: packageInterface, compat: nomosCompat }), "utf8");
|
|
2704
2782
|
|
|
2705
2783
|
// ── 6. the typed Dart frontend (opt-in; the Flutter sibling of step 5, emitted
|
|
2706
2784
|
// after the package hash like the TS client) ──
|
|
@@ -2746,7 +2824,7 @@ async function main(): Promise<void> {
|
|
|
2746
2824
|
// COMPILE ATOMICITY (co2): the Dart emit is transactional (beginAtomicGenDir) — a mid-emit fail()/throw
|
|
2747
2825
|
// restores the prior good packages instead of leaving them wiped/partial. Finalized at process exit.
|
|
2748
2826
|
if (dartPackages !== undefined) {
|
|
2749
|
-
const r = emitDartPackages(
|
|
2827
|
+
const r = emitDartPackages(presentationDomainModules, dartOut, domainHash, packageInterface, dartPackages, dartNames, nomosCompat, cfg.name);
|
|
2750
2828
|
dartFiles = r.written;
|
|
2751
2829
|
dartCursedHints = r.cursed;
|
|
2752
2830
|
} else {
|
|
@@ -2759,7 +2837,7 @@ async function main(): Promise<void> {
|
|
|
2759
2837
|
.replace(/^(?=[0-9])/, "n");
|
|
2760
2838
|
const dartBarrel =
|
|
2761
2839
|
typeof dartCfg === "object" && dartCfg.barrel !== undefined ? dartCfg.barrel : defaultBarrel;
|
|
2762
|
-
dartFiles = emitDart(
|
|
2840
|
+
dartFiles = emitDart(presentationDomainModules, dartOut, domainHash, packageInterface, dartSupportImport, dartBarrel, nomosCompat, dartNames, cfg.name);
|
|
2763
2841
|
}
|
|
2764
2842
|
// COMPILE-VALID MUST MEAN COMPILABLE (co2): `githolon compile` reported success while the generated Dart
|
|
2765
2843
|
// had hard compiler errors (a duplicate id symbol, missing contract-id defs). Run `dart analyze` over the
|
|
@@ -2810,16 +2888,29 @@ async function main(): Promise<void> {
|
|
|
2810
2888
|
}
|
|
2811
2889
|
return undefined;
|
|
2812
2890
|
})();
|
|
2813
|
-
|
|
2814
|
-
|
|
2891
|
+
// Package generation must not depend on which SDKs happen to be installed on the compiler's
|
|
2892
|
+
// machine. Write every source-dogfood override first; the analyzer loop may legitimately stop
|
|
2893
|
+
// at the first missing `dart`, but that must not leave later solve roots pinned to hosted code.
|
|
2815
2894
|
for (const pkg of pkgDirs) {
|
|
2816
2895
|
if (localDart) {
|
|
2817
2896
|
const spec = readFileSync(path.join(pkg, "pubspec.yaml"), "utf8");
|
|
2818
2897
|
const lines = ["dependency_overrides:"];
|
|
2819
|
-
|
|
2820
|
-
|
|
2898
|
+
const usesClient = /(^|\n)\s+nomos_client\s*:/.test(spec);
|
|
2899
|
+
const usesTypes = /(^|\n)\s+nomos_types\s*:/.test(spec);
|
|
2900
|
+
if (usesClient) lines.push(` nomos_client:`, ` path: ${localDart.client}`);
|
|
2901
|
+
// A generated CLIENT or TEST package may only mention nomos_client directly, but that local
|
|
2902
|
+
// package depends on the simultaneously-developed nomos_types. Pub overrides do not propagate
|
|
2903
|
+
// from dependencies, so override the transitive core at THIS solve root as well. Otherwise a
|
|
2904
|
+
// perfectly ordinary recompile of an older generated package can fail version solving before
|
|
2905
|
+
// analyzer ever sees the code — exactly the package-skew ceremony this local dogfood gate exists
|
|
2906
|
+
// to absorb for tenant developers.
|
|
2907
|
+
if (usesTypes || usesClient) lines.push(` nomos_types:`, ` path: ${localDart.types}`);
|
|
2821
2908
|
if (lines.length > 1) writeFileSync(path.join(pkg, "pubspec_overrides.yaml"), lines.join("\n") + "\n", "utf8");
|
|
2822
2909
|
}
|
|
2910
|
+
}
|
|
2911
|
+
let dartMissing = false;
|
|
2912
|
+
let unresolved: string | undefined;
|
|
2913
|
+
for (const pkg of pkgDirs) {
|
|
2823
2914
|
try {
|
|
2824
2915
|
execFileSync("dart", ["pub", "get"], { cwd: pkg, stdio: "pipe", encoding: "utf8" });
|
|
2825
2916
|
} catch (e) {
|
|
@@ -2870,20 +2961,23 @@ async function main(): Promise<void> {
|
|
|
2870
2961
|
}
|
|
2871
2962
|
{
|
|
2872
2963
|
const sum = (pick: (m: (typeof domainModules)[number]) => readonly unknown[] | undefined) =>
|
|
2873
|
-
|
|
2964
|
+
presentationDomainModules.reduce((n, m) => n + (pick(m)?.length ?? 0), 0);
|
|
2874
2965
|
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)`);
|
|
2875
2966
|
}
|
|
2876
2967
|
// SECONDARY-CREATE AUTO-DECLARE (secondary_ensure.ts): surface every type the compiler sanctioned
|
|
2877
2968
|
// from a plan's deterministic secondary `ensure(...)` — the id-mint-gate DX made visible (the author
|
|
2878
2969
|
// wrote `ensure(B, …)`; the compiler declared `Ensure → B` so the deterministic id admits).
|
|
2879
|
-
for (const m of
|
|
2970
|
+
for (const m of presentationDomainModules) {
|
|
2880
2971
|
for (const ty of m.autoDeclaredEnsures ?? []) {
|
|
2881
2972
|
console.log(` ensure auto-declared Ensure→${ty} in '${m.domain ?? m.name}' from a plan's secondary ensure(...) (id-mint gate opened)`);
|
|
2882
2973
|
}
|
|
2883
2974
|
}
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2975
|
+
const presentedIdentityNames = new Set(presentationDomainModules.map((m) => m.domain ?? m.name));
|
|
2976
|
+
const presentedHashes = Object.entries(identity.hashes).filter(([domain]) => presentedIdentityNames.has(domain));
|
|
2977
|
+
const presentedExcluded = identity.excluded.filter((entry) => presentedIdentityNames.has(entry.domain));
|
|
2978
|
+
console.log(` identity ${presentedHashes.length} business domain(s) (private Nomos lifecycle law included but not exposed)${presentedExcluded.length ? ` — ${presentedExcluded.length} EXCLUDED (palette gap)` : ""}`);
|
|
2979
|
+
for (const [dom, h] of presentedHashes) console.log(` ${dom.padEnd(20)} ${h}`);
|
|
2980
|
+
for (const ex of presentedExcluded) console.log(` EXCLUDED ${ex.domain}: ${ex.reason}`);
|
|
2887
2981
|
// STABLE IDS (#58): the minted/carried identity surface + every INFERRED rename —
|
|
2888
2982
|
// the silent lane made visible (if an inference is wrong — you meant remove+add —
|
|
2889
2983
|
// split the edit into two compiles, or answer the evolve gate with a disposition).
|
|
@@ -2895,7 +2989,7 @@ async function main(): Promise<void> {
|
|
|
2895
2989
|
);
|
|
2896
2990
|
}
|
|
2897
2991
|
}
|
|
2898
|
-
for (const m of
|
|
2992
|
+
for (const m of presentationDomainModules) {
|
|
2899
2993
|
if (m.workspaceTypes !== undefined && m.workspaceTypes.length > 0) {
|
|
2900
2994
|
console.log(
|
|
2901
2995
|
` taxonomy ${m.domain ?? m.name}: ${m.workspaceTypes.length} workspace type(s) — homing derived from t.ref chains; birth lanes typed in the client`,
|
|
@@ -2920,9 +3014,15 @@ async function main(): Promise<void> {
|
|
|
2920
3014
|
// gate's refusal vocabulary, unified into ONE report. `githolon check` runs the same pass;
|
|
2921
3015
|
// compile runs it implicitly and REFUSES on any refuse-level finding (a statically-provable
|
|
2922
3016
|
// runtime refusal shipped as law). Warns/notes are printed but never block the compile.
|
|
2923
|
-
const
|
|
3017
|
+
const allCheckFindings = checkDomainModules(domainModules);
|
|
3018
|
+
const isFrameworkFinding = (finding: (typeof allCheckFindings)[number]) =>
|
|
3019
|
+
finding.domain === APPLICATION_HOME_DOMAIN || finding.directiveId?.startsWith("nomos_internal_") === true;
|
|
3020
|
+
const checkFindings = allCheckFindings.filter((finding) => !isFrameworkFinding(finding));
|
|
3021
|
+
const privateRefusals = allCheckFindings.filter(
|
|
3022
|
+
(finding) => isFrameworkFinding(finding) && finding.level === "refuse",
|
|
3023
|
+
);
|
|
2924
3024
|
if (checkFindings.length > 0) {
|
|
2925
|
-
console.log(` check ${checkFindings.length} finding(s) (githolon check):`);
|
|
3025
|
+
console.log(` check ${checkFindings.length} business-law finding(s) (githolon check):`);
|
|
2926
3026
|
for (const line of formatFindings(checkFindings)) {
|
|
2927
3027
|
const mark = line.includes("REFUSE") ? "✗" : line.includes("WARN") ? "⚠" : "•";
|
|
2928
3028
|
console.log(` ${mark} ${line}`);
|
|
@@ -2934,6 +3034,16 @@ async function main(): Promise<void> {
|
|
|
2934
3034
|
process.exitCode = 1;
|
|
2935
3035
|
}
|
|
2936
3036
|
}
|
|
3037
|
+
if (privateRefusals.length > 0) {
|
|
3038
|
+
console.error(
|
|
3039
|
+
` ✗ Nomos lifecycle self-check failed inside this compiler release. Tenant law is not at fault; ` +
|
|
3040
|
+
`upgrade @githolon/dsl or report the compiler version.`,
|
|
3041
|
+
);
|
|
3042
|
+
if (process.env.NOMOS_DEBUG_FRAMEWORK === "1") {
|
|
3043
|
+
for (const line of formatFindings(privateRefusals)) console.error(` ${line}`);
|
|
3044
|
+
}
|
|
3045
|
+
process.exitCode = 1;
|
|
3046
|
+
}
|
|
2937
3047
|
if (dartOut !== undefined) {
|
|
2938
3048
|
if (dartPackages !== undefined) {
|
|
2939
3049
|
const pkgList = [
|