@githolon/dsl 0.108.0 → 0.108.1

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 (94) hide show
  1. package/dart/CHANGELOG.md +5 -0
  2. package/dart/lib/src/application_framework_calls.dart +299 -0
  3. package/dart/lib/src/generated_call.dart +96 -0
  4. package/dart/lib/src/nms_generated_runtime.dart +29 -0
  5. package/dart/lib/src/node_runner_transport.dart +77 -1
  6. package/dart/lib/src/result_usda.dart +487 -0
  7. package/dart/lib/src/runner/node-entry.mjs +6401 -2102
  8. package/dart/lib/src/runner/offline-install.mjs +1538 -163
  9. package/dart/lib/src/runtime_v2_gateway.dart +54 -0
  10. package/dart/lib/src/runtime_v2_transport.dart +117 -0
  11. package/dart/lib/src/session_bound.dart +7 -2
  12. package/dart/lib/src/test_harness.dart +193 -112
  13. package/dart/lib/src/webview_bridge.dart +2120 -569
  14. package/dart/pubspec.yaml +2 -2
  15. package/dart/test/acquire_session_credentials_test.dart +1 -1
  16. package/dart/test/acquire_session_test.dart +68 -14
  17. package/dart/test/adv_realm_interference_test.dart +6 -4
  18. package/dart/test/cluster_births_test.dart +11 -8
  19. package/dart/test/cluster_local_autosync_test.dart +1 -1
  20. package/dart/test/cluster_scale_test.dart +3 -2
  21. package/dart/test/dlq_session_surface_test.dart +52 -35
  22. package/dart/test/first_app_gauntlet_test.dart +1 -1
  23. package/dart/test/local_sync_inert_test.dart +23 -26
  24. package/dart/test/offer_authentication_proof_test.dart +193 -0
  25. package/dart/test/result_usda_test.dart +49 -0
  26. package/dart/test/session_bound_test.dart +8 -11
  27. package/dart/test/stale_bundle_test.dart +18 -3
  28. package/dart/test/test_harness_test.dart +14 -27
  29. package/dart/test/webview_bridge_test.dart +504 -83
  30. package/dart_types/CHANGELOG.md +7 -0
  31. package/dart_types/lib/nomos_kernel_protocol.dart +3 -2
  32. package/dart_types/lib/src/custody.dart +64 -19
  33. package/dart_types/lib/src/local_work_rejected.dart +30 -45
  34. package/dart_types/lib/src/proto/nomos/custody/v1/snapshot.pb.dart +169 -0
  35. package/dart_types/lib/src/proto/nomos/custody/v1/snapshot.pbenum.dart +11 -0
  36. package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pb.dart +2021 -234
  37. package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pbenum.dart +175 -8
  38. package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pb.dart +8664 -0
  39. package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pbenum.dart +369 -0
  40. package/dart_types/lib/src/surfaced.dart +30 -25
  41. package/dart_types/pubspec.yaml +1 -1
  42. package/dart_types/test/surfaced_test.dart +2 -1
  43. package/package.json +1 -1
  44. package/runtime/generated-application-host.js +5736 -2047
  45. package/src/authoring.ts +3 -2
  46. package/src/births.ts +21 -0
  47. package/src/build_package.ts +30 -0
  48. package/src/business_birth.ts +39 -35
  49. package/src/codegen_call_usda.ts +1111 -0
  50. package/src/codegen_dart.ts +207 -282
  51. package/src/codegen_dart_application.ts +195 -252
  52. package/src/codegen_dart_client.ts +1978 -593
  53. package/src/codegen_dart_framework_calls.ts +291 -0
  54. package/src/codegen_dart_scenario.ts +7 -0
  55. package/src/codegen_proof.ts +3 -4
  56. package/src/codegen_provider_dart.ts +21 -7
  57. package/src/codegen_query_usda.ts +214 -0
  58. package/src/codegen_result_usda.ts +685 -0
  59. package/src/codegen_ts.ts +3945 -1111
  60. package/src/compile_package_main.ts +360 -32
  61. package/src/directive.ts +19 -4
  62. package/src/engine_entry.ts +45 -4
  63. package/src/framework/application_home.ts +2 -0
  64. package/src/framework/auth_provider_law.ts +262 -20
  65. package/src/framework/home.ts +32 -28
  66. package/src/framework/owned_custody.ts +19 -11
  67. package/src/framework/owned_custody_value.ts +51 -0
  68. package/src/framework/relations.ts +47 -21
  69. package/src/framework/signing_identity.ts +34 -0
  70. package/src/framework/workspaces.ts +31 -9
  71. package/src/framework_call_definitions.ts +53 -0
  72. package/src/framework_read_definitions.ts +45 -0
  73. package/src/identity_frontier.ts +58 -0
  74. package/src/index.ts +20 -1
  75. package/src/intent.ts +216 -16
  76. package/src/law_check.ts +19 -1
  77. package/src/law_graph.ts +57 -8
  78. package/src/law_graph_usda.ts +73 -5
  79. package/src/law_value_type.ts +106 -19
  80. package/src/read.ts +47 -0
  81. package/src/read_projection_namespace.ts +7 -0
  82. package/src/shape_compat.ts +38 -39
  83. package/src/stable_ids.ts +37 -2
  84. package/src/test_call_usda.ts +83 -0
  85. package/src/wire.ts +36 -2
  86. package/src/wire_encode.ts +45 -1
  87. package/src/workspace_sharing.ts +27 -10
  88. package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pbjson.dart +0 -6096
  89. package/dart_types/lib/src/proto/nomos/kernel/v1/kernel.pbserver.dart +0 -50
  90. package/dart_types/lib/src/proto/nomos/kernel/v1/progress.pbjson.dart +0 -178
  91. package/dart_types/lib/src/proto/nomos/runtime/v1/runtime.pb.dart +0 -828
  92. package/dart_types/lib/src/proto/nomos/runtime/v1/runtime.pbenum.dart +0 -465
  93. package/dart_types/lib/src/proto/nomos/runtime/v1/runtime.pbjson.dart +0 -573
  94. package/dart_types/lib/src/proto/nomos/runtime/v1/runtime.pbserver.dart +0 -50
