@githolon/dsl 0.113.4 → 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.
Files changed (103) hide show
  1. package/assets/operation-contract.wasm +0 -0
  2. package/compile_package.mjs +23 -3
  3. package/compile_proof.d.mts +7 -0
  4. package/compile_proof.mjs +38 -3
  5. package/dart/CHANGELOG.md +60 -0
  6. package/dart/lib/src/application_framework_calls.dart +16 -6
  7. package/dart/lib/src/console_enrolment.dart +7 -0
  8. package/dart/lib/src/console_http_io.dart +22 -15
  9. package/dart/lib/src/dev_cloud.dart +62 -0
  10. package/dart/lib/src/generated_call.dart +14 -3
  11. package/dart/lib/src/nms_generated_runtime.dart +7 -0
  12. package/dart/lib/src/node_runner_transport.dart +77 -8
  13. package/dart/lib/src/nomos_trace.dart +107 -0
  14. package/dart/lib/src/operation_receipts.dart +74 -7
  15. package/dart/lib/src/reception/dart_reception.dart +174 -17
  16. package/dart/lib/src/rows_watch.dart +390 -0
  17. package/dart/lib/src/runner/node-entry.mjs +7678 -2860
  18. package/dart/lib/src/runtime_v2_transport.dart +3 -0
  19. package/dart/lib/src/sync_status_projection.dart +94 -1
  20. package/dart/lib/src/sync_status_reducer.dart +5 -2
  21. package/dart/lib/src/test_harness.dart +107 -41
  22. package/dart/lib/src/testing/test_peer.dart +107 -99
  23. package/dart/lib/src/testing/test_peer_host.dart +305 -0
  24. package/dart/lib/src/typed_watch_registry.dart +26 -3
  25. package/dart/pubspec.lock +1 -1
  26. package/dart/pubspec.yaml +2 -2
  27. package/dart/test/background_model_adoption_test.dart +1 -0
  28. package/dart/test/console_enrolment_test.dart +47 -0
  29. package/dart/test/custodian_warming_test.dart +105 -0
  30. package/dart/test/fixtures/offer_watch_order_peer.dart +74 -0
  31. package/dart/test/kernel_author_after_read_test.dart +6 -3
  32. package/dart/test/kernel_fence_test.dart +4 -1
  33. package/dart/test/model_adoption_test.dart +66 -0
  34. package/dart/test/nomos_trace_test.dart +91 -0
  35. package/dart/test/own_offer_watch_order_test.dart +90 -0
  36. package/dart/test/receiving_group_open_test.dart +4 -8
  37. package/dart/test/replica_readiness_test.dart +14 -4
  38. package/dart/test/rows_watch_test.dart +331 -0
  39. package/dart/test/runtime_projections_test.dart +41 -0
  40. package/dart/test/test_peer_host_selection_test.dart +49 -0
  41. package/dart_types/CHANGELOG.md +39 -0
  42. package/dart_types/lib/src/approved_model.dart +100 -6
  43. package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pb.dart +1063 -3
  44. package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pbenum.dart +89 -0
  45. package/dart_types/lib/src/proto/nomos/runtime/v2/application_desk.pb.dart +14 -0
  46. package/dart_types/lib/src/proto/nomos/runtime/v2/correspondence_desk.pb.dart +2272 -130
  47. package/dart_types/lib/src/proto/nomos/runtime/v2/correspondence_desk.pbenum.dart +65 -0
  48. package/dart_types/lib/src/proto/nomos/runtime/v2/model_adoption_desk.pb.dart +118 -2
  49. package/dart_types/lib/src/proto/nomos/runtime/v2/observability_desk.pb.dart +278 -9
  50. package/dart_types/lib/src/proto/nomos/runtime/v2/receiving_group_desk.pb.dart +7 -85
  51. package/dart_types/lib/src/proto/nomos/runtime/v2/records_desk.pb.dart +16 -0
  52. package/dart_types/lib/src/proto/nomos/runtime/v2/residency_desk.pb.dart +35 -0
  53. package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pb.dart +43 -2
  54. package/dart_types/pubspec.yaml +1 -1
  55. package/package.json +6 -2
  56. package/src/aggregate.ts +93 -0
  57. package/src/anonymous_value_interning.ts +205 -0
  58. package/src/baseline.ts +27 -0
  59. package/src/baseline_export.ts +432 -0
  60. package/src/baseline_import.ts +312 -0
  61. package/src/baseline_usda.ts +186 -0
  62. package/src/birth_key_rule.ts +472 -0
  63. package/src/births.ts +207 -24
  64. package/src/build_provenance.ts +17 -2
  65. package/src/business_birth.ts +50 -4
  66. package/src/check_package_main.ts +50 -6
  67. package/src/codegen_call_proto.ts +5 -18
  68. package/src/codegen_dart.ts +95 -3
  69. package/src/codegen_dart_client.ts +73 -15
  70. package/src/codegen_dart_facade.ts +58 -35
  71. package/src/codegen_dart_framework_calls.ts +32 -10
  72. package/src/codegen_dart_scenario.ts +7 -0
  73. package/src/codegen_proof.ts +5 -2
  74. package/src/codegen_result_proto.ts +8 -6
  75. package/src/codegen_result_usda.ts +4 -0
  76. package/src/codegen_ts.ts +135 -34
  77. package/src/compatibility_graph.ts +41 -4
  78. package/src/compatibility_usda.ts +11 -1
  79. package/src/compile_package_main.ts +272 -105
  80. package/src/composed_wire_identity.ts +24 -0
  81. package/src/directive.ts +6 -0
  82. package/src/domain_requirements.ts +75 -0
  83. package/src/engine_entry.ts +4 -48
  84. package/src/engine_javascript.ts +12 -6
  85. package/src/fields.ts +109 -0
  86. package/src/identity_usda.ts +77 -51
  87. package/src/index.ts +25 -1
  88. package/src/intent.ts +5 -0
  89. package/src/law_graph.ts +142 -1
  90. package/src/law_graph_usda.ts +25 -141
  91. package/src/law_layer_prims.ts +199 -0
  92. package/src/law_unit_selection.ts +45 -0
  93. package/src/law_unit_set_identity.ts +44 -0
  94. package/src/law_version.ts +107 -0
  95. package/src/package_config.ts +44 -0
  96. package/src/package_dependencies.ts +8 -0
  97. package/src/query/compile.ts +0 -0
  98. package/src/release_inspection.ts +24 -0
  99. package/src/release_publication.ts +298 -0
  100. package/src/value_object.ts +6 -3
  101. package/src/wire.ts +2 -0
  102. package/src/wire_paths.ts +17 -0
  103. package/src/workspace_routing.ts +1 -1
