@githolon/dsl 0.100.5 → 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 +12 -0
- package/dart/lib/src/dev_cloud.dart +46 -15
- package/dart/lib/src/test_harness.dart +220 -71
- package/dart/lib/src/webview_bridge.dart +640 -126
- package/dart/pubspec.lock +1 -1
- package/dart/pubspec.yaml +2 -2
- package/dart/test/acquire_session_credentials_test.dart +1 -1
- package/dart/test/adv_realm_interference_test.dart +1 -1
- package/dart/test/bundle_version_pairing_test.dart +11 -22
- package/dart/test/cluster_attested_test.dart +1 -1
- package/dart/test/cluster_births_test.dart +1 -1
- package/dart/test/cluster_device_keyed_acceptance_test.dart +1 -1
- package/dart/test/cluster_local_autosync_test.dart +1 -1
- package/dart/test/cluster_scale_test.dart +1 -1
- package/dart/test/co2_product_gauntlet_test.dart +228 -0
- package/dart/test/dlq_session_surface_test.dart +1 -1
- package/dart/test/errors_test.dart +63 -12
- package/dart/test/first_app_gauntlet_test.dart +132 -87
- package/dart/test/local_sync_inert_test.dart +10 -5
- package/dart/test/parent_signer_recovery_test.dart +1 -1
- package/dart/test/sealing_client_test.dart +1 -1
- package/dart/test/session_bound_test.dart +1 -1
- package/dart/test/test_harness_test.dart +2 -2
- package/dart/test/vo_read_typing_test.dart +1 -1
- package/dart/test/watch_after_offer_stall_test.dart +1 -1
- 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 +165 -29
- package/src/births.ts +53 -22
- package/src/build_package.ts +96 -20
- package/src/business_birth.ts +79 -16
- package/src/codegen_dart.ts +267 -37
- package/src/codegen_dart_client.ts +930 -87
- 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 +172 -53
- 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 +61 -5
- 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.
|
|
@@ -598,10 +602,13 @@ function collectDartSharedSymbols(
|
|
|
598
602
|
const frameworkAggById = new Map<string, AggregateHandle>();
|
|
599
603
|
const frameworkDirById = new Map<string, ModDirective>();
|
|
600
604
|
const frameworkQueryById = new Map<string, ModQuery>();
|
|
605
|
+
const isInternal = (value: unknown): boolean =>
|
|
606
|
+
!!value && typeof value === "object"
|
|
607
|
+
&& (value as { businessBirthInternal?: unknown }).businessBirthInternal === true;
|
|
601
608
|
for (const mod of modules) {
|
|
602
|
-
for (const a of mod.aggregates) if (isFrameworkAggregate(a)) frameworkAggById.set(a.id, a);
|
|
603
|
-
for (const d of mod.directives) if (isFrameworkDirective(d)) frameworkDirById.set(d.id, d);
|
|
604
|
-
for (const q of mod.queries ?? []) if (isFrameworkQuery(q)) frameworkQueryById.set(q.id, q);
|
|
609
|
+
for (const a of mod.aggregates) if (!isInternal(a) && isFrameworkAggregate(a)) frameworkAggById.set(a.id, a);
|
|
610
|
+
for (const d of mod.directives) if (!isInternal(d) && isFrameworkDirective(d)) frameworkDirById.set(d.id, d);
|
|
611
|
+
for (const q of mod.queries ?? []) if (!isInternal(q) && isFrameworkQuery(q)) frameworkQueryById.set(q.id, q);
|
|
605
612
|
}
|
|
606
613
|
const frameworkAggs = [...frameworkAggById.values()];
|
|
607
614
|
const frameworkDirs = [...frameworkDirById.values()];
|
|
@@ -780,6 +787,7 @@ function emitDart(
|
|
|
780
787
|
barrelName = "nomos_domains",
|
|
781
788
|
compat?: NomosCompat,
|
|
782
789
|
names?: Readonly<Record<string, string>>,
|
|
790
|
+
describePackageName = barrelName,
|
|
783
791
|
): string[] {
|
|
784
792
|
const domainSources: string[] = []; // for flat-mode alias validation (dart.names)
|
|
785
793
|
const sourceByFile = new Map<string, string>(); // fileBase → src, for precise alias-import selection
|
|
@@ -886,14 +894,14 @@ function emitDart(
|
|
|
886
894
|
aggregateIdClassNames: packageAggregateIdClassNames(modules),
|
|
887
895
|
}));
|
|
888
896
|
}
|
|
889
|
-
// 2a-ter. the shared ACTIVITY REGISTRY (`activity_registry.dart`) —
|
|
890
|
-
//
|
|
891
|
-
// (
|
|
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.
|
|
892
901
|
const packageActivity = collectActivityDescriptors(modules);
|
|
893
|
-
const
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
}
|
|
902
|
+
const describeModel = buildNomosDescribeModel(modules, describePackageName);
|
|
903
|
+
const activityImportUri = `${ACTIVITY_FILE}.dart`;
|
|
904
|
+
writeGenerated(ACTIVITY_FILE, generateDartActivityRegistry(packageActivity));
|
|
897
905
|
// CROSS-DOMAIN `t.foreignRef` (auto import). A foreignRef field typed `ForeignRef<CatalogueListing>` +
|
|
898
906
|
// `CatalogueListing.fromJson` needs the TARGET aggregate's Dart class — which lives in the target DOMAIN's
|
|
899
907
|
// generated file. Within ONE package the compiler knows which domain owns each aggregate, so we auto-emit
|
|
@@ -969,7 +977,9 @@ function emitDart(
|
|
|
969
977
|
...(compat !== undefined ? { compat } : {}),
|
|
970
978
|
supportImport,
|
|
971
979
|
...(domainFrameworkImport !== undefined ? { frameworkImportUri: domainFrameworkImport } : {}),
|
|
972
|
-
|
|
980
|
+
emitActivity: true,
|
|
981
|
+
activityImportUri,
|
|
982
|
+
describeModel,
|
|
973
983
|
packageAggregateDomains,
|
|
974
984
|
});
|
|
975
985
|
const cp = path.join(genDir, `${mod.name}.client.dart`);
|
|
@@ -1048,11 +1058,11 @@ const DART_TYPES_IMPORT = `import 'package:nomos_types/nomos_types.dart';`;
|
|
|
1048
1058
|
* just the floor generated code needs — a lagging pin forces tenants into dependency_overrides. */
|
|
1049
1059
|
// 0.3.0: SurfacedValue<T>/SurfacedObservation/PendingConflictRow — generated Surfaced-field typing +
|
|
1050
1060
|
// the pendingConflicts read rows.
|
|
1051
|
-
const NOMOS_TYPES_DEP = "^0.
|
|
1061
|
+
const NOMOS_TYPES_DEP = "^0.7.0";
|
|
1052
1062
|
// 0.48.x: session-bound clients (XClient.bind/NomosClientInterface/DomainClientSessionMismatch/
|
|
1053
1063
|
// DomainNotInstalledForSession, engine.follow, pendingConflicts lanes) — the generated client
|
|
1054
1064
|
// REQUIRES this surface. 0.48.1 fixes NomosSession.watchPendingConflicts delegation.
|
|
1055
|
-
const NOMOS_CLIENT_DEP = "^0.
|
|
1065
|
+
const NOMOS_CLIENT_DEP = "^0.63.0";
|
|
1056
1066
|
// DRIFT TRIPWIRE: pubspec_pins.test.ts asserts these equal the CURRENT versions in dsl/dart/pubspec.yaml
|
|
1057
1067
|
// and dsl/dart_types/pubspec.yaml — a Dart release without this bump fails the suite, so tenants never
|
|
1058
1068
|
// land back in dependency_overrides (the exact co2 report this closes, third occurrence).
|
|
@@ -1142,6 +1152,7 @@ function emitDartPackages(
|
|
|
1142
1152
|
packages: { readonly types: string; readonly client: string; readonly test?: string; readonly compat?: string; readonly barrelExports?: "all" | "explicit" },
|
|
1143
1153
|
names: Readonly<Record<string, string>> | undefined,
|
|
1144
1154
|
compat?: NomosCompat,
|
|
1155
|
+
describePackageName = packages.client,
|
|
1145
1156
|
): { written: string[]; cursed: string[] } {
|
|
1146
1157
|
for (const [role, name] of Object.entries(packages)) {
|
|
1147
1158
|
if (typeof name !== "string" || !isPubPackageName(name)) {
|
|
@@ -1157,6 +1168,7 @@ function emitDartPackages(
|
|
|
1157
1168
|
if (new Set(roleNames).size !== roleNames.length) fail(`dart.packages: types/client/test/compat names must be distinct`);
|
|
1158
1169
|
|
|
1159
1170
|
const packageContracts = collectPackageContracts(modules);
|
|
1171
|
+
const describeModel = buildNomosDescribeModel(modules, describePackageName);
|
|
1160
1172
|
const shared = collectDartSharedSymbols(modules, packageContracts);
|
|
1161
1173
|
const written: string[] = [];
|
|
1162
1174
|
const genRel = DART_GENERATED_SUBDIR.split(path.sep).join("/");
|
|
@@ -1219,10 +1231,9 @@ function emitDartPackages(
|
|
|
1219
1231
|
aggregateIdClassNames: packageAggregateIdClassNames(modules),
|
|
1220
1232
|
}));
|
|
1221
1233
|
}
|
|
1222
|
-
// ACTIVITY REGISTRY (layered):
|
|
1223
|
-
// 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.
|
|
1224
1235
|
const packageActivity = collectActivityDescriptors(modules);
|
|
1225
|
-
|
|
1236
|
+
writeTypes(ACTIVITY_FILE, generateDartActivityRegistry(packageActivity));
|
|
1226
1237
|
// CROSS-DOMAIN foreignRef (layered): map aggregate id → its domain's type file, so a foreignRef field's
|
|
1227
1238
|
// target class resolves via a sibling import (the purity gate now permits sibling type files).
|
|
1228
1239
|
const aggIdToTypeFile = new Map<string, string>();
|
|
@@ -1354,7 +1365,8 @@ function emitDartPackages(
|
|
|
1354
1365
|
...(compat !== undefined ? { compat } : {}),
|
|
1355
1366
|
supportImport: "package",
|
|
1356
1367
|
typesImportUri,
|
|
1357
|
-
|
|
1368
|
+
emitActivity: true,
|
|
1369
|
+
describeModel,
|
|
1358
1370
|
packageAggregateDomains: buildPackageAggregateDomains(modules),
|
|
1359
1371
|
// Under 'explicit' the types barrel withholds per-domain classes — import every domain's TYPES
|
|
1360
1372
|
// file directly so the client's read-model/payload/ref/typed-id references resolve. (The no-dup-
|
|
@@ -1549,6 +1561,20 @@ async function main(): Promise<void> {
|
|
|
1549
1561
|
fail(`package name '${cfg.name}' is not a safe basename (letters, digits, spaces, '.', '-', '_')`);
|
|
1550
1562
|
}
|
|
1551
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
|
+
|
|
1552
1578
|
const outDir = path.resolve(cfgDir, cfg.outDir ?? "build");
|
|
1553
1579
|
mkdirSync(outDir, { recursive: true });
|
|
1554
1580
|
|
|
@@ -1596,7 +1622,7 @@ async function main(): Promise<void> {
|
|
|
1596
1622
|
tasksQueryId: string | null;
|
|
1597
1623
|
}[] = [];
|
|
1598
1624
|
|
|
1599
|
-
for (const d of
|
|
1625
|
+
for (const d of domainsToCompile) {
|
|
1600
1626
|
if (typeof d.key !== "string" || !Array.isArray(d.modules) || d.modules.length === 0) {
|
|
1601
1627
|
fail(`each domain needs { key, modules: [path, ...] }; got ${JSON.stringify(d)}`);
|
|
1602
1628
|
}
|
|
@@ -1617,7 +1643,21 @@ async function main(): Promise<void> {
|
|
|
1617
1643
|
}
|
|
1618
1644
|
let merged: Mod = {};
|
|
1619
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
|
+
}
|
|
1620
1659
|
merged = expandBusinessBirthExports(merged, d.key);
|
|
1660
|
+
merged = withOwnedCustodyExports(merged);
|
|
1621
1661
|
// `capability()` bundles expand into discoverable entries (the CLI plane's
|
|
1622
1662
|
// merge point) — queries/sums/sid-minting/manifests all see the pieces.
|
|
1623
1663
|
merged = expandCapabilityExports(merged);
|
|
@@ -1753,7 +1793,7 @@ async function main(): Promise<void> {
|
|
|
1753
1793
|
// taxonomy-free packages emit NOTHING here (the slice-1 byte-stability law).
|
|
1754
1794
|
if (shardingModForDomain !== undefined && shardingLazyExpr !== undefined && !eagerLump) {
|
|
1755
1795
|
const auxKey = `${d.key}/nomos-sharding`;
|
|
1756
|
-
if (
|
|
1796
|
+
if (domainsToCompile.some((x) => x.key === auxKey) || routingInput[auxKey] !== undefined) {
|
|
1757
1797
|
fail(
|
|
1758
1798
|
`domain key '${auxKey}' is reserved for the derived sharding law's invariant routing — rename the domain`,
|
|
1759
1799
|
);
|
|
@@ -1773,7 +1813,9 @@ async function main(): Promise<void> {
|
|
|
1773
1813
|
if (directivesOf(merged).some((dir) => (dir as { birthsChild?: boolean }).birthsChild === true)) {
|
|
1774
1814
|
const haveQuery = new Set(queries.map((q) => q.id));
|
|
1775
1815
|
for (const q of BIRTH_FRAMEWORK_QUERIES) {
|
|
1776
|
-
if (!haveQuery.has(q.id))
|
|
1816
|
+
if (!haveQuery.has(q.id)) {
|
|
1817
|
+
queries.push({ ...q, businessBirthInternal: true } as QueryDecl);
|
|
1818
|
+
}
|
|
1777
1819
|
}
|
|
1778
1820
|
}
|
|
1779
1821
|
// RELATION-USING LAW AUTO-COMPOSES ITS AUDIT READ (co2 recovery DX, same idiom as the birth-meter
|
|
@@ -1906,7 +1948,7 @@ async function main(): Promise<void> {
|
|
|
1906
1948
|
? { dartImports: d.dartImports }
|
|
1907
1949
|
: {}),
|
|
1908
1950
|
...(d.dartRefImports !== undefined && d.dartRefImports.length > 0
|
|
1909
|
-
? { dartRefImports: d.dartRefImports }
|
|
1951
|
+
? { dartRefImports: [...d.dartRefImports] }
|
|
1910
1952
|
: {}),
|
|
1911
1953
|
...(permissionVocabulary !== undefined ? { permissionVocabulary } : {}),
|
|
1912
1954
|
}),
|
|
@@ -2037,6 +2079,13 @@ async function main(): Promise<void> {
|
|
|
2037
2079
|
}
|
|
2038
2080
|
}
|
|
2039
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
|
+
|
|
2040
2089
|
// ── STABLE-ID CONTINUITY (#58 — names are labels, identity is minted) ──
|
|
2041
2090
|
// Derive each composed domain's stable ids from the PRIOR compile: the committed
|
|
2042
2091
|
// `nomos.stable-ids.json` lockfile beside the config (the durable source — survives
|
|
@@ -2060,12 +2109,23 @@ async function main(): Promise<void> {
|
|
|
2060
2109
|
const identityName = mod.name;
|
|
2061
2110
|
// The CURRENT canonical aggregate schemas (a pre-continuity manifest pass —
|
|
2062
2111
|
// aggregates/schemas do not depend on continuity).
|
|
2063
|
-
let currentAggs: {
|
|
2112
|
+
let currentAggs: {
|
|
2113
|
+
id: string;
|
|
2114
|
+
schema: WireSchema;
|
|
2115
|
+
kinds?: Record<string, string>;
|
|
2116
|
+
global?: boolean;
|
|
2117
|
+
}[];
|
|
2064
2118
|
try {
|
|
2065
2119
|
const preManifest = domainManifest(mod);
|
|
2066
2120
|
currentAggs = preManifest.aggregates.map((a) => ({
|
|
2067
2121
|
id: a.id,
|
|
2068
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
|
+
),
|
|
2069
2129
|
// The CURRENT field kinds (off the pre-continuity stableIds emission) — the
|
|
2070
2130
|
// pair rule's kind axis ("rename + add a field" in one release still infers).
|
|
2071
2131
|
kinds: Object.fromEntries(
|
|
@@ -2149,7 +2209,7 @@ async function main(): Promise<void> {
|
|
|
2149
2209
|
// `connect()` negotiates compatibility by SHAPE (stable-id subtyping), not by law hash.
|
|
2150
2210
|
// architecture/shape_compatibility.md. Multiple modules sharing a domain key merge.
|
|
2151
2211
|
const packageInterface: Record<string, DomainInterface> = {};
|
|
2152
|
-
for (const mod of
|
|
2212
|
+
for (const mod of presentationDomainModules) {
|
|
2153
2213
|
const key = mod.domain ?? mod.name;
|
|
2154
2214
|
const di = domainInterface(mod, nextLock.domains[mod.name]?.stableIds);
|
|
2155
2215
|
const prior = packageInterface[key];
|
|
@@ -2171,7 +2231,7 @@ async function main(): Promise<void> {
|
|
|
2171
2231
|
// supported: each codegen layer mints a named recursive type for it (TS `type <Name>`, Dart
|
|
2172
2232
|
// recursive class). Surfaced here so the tenant sees which fields became which named types.
|
|
2173
2233
|
const recursiveNotes: string[] = [];
|
|
2174
|
-
for (const mod of
|
|
2234
|
+
for (const mod of presentationDomainModules) {
|
|
2175
2235
|
for (const d of (mod.directives ?? []) as Array<{ id?: unknown; payloadSchema?: unknown }>) {
|
|
2176
2236
|
if (!d || typeof d.id !== "string" || !d.payloadSchema || typeof d.payloadSchema !== "object") continue;
|
|
2177
2237
|
for (const { path, name } of recursiveLazyTypes(d.payloadSchema as Parameters<typeof recursiveLazyTypes>[0], d.id)) {
|
|
@@ -2306,6 +2366,24 @@ async function main(): Promise<void> {
|
|
|
2306
2366
|
// JS shim with the platform-native binary, which only an exec can run.
|
|
2307
2367
|
const esbuildBin = path.join(path.dirname(esbuildPkgJson), esbuildBinRel ?? "bin/esbuild");
|
|
2308
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
|
+
|
|
2309
2387
|
const compact = compactFlag || cfg.compact === true;
|
|
2310
2388
|
let javascript: string;
|
|
2311
2389
|
if (compact) {
|
|
@@ -2344,6 +2422,7 @@ async function main(): Promise<void> {
|
|
|
2344
2422
|
{ encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], cwd: cfgDir, maxBuffer: 256 * 1024 * 1024 },
|
|
2345
2423
|
).trimEnd() + "\n";
|
|
2346
2424
|
}
|
|
2425
|
+
javascript = canonicalizeEngineJavascript(javascript);
|
|
2347
2426
|
if (!/globalThis\.plan\s*=/.test(javascript) && !/globalThis\["plan"\]\s*=/.test(javascript)) {
|
|
2348
2427
|
fail(`bundled engine entry does not assign globalThis.plan — refusing to package`);
|
|
2349
2428
|
}
|
|
@@ -2437,7 +2516,7 @@ async function main(): Promise<void> {
|
|
|
2437
2516
|
"utf8",
|
|
2438
2517
|
);
|
|
2439
2518
|
try {
|
|
2440
|
-
execFileSync(process.execPath, [probePath, lumpPath, JSON.stringify(
|
|
2519
|
+
execFileSync(process.execPath, [probePath, lumpPath, JSON.stringify(domainsToCompile.map((d) => d.key))], {
|
|
2441
2520
|
encoding: "utf8",
|
|
2442
2521
|
stdio: ["ignore", "ignore", "pipe"],
|
|
2443
2522
|
});
|
|
@@ -2550,7 +2629,7 @@ async function main(): Promise<void> {
|
|
|
2550
2629
|
}
|
|
2551
2630
|
})();
|
|
2552
2631
|
const compatDomains: NomosCompat["domains"] = {};
|
|
2553
|
-
for (const m of
|
|
2632
|
+
for (const m of presentationDomainModules) {
|
|
2554
2633
|
const key = m.domain ?? m.name;
|
|
2555
2634
|
const identityHash = identity.hashes[key];
|
|
2556
2635
|
compatDomains[key] = identityHash === undefined ? {} : { identityHash };
|
|
@@ -2559,7 +2638,11 @@ async function main(): Promise<void> {
|
|
|
2559
2638
|
// era-key features). Baked into the client so connect() can check it against the target
|
|
2560
2639
|
// kernel's advertised capabilities BEFORE the law folds (kernel_capabilities.ts).
|
|
2561
2640
|
const requiresKernel = ((): string[] => {
|
|
2562
|
-
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
|
+
}));
|
|
2563
2646
|
try {
|
|
2564
2647
|
const parsed = JSON.parse(usdJson) as { layers?: Record<string, unknown>[] };
|
|
2565
2648
|
for (const layer of parsed.layers ?? []) probes.push({ layer });
|
|
@@ -2583,12 +2666,16 @@ async function main(): Promise<void> {
|
|
|
2583
2666
|
// the read overlay; the workspace's full spec is the runtime merge of installed packages' specs
|
|
2584
2667
|
// (currentLaw); the host ingests it and builds its router from it — no domain/directive name in host
|
|
2585
2668
|
// source. Self-describing for the whole web ecosystem (Swagger/codegen/Hono/agent tool-calling).
|
|
2586
|
-
const
|
|
2669
|
+
const publicOpenapi = mergeOpenApiFragments(
|
|
2587
2670
|
domainModules.map((m) => generateOpenApiFragment(m, { lawHash: domainHash })),
|
|
2588
2671
|
{ title: `${cfg.name} (nomos package)`, lawHash: domainHash },
|
|
2589
2672
|
);
|
|
2673
|
+
const runtimeOpenapi = mergeOpenApiFragments(
|
|
2674
|
+
domainModules.map((m) => generateOpenApiFragment(m, { lawHash: domainHash, includeFrameworkRoutes: true })),
|
|
2675
|
+
{ title: `${cfg.name} (nomos package)`, lawHash: domainHash },
|
|
2676
|
+
);
|
|
2590
2677
|
const openapiPath = path.join(outDir, `${cfg.name}.openapi.json`);
|
|
2591
|
-
writeFileSync(openapiPath, JSON.stringify(
|
|
2678
|
+
writeFileSync(openapiPath, JSON.stringify(publicOpenapi, null, 2) + "\n", "utf8");
|
|
2592
2679
|
|
|
2593
2680
|
// ── 4. the one-call deploy body (package only) ──
|
|
2594
2681
|
// SELF-DESCRIBING: `summary` states what the (otherwise hex-opaque) package
|
|
@@ -2598,7 +2685,7 @@ async function main(): Promise<void> {
|
|
|
2598
2685
|
const summary = {
|
|
2599
2686
|
package: cfg.name,
|
|
2600
2687
|
domainHash,
|
|
2601
|
-
domains:
|
|
2688
|
+
domains: presentationDomainModules.map((m) => ({
|
|
2602
2689
|
domain: m.domain ?? m.name,
|
|
2603
2690
|
aggregates: m.aggregates.map((a) => a.id),
|
|
2604
2691
|
directives: m.directives.map((d) => d.id),
|
|
@@ -2620,7 +2707,7 @@ async function main(): Promise<void> {
|
|
|
2620
2707
|
interface: packageInterface,
|
|
2621
2708
|
// THE SELF-DESCRIBING API: this package's OpenAPI spec (law-derived). The worker stages it on the
|
|
2622
2709
|
// manifest overlay; a read serves the workspace's merged spec; the host builds its router from it.
|
|
2623
|
-
openapi,
|
|
2710
|
+
openapi: runtimeOpenapi,
|
|
2624
2711
|
// THE CLIENT/LAW COMPAT MANIFEST (§5): a DIAGNOSIS surface (law hash + interface hash + generator
|
|
2625
2712
|
// provenance) the connect-time classifier reads. Frontend-only — the package bytes above ignore it.
|
|
2626
2713
|
nomosCompat,
|
|
@@ -2638,14 +2725,14 @@ async function main(): Promise<void> {
|
|
|
2638
2725
|
let birthWarnings: string[] = [];
|
|
2639
2726
|
let proofNotes: string[] = [];
|
|
2640
2727
|
try {
|
|
2641
|
-
const proofSrc = generateTsProof(
|
|
2728
|
+
const proofSrc = generateTsProof(presentationDomainModules, { packageName: cfg.name, domainHash, interface: packageInterface });
|
|
2642
2729
|
proofPath = path.join(outDir, `${cfg.name}.proof.mts`);
|
|
2643
2730
|
writeFileSync(proofPath, proofSrc, "utf8");
|
|
2644
2731
|
// THE PER-DOMAIN LEGS INDEX: every domain with a creating write, so
|
|
2645
2732
|
// `githolon proof --domain <key>` proves ANY of them offline (the .mts
|
|
2646
2733
|
// proves the primary one live). A multi-domain package no longer locks the
|
|
2647
2734
|
// proof to whichever domain happens to be first.
|
|
2648
|
-
const legsIndex = proofLegsIndex(
|
|
2735
|
+
const legsIndex = proofLegsIndex(presentationDomainModules, packageInterface);
|
|
2649
2736
|
if (legsIndex !== null) {
|
|
2650
2737
|
writeFileSync(path.join(outDir, `${cfg.name}.proof-legs.json`), JSON.stringify(legsIndex, null, 2) + "\n", "utf8");
|
|
2651
2738
|
proofDomains = Object.keys(legsIndex.domains);
|
|
@@ -2662,7 +2749,7 @@ async function main(): Promise<void> {
|
|
|
2662
2749
|
// itself failed, still derive the per-domain diagnostics (best-effort).
|
|
2663
2750
|
if (proofSkip !== undefined && birthWarnings.length === 0) {
|
|
2664
2751
|
try {
|
|
2665
|
-
const idx = proofLegsIndex(
|
|
2752
|
+
const idx = proofLegsIndex(presentationDomainModules, packageInterface);
|
|
2666
2753
|
if (idx !== null) {
|
|
2667
2754
|
birthWarnings = Object.values(idx.domains).flatMap((l) => l.birthDiagnostics ?? []);
|
|
2668
2755
|
proofNotes = Object.values(idx.domains).flatMap((l) => l.proofDiagnostics ?? []);
|
|
@@ -2680,7 +2767,7 @@ async function main(): Promise<void> {
|
|
|
2680
2767
|
` queries: ${d.queries.join(", ") || "—"} counts: ${d.counts.join(", ") || "—"} sums: ${d.sums.join(", ") || "—"}`,
|
|
2681
2768
|
]),
|
|
2682
2769
|
`deploy: POST ${cfg.name}.deploy.json to /v2/workspaces/<ws>/domains (or: githolon deploy <ws>)`,
|
|
2683
|
-
`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`,
|
|
2684
2771
|
proofPath !== undefined
|
|
2685
2772
|
? `generated proof: ${cfg.name}.proof.mts — run: githolon proof (live; ends ALL GREEN or names the jam)`
|
|
2686
2773
|
: `generated proof: SKIPPED — ${proofSkip}`,
|
|
@@ -2691,7 +2778,7 @@ async function main(): Promise<void> {
|
|
|
2691
2778
|
// ── 5. the typed TS client (#10 — the web sibling of codegen_dart), with the
|
|
2692
2779
|
// deployed law's content hash baked in (emitted AFTER the package is hashed) ──
|
|
2693
2780
|
const clientPath = path.join(outDir, `${cfg.name}.client.ts`);
|
|
2694
|
-
writeFileSync(clientPath, generateTsClient(
|
|
2781
|
+
writeFileSync(clientPath, generateTsClient(presentationDomainModules, { packageName: cfg.name, domainHash, interface: packageInterface, compat: nomosCompat }), "utf8");
|
|
2695
2782
|
|
|
2696
2783
|
// ── 6. the typed Dart frontend (opt-in; the Flutter sibling of step 5, emitted
|
|
2697
2784
|
// after the package hash like the TS client) ──
|
|
@@ -2737,7 +2824,7 @@ async function main(): Promise<void> {
|
|
|
2737
2824
|
// COMPILE ATOMICITY (co2): the Dart emit is transactional (beginAtomicGenDir) — a mid-emit fail()/throw
|
|
2738
2825
|
// restores the prior good packages instead of leaving them wiped/partial. Finalized at process exit.
|
|
2739
2826
|
if (dartPackages !== undefined) {
|
|
2740
|
-
const r = emitDartPackages(
|
|
2827
|
+
const r = emitDartPackages(presentationDomainModules, dartOut, domainHash, packageInterface, dartPackages, dartNames, nomosCompat, cfg.name);
|
|
2741
2828
|
dartFiles = r.written;
|
|
2742
2829
|
dartCursedHints = r.cursed;
|
|
2743
2830
|
} else {
|
|
@@ -2750,7 +2837,7 @@ async function main(): Promise<void> {
|
|
|
2750
2837
|
.replace(/^(?=[0-9])/, "n");
|
|
2751
2838
|
const dartBarrel =
|
|
2752
2839
|
typeof dartCfg === "object" && dartCfg.barrel !== undefined ? dartCfg.barrel : defaultBarrel;
|
|
2753
|
-
dartFiles = emitDart(
|
|
2840
|
+
dartFiles = emitDart(presentationDomainModules, dartOut, domainHash, packageInterface, dartSupportImport, dartBarrel, nomosCompat, dartNames, cfg.name);
|
|
2754
2841
|
}
|
|
2755
2842
|
// COMPILE-VALID MUST MEAN COMPILABLE (co2): `githolon compile` reported success while the generated Dart
|
|
2756
2843
|
// had hard compiler errors (a duplicate id symbol, missing contract-id defs). Run `dart analyze` over the
|
|
@@ -2801,16 +2888,29 @@ async function main(): Promise<void> {
|
|
|
2801
2888
|
}
|
|
2802
2889
|
return undefined;
|
|
2803
2890
|
})();
|
|
2804
|
-
|
|
2805
|
-
|
|
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.
|
|
2806
2894
|
for (const pkg of pkgDirs) {
|
|
2807
2895
|
if (localDart) {
|
|
2808
2896
|
const spec = readFileSync(path.join(pkg, "pubspec.yaml"), "utf8");
|
|
2809
2897
|
const lines = ["dependency_overrides:"];
|
|
2810
|
-
|
|
2811
|
-
|
|
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}`);
|
|
2812
2908
|
if (lines.length > 1) writeFileSync(path.join(pkg, "pubspec_overrides.yaml"), lines.join("\n") + "\n", "utf8");
|
|
2813
2909
|
}
|
|
2910
|
+
}
|
|
2911
|
+
let dartMissing = false;
|
|
2912
|
+
let unresolved: string | undefined;
|
|
2913
|
+
for (const pkg of pkgDirs) {
|
|
2814
2914
|
try {
|
|
2815
2915
|
execFileSync("dart", ["pub", "get"], { cwd: pkg, stdio: "pipe", encoding: "utf8" });
|
|
2816
2916
|
} catch (e) {
|
|
@@ -2861,20 +2961,23 @@ async function main(): Promise<void> {
|
|
|
2861
2961
|
}
|
|
2862
2962
|
{
|
|
2863
2963
|
const sum = (pick: (m: (typeof domainModules)[number]) => readonly unknown[] | undefined) =>
|
|
2864
|
-
|
|
2964
|
+
presentationDomainModules.reduce((n, m) => n + (pick(m)?.length ?? 0), 0);
|
|
2865
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)`);
|
|
2866
2966
|
}
|
|
2867
2967
|
// SECONDARY-CREATE AUTO-DECLARE (secondary_ensure.ts): surface every type the compiler sanctioned
|
|
2868
2968
|
// from a plan's deterministic secondary `ensure(...)` — the id-mint-gate DX made visible (the author
|
|
2869
2969
|
// wrote `ensure(B, …)`; the compiler declared `Ensure → B` so the deterministic id admits).
|
|
2870
|
-
for (const m of
|
|
2970
|
+
for (const m of presentationDomainModules) {
|
|
2871
2971
|
for (const ty of m.autoDeclaredEnsures ?? []) {
|
|
2872
2972
|
console.log(` ensure auto-declared Ensure→${ty} in '${m.domain ?? m.name}' from a plan's secondary ensure(...) (id-mint gate opened)`);
|
|
2873
2973
|
}
|
|
2874
2974
|
}
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
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}`);
|
|
2878
2981
|
// STABLE IDS (#58): the minted/carried identity surface + every INFERRED rename —
|
|
2879
2982
|
// the silent lane made visible (if an inference is wrong — you meant remove+add —
|
|
2880
2983
|
// split the edit into two compiles, or answer the evolve gate with a disposition).
|
|
@@ -2886,7 +2989,7 @@ async function main(): Promise<void> {
|
|
|
2886
2989
|
);
|
|
2887
2990
|
}
|
|
2888
2991
|
}
|
|
2889
|
-
for (const m of
|
|
2992
|
+
for (const m of presentationDomainModules) {
|
|
2890
2993
|
if (m.workspaceTypes !== undefined && m.workspaceTypes.length > 0) {
|
|
2891
2994
|
console.log(
|
|
2892
2995
|
` taxonomy ${m.domain ?? m.name}: ${m.workspaceTypes.length} workspace type(s) — homing derived from t.ref chains; birth lanes typed in the client`,
|
|
@@ -2895,7 +2998,7 @@ async function main(): Promise<void> {
|
|
|
2895
2998
|
}
|
|
2896
2999
|
console.log(` client ${rel(clientPath)} (typed TS client — payloads, read models, query accessors)`);
|
|
2897
3000
|
for (const note of recursiveNotes) console.log(` note ${note}`);
|
|
2898
|
-
console.log(` openapi ${rel(openapiPath)} (${Object.keys(
|
|
3001
|
+
console.log(` openapi ${rel(openapiPath)} (${Object.keys(publicOpenapi.paths).length} operation(s) — the public business API; private framework routes ride only in the deploy manifest)`);
|
|
2899
3002
|
if (proofPath !== undefined) {
|
|
2900
3003
|
console.log(` proof ${rel(proofPath)} (a runnable e2e GENERATED from your law — run: githolon proof)`);
|
|
2901
3004
|
} else {
|
|
@@ -2911,9 +3014,15 @@ async function main(): Promise<void> {
|
|
|
2911
3014
|
// gate's refusal vocabulary, unified into ONE report. `githolon check` runs the same pass;
|
|
2912
3015
|
// compile runs it implicitly and REFUSES on any refuse-level finding (a statically-provable
|
|
2913
3016
|
// runtime refusal shipped as law). Warns/notes are printed but never block the compile.
|
|
2914
|
-
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
|
+
);
|
|
2915
3024
|
if (checkFindings.length > 0) {
|
|
2916
|
-
console.log(` check ${checkFindings.length} finding(s) (githolon check):`);
|
|
3025
|
+
console.log(` check ${checkFindings.length} business-law finding(s) (githolon check):`);
|
|
2917
3026
|
for (const line of formatFindings(checkFindings)) {
|
|
2918
3027
|
const mark = line.includes("REFUSE") ? "✗" : line.includes("WARN") ? "⚠" : "•";
|
|
2919
3028
|
console.log(` ${mark} ${line}`);
|
|
@@ -2925,6 +3034,16 @@ async function main(): Promise<void> {
|
|
|
2925
3034
|
process.exitCode = 1;
|
|
2926
3035
|
}
|
|
2927
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
|
+
}
|
|
2928
3047
|
if (dartOut !== undefined) {
|
|
2929
3048
|
if (dartPackages !== undefined) {
|
|
2930
3049
|
const pkgList = [
|