@githolon/dsl 0.114.0 → 0.115.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/assets/operation-contract.wasm +0 -0
- package/dart/CHANGELOG.md +40 -0
- package/dart/lib/src/application_framework_calls.dart +7 -1
- package/dart/lib/src/console_enrolment.dart +7 -0
- package/dart/lib/src/console_http_io.dart +22 -15
- package/dart/lib/src/dev_cloud.dart +62 -0
- package/dart/lib/src/operation_receipts.dart +74 -7
- package/dart/lib/src/reception/dart_reception.dart +26 -6
- package/dart/lib/src/runner/node-entry.mjs +7129 -4424
- package/dart/lib/src/runtime_v2_transport.dart +3 -0
- package/dart/pubspec.lock +1 -1
- package/dart/pubspec.yaml +2 -2
- package/dart/test/console_enrolment_test.dart +47 -0
- package/dart/test/model_adoption_test.dart +49 -0
- package/dart/test/runtime_projections_test.dart +41 -0
- package/dart_types/CHANGELOG.md +24 -0
- package/dart_types/lib/src/approved_model.dart +78 -1
- package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pb.dart +528 -2
- package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pbenum.dart +24 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/correspondence_desk.pb.dart +1897 -112
- package/dart_types/lib/src/proto/nomos/runtime/v2/model_adoption_desk.pb.dart +98 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/records_desk.pb.dart +16 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pb.dart +43 -2
- package/dart_types/pubspec.yaml +1 -1
- package/package.json +4 -2
- package/src/aggregate.ts +93 -0
- package/src/anonymous_value_interning.ts +205 -0
- package/src/baseline.ts +27 -0
- package/src/baseline_export.ts +432 -0
- package/src/baseline_import.ts +312 -0
- package/src/baseline_usda.ts +186 -0
- package/src/birth_key_rule.ts +472 -0
- package/src/births.ts +207 -24
- package/src/build_provenance.ts +10 -0
- package/src/business_birth.ts +50 -4
- package/src/check_package_main.ts +50 -6
- package/src/codegen_call_proto.ts +5 -18
- package/src/codegen_dart.ts +95 -3
- package/src/codegen_dart_client.ts +52 -6
- package/src/codegen_dart_facade.ts +57 -35
- package/src/codegen_dart_framework_calls.ts +20 -1
- package/src/codegen_proof.ts +5 -2
- package/src/codegen_result_proto.ts +8 -6
- package/src/codegen_result_usda.ts +4 -0
- package/src/codegen_ts.ts +109 -10
- package/src/compatibility_graph.ts +41 -4
- package/src/compatibility_usda.ts +11 -1
- package/src/compile_package_main.ts +214 -51
- package/src/composed_wire_identity.ts +24 -0
- package/src/directive.ts +6 -0
- package/src/domain_requirements.ts +75 -0
- package/src/engine_javascript.ts +12 -6
- package/src/fields.ts +109 -0
- package/src/identity_usda.ts +77 -51
- package/src/index.ts +25 -1
- package/src/intent.ts +5 -0
- package/src/law_graph.ts +142 -1
- package/src/law_graph_usda.ts +25 -141
- package/src/law_layer_prims.ts +199 -0
- package/src/law_unit_selection.ts +45 -0
- package/src/law_version.ts +107 -0
- package/src/package_config.ts +44 -0
- package/src/package_dependencies.ts +8 -0
- package/src/value_object.ts +6 -3
- package/src/wire.ts +2 -0
- package/src/wire_paths.ts +17 -0
- package/src/workspace_routing.ts +1 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { collectPackageSources, findBirthKeyWrites, formatBirthKeyWriteWarnings } from "./birth_key_rule.js";
|
|
1
2
|
import type { Directive } from "./directive.js";
|
|
2
3
|
// NOMOS — Nomos Sovereign: participants act · verify · remember LOCALLY; hosted
|
|
3
4
|
// remotes are replaceable custody/transport, not truth. ⇒ ONE Nomos GitHolon
|
|
@@ -46,6 +47,7 @@ import type { Directive } from "./directive.js";
|
|
|
46
47
|
import { execFile, execFileSync } from "node:child_process";
|
|
47
48
|
import { promisify } from "node:util";
|
|
48
49
|
import { checkOperationContracts, deriveInterfaceOffer } from "./operation_contract_check.js";
|
|
50
|
+
import { lawVersionClaim, type LawVersionClaim } from "./law_version.js";
|
|
49
51
|
import { compilerIntermediateCacheRoot, compilerSourceName, compilerSourceRoot } from "./compiler_cache.js";
|
|
50
52
|
import {
|
|
51
53
|
APPLICATION_CONTRACT_MODULE,
|
|
@@ -80,6 +82,7 @@ import ts from "typescript";
|
|
|
80
82
|
import type { AggregateHandle } from "./aggregate.js";
|
|
81
83
|
import {
|
|
82
84
|
generateDartDomain,
|
|
85
|
+
dartBrandNamesForModule,
|
|
83
86
|
generateDartContracts,
|
|
84
87
|
generateDartActivityRegistry,
|
|
85
88
|
collectActivityDescriptors,
|
|
@@ -97,6 +100,8 @@ import {
|
|
|
97
100
|
} from "./evolution_files.js";
|
|
98
101
|
import { assertEvolutionModuleExports } from "./evolution.js";
|
|
99
102
|
import { readHistoricalIdentityFrontier } from "./identity_frontier.js";
|
|
103
|
+
import { parseBaselineUsda, type ReleasedBaseline } from "./baseline_usda.js";
|
|
104
|
+
import { BaselineRefusal, assertBaselineRetained, importBaseline, verifyBaselinePin } from "./baseline_import.js";
|
|
100
105
|
import {
|
|
101
106
|
dartBridgeClientOperationDirectiveIds,
|
|
102
107
|
generateDartDomainClient,
|
|
@@ -266,6 +271,7 @@ import {
|
|
|
266
271
|
splitLawUnits,
|
|
267
272
|
} from "./law_units.js";
|
|
268
273
|
import { lawUnitSetIdentityWith } from "./law_unit_set_identity.js";
|
|
274
|
+
import { domainRequirementsOf, type DomainUnitRequirement } from "./domain_requirements.js";
|
|
269
275
|
import { checkDomainModules, formatFindings, hasRefusal } from "./law_check.js";
|
|
270
276
|
import {
|
|
271
277
|
currentEvolveLaw,
|
|
@@ -624,6 +630,7 @@ const compareLogicalPath = (left: string, right: string): number =>
|
|
|
624
630
|
* inventories the USDZ/Git tree and re-hashes every logically named layer. */
|
|
625
631
|
function emitLawClosure(
|
|
626
632
|
packageName: string,
|
|
633
|
+
claimedVersion: LawVersionClaim | undefined,
|
|
627
634
|
exportedDomains: readonly string[],
|
|
628
635
|
runtimeDependencies: readonly RuntimePackageDependency[],
|
|
629
636
|
domainAssets: readonly EmittedLawClosureAsset[],
|
|
@@ -670,6 +677,7 @@ function emitLawClosure(
|
|
|
670
677
|
"package.usda",
|
|
671
678
|
packageContractUsda({
|
|
672
679
|
packageName,
|
|
680
|
+
...(claimedVersion === undefined ? {} : { claimedVersion }),
|
|
673
681
|
exportedDomains,
|
|
674
682
|
runtimeDependencies,
|
|
675
683
|
})
|
|
@@ -1265,6 +1273,7 @@ function closeComposedBusinessBirthPresentation(
|
|
|
1265
1273
|
aggregateId?: unknown;
|
|
1266
1274
|
rootId?: unknown;
|
|
1267
1275
|
namespace?: unknown;
|
|
1276
|
+
keyMode?: unknown;
|
|
1268
1277
|
keyField?: unknown;
|
|
1269
1278
|
};
|
|
1270
1279
|
type BirthDirective = DomainModule["directives"][number] & {
|
|
@@ -1278,14 +1287,15 @@ function closeComposedBusinessBirthPresentation(
|
|
|
1278
1287
|
typeof birth.aggregateId !== "string" ||
|
|
1279
1288
|
typeof birth.rootId !== "string" ||
|
|
1280
1289
|
typeof birth.namespace !== "string" ||
|
|
1281
|
-
typeof birth.keyField !== "string"
|
|
1290
|
+
(typeof birth.keyField !== "string" && birth.keyMode !== "minted")
|
|
1282
1291
|
)
|
|
1283
1292
|
return undefined;
|
|
1284
1293
|
return [
|
|
1285
1294
|
birth.aggregateId,
|
|
1286
1295
|
birth.rootId,
|
|
1287
1296
|
birth.namespace,
|
|
1288
|
-
birth.
|
|
1297
|
+
// A minted birth has no key field; its identity here is the minted mode itself.
|
|
1298
|
+
typeof birth.keyField === "string" ? birth.keyField : "\u0001minted",
|
|
1289
1299
|
].join("\u0000");
|
|
1290
1300
|
};
|
|
1291
1301
|
|
|
@@ -1335,6 +1345,8 @@ interface DartSharedSymbols {
|
|
|
1335
1345
|
readonly frameworkDirIds: ReadonlySet<string>;
|
|
1336
1346
|
readonly frameworkQueryIds: ReadonlySet<string>;
|
|
1337
1347
|
readonly sharedVoNames: ReadonlySet<string>;
|
|
1348
|
+
/** Branded-id extension types used by ≥2 domains — declared ONCE in the framework file. */
|
|
1349
|
+
readonly sharedBrandNames: ReadonlySet<string>;
|
|
1338
1350
|
readonly hasFrameworkSymbols: boolean;
|
|
1339
1351
|
/** The synthetic module whose emit IS `nomos_framework.dart` — undefined when nothing is shared. */
|
|
1340
1352
|
readonly frameworkMod: DomainModule | undefined;
|
|
@@ -1496,11 +1508,23 @@ function collectDartSharedSymbols(
|
|
|
1496
1508
|
const sharedVos = [...sharedVoNames]
|
|
1497
1509
|
.sort()
|
|
1498
1510
|
.map((name) => voDescriptorByName.get(name)!);
|
|
1511
|
+
// TYPED IDS: a branded id used by two domains (a parent's business-birth payload and the child's key
|
|
1512
|
+
// field, typically) would otherwise declare one extension type per file and make the barrel ambiguous.
|
|
1513
|
+
const brandDomains = new Map<string, number>();
|
|
1514
|
+
for (const mod of modules) {
|
|
1515
|
+
for (const brand of dartBrandNamesForModule(mod)) {
|
|
1516
|
+
brandDomains.set(brand, (brandDomains.get(brand) ?? 0) + 1);
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
const sharedBrandNames: ReadonlySet<string> = new Set(
|
|
1520
|
+
[...brandDomains.entries()].filter(([, n]) => n > 1).map(([name]) => name).sort()
|
|
1521
|
+
);
|
|
1499
1522
|
const hasFrameworkSymbols =
|
|
1500
1523
|
frameworkAggs.length > 0 ||
|
|
1501
1524
|
frameworkDirs.length > 0 ||
|
|
1502
1525
|
frameworkQueries.length > 0 ||
|
|
1503
|
-
sharedVos.length > 0
|
|
1526
|
+
sharedVos.length > 0 ||
|
|
1527
|
+
sharedBrandNames.size > 0;
|
|
1504
1528
|
const frameworkMod: DomainModule | undefined = hasFrameworkSymbols
|
|
1505
1529
|
? {
|
|
1506
1530
|
name: FRAMEWORK_FILE,
|
|
@@ -1518,6 +1542,7 @@ function collectDartSharedSymbols(
|
|
|
1518
1542
|
frameworkDirIds: new Set(frameworkDirById.keys()),
|
|
1519
1543
|
frameworkQueryIds: new Set(frameworkQueryById.keys()),
|
|
1520
1544
|
sharedVoNames,
|
|
1545
|
+
sharedBrandNames,
|
|
1521
1546
|
hasFrameworkSymbols,
|
|
1522
1547
|
frameworkMod,
|
|
1523
1548
|
};
|
|
@@ -1535,6 +1560,7 @@ function domainDedupOpts(
|
|
|
1535
1560
|
readonly skipDirectiveIds: Set<string>;
|
|
1536
1561
|
readonly skipQueryIds: Set<string>;
|
|
1537
1562
|
readonly skipValueObjectNames: Set<string>;
|
|
1563
|
+
readonly skipBrandNames: Set<string>;
|
|
1538
1564
|
};
|
|
1539
1565
|
readonly foldsFramework: boolean;
|
|
1540
1566
|
} {
|
|
@@ -1562,11 +1588,17 @@ function domainDedupOpts(
|
|
|
1562
1588
|
.filter((d) => shared.sharedVoNames.has(d.name))
|
|
1563
1589
|
.map((d) => d.name)
|
|
1564
1590
|
);
|
|
1591
|
+
const skipBrandNames = new Set(
|
|
1592
|
+
[...dartBrandNamesForModule(modForDart)].filter((name) =>
|
|
1593
|
+
shared.sharedBrandNames.has(name)
|
|
1594
|
+
)
|
|
1595
|
+
);
|
|
1565
1596
|
const foldsFramework =
|
|
1566
1597
|
skipAggregateIds.size > 0 ||
|
|
1567
1598
|
skipDirectiveIds.size > 0 ||
|
|
1568
1599
|
skipQueryIds.size > 0 ||
|
|
1569
|
-
skipValueObjectNames.size > 0
|
|
1600
|
+
skipValueObjectNames.size > 0 ||
|
|
1601
|
+
skipBrandNames.size > 0;
|
|
1570
1602
|
return {
|
|
1571
1603
|
modForDart,
|
|
1572
1604
|
skips: {
|
|
@@ -1574,6 +1606,7 @@ function domainDedupOpts(
|
|
|
1574
1606
|
skipDirectiveIds,
|
|
1575
1607
|
skipQueryIds,
|
|
1576
1608
|
skipValueObjectNames,
|
|
1609
|
+
skipBrandNames,
|
|
1577
1610
|
},
|
|
1578
1611
|
foldsFramework,
|
|
1579
1612
|
};
|
|
@@ -2146,6 +2179,8 @@ function emitDartOperationProto(
|
|
|
2146
2179
|
interface CompiledLawIdentities {
|
|
2147
2180
|
readonly unitSet: string;
|
|
2148
2181
|
readonly packageSha256: string;
|
|
2182
|
+
/** One requirement per application domain (CAP-666): its unit hash and its generated requirement identity. */
|
|
2183
|
+
readonly domainRequirements: readonly DomainUnitRequirement[];
|
|
2149
2184
|
}
|
|
2150
2185
|
|
|
2151
2186
|
function emitDart(
|
|
@@ -2227,7 +2262,7 @@ function emitDart(
|
|
|
2227
2262
|
? []
|
|
2228
2263
|
: [{ module, graph, paths }];
|
|
2229
2264
|
}),
|
|
2230
|
-
{ lawUnitSet: law.unitSet, lawPackageSha256: law.packageSha256 }
|
|
2265
|
+
{ lawUnitSet: law.unitSet, lawPackageSha256: law.packageSha256, domainRequirements: law.domainRequirements }
|
|
2231
2266
|
);
|
|
2232
2267
|
if (applicationFrameworkCallsSource !== undefined) {
|
|
2233
2268
|
const applicationFrameworkCallsPath = path.join(
|
|
@@ -2249,6 +2284,7 @@ function emitDart(
|
|
|
2249
2284
|
FRAMEWORK_FILE,
|
|
2250
2285
|
generateDartDomain(shared.frameworkMod, {
|
|
2251
2286
|
additionalValueObjects: shared.frameworkMod.valueObjects ?? [],
|
|
2287
|
+
extraBrandNames: [...shared.sharedBrandNames],
|
|
2252
2288
|
})
|
|
2253
2289
|
);
|
|
2254
2290
|
}
|
|
@@ -2542,12 +2578,12 @@ const dartTypesImportFor = (generatedSource: string): string => {
|
|
|
2542
2578
|
* just the floor generated code needs — a lagging pin forces tenants into dependency_overrides. */
|
|
2543
2579
|
// 0.3.0: SurfacedValue<T>/SurfacedObservation/PendingConflictRow — generated Surfaced-field typing +
|
|
2544
2580
|
// the pendingConflicts read rows.
|
|
2545
|
-
const NOMOS_TYPES_DEP = "^0.
|
|
2581
|
+
const NOMOS_TYPES_DEP = "^0.14.0";
|
|
2546
2582
|
// 0.48.x: session-bound clients (XClient.bind/NomosClientInterface/DomainClientSessionMismatch/
|
|
2547
2583
|
// DomainNotInstalledForSession, engine.follow, pendingConflicts lanes) — the generated client
|
|
2548
2584
|
// REQUIRES this surface. 0.48.1 fixes NomosSession.watchPendingConflicts delegation.
|
|
2549
|
-
const NOMOS_CLIENT_DEP = "^0.
|
|
2550
|
-
const NOMOS_FLUTTER_DEP = "^0.
|
|
2585
|
+
const NOMOS_CLIENT_DEP = "^0.69.0";
|
|
2586
|
+
const NOMOS_FLUTTER_DEP = "^0.68.0";
|
|
2551
2587
|
// DRIFT TRIPWIRE: pubspec_pins.test.ts asserts these equal the CURRENT versions in the Dart and Flutter
|
|
2552
2588
|
// package pubspecs — a release without this bump fails the suite, so tenants never
|
|
2553
2589
|
// land back in dependency_overrides (the exact co2 report this closes, third occurrence).
|
|
@@ -3390,6 +3426,7 @@ function emitDartPackages(
|
|
|
3390
3426
|
FRAMEWORK_FILE,
|
|
3391
3427
|
generateDartDomain(shared.frameworkMod, {
|
|
3392
3428
|
additionalValueObjects: shared.frameworkMod.valueObjects ?? [],
|
|
3429
|
+
extraBrandNames: [...shared.sharedBrandNames],
|
|
3393
3430
|
})
|
|
3394
3431
|
);
|
|
3395
3432
|
}
|
|
@@ -3680,7 +3717,7 @@ function emitDartPackages(
|
|
|
3680
3717
|
? []
|
|
3681
3718
|
: [{ module, graph, paths }];
|
|
3682
3719
|
}),
|
|
3683
|
-
{ lawUnitSet: law.unitSet, lawPackageSha256: law.packageSha256 }
|
|
3720
|
+
{ lawUnitSet: law.unitSet, lawPackageSha256: law.packageSha256, domainRequirements: law.domainRequirements }
|
|
3684
3721
|
);
|
|
3685
3722
|
const workspaceAccessReadImports = new Map<string, string>();
|
|
3686
3723
|
for (const module of operationProtoModules) {
|
|
@@ -4205,6 +4242,7 @@ async function main(): Promise<void> {
|
|
|
4205
4242
|
"--preflight",
|
|
4206
4243
|
"--inspect-sqlite",
|
|
4207
4244
|
"--inspect-law",
|
|
4245
|
+
"--publishable",
|
|
4208
4246
|
]);
|
|
4209
4247
|
for (const flag of argv.filter((arg) => arg.startsWith("--"))) {
|
|
4210
4248
|
if (supportedFlags.has(flag)) continue;
|
|
@@ -4240,6 +4278,9 @@ async function main(): Promise<void> {
|
|
|
4240
4278
|
// `dart analyze` on the generated Dart package after emission and fails the compile on red.
|
|
4241
4279
|
const analyzeFlag =
|
|
4242
4280
|
argv.includes("--analyze") || process.env.NOMOS_ANALYZE === "1";
|
|
4281
|
+
// A PUBLISHABLE compile (architecture/domain_release_lifecycle.md, step 1) must start from the
|
|
4282
|
+
// baseline exported from released custody: it refuses without a pinned `nomos.baseline.usda`.
|
|
4283
|
+
const publishableFlag = argv.includes("--publishable");
|
|
4243
4284
|
const configArg = argv.find((a) => !a.startsWith("--")) ?? "nomos.project.ts";
|
|
4244
4285
|
const configPath = path.resolve(process.cwd(), configArg);
|
|
4245
4286
|
if (!existsSync(configPath)) fail(`config not found: ${configPath}`);
|
|
@@ -4324,6 +4365,39 @@ async function main(): Promise<void> {
|
|
|
4324
4365
|
"nomos.project.ts no longer accepts 'layered': every law closure is layered, with no alternate compile lane"
|
|
4325
4366
|
);
|
|
4326
4367
|
}
|
|
4368
|
+
// ── THE RELEASED BASELINE (CAP-660) ──────────────────────────────────────────────────────────
|
|
4369
|
+
// `nomos.project.ts` pins the baseline by content address. Verify the bytes are the pinned ones
|
|
4370
|
+
// and read it now, before any identity is touched; the import and the retention proof follow.
|
|
4371
|
+
const baselineRefused = (error: unknown): never => {
|
|
4372
|
+
if (error instanceof BaselineRefusal) fail(`[${error.code}] ${error.message}`);
|
|
4373
|
+
throw error;
|
|
4374
|
+
};
|
|
4375
|
+
let releasedBaseline: ReleasedBaseline | undefined;
|
|
4376
|
+
let releasedBaselineSha256: string | undefined;
|
|
4377
|
+
if (cfg.baseline === undefined) {
|
|
4378
|
+
if (publishableFlag) {
|
|
4379
|
+
fail(
|
|
4380
|
+
"[baseline-required] a publishable compile must name the released baseline it extends: " +
|
|
4381
|
+
`run \`githolon baseline export --units build/${cfg.name}.units\` (or --release <id>) against the release ` +
|
|
4382
|
+
"you are extending, commit nomos.baseline.usda, and pin it in nomos.project.ts as " +
|
|
4383
|
+
"baseline: { artifact: \"./nomos.baseline.usda\", sha256: \"<printed sha256>\" }"
|
|
4384
|
+
);
|
|
4385
|
+
}
|
|
4386
|
+
} else {
|
|
4387
|
+
const baselinePath = path.resolve(cfgDir, cfg.baseline.artifact);
|
|
4388
|
+
if (!existsSync(baselinePath)) {
|
|
4389
|
+
fail(`[baseline-unreadable] pinned baseline not found: ${baselinePath}`);
|
|
4390
|
+
}
|
|
4391
|
+
const baselineText = readFileSync(baselinePath, "utf8");
|
|
4392
|
+
try {
|
|
4393
|
+
verifyBaselinePin(baselineText, cfg.baseline);
|
|
4394
|
+
releasedBaseline = parseBaselineUsda(baselineText);
|
|
4395
|
+
} catch (error) {
|
|
4396
|
+
if (error instanceof BaselineRefusal) baselineRefused(error);
|
|
4397
|
+
fail(`[baseline-unreadable] ${cfg.baseline.artifact}: ${(error as Error).message}`);
|
|
4398
|
+
}
|
|
4399
|
+
releasedBaselineSha256 = cfg.baseline.sha256;
|
|
4400
|
+
}
|
|
4327
4401
|
let sourceTopologyDiagnostics: ReturnType<
|
|
4328
4402
|
typeof assertPackageFeatureTopology
|
|
4329
4403
|
> = [];
|
|
@@ -4395,6 +4469,7 @@ async function main(): Promise<void> {
|
|
|
4395
4469
|
if (cfg.rootPart !== undefined) {
|
|
4396
4470
|
applicationBirthPolicyDomains.push(APPLICATION_HOME_DOMAIN);
|
|
4397
4471
|
}
|
|
4472
|
+
const authoredDomainModules: Mod[] = [];
|
|
4398
4473
|
for (const domain of cfg.domains) {
|
|
4399
4474
|
let authored: Mod = {};
|
|
4400
4475
|
for (const rel of domain.modules) {
|
|
@@ -4420,10 +4495,32 @@ async function main(): Promise<void> {
|
|
|
4420
4495
|
}
|
|
4421
4496
|
}
|
|
4422
4497
|
const expanded = expandBusinessBirthExports(authored, domain.key);
|
|
4498
|
+
authoredDomainModules.push(authored);
|
|
4423
4499
|
if (directivesOf(expanded).some((dir) => dir.birthsChild === true)) {
|
|
4424
4500
|
applicationBirthPolicyDomains.push(domain.key);
|
|
4425
4501
|
}
|
|
4426
4502
|
}
|
|
4503
|
+
// A workspace name is fixed at birth, and the framework enforces it at the kernel: every field-keyed
|
|
4504
|
+
// birth's key is write-once (aggregate.ts BIRTH_KEY_WRITE_ONCE_CODE). Statically WARN at each source line
|
|
4505
|
+
// that writes a key outside the birth in a way that rule will refuse, or that keys another instance
|
|
4506
|
+
// (CAP-804; architecture/choosing_a_birth_key.md). Advisory only — the runtime rule is the guarantee.
|
|
4507
|
+
{
|
|
4508
|
+
const birthKeyWarnings = findBirthKeyWrites(
|
|
4509
|
+
authoredDomainModules,
|
|
4510
|
+
collectPackageSources(
|
|
4511
|
+
cfg.domains.flatMap((domain) => domain.modules.map((rel) => path.resolve(cfgDir, rel))),
|
|
4512
|
+
cfgDir
|
|
4513
|
+
),
|
|
4514
|
+
{ root: cfgDir }
|
|
4515
|
+
);
|
|
4516
|
+
if (birthKeyWarnings.length > 0) {
|
|
4517
|
+
console.warn(
|
|
4518
|
+
`nomos-compile: ${birthKeyWarnings.length} birth-key write warning(s)`
|
|
4519
|
+
);
|
|
4520
|
+
for (const line of formatBirthKeyWriteWarnings(birthKeyWarnings))
|
|
4521
|
+
console.warn(line);
|
|
4522
|
+
}
|
|
4523
|
+
}
|
|
4427
4524
|
stage("domain discovery imports");
|
|
4428
4525
|
if (
|
|
4429
4526
|
cfg.application?.homeGenesis !== undefined &&
|
|
@@ -5617,12 +5714,36 @@ async function main(): Promise<void> {
|
|
|
5617
5714
|
? parseIdentityUsda(readFileSync(lockPath, "utf8"))
|
|
5618
5715
|
: undefined;
|
|
5619
5716
|
const historicalFrontier = readHistoricalIdentityFrontier(lockPath);
|
|
5717
|
+
// Outside Git custody (a clean export, a CI checkout without history) the released baseline IS
|
|
5718
|
+
// the evolution frontier: it carries every released aggregate and field by sid, so a removal
|
|
5719
|
+
// without a declared retirement still refuses. It carries no value contracts, so it never
|
|
5720
|
+
// produces a false in-place refusal.
|
|
5620
5721
|
const historicalLock: CompilerIdentityModel | undefined =
|
|
5621
5722
|
historicalFrontier === undefined
|
|
5622
|
-
?
|
|
5723
|
+
? releasedBaseline?.continuity
|
|
5623
5724
|
: parseIdentityUsda(historicalFrontier.source);
|
|
5624
5725
|
const inferredRenames: { domain: string; renames: InferredRename[] }[] = [];
|
|
5625
5726
|
let nextIdentity = identityRegistryFromModel(priorLock);
|
|
5727
|
+
if (releasedBaseline !== undefined) {
|
|
5728
|
+
// Verify the ledger against released custody and import what it lacks, so a clean checkout
|
|
5729
|
+
// allocates the released sids and wire keys rather than fresh ones, and a diverged branch
|
|
5730
|
+
// refuses with the coordinate named (baseline_import.ts).
|
|
5731
|
+
try {
|
|
5732
|
+
const imported = importBaseline(
|
|
5733
|
+
nextIdentity,
|
|
5734
|
+
releasedBaseline,
|
|
5735
|
+
cfg.domains.flatMap((domain) => [domain.key, ...(domain.name === undefined ? [] : [domain.name])])
|
|
5736
|
+
);
|
|
5737
|
+
nextIdentity = imported.registry;
|
|
5738
|
+
console.log(
|
|
5739
|
+
`baseline: ${releasedBaseline.release === "none" ? "unreleased units" : `release ${releasedBaseline.release}`} ` +
|
|
5740
|
+
`(law ${releasedBaseline.unitSet}) — ${imported.verified} verified, ${imported.imported.length} identit${imported.imported.length === 1 ? "y" : "ies"} ` +
|
|
5741
|
+
`and ${imported.allocated.length} wire allocation(s) imported${imported.relabelled.length === 0 ? "" : `, ${imported.relabelled.length} released rename(s) carried`}`
|
|
5742
|
+
);
|
|
5743
|
+
} catch (error) {
|
|
5744
|
+
baselineRefused(error);
|
|
5745
|
+
}
|
|
5746
|
+
}
|
|
5626
5747
|
const typedLawGraphs = new Map<string, LawGraph>();
|
|
5627
5748
|
// The lock is project-wide, not package-local. Several package configs commonly live beside one
|
|
5628
5749
|
// application stage; compiling one must not erase the stable identity of domains owned by its siblings.
|
|
@@ -5832,6 +5953,18 @@ async function main(): Promise<void> {
|
|
|
5832
5953
|
return;
|
|
5833
5954
|
}
|
|
5834
5955
|
|
|
5956
|
+
// ── BASELINE RETENTION PROOF (CAP-660) ───────────────────────────────────────────
|
|
5957
|
+
// Every released identity still resolves to its released sid and every released wire key is still
|
|
5958
|
+
// the canonical allocation. Reconciliation never rewrites an allocation, so this holds by
|
|
5959
|
+
// construction; proving it here keeps "the candidate extends the release" a checked fact.
|
|
5960
|
+
if (releasedBaseline !== undefined) {
|
|
5961
|
+
try {
|
|
5962
|
+
assertBaselineRetained(nextIdentity, releasedBaseline);
|
|
5963
|
+
} catch (error) {
|
|
5964
|
+
baselineRefused(error);
|
|
5965
|
+
}
|
|
5966
|
+
}
|
|
5967
|
+
|
|
5835
5968
|
// ── ORDINARY-COMPILE EVOLUTION GATE ──────────────────────────────────────────────
|
|
5836
5969
|
// Agents reliably run `compile`; they do not reliably discover an optional migration command.
|
|
5837
5970
|
// Compare the candidate against the committed identity frontier here, after stable-id
|
|
@@ -5910,6 +6043,44 @@ async function main(): Promise<void> {
|
|
|
5910
6043
|
// giant formatting-only diff in an established lock.
|
|
5911
6044
|
writeFileSync(lockPath, serializeIdentityUsda(nextLock), "utf8");
|
|
5912
6045
|
|
|
6046
|
+
// USDA is rendered directly from the typed graph. The final closure writer below publishes these
|
|
6047
|
+
// exact texts under their logical paths; no parallel layer directory or JSON reconstruction exists.
|
|
6048
|
+
const v3Closure = [...typedLawGraphs.values()];
|
|
6049
|
+
const v3DomainAssets: EmittedLawClosureAsset[] = [];
|
|
6050
|
+
const v3DomainRoots: string[] = [];
|
|
6051
|
+
const v3LawPathByNode = new Map<LawGraph["nodes"][number], string>();
|
|
6052
|
+
const v3CompiledGraphs = new Map<LawGraph, ReturnType<typeof compileSparseLawGraphUsda>>();
|
|
6053
|
+
const typedDomainIdentityByName = new Map<string, string>();
|
|
6054
|
+
const typedLawPathsByName = new Map<string, ReadonlyMap<string, string>>();
|
|
6055
|
+
for (const [domain, graph] of typedLawGraphs) {
|
|
6056
|
+
const safeDomain = domain.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
6057
|
+
const logicalPath = `domains/${safeDomain}.usda`;
|
|
6058
|
+
const compiledLayer = compileSparseLawGraphUsda(
|
|
6059
|
+
graph,
|
|
6060
|
+
logicalPath,
|
|
6061
|
+
v3Closure
|
|
6062
|
+
);
|
|
6063
|
+
v3CompiledGraphs.set(graph, compiledLayer);
|
|
6064
|
+
const layerText = compiledLayer.text;
|
|
6065
|
+
const sha256 = sha256HexUtf8(layerText);
|
|
6066
|
+
v3DomainAssets.push({
|
|
6067
|
+
logicalPath,
|
|
6068
|
+
sha256,
|
|
6069
|
+
utf8: layerText,
|
|
6070
|
+
});
|
|
6071
|
+
const domainRoot = compiledLayer.paths.get(graph.domain.entity.id);
|
|
6072
|
+
if (domainRoot === undefined) {
|
|
6073
|
+
fail(`domain '${domain}' did not emit its canonical OpenUSD root path`);
|
|
6074
|
+
}
|
|
6075
|
+
v3DomainRoots.push(domainRoot);
|
|
6076
|
+
for (const node of graph.nodes) {
|
|
6077
|
+
const lawPath = compiledLayer.paths.get(node.entity.id);
|
|
6078
|
+
if (lawPath !== undefined) v3LawPathByNode.set(node, lawPath);
|
|
6079
|
+
}
|
|
6080
|
+
typedDomainIdentityByName.set(domain, sha256);
|
|
6081
|
+
typedLawPathsByName.set(domain, compiledLayer.paths);
|
|
6082
|
+
}
|
|
6083
|
+
|
|
5913
6084
|
// ── THE STRUCTURAL INTERFACE (#72) — directives (payload shapes) + aggregates (read
|
|
5914
6085
|
// shapes, sid-keyed), keyed by DOMAIN. The SAME object is (a) baked into the generated
|
|
5915
6086
|
// clients as their requirement and (b) staged on the deploy as the workspace's offer, so
|
|
@@ -5924,7 +6095,12 @@ async function main(): Promise<void> {
|
|
|
5924
6095
|
`compiler surface invariant: domain '${key}' has no typed USDA graph`
|
|
5925
6096
|
);
|
|
5926
6097
|
}
|
|
5927
|
-
|
|
6098
|
+
// Nested record members carry the allocation the generated codecs encode them under, which
|
|
6099
|
+
// follows the composed layer's canonical prim (CAP-681).
|
|
6100
|
+
const offeredInterface = domainInterfaceFromLawGraph(
|
|
6101
|
+
graph,
|
|
6102
|
+
typedLawPathsByName.get(mod.name)
|
|
6103
|
+
);
|
|
5928
6104
|
const di = publicClientInterface([mod], { [key]: offeredInterface })[key]!;
|
|
5929
6105
|
const graphRoutes = graph.nodes
|
|
5930
6106
|
.filter((node) => node.kind === "intent" && node.public)
|
|
@@ -6017,44 +6193,6 @@ async function main(): Promise<void> {
|
|
|
6017
6193
|
}
|
|
6018
6194
|
}
|
|
6019
6195
|
|
|
6020
|
-
// USDA is rendered directly from the typed graph. The final closure writer below publishes these
|
|
6021
|
-
// exact texts under their logical paths; no parallel layer directory or JSON reconstruction exists.
|
|
6022
|
-
const v3Closure = [...typedLawGraphs.values()];
|
|
6023
|
-
const v3DomainAssets: EmittedLawClosureAsset[] = [];
|
|
6024
|
-
const v3DomainRoots: string[] = [];
|
|
6025
|
-
const v3LawPathByNode = new Map<LawGraph["nodes"][number], string>();
|
|
6026
|
-
const v3CompiledGraphs = new Map<LawGraph, ReturnType<typeof compileSparseLawGraphUsda>>();
|
|
6027
|
-
const typedDomainIdentityByName = new Map<string, string>();
|
|
6028
|
-
const typedLawPathsByName = new Map<string, ReadonlyMap<string, string>>();
|
|
6029
|
-
for (const [domain, graph] of typedLawGraphs) {
|
|
6030
|
-
const safeDomain = domain.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
6031
|
-
const logicalPath = `domains/${safeDomain}.usda`;
|
|
6032
|
-
const compiledLayer = compileSparseLawGraphUsda(
|
|
6033
|
-
graph,
|
|
6034
|
-
logicalPath,
|
|
6035
|
-
v3Closure
|
|
6036
|
-
);
|
|
6037
|
-
v3CompiledGraphs.set(graph, compiledLayer);
|
|
6038
|
-
const layerText = compiledLayer.text;
|
|
6039
|
-
const sha256 = sha256HexUtf8(layerText);
|
|
6040
|
-
v3DomainAssets.push({
|
|
6041
|
-
logicalPath,
|
|
6042
|
-
sha256,
|
|
6043
|
-
utf8: layerText,
|
|
6044
|
-
});
|
|
6045
|
-
const domainRoot = compiledLayer.paths.get(graph.domain.entity.id);
|
|
6046
|
-
if (domainRoot === undefined) {
|
|
6047
|
-
fail(`domain '${domain}' did not emit its canonical OpenUSD root path`);
|
|
6048
|
-
}
|
|
6049
|
-
v3DomainRoots.push(domainRoot);
|
|
6050
|
-
for (const node of graph.nodes) {
|
|
6051
|
-
const lawPath = compiledLayer.paths.get(node.entity.id);
|
|
6052
|
-
if (lawPath !== undefined) v3LawPathByNode.set(node, lawPath);
|
|
6053
|
-
}
|
|
6054
|
-
typedDomainIdentityByName.set(domain, sha256);
|
|
6055
|
-
typedLawPathsByName.set(domain, compiledLayer.paths);
|
|
6056
|
-
}
|
|
6057
|
-
|
|
6058
6196
|
// Index the transient graph once. Both projections follow the same nominal edges, including
|
|
6059
6197
|
// transitive cross-domain dependencies. Per-command selection also follows reverse guard edges;
|
|
6060
6198
|
// the retained package command projection remains the compatibility consumer until the runtime
|
|
@@ -7729,6 +7867,7 @@ async function main(): Promise<void> {
|
|
|
7729
7867
|
};
|
|
7730
7868
|
let lawClosure = emitLawClosure(
|
|
7731
7869
|
cfg.name,
|
|
7870
|
+
cfg.version === undefined ? undefined : lawVersionClaim(cfg.version),
|
|
7732
7871
|
domainModules.map((module) => module.domain ?? module.name),
|
|
7733
7872
|
runtimeDependencies,
|
|
7734
7873
|
v3DomainAssets,
|
|
@@ -7890,6 +8029,7 @@ async function main(): Promise<void> {
|
|
|
7890
8029
|
};
|
|
7891
8030
|
lawClosure = emitLawClosure(
|
|
7892
8031
|
cfg.name,
|
|
8032
|
+
cfg.version === undefined ? undefined : lawVersionClaim(cfg.version),
|
|
7893
8033
|
domainModules.map((module) => module.domain ?? module.name),
|
|
7894
8034
|
runtimeDependencies,
|
|
7895
8035
|
v3DomainAssets,
|
|
@@ -7941,6 +8081,10 @@ async function main(): Promise<void> {
|
|
|
7941
8081
|
// THE LAW IDENTITY (CAP-773): the unit set identity of the units below, the kernel's own definition
|
|
7942
8082
|
// (law_unit_set_identity.ts). Releases, generated clients and qualification name the law by it.
|
|
7943
8083
|
let unitSetIdentity: string;
|
|
8084
|
+
// THE PER-DOMAIN REQUIREMENTS (CAP-666): each application domain's unit hash beside the identity of its own
|
|
8085
|
+
// compatibility requirement, derived from the units just split and the interfaces just emitted. Written into
|
|
8086
|
+
// no law or package (the era rule); the generated clients, the approved model and the inventory carry them.
|
|
8087
|
+
let domainRequirements: readonly DomainUnitRequirement[];
|
|
7944
8088
|
{
|
|
7945
8089
|
const lawUnits = (() => {
|
|
7946
8090
|
try {
|
|
@@ -7968,6 +8112,7 @@ async function main(): Promise<void> {
|
|
|
7968
8112
|
);
|
|
7969
8113
|
// The law identity on its own line, for publishers and gates that need it and nothing else.
|
|
7970
8114
|
writeFileSync(path.join(outDir, `${cfg.name}.units.sha256`), `${unitSetIdentity}\n`, "utf8");
|
|
8115
|
+
domainRequirements = domainRequirementsOf(lawUnits, packageInterface, sha256HexUtf8);
|
|
7971
8116
|
}
|
|
7972
8117
|
const layeredRootPath = path.join(
|
|
7973
8118
|
lawClosureAssetsPath,
|
|
@@ -8163,6 +8308,7 @@ async function main(): Promise<void> {
|
|
|
8163
8308
|
const summaryTxt = [
|
|
8164
8309
|
`${cfg.name} — compiled Nomos domain package`,
|
|
8165
8310
|
`law (unit set): ${unitSetIdentity} # THE law identity: ${cfg.name}.units/, as releases, clients and qualification name it (${cfg.name}.units.sha256)`,
|
|
8311
|
+
`claimed version: ${cfg.version ?? "none"} # orders versions of law '${cfg.name}' (nomos.project.ts version); covered by the unit set identity`,
|
|
8166
8312
|
`package closure: ${domainHash} # package — not what targets serve: this compiler's closure of ${cfg.name}.law.usdz (${cfg.name}.law.sha256)`,
|
|
8167
8313
|
`served law: githolon domains status <ws> # each target's kernel composes the units into its own closure (it depends on that kernel's composer)`,
|
|
8168
8314
|
`law transport: ${path.basename(
|
|
@@ -8186,6 +8332,11 @@ async function main(): Promise<void> {
|
|
|
8186
8332
|
d.counts.join(", ") || "—"
|
|
8187
8333
|
} sums: ${d.sums.join(", ") || "—"}`,
|
|
8188
8334
|
]),
|
|
8335
|
+
...(releasedBaseline === undefined
|
|
8336
|
+
? [`baseline: NONE # not a publishable build; githolon compile --publishable needs a pinned nomos.baseline.usda`]
|
|
8337
|
+
: [
|
|
8338
|
+
`baseline: ${releasedBaselineSha256} # extends ${releasedBaseline.release === "none" ? "unreleased units" : `release ${releasedBaseline.release}`}, law ${releasedBaseline.unitSet} (${releasedBaseline.source})`,
|
|
8339
|
+
]),
|
|
8189
8340
|
`deploy: githolon deploy <ws> --file ${cfg.name}.law.usdz`,
|
|
8190
8341
|
packageAssetPath !== undefined
|
|
8191
8342
|
? `package asset: ${path.basename(
|
|
@@ -8242,6 +8393,16 @@ async function main(): Promise<void> {
|
|
|
8242
8393
|
id: "https://github.com/Captain-App/nomos2",
|
|
8243
8394
|
version: dslVersion,
|
|
8244
8395
|
},
|
|
8396
|
+
...(releasedBaseline === undefined || releasedBaselineSha256 === undefined
|
|
8397
|
+
? {}
|
|
8398
|
+
: {
|
|
8399
|
+
baseline: {
|
|
8400
|
+
sha256: releasedBaselineSha256,
|
|
8401
|
+
source: releasedBaseline.source,
|
|
8402
|
+
release: releasedBaseline.release,
|
|
8403
|
+
unitSet: releasedBaseline.unitSet,
|
|
8404
|
+
},
|
|
8405
|
+
}),
|
|
8245
8406
|
});
|
|
8246
8407
|
writeFileSync(
|
|
8247
8408
|
path.join(outDir, `${cfg.name}.provenance.json`),
|
|
@@ -8271,6 +8432,7 @@ async function main(): Promise<void> {
|
|
|
8271
8432
|
packageName: cfg.name,
|
|
8272
8433
|
// THE LAW the generated clients name: the unit set (CAP-773), never the package closure.
|
|
8273
8434
|
domainHash: unitSetIdentity,
|
|
8435
|
+
domainRequirements,
|
|
8274
8436
|
lawAssetName: `${cfg.name}.law.usdz`,
|
|
8275
8437
|
interface: packageInterface,
|
|
8276
8438
|
kernelContracts,
|
|
@@ -8860,7 +9022,7 @@ async function main(): Promise<void> {
|
|
|
8860
9022
|
const r = emitDartPackages(
|
|
8861
9023
|
presentationDomainModules,
|
|
8862
9024
|
dartOut,
|
|
8863
|
-
{ unitSet: unitSetIdentity, packageSha256: domainHash },
|
|
9025
|
+
{ unitSet: unitSetIdentity, packageSha256: domainHash, domainRequirements },
|
|
8864
9026
|
typedLawGraphs,
|
|
8865
9027
|
typedLawPathsByName,
|
|
8866
9028
|
packageInterface,
|
|
@@ -8888,7 +9050,7 @@ async function main(): Promise<void> {
|
|
|
8888
9050
|
dartFiles = emitDart(
|
|
8889
9051
|
presentationDomainModules,
|
|
8890
9052
|
dartOut,
|
|
8891
|
-
{ unitSet: unitSetIdentity, packageSha256: domainHash },
|
|
9053
|
+
{ unitSet: unitSetIdentity, packageSha256: domainHash, domainRequirements },
|
|
8892
9054
|
typedLawGraphs,
|
|
8893
9055
|
typedLawPathsByName,
|
|
8894
9056
|
packageInterface,
|
|
@@ -9272,6 +9434,7 @@ async function main(): Promise<void> {
|
|
|
9272
9434
|
const rel = (p: string) => path.relative(process.cwd(), p);
|
|
9273
9435
|
console.log(`nomos-compile: ${cfg.name}`);
|
|
9274
9436
|
console.log(` law unit set ${unitSetIdentity} (${rel(path.join(outDir, `${cfg.name}.units`))})`);
|
|
9437
|
+
if (cfg.version !== undefined) console.log(` version ${cfg.name}@${cfg.version} (claimed; covered by the unit set identity)`);
|
|
9275
9438
|
console.log(
|
|
9276
9439
|
` package ${domainHash} — package — not what targets serve (${rel(lawUsdzPath)}, ${lawUsdz.byteLength} transport bytes)`
|
|
9277
9440
|
);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// NOMOS — The wire identity of an operation field under OpenUSD composition.
|
|
2
|
+
//
|
|
3
|
+
// Node-free on purpose: the compatibility graph reaches this from the law bundle (the release law's
|
|
4
|
+
// plans bundle for a neutral platform), where `codegen_call_proto.ts` cannot live (it mints stable
|
|
5
|
+
// ids through `node:crypto`). Both the generated codecs and the compatibility requirement derive a
|
|
6
|
+
// nested member's allocation here, so the two can never disagree (CAP-681).
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* OpenUSD composition may share structurally identical anonymous records between
|
|
10
|
+
* operation contracts. `compileSparseLawGraphUsda` records that sharing by
|
|
11
|
+
* redirecting each duplicate field path to the canonical field prim. The wire
|
|
12
|
+
* identity must follow that composed path too; using the duplicate graph-local
|
|
13
|
+
* SID makes generated clients speak a different Protobuf schema from the law the
|
|
14
|
+
* kernel actually installs.
|
|
15
|
+
*/
|
|
16
|
+
export function composedWireIdentity(
|
|
17
|
+
paths: ReadonlyMap<string, string>,
|
|
18
|
+
entity: { readonly id: string; readonly sid: string; readonly wireKey?: string },
|
|
19
|
+
): string {
|
|
20
|
+
if (entity.wireKey !== undefined) return entity.wireKey;
|
|
21
|
+
const path = paths.get(entity.id);
|
|
22
|
+
const canonical = path?.match(/\/(?:Fields\/f_|Variants\/v_)([0-9a-f]{16})$/i)?.[1];
|
|
23
|
+
return canonical ?? entity.sid;
|
|
24
|
+
}
|
package/src/directive.ts
CHANGED
|
@@ -536,6 +536,12 @@ export interface Directive<P = unknown> extends AuthenticatedMember {
|
|
|
536
536
|
* `attestationAuthorizedGate`/`.attestationAuthorized()` naming convention; the declaration is the noun.)
|
|
537
537
|
*/
|
|
538
538
|
readonly birthsChild?: boolean;
|
|
539
|
+
/** THE TYPED BIRTH KEY of a business birth (`birth(Aggregate, spec)`): the key's typed-id family, brand and
|
|
540
|
+
* the name's namespace. Lowered to the `nomos:birthKeyType` / `nomos:birthKeyBrand` /
|
|
541
|
+
* `nomos:birthKeyNamespace` era keys on the birthing intent; the kernel then requires every carried recipe
|
|
542
|
+
* of this intent to carry `nomos:birthKey`, checks its shape, and re-derives the child's name from it.
|
|
543
|
+
* Absent on every other directive (and on all historical law), so those chains replay unchanged. */
|
|
544
|
+
readonly birthKey?: import("./births.js").BirthKeyDeclaration;
|
|
539
545
|
/** Additional ordinary offers which the born workspace's typed law requires in genesis.
|
|
540
546
|
* This is compiler/runtime metadata attached only to a birthing directive. It contains no
|
|
541
547
|
* payload or fallback value: the kernel checks that the re-derived recipe invokes each named
|