@@ -0,0 +1,432 @@
1
+ // NOMOS — EXPORT A RELEASED BASELINE FROM CUSTODY (architecture/domain_release_lifecycle.md, step 1).
2
+ //
3
+ // Input: a verified law unit set — the compiler's `build/<name>.units`, a release's units downloaded
4
+ // from the console registry, or the units a workspace's installed law names. Every unit hash is
5
+ // re-derived from the bytes before any opinion is read (release_inspection.ts `readInspectionUnits`),
6
+ // so the baseline can only ever describe law that actually exists.
7
+ //
8
+ // Output: the continuity released law carries, in the baseline artifact (baseline_usda.ts):
9
+ //
10
+ // * every ledger-minted declaration — its sid (the prim name), current label, prior labels and
11
+ // parent — with the generation recovered by re-minting (law_identity.ts mints a sid from
12
+ // `kind:parent:label:generation`, so the generation is provable from the sid, never guessed);
13
+ // * every retirement the released law declares, as a tombstone;
14
+ // * every operation field's transport allocation (canonical wire key + aliases), top-level and
15
+ // nested, under the ledger coordinate law_graph.ts allocates it by (wire_paths.ts).
16
+ //
17
+ // What released law does NOT carry — value contracts, merge drivers, tombstones older than the
18
+ // release's own declarations — stays in `nomos.identity.usda`. The baseline is the anchor, not
19
+ // the ledger. Prims whose sid is owned or structural (payload contracts, anonymous value types) are
20
+ // not identities the compiler reconciles, so they are read for their wire keys and nothing else.
21
+ import { createHash } from "node:crypto";
22
+ import { readInspectionUnits } from "./release_inspection.js";
23
+ import { lawUnitSetIdentityWith } from "./law_unit_set_identity.js";
24
+ import {
25
+ LAW_FRAMEWORK_PARENT,
26
+ lawEntityKey,
27
+ validateLawIdentityRegistry,
28
+ type LawEntityKind,
29
+ type LawIdentityEntity,
30
+ type LawIdentityRegistry,
31
+ } from "./law_identity.js";
32
+ import {
33
+ mintAggregateSid,
34
+ mintDomainSid,
35
+ mintFieldSid,
36
+ mintGlobalAggregateSid,
37
+ mintStableId,
38
+ } from "./stable_ids.js";
39
+ import type { StableAggregateId, StableFieldId, StableIds } from "./stable_ids_types.js";
40
+ import type { CompilerIdentityModel } from "./identity_model.js";
41
+ import {
42
+ indexUsdaPrims,
43
+ readUsdaPrims,
44
+ usdaChild,
45
+ usdaString,
46
+ usdaStringList,
47
+ type UsdaPrim,
48
+ } from "./law_layer_prims.js";
49
+ import {
50
+ BASELINE_NO_RELEASE,
51
+ serializeBaselineUsda,
52
+ baselineSha256,
53
+ type BaselineSource,
54
+ type BaselineWireAllocation,
55
+ type ReleasedBaseline,
56
+ } from "./baseline_usda.js";
57
+ import { listElementPath, mapValuePath, nestedMemberPath, unionVariantPath } from "./wire_paths.js";
58
+
59
+ /** The deepest generation re-minting looks for. A label recreated more often than this is unheard of. */
60
+ const MAX_RECOVERED_GENERATION = 64;
61
+
62
+ const sha256Hex = (bytes: Uint8Array): string => createHash("sha256").update(bytes).digest("hex");
63
+
64
+ /** Container prim name → the entity kind its children declare. */
65
+ const CONTAINER_KINDS: Readonly<Record<string, LawEntityKind>> = {
66
+ Aggregates: "aggregate",
67
+ Types: "type",
68
+ ObjectTypes: "object-type",
69
+ Contracts: "contract",
70
+ Relations: "relation",
71
+ Intents: "intent",
72
+ Reads: "read",
73
+ Policies: "policy",
74
+ Invariants: "invariant",
75
+ Capabilities: "capability",
76
+ WorkspaceTypes: "workspace-type",
77
+ Flows: "flow",
78
+ };
79
+
80
+ const SID = /^[0-9a-f]{16}$/u;
81
+
82
+ export interface BaselineExportInput {
83
+ /** A directory of law units (`build/<name>.units` or a materialised release). */
84
+ readonly unitsDir: string;
85
+ readonly source: BaselineSource;
86
+ readonly release?: string;
87
+ readonly series?: string;
88
+ readonly predecessor?: string;
89
+ readonly workspace?: string;
90
+ readonly workspaceHead?: string;
91
+ }
92
+
93
+ export interface BaselineExport {
94
+ readonly baseline: ReleasedBaseline;
95
+ /** The artifact bytes, deterministic for the same units and provenance. */
96
+ readonly text: string;
97
+ /** Its content address — what `nomos.project.ts` pins. */
98
+ readonly sha256: string;
99
+ /** Declarations whose sid is owned or structural; read for wire keys only. */
100
+ readonly nonLedgerPrims: number;
101
+ }
102
+
103
+ interface ScannedEntity {
104
+ readonly key: string;
105
+ readonly entity: LawIdentityEntity;
106
+ }
107
+
108
+ function generationOf(
109
+ kind: LawEntityKind,
110
+ parent: string | undefined,
111
+ labels: readonly string[],
112
+ sid: string,
113
+ ): number | undefined {
114
+ for (const label of labels) {
115
+ for (let generation = 0; generation <= MAX_RECOVERED_GENERATION; generation += 1) {
116
+ if (mintStableId(`law-entity:${kind}:${parent ?? "@root"}:${label}:generation:${generation}`) === sid) {
117
+ return generation;
118
+ }
119
+ }
120
+ }
121
+ return undefined;
122
+ }
123
+
124
+ /**
125
+ * Prove that `sid` is a ledger identity for (kind, parent, label lineage): either minted by
126
+ * law_identity.ts (generation recovered) or a legacy stable_ids.ts mint (generation 0). Returns the
127
+ * parent the ledger reconciles it under — a framework aggregate's is `@framework`, not its domain.
128
+ */
129
+ function classifyLedgerEntity(
130
+ kind: LawEntityKind,
131
+ parent: string | undefined,
132
+ domainSid: string | undefined,
133
+ labels: readonly string[],
134
+ sid: string,
135
+ ): { parent: string | undefined; generation: number } | undefined {
136
+ const generation = generationOf(kind, parent, labels, sid);
137
+ if (generation !== undefined) return { parent, generation };
138
+ if (kind === "aggregate") {
139
+ const framework = generationOf(kind, LAW_FRAMEWORK_PARENT, labels, sid);
140
+ if (framework !== undefined) return { parent: LAW_FRAMEWORK_PARENT, generation: framework };
141
+ if (labels.some((label) => mintGlobalAggregateSid(label) === sid)) return { parent: LAW_FRAMEWORK_PARENT, generation: 0 };
142
+ if (domainSid !== undefined && labels.some((label) => mintAggregateSid(domainSid, label) === sid)) {
143
+ return { parent, generation: 0 };
144
+ }
145
+ }
146
+ if (kind === "domain" && labels.some((label) => mintDomainSid(label) === sid)) return { parent: undefined, generation: 0 };
147
+ if (kind === "field" && parent !== undefined) {
148
+ const parentSid = parent.slice(parent.indexOf("_") + 1);
149
+ if (labels.some((label) => mintFieldSid(parentSid, label) === sid)) return { parent, generation: 0 };
150
+ }
151
+ return undefined;
152
+ }
153
+
154
+ function sidOf(prim: UsdaPrim): string | undefined {
155
+ const split = prim.name.indexOf("_");
156
+ const sid = split === -1 ? "" : prim.name.slice(split + 1);
157
+ return SID.test(sid) ? sid : undefined;
158
+ }
159
+
160
+ /** Walk one domain layer for its ledger entities, declared retirements and stable-id surface. */
161
+ function scanDomainLayer(
162
+ domainPrim: UsdaPrim,
163
+ out: { entities: ScannedEntity[]; nonLedger: { value: number } },
164
+ ): { name: string; stableIds: StableIds } | undefined {
165
+ const domainSid = sidOf(domainPrim);
166
+ const domainLabel = usdaString(domainPrim, "label");
167
+ if (domainSid === undefined || domainLabel === undefined) return undefined;
168
+ const domainLabels = [domainLabel, ...(usdaStringList(domainPrim, "was") ?? [])];
169
+ const domainClass = classifyLedgerEntity("domain", undefined, undefined, domainLabels, domainSid);
170
+ const domainKey = lawEntityKey("domain", domainSid);
171
+ if (domainClass !== undefined) {
172
+ out.entities.push({
173
+ key: domainKey,
174
+ entity: {
175
+ kind: "domain",
176
+ sid: domainSid,
177
+ label: domainLabel,
178
+ ...(domainLabels.length > 1 ? { priorLabels: domainLabels.slice(1) } : {}),
179
+ generation: domainClass.generation,
180
+ status: "active",
181
+ },
182
+ });
183
+ } else {
184
+ out.nonLedger.value += 1;
185
+ }
186
+
187
+ const aggregates: Record<string, StableAggregateId> = {};
188
+ const scanFields = (owner: UsdaPrim, ownerKey: string): Record<string, StableFieldId> => {
189
+ const fields: Record<string, StableFieldId> = {};
190
+ for (const fieldPrim of usdaChild(owner, "Fields")?.children ?? []) {
191
+ const sid = sidOf(fieldPrim);
192
+ const label = usdaString(fieldPrim, "label");
193
+ if (sid === undefined || label === undefined) continue;
194
+ const was = usdaStringList(fieldPrim, "was") ?? [];
195
+ const classified = classifyLedgerEntity("field", ownerKey, undefined, [label, ...was], sid);
196
+ if (classified === undefined) {
197
+ out.nonLedger.value += 1;
198
+ continue;
199
+ }
200
+ out.entities.push({
201
+ key: lawEntityKey("field", sid),
202
+ entity: {
203
+ kind: "field",
204
+ sid,
205
+ parent: ownerKey,
206
+ label,
207
+ ...(was.length > 0 ? { priorLabels: was } : {}),
208
+ generation: classified.generation,
209
+ status: "active",
210
+ },
211
+ });
212
+ fields[label] = { sid, ...(was.length > 0 ? { was: [...was] } : {}) };
213
+ }
214
+ return fields;
215
+ };
216
+
217
+ for (const container of domainPrim.children) {
218
+ const kind = CONTAINER_KINDS[container.name];
219
+ if (kind === undefined) continue;
220
+ for (const prim of container.children) {
221
+ const sid = sidOf(prim);
222
+ const label = usdaString(prim, "label");
223
+ if (sid === undefined || label === undefined) continue;
224
+ const was = usdaStringList(prim, "was") ?? [];
225
+ const classified = classifyLedgerEntity(kind, domainKey, domainSid, [label, ...was], sid);
226
+ if (classified === undefined) {
227
+ out.nonLedger.value += 1;
228
+ continue;
229
+ }
230
+ const key = lawEntityKey(kind, sid);
231
+ out.entities.push({
232
+ key,
233
+ entity: {
234
+ kind,
235
+ sid,
236
+ ...(classified.parent === undefined ? {} : { parent: classified.parent }),
237
+ label,
238
+ ...(was.length > 0 ? { priorLabels: was } : {}),
239
+ generation: classified.generation,
240
+ status: "active",
241
+ },
242
+ });
243
+ if (kind === "aggregate") {
244
+ const fields = scanFields(prim, key);
245
+ aggregates[label] = { sid, ...(was.length > 0 ? { was: [...was] } : {}), fields };
246
+ } else if (kind === "contract") {
247
+ scanFields(prim, key);
248
+ }
249
+ }
250
+ }
251
+
252
+ for (const retirement of usdaChild(domainPrim, "Retirements")?.children ?? []) {
253
+ const kind = usdaString(retirement, "entityKind");
254
+ const sid = usdaString(retirement, "sid");
255
+ const label = usdaString(retirement, "label");
256
+ if ((kind !== "aggregate" && kind !== "field") || sid === undefined || label === undefined || !SID.test(sid)) continue;
257
+ const parentSid = usdaString(retirement, "parentSid");
258
+ const parent = kind === "field"
259
+ ? (parentSid === undefined ? undefined : lawEntityKey("aggregate", parentSid))
260
+ : domainKey;
261
+ const classified = classifyLedgerEntity(kind, parent, domainSid, [label], sid);
262
+ if (classified === undefined) {
263
+ out.nonLedger.value += 1;
264
+ continue;
265
+ }
266
+ out.entities.push({
267
+ key: lawEntityKey(kind, sid),
268
+ entity: {
269
+ kind,
270
+ sid,
271
+ ...(classified.parent === undefined ? {} : { parent: classified.parent }),
272
+ label,
273
+ generation: classified.generation,
274
+ status: "retired",
275
+ },
276
+ });
277
+ }
278
+
279
+ return { name: domainLabel, stableIds: { v: 1, domain: domainSid, aggregates } };
280
+ }
281
+
282
+ /** Walk an intent's payload contracts for every field's transport allocation, nested included. */
283
+ function scanWireAllocations(
284
+ intentPrim: UsdaPrim,
285
+ prims: ReadonlyMap<string, UsdaPrim>,
286
+ out: BaselineWireAllocation[],
287
+ ): void {
288
+ const intentSid = sidOf(intentPrim);
289
+ if (intentSid === undefined) return;
290
+ const intent = lawEntityKey("intent", intentSid);
291
+ const seen = new Set<string>();
292
+ const allocate = (field: UsdaPrim, path: string): void => {
293
+ const canonical = usdaString(field, "wireKey");
294
+ if (canonical === undefined) return;
295
+ const aliases = usdaStringList(field, "wireAliases") ?? [];
296
+ const coordinate = `${intent}\u0000${path}`;
297
+ if (seen.has(coordinate)) return;
298
+ seen.add(coordinate);
299
+ out.push({ intent, field: path, protobuf: { canonical, ...(aliases.length > 0 ? { aliases } : {}) } });
300
+ };
301
+ const walkType = (typePath: string | undefined, path: string, visiting: ReadonlySet<string>): void => {
302
+ if (typePath === undefined || visiting.has(typePath)) return;
303
+ const type = prims.get(typePath);
304
+ if (type === undefined) return;
305
+ const next = new Set(visiting).add(typePath);
306
+ switch (usdaString(type, "typeKind")) {
307
+ case "record":
308
+ for (const field of usdaChild(type, "Fields")?.children ?? []) walkField(field, path, next);
309
+ break;
310
+ case "list":
311
+ walkType(type.rels.get("elementType")?.[0], listElementPath(path), next);
312
+ break;
313
+ case "map":
314
+ walkType(type.rels.get("valueType")?.[0], mapValuePath(path), next);
315
+ break;
316
+ case "union": {
317
+ const variants = usdaChild(type, "Variants")?.children ?? [];
318
+ variants.forEach((variant, index) => {
319
+ const label = usdaString(variant, "label") ?? String(index);
320
+ walkType(variant.rels.get("type")?.[0], unionVariantPath(path, label), next);
321
+ });
322
+ break;
323
+ }
324
+ case "recursive":
325
+ walkType(type.rels.get("body")?.[0], path, next);
326
+ break;
327
+ default:
328
+ break;
329
+ }
330
+ };
331
+ const walkField = (field: UsdaPrim, parentPath: string, visiting: ReadonlySet<string>): void => {
332
+ const label = usdaString(field, "label");
333
+ if (label === undefined) return;
334
+ const path = parentPath === "" ? label : nestedMemberPath(parentPath, label);
335
+ allocate(field, path);
336
+ walkType(field.rels.get("type")?.[0], path, visiting);
337
+ };
338
+ for (const relation of ["accepts", "publicAccepts"]) {
339
+ const contract = prims.get(intentPrim.rels.get(relation)?.[0] ?? "");
340
+ if (contract === undefined) continue;
341
+ for (const field of usdaChild(contract, "Fields")?.children ?? []) walkField(field, "", new Set());
342
+ }
343
+ }
344
+
345
+ /** Order entities so every parent precedes its children (validation and import both need it). */
346
+ function orderByParent(entities: readonly ScannedEntity[]): ScannedEntity[] {
347
+ const byKey = new Map(entities.map((scanned) => [scanned.key, scanned]));
348
+ const ordered: ScannedEntity[] = [];
349
+ const placed = new Set<string>();
350
+ const place = (scanned: ScannedEntity, trail: ReadonlySet<string>): void => {
351
+ if (placed.has(scanned.key)) return;
352
+ const parent = scanned.entity.parent;
353
+ if (parent !== undefined && parent !== LAW_FRAMEWORK_PARENT && !trail.has(parent)) {
354
+ const parentEntity = byKey.get(parent);
355
+ if (parentEntity !== undefined) place(parentEntity, new Set(trail).add(scanned.key));
356
+ }
357
+ placed.add(scanned.key);
358
+ ordered.push(scanned);
359
+ };
360
+ for (const scanned of [...entities].sort((l, r) => (l.key < r.key ? -1 : l.key > r.key ? 1 : 0))) place(scanned, new Set());
361
+ return ordered;
362
+ }
363
+
364
+ /** Export the baseline a verified unit set carries. Throws on unverifiable units or an unreadable layer. */
365
+ export function exportBaselineFromUnits(input: BaselineExportInput): BaselineExport {
366
+ const units = readInspectionUnits(input.unitsDir);
367
+ const unitSet = lawUnitSetIdentityWith(sha256Hex, units.map((unit) => ({ key: unit.key, unitHash: unit.hash })));
368
+
369
+ const roots: UsdaPrim[] = [];
370
+ for (const unit of units) {
371
+ for (const asset of unit.assets) {
372
+ if (!/^domains\/[^/]+\.usda$/u.test(asset.logicalPath) && asset.logicalPath !== "framework.usda") continue;
373
+ roots.push(...readUsdaPrims(new TextDecoder().decode(asset.bytes)));
374
+ }
375
+ }
376
+ const prims = indexUsdaPrims(roots);
377
+
378
+ const scanned = { entities: [] as ScannedEntity[], nonLedger: { value: 0 } };
379
+ const domains: CompilerIdentityModel["domains"] = {};
380
+ const wireAllocations: BaselineWireAllocation[] = [];
381
+ for (const [primPath, prim] of prims) {
382
+ if (!/^\/Nomos\/Domains\/d_[0-9a-f]{16}$/u.test(primPath)) continue;
383
+ const domain = scanDomainLayer(prim, scanned);
384
+ if (domain !== undefined) domains[domain.name] = { stableIds: domain.stableIds };
385
+ for (const intent of usdaChild(prim, "Intents")?.children ?? []) scanWireAllocations(intent, prims, wireAllocations);
386
+ }
387
+
388
+ const entities: Record<string, LawIdentityEntity> = {};
389
+ for (const { key, entity } of orderByParent(scanned.entities)) {
390
+ const prior = entities[key];
391
+ if (prior !== undefined) {
392
+ // One framework aggregate composed into several domain layers is one identity; the layers agree.
393
+ if (prior.kind !== entity.kind || prior.label !== entity.label) {
394
+ throw new Error(`baseline export: ${key} is declared as '${prior.label}' and '${entity.label}' in the same unit set`);
395
+ }
396
+ continue;
397
+ }
398
+ // A field's aggregate or a retirement's parent must be a ledger entity of this set; a child of a
399
+ // non-ledger prim (an owned contract's field) is read for wire keys elsewhere, not as identity.
400
+ const parent = entity.parent;
401
+ if (parent !== undefined && parent !== LAW_FRAMEWORK_PARENT && entities[parent] === undefined) {
402
+ scanned.nonLedger.value += 1;
403
+ continue;
404
+ }
405
+ entities[key] = entity;
406
+ }
407
+ const identity: LawIdentityRegistry = {
408
+ v: 1,
409
+ entities: Object.fromEntries(Object.entries(entities).sort(([l], [r]) => (l < r ? -1 : l > r ? 1 : 0))),
410
+ };
411
+ validateLawIdentityRegistry(identity);
412
+
413
+ const baselineBody: Omit<ReleasedBaseline, "format"> = {
414
+ source: input.source,
415
+ release: input.release ?? BASELINE_NO_RELEASE,
416
+ series: input.series ?? "",
417
+ predecessor: input.predecessor ?? "",
418
+ unitSet,
419
+ units: units.map((unit) => ({ key: unit.key, unitHash: unit.hash })),
420
+ workspace: input.workspace ?? "",
421
+ workspaceHead: input.workspaceHead ?? "",
422
+ continuity: { v: 1, domains, identity },
423
+ wireAllocations: [...wireAllocations].sort((l, r) => (l.intent < r.intent ? -1 : l.intent > r.intent ? 1 : l.field < r.field ? -1 : l.field > r.field ? 1 : 0)),
424
+ };
425
+ const text = serializeBaselineUsda(baselineBody);
426
+ return {
427
+ baseline: { format: "nomos.baseline.v1", ...baselineBody },
428
+ text,
429
+ sha256: baselineSha256(text),
430
+ nonLedgerPrims: scanned.nonLedger.value,
431
+ };
432
+ }