@@ -0,0 +1,685 @@
1
+ import type { z } from "zod";
2
+
3
+ import {
4
+ admitsNull,
5
+ isGitObjectIdSchema,
6
+ isSha256DigestSchema,
7
+ type Field,
8
+ type ValueObjectDescriptor,
9
+ type ValueObjectFieldDescriptor,
10
+ } from "./fields.js";
11
+ import {
12
+ zodArrayElement,
13
+ zodDef,
14
+ zodEnumValues,
15
+ zodKind,
16
+ zodObjectShape,
17
+ } from "./zod_introspection.js";
18
+
19
+ export interface TsResultField {
20
+ readonly name: string;
21
+ readonly lawPath: string;
22
+ readonly field?: Field;
23
+ readonly projectionSchema?: z.ZodTypeAny;
24
+ readonly required: boolean;
25
+ readonly attributed?: boolean;
26
+ }
27
+
28
+ export interface TsResultAggregate {
29
+ readonly typeName: string;
30
+ readonly lawPath: string;
31
+ readonly fields: readonly TsResultField[];
32
+ }
33
+
34
+ /** A constrained parser for the canonical USDA emitted by the Nomos kernel.
35
+ * It is syntax machinery, not a tenant value model: generated decoders below
36
+ * name every accepted aggregate and field relationship at compile time. */
37
+ export const TS_RESULT_USDA_PRELUDE = [
38
+ `type _NmsUsdaProperty = { readonly name: string; readonly value: string | number | boolean | readonly string[] };`,
39
+ `type _NmsUsdaPrim = { readonly typeName: string; readonly name: string; readonly properties: readonly _NmsUsdaProperty[]; readonly children: readonly _NmsUsdaPrim[] };`,
40
+ `const _nmsUsdaUnquote = (source: string): string => {`,
41
+ ` if (!source.startsWith('"') || !source.endsWith('"')) throw new Error("invalid USDA string");`,
42
+ ` let out = "";`,
43
+ ` for (let i = 1; i < source.length - 1; i += 1) {`,
44
+ ` const c = source[i]!; if (c !== "\\\\") { out += c; continue; }`,
45
+ ` const e = source[++i]; if (e === undefined) throw new Error("truncated USDA escape");`,
46
+ ` if (e === "n") out += "\\n"; else if (e === "r") out += "\\r"; else if (e === "t") out += "\\t";`,
47
+ ` else if (e === "b") out += "\\b"; else if (e === "f") out += "\\f"; else if (e === '"' || e === "\\\\") out += e;`,
48
+ ` else if (e === "u") { const hex = source.slice(i + 1, i + 5); if (!/^[0-9a-fA-F]{4}$/.test(hex)) throw new Error("invalid USDA unicode escape"); out += String.fromCharCode(Number.parseInt(hex, 16)); i += 4; }`,
49
+ ` else throw new Error("unsupported USDA escape: " + e);`,
50
+ ` } return out;`,
51
+ `};`,
52
+ `const _nmsUsdaAtom = (raw: string): string | number | boolean | readonly string[] => {`,
53
+ ` const value = raw.trim();`,
54
+ ` if (value.startsWith('"')) return _nmsUsdaUnquote(value);`,
55
+ ` if (value === "true" || value === "false") return value === "true";`,
56
+ ` if (/^-?(?:0|[1-9][0-9]*)(?:\\.[0-9]+)?$/.test(value)) return Number(value);`,
57
+ ` if (value.startsWith("<") && value.endsWith(">")) return value.slice(1, -1);`,
58
+ ` if (value.startsWith("[") && value.endsWith("]")) {`,
59
+ ` const body = value.slice(1, -1).trim(); if (!body) return [];`,
60
+ ` return body.split(",").map((entry) => _nmsUsdaAtom(entry)).map((entry) => { if (typeof entry !== "string") throw new Error("USDA relationship array is not textual"); return entry; });`,
61
+ ` }`,
62
+ ` throw new Error("unsupported USDA value " + value);`,
63
+ `};`,
64
+ `const _nmsParseResultUsda = (bytes: Uint8Array): _NmsUsdaPrim => {`,
65
+ ` const lines = new TextDecoder("utf-8", { fatal: true }).decode(bytes).split(/\\r?\\n/);`,
66
+ ` const roots: { typeName: string; name: string; properties: _NmsUsdaProperty[]; children: _NmsUsdaPrim[] }[] = [];`,
67
+ ` const stack: typeof roots = []; let pending: (typeof roots)[number] | undefined;`,
68
+ ` for (const original of lines) { const line = original.trim(); if (!line || line.startsWith("#") || line === "(" || line === ")" || line.startsWith("defaultPrim")) continue;`,
69
+ ` const declaration = /^def\\s+([A-Za-z_][A-Za-z0-9_]*)\\s+("(?:[^"\\\\]|\\\\.)*")$/.exec(line);`,
70
+ ` if (declaration) { pending = { typeName: declaration[1]!, name: _nmsUsdaUnquote(declaration[2]!), properties: [], children: [] }; continue; }`,
71
+ ` if (line === "{") { if (!pending) throw new Error("USDA scope has no declaration"); const parent = stack.at(-1); if (parent) parent.children.push(pending); else roots.push(pending); stack.push(pending); pending = undefined; continue; }`,
72
+ ` if (line === "}") { if (!stack.pop()) throw new Error("unbalanced USDA scope"); continue; }`,
73
+ ` const property = /^custom(?:\\s+uniform)?\\s+(?:rel|[A-Za-z0-9_\\[\\]]+)\\s+([A-Za-z0-9_:]+)\\s*=\\s*(.+)$/.exec(line);`,
74
+ ` if (property) { const owner = stack.at(-1); if (!owner) throw new Error("USDA property outside prim"); owner.properties.push({ name: property[1]!, value: _nmsUsdaAtom(property[2]!) }); continue; }`,
75
+ ` throw new Error("unsupported canonical USDA line: " + line);`,
76
+ ` }`,
77
+ ` if (stack.length || roots.length !== 1) throw new Error("USDA result must contain one balanced root prim"); return roots[0]!;`,
78
+ `};`,
79
+ `const _nmsUsdaProperty = (prim: _NmsUsdaPrim, name: string) => prim.properties.find((property) => property.name === name)?.value;`,
80
+ `const _nmsResultUsdaRel = (prim: _NmsUsdaPrim, name: string): string | undefined => { const value = _nmsUsdaProperty(prim, name); return typeof value === "string" ? value : undefined; };`,
81
+ `const _nmsUsdaRows = (bytes: Uint8Array): readonly _NmsUsdaPrim[] => { const root = _nmsParseResultUsda(bytes); if (root.typeName !== "NomosReadResult") throw new Error("expected NomosReadResult"); const rows = root.children.find((child) => child.typeName === "NomosListValue" && child.name === "Rows"); if (!rows) throw new Error("NomosReadResult has no Rows"); return rows.children; };`,
82
+ `const _nmsConflictUsdaRows = (bytes: Uint8Array): readonly _NmsUsdaPrim[] => { const root = _nmsParseResultUsda(bytes); if (root.typeName !== "NomosPendingConflicts" || root.name !== "Conflicts") throw new Error("expected NomosPendingConflicts"); const rows = root.children.find((child) => child.typeName === "NomosListValue" && child.name === "Rows"); if (!rows) throw new Error("NomosPendingConflicts has no Rows"); return rows.children; };`,
83
+ `type _NmsConflictCount = { readonly aggregatePath: string; readonly count: number };`,
84
+ `type _NmsConflictSummary = { readonly total: number; readonly ready: number; readonly evolutionRequired: number; readonly byAggregate: readonly _NmsConflictCount[] };`,
85
+ `const _nmsConflictUsdaSummary = (bytes: Uint8Array): _NmsConflictSummary => { const root = _nmsParseResultUsda(bytes); if (root.typeName !== "NomosPendingConflictSummary" || root.name !== "ConflictSummary") throw new Error("expected NomosPendingConflictSummary"); const integer = (name: string): number => { const value = _nmsUsdaProperty(root, name); if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) throw new Error(name + " is not an unsigned integer"); return value; }; const counts = root.children.find((child) => child.typeName === "NomosConflictCounts" && child.name === "ByAggregate"); if (!counts) throw new Error("NomosPendingConflictSummary has no ByAggregate counts"); return { total: integer("nomos:total"), ready: integer("nomos:ready"), evolutionRequired: integer("nomos:evolutionRequired"), byAggregate: counts.children.map((entry) => { const aggregatePath = _nmsResultUsdaRel(entry, "nomos:type"); const count = _nmsUsdaProperty(entry, "nomos:count"); if (aggregatePath === undefined || typeof count !== "number" || !Number.isSafeInteger(count) || count < 0) throw new Error("invalid NomosConflictCount"); return { aggregatePath, count }; }) }; };`,
86
+ `const _nmsUsdaPage = (bytes: Uint8Array): { readonly rows: readonly _NmsUsdaPrim[]; readonly cursor: string | null; readonly done: boolean } => { const root = _nmsParseResultUsda(bytes); if (root.typeName !== "NomosReadResult") throw new Error("expected NomosReadResult"); const rows = root.children.find((child) => child.typeName === "NomosListValue" && child.name === "Rows"); if (!rows) throw new Error("NomosReadResult has no Rows"); const cursor = _nmsUsdaProperty(root, "nomos:cursor"); const done = _nmsUsdaProperty(root, "nomos:done"); if (cursor !== undefined && typeof cursor !== "string") throw new Error("NomosReadResult cursor is not textual"); if (typeof done !== "boolean") throw new Error("NomosReadResult has no boolean done marker"); return { rows: rows.children, cursor: cursor ?? null, done }; };`,
87
+ `const _nmsUsdaField = (row: _NmsUsdaPrim, lawPath: string): _NmsUsdaPrim | undefined => row.children.find((child) => _nmsResultUsdaRel(child, "nomos:field") === lawPath);`,
88
+ `const _nmsUsdaRequired = (row: _NmsUsdaPrim, lawPath: string): _NmsUsdaPrim => { const value = _nmsUsdaField(row, lawPath); if (!value) throw new Error("USDA row omits required law field " + lawPath); return value; };`,
89
+ `const _nmsUsdaStringValue = (prim: _NmsUsdaPrim): string => { const value = _nmsUsdaProperty(prim, "nomos:value"); if (typeof value !== "string") throw new Error("USDA value is not string/token"); return value; };`,
90
+ `const _nmsUsdaNumberValue = (prim: _NmsUsdaPrim): number => { const value = _nmsUsdaProperty(prim, "nomos:value"); if (typeof value !== "number") throw new Error("USDA value is not numeric"); return value; };`,
91
+ `const _nmsUsdaBoolValue = (prim: _NmsUsdaPrim): boolean => { const value = _nmsUsdaProperty(prim, "nomos:value"); if (typeof value !== "boolean") throw new Error("USDA value is not bool"); return value; };`,
92
+ `const _nmsUsdaJsonValue = (prim: _NmsUsdaPrim): unknown => {`,
93
+ ` if (prim.typeName === "NomosNullValue") return null; if (prim.typeName === "NomosBoolValue") return _nmsUsdaBoolValue(prim);`,
94
+ ` if (prim.typeName === "NomosIntValue" || prim.typeName === "NomosNumberValue") return _nmsUsdaNumberValue(prim); if (prim.typeName === "NomosStringValue" || prim.typeName === "NomosTokenValue") return _nmsUsdaStringValue(prim);`,
95
+ ` if (prim.typeName === "NomosJsonValue") { const value = prim.children.find((child) => child.name === "Value"); if (!value) throw new Error("NomosJsonValue has no Value"); return _nmsUsdaJsonValue(value); }`,
96
+ ` if (prim.typeName === "NomosJsonArray") return prim.children.map(_nmsUsdaJsonValue);`,
97
+ ` if (prim.typeName === "NomosJsonObject") { const out: Record<string, unknown> = {}; for (const member of prim.children) { const key = _nmsUsdaProperty(member, "nomos:key"); const value = member.children.find((child) => child.name === "Value"); if (typeof key !== "string" || !value) throw new Error("invalid NomosJsonMember"); out[key] = _nmsUsdaJsonValue(value); } return out; }`,
98
+ ` throw new Error("unsupported nominal JSON prim " + prim.typeName);`,
99
+ `};`,
100
+ `const _nmsUsdaTypedMapValue = <T>(prim: _NmsUsdaPrim, decode: (value: _NmsUsdaPrim, key: string) => T): { readonly [key: string]: T } => { const entries: Array<readonly [string, T]> = []; for (const entry of prim.children) { const key = _nmsUsdaProperty(entry, "nomos:key"); const value = entry.children.find((child) => child.name === "Value"); if (typeof key !== "string" || !value) throw new Error("invalid NomosMapEntry"); entries.push([key, decode(value, key)]); } return Object.fromEntries(entries) as { readonly [key: string]: T }; };`,
101
+ `const _nmsVoObject = (value: unknown, path: string): object => { if (typeof value !== "object" || value === null || Array.isArray(value)) throw new TypeError(path + " must be an object"); return value; };`,
102
+ `const _nmsVoField = (value: object, name: string): unknown => Reflect.get(value, name);`,
103
+ `const _nmsVoExactKeys = (value: object, expected: readonly string[], path: string): void => { const allowed = new Set(expected); for (const key of Object.keys(value)) if (!allowed.has(key)) throw new TypeError(path + " has undeclared field " + key); };`,
104
+ `const _nmsVoString = (value: unknown, path: string): string => { if (typeof value !== "string") throw new TypeError(path + " must be a string"); return value; };`,
105
+ `const _nmsVoNumber = (value: unknown, path: string, integer: boolean): number => { if (typeof value !== "number" || !Number.isFinite(value) || (integer && !Number.isInteger(value))) throw new TypeError(path + (integer ? " must be an integer" : " must be a finite number")); return value; };`,
106
+ `const _nmsVoBoolean = (value: unknown, path: string): boolean => { if (typeof value !== "boolean") throw new TypeError(path + " must be a boolean"); return value; };`,
107
+ `const _nmsVoArray = (value: unknown, path: string): readonly unknown[] => { if (!Array.isArray(value)) throw new TypeError(path + " must be an array"); return value; };`,
108
+ `const _nmsVoEnum = <const Values extends readonly string[]>(value: unknown, allowed: Values, path: string): Values[number] => { if (typeof value !== "string" || !allowed.includes(value as Values[number])) throw new TypeError(path + " has an unknown enum value"); return value as Values[number]; };`,
109
+ `const _nmsVoLiteral = <T extends string>(value: unknown, expected: T, path: string): T => { if (value !== expected) throw new TypeError(path + " must equal " + expected); return expected; };`,
110
+ `const _nmsVoMap = <T>(value: unknown, path: string, decode: (entry: unknown, key: string) => T): { readonly [key: string]: T } => { const object = _nmsVoObject(value, path); return Object.fromEntries(Object.keys(object).map((key) => [key, decode(_nmsVoField(object, key), key)])) as { readonly [key: string]: T }; };`,
111
+ ``,
112
+ ] as const;
113
+
114
+ const voSymbol = (value: string): string =>
115
+ value.replace(/[^A-Za-z0-9_$]+/g, "_").replace(/^[^A-Za-z_$]/, "_$&");
116
+
117
+ const voDecoderName = (name: string): string =>
118
+ `_nmsDecodeValueObject_${voSymbol(name)}`;
119
+
120
+ const voFieldDecode = (
121
+ field: ValueObjectFieldDescriptor,
122
+ value: string,
123
+ path: string,
124
+ workspace: string
125
+ ): string => {
126
+ switch (field.type) {
127
+ case "string": {
128
+ const decoded = `_nmsVoString(${value}, ${path})`;
129
+ if (field.idOf !== undefined) {
130
+ return `_nmsRef<${field.idOf}>(${workspace}, ${JSON.stringify(
131
+ field.idOf
132
+ )}, ${decoded})`;
133
+ }
134
+ if (field.digest === "sha256") return `sha256Digest(${decoded})`;
135
+ return field.brand === undefined
136
+ ? decoded
137
+ : `${decoded} as ${field.brand}`;
138
+ }
139
+ case "number":
140
+ return `_nmsVoNumber(${value}, ${path}, ${
141
+ field.int === true ? "true" : "false"
142
+ })`;
143
+ case "boolean":
144
+ return `_nmsVoBoolean(${value}, ${path})`;
145
+ case "enum":
146
+ return `_nmsVoEnum(${value}, ${JSON.stringify(field.values)}, ${path})`;
147
+ case "literal":
148
+ return `_nmsVoLiteral(${value}, ${JSON.stringify(field.value)}, ${path})`;
149
+ case "array":
150
+ return `_nmsVoArray(${value}, ${path}).map((entry, index) => ${voFieldDecode(
151
+ field.items,
152
+ "entry",
153
+ `${path} + "[" + index + "]"`,
154
+ workspace
155
+ )})`;
156
+ case "map":
157
+ return `_nmsVoMap(${value}, ${path}, (entry, key) => ${voFieldDecode(
158
+ field.values,
159
+ "entry",
160
+ `${path} + "." + key`,
161
+ workspace
162
+ )})`;
163
+ case "object":
164
+ case "geometry":
165
+ return `${voDecoderName(field.ref)}(${value}, ${workspace}, ${path})`;
166
+ }
167
+ };
168
+
169
+ /** Generate exact value-object validators from the descriptor graph that also
170
+ * generates the public interfaces. An untrusted USDA value becomes nominal
171
+ * only after every field, optional arm and discriminator has been checked. */
172
+ export function emitTsValueObjectDecoders(
173
+ descriptors: readonly ValueObjectDescriptor[]
174
+ ): readonly string[] {
175
+ const lines: string[] = [];
176
+ const geometryDepth = (geometry: string): number => {
177
+ switch (geometry) {
178
+ case "Point":
179
+ return 1;
180
+ case "LineString":
181
+ case "MultiPoint":
182
+ return 2;
183
+ case "Polygon":
184
+ return 3;
185
+ default:
186
+ throw new Error(`unsupported geometry '${geometry}'`);
187
+ }
188
+ };
189
+ const coordinates = (
190
+ value: string,
191
+ path: string,
192
+ remaining: number
193
+ ): string =>
194
+ remaining === 0
195
+ ? `_nmsVoNumber(${value}, ${path}, false)`
196
+ : `_nmsVoArray(${value}, ${path}).map((entry, index) => ${coordinates(
197
+ "entry",
198
+ `${path} + "[" + index + "]"`,
199
+ remaining - 1
200
+ )})`;
201
+
202
+ for (const descriptor of descriptors) {
203
+ const name = voDecoderName(descriptor.name);
204
+ if (descriptor.geometry !== undefined) {
205
+ lines.push(
206
+ `const ${name} = (value: unknown, _workspace: string, path = ${JSON.stringify(
207
+ descriptor.name
208
+ )}): ${descriptor.name} => {`,
209
+ ` const object = _nmsVoObject(value, path); _nmsVoExactKeys(object, ["type", "coordinates"], path);`,
210
+ ` return { type: _nmsVoLiteral(_nmsVoField(object, "type"), ${JSON.stringify(
211
+ descriptor.geometry
212
+ )}, path + ".type"), coordinates: ${coordinates(
213
+ `_nmsVoField(object, "coordinates")`,
214
+ `path + ".coordinates"`,
215
+ geometryDepth(descriptor.geometry)
216
+ )} };`,
217
+ `};`,
218
+ ``
219
+ );
220
+ continue;
221
+ }
222
+ if (descriptor.union !== undefined) {
223
+ lines.push(
224
+ `const ${name} = (value: unknown, workspace: string, path = ${JSON.stringify(
225
+ descriptor.name
226
+ )}): ${descriptor.name} => {`,
227
+ ` const object = _nmsVoObject(value, path); const type = _nmsVoString(_nmsVoField(object, "type"), path + ".type");`,
228
+ ` switch (type) {`
229
+ );
230
+ for (const [armName, arm] of Object.entries(descriptor.union)) {
231
+ if ("ref" in arm) {
232
+ lines.push(
233
+ ` case ${JSON.stringify(
234
+ armName
235
+ )}: _nmsVoExactKeys(object, ["type", "value"], path); return { type: ${JSON.stringify(
236
+ armName
237
+ )}, value: ${voDecoderName(
238
+ arm.ref
239
+ )}(_nmsVoField(object, "value"), workspace, path + ".value") };`
240
+ );
241
+ continue;
242
+ }
243
+ const fields = Object.entries(arm.fields);
244
+ lines.push(
245
+ ` case ${JSON.stringify(armName)}: {`,
246
+ ` _nmsVoExactKeys(object, ${JSON.stringify([
247
+ "type",
248
+ ...fields.map(([field]) => field),
249
+ ])}, path);`
250
+ );
251
+ for (const [field] of fields) {
252
+ lines.push(
253
+ ` const field_${voSymbol(
254
+ field
255
+ )} = _nmsVoField(object, ${JSON.stringify(field)});`
256
+ );
257
+ }
258
+ lines.push(` return { type: ${JSON.stringify(armName)},`);
259
+ for (const [field, spec] of fields) {
260
+ const raw = `field_${voSymbol(field)}`;
261
+ const decoded = voFieldDecode(
262
+ spec,
263
+ raw,
264
+ `path + ${JSON.stringify(`.${field}`)}`,
265
+ "workspace"
266
+ );
267
+ lines.push(
268
+ spec.optional === true
269
+ ? ` ...(${raw} === undefined ? {} : { ${JSON.stringify(
270
+ field
271
+ )}: ${decoded} }),`
272
+ : ` ${JSON.stringify(field)}: ${decoded},`
273
+ );
274
+ }
275
+ lines.push(` };`, ` }`);
276
+ }
277
+ lines.push(
278
+ ` default: throw new TypeError(path + " has unknown discriminator " + type);`,
279
+ ` }`,
280
+ `};`,
281
+ ``
282
+ );
283
+ continue;
284
+ }
285
+ const fields = Object.entries(descriptor.fields ?? {});
286
+ lines.push(
287
+ `const ${name} = (value: unknown, workspace: string, path = ${JSON.stringify(
288
+ descriptor.name
289
+ )}): ${descriptor.name} => {`,
290
+ ` const object = _nmsVoObject(value, path); _nmsVoExactKeys(object, ${JSON.stringify(
291
+ fields.map(([field]) => field)
292
+ )}, path);`
293
+ );
294
+ for (const [field] of fields) {
295
+ lines.push(
296
+ ` const field_${voSymbol(
297
+ field
298
+ )} = _nmsVoField(object, ${JSON.stringify(field)});`
299
+ );
300
+ }
301
+ lines.push(` return {`);
302
+ for (const [field, spec] of fields) {
303
+ const raw = `field_${voSymbol(field)}`;
304
+ const decoded = voFieldDecode(
305
+ spec,
306
+ raw,
307
+ `path + ${JSON.stringify(`.${field}`)}`,
308
+ "workspace"
309
+ );
310
+ lines.push(
311
+ spec.optional === true
312
+ ? ` ...(${raw} === undefined ? {} : { ${JSON.stringify(
313
+ field
314
+ )}: ${decoded} }),`
315
+ : ` ${JSON.stringify(field)}: ${decoded},`
316
+ );
317
+ }
318
+ lines.push(` };`, `};`, ``);
319
+ }
320
+ return lines;
321
+ }
322
+
323
+ const decodeSurfacedScalar = (field: Field, expression: string): string => {
324
+ const path = JSON.stringify("Surfaced observation value");
325
+ switch (field.kind) {
326
+ case "string": {
327
+ const value = `_nmsVoString(${expression}, ${path})`;
328
+ return isSha256DigestSchema(field.zod)
329
+ ? `sha256Digest(${value})`
330
+ : isGitObjectIdSchema(field.zod)
331
+ ? `gitObjectId(${value})`
332
+ : value;
333
+ }
334
+ case "position":
335
+ return `_nmsVoString(${expression}, ${path})`;
336
+ case "int":
337
+ case "counter":
338
+ return `_nmsVoNumber(${expression}, ${path}, true)`;
339
+ case "bool":
340
+ return `_nmsVoBoolean(${expression}, ${path})`;
341
+ case "enum":
342
+ return `_nmsVoEnum(${expression}, ${JSON.stringify(
343
+ zodEnumValues(field.zod)
344
+ )}, ${path})`;
345
+ case "ref": {
346
+ const id = `_nmsVoString(${expression}, ${path})`;
347
+ return field.foreignRef === undefined &&
348
+ field.nomosRef === undefined &&
349
+ field.versionedForeignRef === undefined &&
350
+ field.refAggregateId !== undefined
351
+ ? `_nmsRef<${field.refAggregateId}>(workspace, ${JSON.stringify(
352
+ field.refAggregateId
353
+ )}, ${id})`
354
+ : id;
355
+ }
356
+ default:
357
+ throw new Error(
358
+ `result USDA codegen does not support Surfaced field kind '${field.kind}'`
359
+ );
360
+ }
361
+ };
362
+
363
+ /** Emit the value decoder for one observation in the kernel-owned pending
364
+ * conflict index. The wrapper is framework syntax, while the value itself is
365
+ * decoded from the same DSL Field that generates the aggregate read model. */
366
+ export const tsConflictObservationValue = (
367
+ field: Field,
368
+ expression: string
369
+ ): string =>
370
+ decodeSurfacedScalar(field, `_nmsUsdaJsonValue(${expression})`);
371
+
372
+ const decode = (field: Field, expression: string): string => {
373
+ const structured =
374
+ field.nomosRef !== undefined || field.versionedForeignRef !== undefined;
375
+ const authored =
376
+ field.driver.kind === "Surfaced"
377
+ ? `_nmsDecodeSurfaced(_nmsUsdaJsonValue(${expression}), (value) => ${decodeSurfacedScalar(
378
+ field,
379
+ "value"
380
+ )})`
381
+ : structured
382
+ ? `_nmsUsdaJsonValue(${expression})`
383
+ : (() => {
384
+ switch (field.kind) {
385
+ case "string":
386
+ return isSha256DigestSchema(field.zod)
387
+ ? `sha256Digest(_nmsUsdaStringValue(${expression}))`
388
+ : isGitObjectIdSchema(field.zod)
389
+ ? `gitObjectId(_nmsUsdaStringValue(${expression}))`
390
+ : `_nmsUsdaStringValue(${expression})`;
391
+ case "position":
392
+ return `_nmsUsdaStringValue(${expression})`;
393
+ case "ref": {
394
+ // A same-workspace reference is not a string in the generated API. The
395
+ // kernel's canonical USDA stores its stable id; reconstruct the nominal
396
+ // reference here while the decoder still has the authenticated workspace.
397
+ // Foreign/atomic/versioned references need additional generated fields and
398
+ // are completed by the generated hydration pass immediately afterwards.
399
+ if (
400
+ field.foreignRef === undefined &&
401
+ field.nomosRef === undefined &&
402
+ field.versionedForeignRef === undefined &&
403
+ field.refAggregateId !== undefined
404
+ ) {
405
+ return `_nmsRef<${
406
+ field.refAggregateId
407
+ }>(workspace, ${JSON.stringify(
408
+ field.refAggregateId
409
+ )}, _nmsUsdaStringValue(${expression}))`;
410
+ }
411
+ return `_nmsUsdaStringValue(${expression})`;
412
+ }
413
+ case "int":
414
+ case "counter":
415
+ return `_nmsUsdaNumberValue(${expression})`;
416
+ case "bool":
417
+ return `_nmsUsdaBoolValue(${expression})`;
418
+ case "enum":
419
+ return `_nmsUsdaStringValue(${expression}) as ${enumUnion(
420
+ field
421
+ )}`;
422
+ case "set":
423
+ return `${expression}.children.map(_nmsUsdaStringValue)`;
424
+ case "json":
425
+ return field.valueObject === undefined
426
+ ? `_nmsUsdaJsonValue(${expression}) as ${
427
+ field.jsonShape === "object"
428
+ ? "Record<string, unknown>"
429
+ : "unknown"
430
+ }`
431
+ : `${voDecoderName(
432
+ field.valueObject.name
433
+ )}(_nmsUsdaJsonValue(${expression}), workspace)`;
434
+ case "evidence":
435
+ return `_nmsUsdaJsonValue(${expression}) as EvidenceRef`;
436
+ case "map": {
437
+ const inner =
438
+ field.mapValueKind === "int"
439
+ ? "_nmsUsdaNumberValue"
440
+ : field.mapValueKind === "json"
441
+ ? "_nmsUsdaJsonValue"
442
+ : "_nmsUsdaStringValue";
443
+ const target =
444
+ field.mapValueVo?.name ??
445
+ (field.mapValueKind === "int"
446
+ ? "number"
447
+ : field.mapValueKind === "json"
448
+ ? "unknown"
449
+ : "string");
450
+ return field.mapValueVo === undefined
451
+ ? `_nmsUsdaTypedMapValue<${target}>(${expression}, (value) => ${inner}(value) as ${target})`
452
+ : `_nmsUsdaTypedMapValue<${target}>(${expression}, (value, key) => ${voDecoderName(
453
+ field.mapValueVo.name
454
+ )}(_nmsUsdaJsonValue(value), workspace, ${JSON.stringify(
455
+ field.mapValueVo.name
456
+ )} + "." + key))`;
457
+ }
458
+ default:
459
+ throw new Error(
460
+ `result USDA codegen does not support field kind '${field.kind}'`
461
+ );
462
+ }
463
+ })();
464
+ return admitsNull(field)
465
+ ? `(${expression}.typeName === "NomosNullValue" ? null : ${authored})`
466
+ : authored;
467
+ };
468
+
469
+ const projectionPresence = (
470
+ schema: z.ZodTypeAny
471
+ ): { readonly schema: z.ZodTypeAny; readonly optional: boolean } => {
472
+ let inner = schema;
473
+ let optional = false;
474
+ while (zodKind(inner) === "optional" || zodKind(inner) === "default") {
475
+ optional = true;
476
+ const next = zodDef(inner).innerType;
477
+ if (next === undefined) {
478
+ throw new Error("projection USDA codegen: wrapper has no inner schema");
479
+ }
480
+ inner = next;
481
+ }
482
+ return { schema: inner, optional };
483
+ };
484
+
485
+ /** Decode one engine-projected value from the exact schema authored on the read.
486
+ * This deliberately emits structural validation rather than returning `unknown` and
487
+ * asserting the desired result type. The read schema is the sole type authority. */
488
+ const decodeProjectionValue = (
489
+ schema: z.ZodTypeAny,
490
+ value: string,
491
+ path: string
492
+ ): string => {
493
+ const { schema: inner } = projectionPresence(schema);
494
+ switch (zodKind(inner)) {
495
+ case "nullable": {
496
+ const nested = zodDef(inner).innerType;
497
+ if (nested === undefined) {
498
+ throw new Error("projection USDA codegen: nullable has no inner schema");
499
+ }
500
+ return `(${value} === null ? null : ${decodeProjectionValue(
501
+ nested,
502
+ value,
503
+ path
504
+ )})`;
505
+ }
506
+ case "string":
507
+ return `_nmsVoString(${value}, ${path})`;
508
+ case "enum":
509
+ return `_nmsVoEnum(${value}, ${JSON.stringify(
510
+ zodEnumValues(inner)
511
+ )}, ${path})`;
512
+ case "boolean":
513
+ return `_nmsVoBoolean(${value}, ${path})`;
514
+ case "number":
515
+ return `_nmsVoNumber(${value}, ${path}, false)`;
516
+ case "literal": {
517
+ const expected = zodDef(inner).values?.[0] ?? zodDef(inner).value;
518
+ if (typeof expected !== "string") {
519
+ throw new Error(
520
+ "projection USDA codegen: only textual literals are supported"
521
+ );
522
+ }
523
+ return `_nmsVoLiteral(${value}, ${JSON.stringify(expected)}, ${path})`;
524
+ }
525
+ case "array":
526
+ return `_nmsVoArray(${value}, ${path}).map((entry, index) => ${decodeProjectionValue(
527
+ zodArrayElement(inner),
528
+ "entry",
529
+ `${path} + "[" + index + "]"`
530
+ )})`;
531
+ case "record": {
532
+ const recordValue = zodDef(inner).valueType;
533
+ if (recordValue === undefined) {
534
+ throw new Error("projection USDA codegen: record has no value schema");
535
+ }
536
+ return `_nmsVoMap(${value}, ${path}, (entry, key) => ${decodeProjectionValue(
537
+ recordValue,
538
+ "entry",
539
+ `${path} + "." + key`
540
+ )})`;
541
+ }
542
+ case "object": {
543
+ const fields = Object.entries(zodObjectShape(inner));
544
+ const expected = JSON.stringify(fields.map(([name]) => name));
545
+ const members = fields.map(([name, field]) => {
546
+ const selected = `_nmsVoField(object, ${JSON.stringify(name)})`;
547
+ const presence = projectionPresence(field);
548
+ const decoded = decodeProjectionValue(
549
+ presence.schema,
550
+ selected,
551
+ `path + ${JSON.stringify(`.${name}`)}`
552
+ );
553
+ return presence.optional
554
+ ? `...(${selected} === undefined ? {} : { ${JSON.stringify(
555
+ name
556
+ )}: ${decoded} })`
557
+ : `${JSON.stringify(name)}: ${decoded}`;
558
+ });
559
+ return `((projected, path) => { const object = _nmsVoObject(projected, path); _nmsVoExactKeys(object, ${expected}, path); return { ${members.join(
560
+ ", "
561
+ )} }; })(${value}, ${path})`;
562
+ }
563
+ default:
564
+ throw new Error(
565
+ `projection USDA codegen: unsupported declared schema '${zodKind(inner)}'`
566
+ );
567
+ }
568
+ };
569
+
570
+ const decodeProjection = (schema: z.ZodTypeAny, expression: string): string =>
571
+ decodeProjectionValue(
572
+ schema,
573
+ `_nmsUsdaJsonValue(${expression})`,
574
+ JSON.stringify("Projected read value")
575
+ );
576
+
577
+ const enumUnion = (field: Field): string => {
578
+ try {
579
+ const values = zodEnumValues(field.zod);
580
+ return values.length
581
+ ? values.map((value) => JSON.stringify(value)).join(" | ")
582
+ : "string";
583
+ } catch {
584
+ return "string";
585
+ }
586
+ };
587
+
588
+ export function emitTsResultDecoder(
589
+ aggregate: TsResultAggregate
590
+ ): readonly string[] {
591
+ const functionName = `_nmsDecode${aggregate.typeName}Rows`;
592
+ const local = (name: string) =>
593
+ `field_${name.replace(/[^A-Za-z0-9_$]/g, "_")}`;
594
+ const members = aggregate.fields.map(
595
+ ({ name, lawPath, field, projectionSchema, required }) => {
596
+ const selected = `_nmsUsdaField(row, ${JSON.stringify(lawPath)})`;
597
+ const value = required
598
+ ? `_nmsUsdaRequired(row, ${JSON.stringify(lawPath)})`
599
+ : `${local(name)}!`;
600
+ const authored =
601
+ field !== undefined
602
+ ? decode(field, value)
603
+ : projectionSchema !== undefined
604
+ ? decodeProjection(projectionSchema, value)
605
+ : (() => {
606
+ throw new Error(
607
+ `result USDA decoder field '${name}' has no DSL schema`
608
+ );
609
+ })();
610
+ return required
611
+ ? ` ${JSON.stringify(name)}: ${authored},`
612
+ : ` ${JSON.stringify(name)}: (${local(
613
+ name
614
+ )} = ${selected}) === undefined ? undefined : ${authored},`;
615
+ }
616
+ );
617
+ const declarations = aggregate.fields
618
+ .filter((field) => !field.required)
619
+ .map(({ name }) => ` let ${local(name)}: _NmsUsdaPrim | undefined;`);
620
+ const attributed = aggregate.fields.filter(
621
+ (field) => field.attributed === true
622
+ );
623
+ const requiresHydration = aggregate.fields.some(
624
+ ({ field }) =>
625
+ field !== undefined &&
626
+ (field.foreignRef !== undefined ||
627
+ field.nomosRef !== undefined ||
628
+ field.versionedForeignRef !== undefined)
629
+ );
630
+ const dataAssertion = requiresHydration
631
+ ? ` as unknown as ${aggregate.typeName}`
632
+ : ` satisfies ${aggregate.typeName}`;
633
+ const provenance =
634
+ attributed.length === 0
635
+ ? []
636
+ : [
637
+ ` "__prov": {`,
638
+ ...attributed.map(({ name, lawPath }) => {
639
+ const selected = `_nmsUsdaField(row, ${JSON.stringify(lawPath)})`;
640
+ return ` ...(${selected} === undefined ? {} : { ${JSON.stringify(
641
+ name
642
+ )}: { author: typeof _nmsUsdaProperty(${selected}!, "nomos:author") === "string" ? _nmsUsdaProperty(${selected}!, "nomos:author") as string : null, wasContested: _nmsUsdaProperty(${selected}!, "nomos:wasContested") === true } }),`;
643
+ }),
644
+ ` },`,
645
+ ];
646
+ return [
647
+ `const ${functionName} = (bytes: Uint8Array, workspace: string): Row<${aggregate.typeName}>[] => _nmsUsdaRows(bytes).map((row) => {`,
648
+ ` if (_nmsResultUsdaRel(row, "nomos:type") !== ${JSON.stringify(
649
+ aggregate.lawPath
650
+ )}) throw new Error("USDA row has the wrong law type for ${
651
+ aggregate.typeName
652
+ }");`,
653
+ ` const id = _nmsUsdaProperty(row, "nomos:id"); if (typeof id !== "string") throw new Error("USDA row has no string identity");`,
654
+ ...declarations,
655
+ ` return {`,
656
+ ` data: {`,
657
+ ...members,
658
+ ...provenance,
659
+ ` }${dataAssertion},`,
660
+ ` ref: _nmsRef<${aggregate.typeName}>(workspace, ${JSON.stringify(
661
+ aggregate.typeName
662
+ )}, id),`,
663
+ ` type: ${JSON.stringify(aggregate.typeName)},`,
664
+ ` };`,
665
+ `});`,
666
+ `const _nmsDecode${aggregate.typeName}Page = (bytes: Uint8Array, workspace: string): { rows: Row<${aggregate.typeName}>[]; cursor: string | null; done: boolean } => { const page = _nmsUsdaPage(bytes); return { rows: page.rows.map((row) => {`,
667
+ ` if (_nmsResultUsdaRel(row, "nomos:type") !== ${JSON.stringify(
668
+ aggregate.lawPath
669
+ )}) throw new Error("USDA row has the wrong law type for ${
670
+ aggregate.typeName
671
+ }");`,
672
+ ` const id = _nmsUsdaProperty(row, "nomos:id"); if (typeof id !== "string") throw new Error("USDA row has no string identity");`,
673
+ ...declarations,
674
+ ` return { data: {`,
675
+ ...members,
676
+ ...provenance,
677
+ ` }${dataAssertion}, ref: _nmsRef<${
678
+ aggregate.typeName
679
+ }>(workspace, ${JSON.stringify(
680
+ aggregate.typeName
681
+ )}, id), type: ${JSON.stringify(aggregate.typeName)} };`,
682
+ `}), cursor: page.cursor, done: page.done }; };`,
683
+ ``,
684
+ ];
685
+ }