@unson/brainbase-mcp 0.6.0 → 0.8.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 (148) hide show
  1. package/contracts/foundation/graph-history.sql +634 -0
  2. package/contracts/judgment-value-proof/schema.json +43 -1
  3. package/dist/canonical-task-contract.d.ts +9 -0
  4. package/dist/canonical-task-contract.js +39 -0
  5. package/dist/canonical-task-principal.d.ts +16 -0
  6. package/dist/canonical-task-principal.js +36 -0
  7. package/dist/canonical-task-service.d.ts +251 -0
  8. package/dist/canonical-task-service.js +820 -0
  9. package/dist/cli.d.ts +2 -0
  10. package/dist/cli.js +107 -0
  11. package/dist/company-os-evaluation.d.ts +193 -0
  12. package/dist/company-os-evaluation.js +1150 -0
  13. package/dist/company-os-impact-review.d.ts +248 -0
  14. package/dist/company-os-impact-review.js +663 -0
  15. package/dist/company-os-learning-adoption.d.ts +288 -0
  16. package/dist/company-os-learning-adoption.js +944 -0
  17. package/dist/company-os-objectives.d.ts +63 -0
  18. package/dist/company-os-objectives.js +234 -0
  19. package/dist/company-os-receipt-adapter.d.ts +109 -0
  20. package/dist/company-os-receipt-adapter.js +636 -0
  21. package/dist/constraint-exception-store.d.ts +23 -0
  22. package/dist/constraint-exception-store.js +108 -0
  23. package/dist/constraint-resolution.d.ts +175 -0
  24. package/dist/constraint-resolution.js +922 -0
  25. package/dist/decision-adapter.d.ts +145 -0
  26. package/dist/decision-adapter.js +586 -0
  27. package/dist/durable-wait-http.d.ts +51 -0
  28. package/dist/durable-wait-http.js +497 -0
  29. package/dist/durable-waits.d.ts +234 -0
  30. package/dist/durable-waits.js +944 -0
  31. package/dist/execution-authority-http.d.ts +28 -0
  32. package/dist/execution-authority-http.js +359 -0
  33. package/dist/execution-authority.d.ts +201 -0
  34. package/dist/execution-authority.js +634 -0
  35. package/dist/foundation-authenticated-tools.d.ts +56 -0
  36. package/dist/foundation-authenticated-tools.js +347 -0
  37. package/dist/foundation-catalog.d.ts +26 -0
  38. package/dist/foundation-catalog.js +206 -0
  39. package/dist/foundation-constraint-store.d.ts +50 -0
  40. package/dist/foundation-constraint-store.js +215 -0
  41. package/dist/foundation-graph-http.d.ts +43 -0
  42. package/dist/foundation-graph-http.js +243 -0
  43. package/dist/foundation-graph-write.d.ts +90 -0
  44. package/dist/foundation-graph-write.js +447 -0
  45. package/dist/foundation-http.d.ts +90 -0
  46. package/dist/foundation-http.js +439 -0
  47. package/dist/foundation-public-provider.d.ts +140 -0
  48. package/dist/foundation-public-provider.js +192 -0
  49. package/dist/foundation-store.d.ts +132 -0
  50. package/dist/foundation-store.js +654 -0
  51. package/dist/graph-corrections.d.ts +157 -0
  52. package/dist/graph-corrections.js +620 -0
  53. package/dist/graph-foundation-reader.d.ts +60 -0
  54. package/dist/graph-foundation-reader.js +494 -0
  55. package/dist/graph-retrieval.d.ts +6 -1
  56. package/dist/graph-revision-reader.d.ts +80 -0
  57. package/dist/graph-revision-reader.js +246 -0
  58. package/dist/graph-web-http.d.ts +26 -0
  59. package/dist/graph-web-http.js +215 -0
  60. package/dist/graph-web.d.ts +364 -0
  61. package/dist/graph-web.js +639 -0
  62. package/dist/judgment-dag-composition.d.ts +224 -0
  63. package/dist/judgment-dag-composition.js +731 -0
  64. package/dist/judgment-dag.d.ts +2 -0
  65. package/dist/judgment-dag.js +1 -0
  66. package/dist/judgment-problem-snapshot.d.ts +213 -0
  67. package/dist/judgment-problem-snapshot.js +1073 -0
  68. package/dist/judgment-value-proof-review.d.ts +166 -0
  69. package/dist/judgment-value-proof-review.js +437 -0
  70. package/dist/judgment-value-proof.d.ts +28 -1
  71. package/dist/judgment-value-proof.js +53 -8
  72. package/dist/judgment-view-http.d.ts +22 -0
  73. package/dist/judgment-view-http.js +128 -0
  74. package/dist/judgment-view.d.ts +222 -0
  75. package/dist/judgment-view.js +627 -0
  76. package/dist/knowledge-adapter.d.ts +112 -0
  77. package/dist/knowledge-adapter.js +691 -0
  78. package/dist/knowledge-continuation.d.ts +127 -0
  79. package/dist/knowledge-continuation.js +446 -0
  80. package/dist/knowledge-lookup.d.ts +178 -0
  81. package/dist/knowledge-lookup.js +758 -0
  82. package/dist/local-web-fetch-bridge.d.ts +5 -0
  83. package/dist/local-web-fetch-bridge.js +37 -0
  84. package/dist/local-web-host.d.ts +109 -0
  85. package/dist/local-web-host.js +688 -0
  86. package/dist/local-web-security.d.ts +25 -0
  87. package/dist/local-web-security.js +95 -0
  88. package/dist/ontology-foundation.d.ts +209 -0
  89. package/dist/ontology-foundation.js +1000 -0
  90. package/dist/ontology.d.ts +13 -0
  91. package/dist/ontology.js +14 -0
  92. package/dist/organization-connection.d.ts +164 -0
  93. package/dist/organization-connection.js +428 -0
  94. package/dist/organization-graph.d.ts +15 -0
  95. package/dist/organization-graph.js +24 -4
  96. package/dist/personal-knowledge.d.ts +132 -0
  97. package/dist/personal-knowledge.js +779 -0
  98. package/dist/personal-memory-handover.d.ts +108 -0
  99. package/dist/personal-memory-handover.js +369 -0
  100. package/dist/philosophy-revision-reader.d.ts +85 -0
  101. package/dist/philosophy-revision-reader.js +241 -0
  102. package/dist/portable-graph.d.ts +24 -0
  103. package/dist/portable-graph.js +77 -0
  104. package/dist/problem-candidates.d.ts +149 -0
  105. package/dist/problem-candidates.js +898 -0
  106. package/dist/problem-selection.d.ts +238 -0
  107. package/dist/problem-selection.js +995 -0
  108. package/dist/resource-reservation-http.d.ts +31 -0
  109. package/dist/resource-reservation-http.js +371 -0
  110. package/dist/resource-reservations.d.ts +221 -0
  111. package/dist/resource-reservations.js +577 -0
  112. package/dist/server.d.ts +104 -2
  113. package/dist/server.js +186 -4
  114. package/dist/ssot.d.ts +6 -1
  115. package/dist/ssot.js +63 -5
  116. package/dist/streamable-http.d.ts +42 -0
  117. package/dist/streamable-http.js +288 -0
  118. package/dist/types.d.ts +20 -0
  119. package/dist/value-proof-review-http.d.ts +25 -0
  120. package/dist/value-proof-review-http.js +185 -0
  121. package/dist/world-model.d.ts +199 -0
  122. package/dist/world-model.js +955 -0
  123. package/package.json +230 -3
  124. package/ui/brainbase-tokens.css +56 -0
  125. package/ui/graph-own-share.js +367 -0
  126. package/ui/graph-projects-view.css +23 -0
  127. package/ui/graph-projects-view.js +730 -0
  128. package/ui/graph-registry-view.css +101 -0
  129. package/ui/graph-registry-view.js +804 -0
  130. package/ui/graph-view-shared.css +522 -0
  131. package/ui/graph-view-shared.js +1227 -0
  132. package/ui/judgment-view.css +312 -0
  133. package/ui/judgment-view.js +508 -0
  134. package/ui/local-web-shell.css +396 -0
  135. package/ui/local-web-shell.js +378 -0
  136. package/ui/objective-editor-http-port.js +154 -0
  137. package/ui/objective-editor.css +286 -0
  138. package/ui/objective-editor.js +1586 -0
  139. package/ui/outcome-knowledge.css +50 -14
  140. package/ui/outcome-knowledge.js +15 -1
  141. package/ui/outcome-mana.css +91 -14
  142. package/ui/outcome-mana.js +958 -61
  143. package/ui/value-proof-review.css +504 -0
  144. package/ui/value-proof-review.js +1104 -0
  145. package/ui/workspace-kit.css +485 -0
  146. package/ui/workspace-kit.js +229 -0
  147. package/ui/world-model-view.css +188 -0
  148. package/ui/world-model-view.js +486 -0
@@ -0,0 +1,731 @@
1
+ /**
2
+ * Contract for composing versioned Judgment DAGs into one parent judgment.
3
+ *
4
+ * This module intentionally has no persistence or host adapter dependency.
5
+ * It validates the composition, freezes the evaluation boundary, and records
6
+ * the result of each child without changing the J0 single-DAG run artifact.
7
+ */
8
+ import { JUDGMENT_DAG_SCOPE_TYPES } from './judgment-dag-core.js';
9
+ export const JUDGMENT_DAG_COMPOSITION_VERSION = 'judgment-dag-composition.v1';
10
+ export const JUDGMENT_DAG_COMPOSITION_STATUSES = Object.freeze([
11
+ 'completed',
12
+ 'failed',
13
+ 'held'
14
+ ]);
15
+ export const JUDGMENT_DAG_SUBDAG_STATUSES = Object.freeze([
16
+ 'completed',
17
+ 'failed',
18
+ 'held'
19
+ ]);
20
+ export class JudgmentDAGCompositionError extends Error {
21
+ code;
22
+ invocation_id;
23
+ dependency_id;
24
+ cycle;
25
+ constructor(code, message, details = {}) {
26
+ super(message);
27
+ this.name = 'JudgmentDAGCompositionError';
28
+ this.code = code;
29
+ this.invocation_id = details.invocation_id;
30
+ this.dependency_id = details.dependency_id;
31
+ this.cycle = details.cycle;
32
+ }
33
+ }
34
+ function isRecord(value) {
35
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
36
+ }
37
+ function isPlainRecord(value) {
38
+ return (isRecord(value) &&
39
+ (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null));
40
+ }
41
+ function isSafeString(value) {
42
+ return typeof value === 'string' && value.trim().length > 0 && !/[\u0000-\u001F\u007F]/u.test(value);
43
+ }
44
+ function invalidContract(message) {
45
+ throw new JudgmentDAGCompositionError('invalid_contract', message);
46
+ }
47
+ function requireRecord(value, path) {
48
+ if (!isPlainRecord(value)) {
49
+ invalidContract(`${path} must be a plain object`);
50
+ }
51
+ return value;
52
+ }
53
+ function requireExactKeys(value, allowed, path) {
54
+ for (const key of Object.keys(value)) {
55
+ if (!allowed.includes(key)) {
56
+ invalidContract(`${path}.${key} is not an allowed contract field`);
57
+ }
58
+ }
59
+ }
60
+ function requireString(value, path) {
61
+ if (!isSafeString(value)) {
62
+ invalidContract(`${path} must be a non-empty string without control characters`);
63
+ }
64
+ return value;
65
+ }
66
+ function requireArray(value, path) {
67
+ if (!Array.isArray(value)) {
68
+ invalidContract(`${path} must be an array`);
69
+ }
70
+ return value;
71
+ }
72
+ function snapshotJSON(value, path, active = new Set()) {
73
+ if (value === null || typeof value === 'string' || typeof value === 'boolean') {
74
+ return value;
75
+ }
76
+ if (typeof value === 'number') {
77
+ if (Number.isFinite(value)) {
78
+ return value;
79
+ }
80
+ invalidContract(`${path} must contain only finite JSON numbers`);
81
+ }
82
+ if (typeof value !== 'object') {
83
+ invalidContract(`${path} must be a JSON value`);
84
+ }
85
+ const objectValue = value;
86
+ if (active.has(objectValue)) {
87
+ invalidContract(`${path} must not contain cyclic values`);
88
+ }
89
+ active.add(objectValue);
90
+ try {
91
+ if (Array.isArray(value)) {
92
+ const result = [];
93
+ for (let index = 0; index < value.length; index += 1) {
94
+ if (!(index in value)) {
95
+ invalidContract(`${path}[${index}] must be defined`);
96
+ }
97
+ result.push(snapshotJSON(value[index], `${path}[${index}]`, active));
98
+ }
99
+ return result;
100
+ }
101
+ if (!isPlainRecord(value)) {
102
+ invalidContract(`${path} must contain only plain objects`);
103
+ }
104
+ const result = {};
105
+ for (const key of Object.keys(value)) {
106
+ result[key] = snapshotJSON(value[key], `${path}.${key}`, active);
107
+ }
108
+ return result;
109
+ }
110
+ catch (error) {
111
+ if (error instanceof JudgmentDAGCompositionError) {
112
+ throw error;
113
+ }
114
+ invalidContract(`${path} must be readable`);
115
+ }
116
+ finally {
117
+ active.delete(objectValue);
118
+ }
119
+ }
120
+ function deepFreeze(value) {
121
+ if (value !== null && typeof value === 'object' && !Object.isFrozen(value)) {
122
+ Object.freeze(value);
123
+ for (const child of Object.values(value)) {
124
+ deepFreeze(child);
125
+ }
126
+ }
127
+ return value;
128
+ }
129
+ function parseScope(value, path) {
130
+ const scope = requireRecord(value, path);
131
+ requireExactKeys(scope, ['type', 'id'], path);
132
+ if (!JUDGMENT_DAG_SCOPE_TYPES.includes(scope.type)) {
133
+ invalidContract(`${path}.type must be a supported scope type`);
134
+ }
135
+ return {
136
+ type: scope.type,
137
+ id: requireString(scope.id, `${path}.id`)
138
+ };
139
+ }
140
+ function parseVersionReference(value, path) {
141
+ const reference = requireRecord(value, path);
142
+ requireExactKeys(reference, ['id', 'version'], path);
143
+ return {
144
+ id: requireString(reference.id, `${path}.id`),
145
+ version: requireString(reference.version, `${path}.version`)
146
+ };
147
+ }
148
+ const SNAPSHOT_ID_PATTERN = /^sha256:[0-9a-f]{64}$/u;
149
+ function parseProblemSnapshotReference(value, path) {
150
+ const reference = requireRecord(value, path);
151
+ requireExactKeys(reference, ['snapshot_id', 'problem_id', 'revision'], path);
152
+ const snapshotId = requireString(reference.snapshot_id, `${path}.snapshot_id`);
153
+ if (!SNAPSHOT_ID_PATTERN.test(snapshotId)) {
154
+ invalidContract(`${path}.snapshot_id must be sha256:<64 lowercase hex>`);
155
+ }
156
+ const problemId = requireString(reference.problem_id, `${path}.problem_id`);
157
+ const revision = requireString(reference.revision, `${path}.revision`);
158
+ if (!/^[1-9]\d*$/u.test(revision)) {
159
+ invalidContract(`${path}.revision must be a positive decimal revision`);
160
+ }
161
+ return deepFreeze({
162
+ snapshot_id: snapshotId,
163
+ problem_id: problemId,
164
+ revision
165
+ });
166
+ }
167
+ function parseStringList(value, path) {
168
+ const values = requireArray(value, path).map((entry, index) => requireString(entry, `${path}[${index}]`));
169
+ if (new Set(values).size !== values.length) {
170
+ invalidContract(`${path} must not contain duplicates`);
171
+ }
172
+ return [...values].sort();
173
+ }
174
+ function parseChild(value, index) {
175
+ const path = `children[${index}]`;
176
+ const child = requireRecord(value, path);
177
+ requireExactKeys(child, [
178
+ 'invocation_id',
179
+ 'dag',
180
+ 'question',
181
+ 'input_contract',
182
+ 'output_contract',
183
+ 'required_capabilities',
184
+ 'depends_on'
185
+ ], path);
186
+ return {
187
+ invocation_id: requireString(child.invocation_id, `${path}.invocation_id`),
188
+ dag: parseVersionReference(child.dag, `${path}.dag`),
189
+ question: requireString(child.question, `${path}.question`),
190
+ input_contract: requireString(child.input_contract, `${path}.input_contract`),
191
+ output_contract: requireString(child.output_contract, `${path}.output_contract`),
192
+ required_capabilities: parseStringList(child.required_capabilities, `${path}.required_capabilities`),
193
+ depends_on: parseStringList(child.depends_on, `${path}.depends_on`)
194
+ };
195
+ }
196
+ function parseComposition(value) {
197
+ const composition = requireRecord(value, 'composition');
198
+ requireExactKeys(composition, ['composition_id', 'composition_version', 'scope', 'parent_dag', 'children'], 'composition');
199
+ const children = requireArray(composition.children, 'composition.children')
200
+ .map((child, index) => parseChild(child, index))
201
+ .sort((left, right) => left.invocation_id.localeCompare(right.invocation_id));
202
+ return {
203
+ composition_id: requireString(composition.composition_id, 'composition.composition_id'),
204
+ composition_version: requireString(composition.composition_version, 'composition.composition_version'),
205
+ scope: parseScope(composition.scope, 'composition.scope'),
206
+ parent_dag: parseVersionReference(composition.parent_dag, 'composition.parent_dag'),
207
+ children
208
+ };
209
+ }
210
+ function equalScope(left, right) {
211
+ return left.type === right.type && left.id === right.id;
212
+ }
213
+ function equalVersionReference(left, right) {
214
+ return left.id === right.id && left.version === right.version;
215
+ }
216
+ function equalProblemSnapshotReference(left, right) {
217
+ return left.snapshot_id === right.snapshot_id &&
218
+ left.problem_id === right.problem_id &&
219
+ left.revision === right.revision;
220
+ }
221
+ function validateTopology(composition) {
222
+ const childById = new Map();
223
+ for (const child of composition.children) {
224
+ if (childById.has(child.invocation_id)) {
225
+ throw new JudgmentDAGCompositionError('duplicate_invocation', `composition contains duplicate invocation ${child.invocation_id}`, { invocation_id: child.invocation_id });
226
+ }
227
+ childById.set(child.invocation_id, child);
228
+ }
229
+ const remaining = new Map();
230
+ const dependents = new Map();
231
+ for (const child of composition.children) {
232
+ remaining.set(child.invocation_id, child.depends_on.length);
233
+ dependents.set(child.invocation_id, []);
234
+ }
235
+ for (const child of composition.children) {
236
+ for (const dependencyId of child.depends_on) {
237
+ if (!childById.has(dependencyId)) {
238
+ throw new JudgmentDAGCompositionError('missing_dependency', `invocation ${child.invocation_id} depends on missing invocation ${dependencyId}`, { invocation_id: child.invocation_id, dependency_id: dependencyId });
239
+ }
240
+ dependents.get(dependencyId)?.push(child.invocation_id);
241
+ }
242
+ }
243
+ const ready = composition.children
244
+ .filter((child) => remaining.get(child.invocation_id) === 0)
245
+ .map((child) => child.invocation_id)
246
+ .sort();
247
+ const executionOrder = [];
248
+ while (ready.length > 0) {
249
+ const invocationId = ready.shift();
250
+ if (invocationId === undefined) {
251
+ break;
252
+ }
253
+ executionOrder.push(invocationId);
254
+ for (const dependentId of [...(dependents.get(invocationId) ?? [])].sort()) {
255
+ const next = (remaining.get(dependentId) ?? 0) - 1;
256
+ remaining.set(dependentId, next);
257
+ if (next === 0) {
258
+ ready.push(dependentId);
259
+ ready.sort();
260
+ }
261
+ }
262
+ }
263
+ if (executionOrder.length !== composition.children.length) {
264
+ const cycle = composition.children
265
+ .filter((child) => (remaining.get(child.invocation_id) ?? 0) > 0)
266
+ .map((child) => child.invocation_id)
267
+ .sort();
268
+ throw new JudgmentDAGCompositionError('cycle', `composition contains an execution dependency cycle: ${cycle.join(' -> ')}`, { cycle });
269
+ }
270
+ return {
271
+ valid: true,
272
+ composition_id: composition.composition_id,
273
+ composition_version: composition.composition_version,
274
+ execution_order: executionOrder
275
+ };
276
+ }
277
+ export function validateJudgmentDAGComposition(value) {
278
+ return validateTopology(parseComposition(value));
279
+ }
280
+ export function assertValidJudgmentDAGComposition(value) {
281
+ validateJudgmentDAGComposition(value);
282
+ }
283
+ export function createJudgmentDAGCompositionDefinition(value) {
284
+ const composition = parseComposition(value);
285
+ validateTopology(composition);
286
+ return deepFreeze(composition);
287
+ }
288
+ function parseDelegation(value, expectedScope) {
289
+ const delegation = requireRecord(value, 'request.delegation');
290
+ requireExactKeys(delegation, ['scope', 'capabilities'], 'request.delegation');
291
+ const scope = parseScope(delegation.scope, 'request.delegation.scope');
292
+ if (!equalScope(scope, expectedScope)) {
293
+ throw new JudgmentDAGCompositionError('scope_mismatch', 'request delegation scope must match the composition scope');
294
+ }
295
+ return {
296
+ scope,
297
+ capabilities: parseStringList(delegation.capabilities, 'request.delegation.capabilities')
298
+ };
299
+ }
300
+ function hasCapabilities(available, required) {
301
+ const availableSet = new Set(available);
302
+ return required.every((capability) => availableSet.has(capability));
303
+ }
304
+ function parseRunReference(value, child) {
305
+ if (value === null) {
306
+ return null;
307
+ }
308
+ const reference = requireRecord(value, 'child.result.run_reference');
309
+ requireExactKeys(reference, ['run_id', 'dag', 'artifact_id'], 'child.result.run_reference');
310
+ const dag = parseVersionReference(reference.dag, 'child.result.run_reference.dag');
311
+ if (dag.id !== child.dag.id || dag.version !== child.dag.version) {
312
+ throw new JudgmentDAGCompositionError('dag_mismatch', `child ${child.invocation_id} returned a run for a different DAG`, { invocation_id: child.invocation_id });
313
+ }
314
+ const runId = requireString(reference.run_id, 'child.result.run_reference.run_id');
315
+ const artifactId = reference.artifact_id === undefined
316
+ ? undefined
317
+ : requireString(reference.artifact_id, 'child.result.run_reference.artifact_id');
318
+ if (artifactId !== undefined && !/^sha256:[0-9a-f]{64}$/u.test(artifactId)) {
319
+ invalidContract('child.result.run_reference.artifact_id must be sha256:<64 lowercase hex>');
320
+ }
321
+ return {
322
+ run_id: runId,
323
+ dag,
324
+ ...(artifactId === undefined
325
+ ? {}
326
+ : { artifact_id: artifactId })
327
+ };
328
+ }
329
+ function parseEvidence(value) {
330
+ return requireArray(value, 'child.result.evidence').map((entry, index) => {
331
+ const path = `child.result.evidence[${index}]`;
332
+ const evidence = requireRecord(entry, path);
333
+ requireExactKeys(evidence, ['kind', 'id', 'revision'], path);
334
+ const baseResult = {
335
+ kind: requireString(evidence.kind, `${path}.kind`),
336
+ id: requireString(evidence.id, `${path}.id`)
337
+ };
338
+ const revision = evidence.revision === undefined
339
+ ? undefined
340
+ : requireString(evidence.revision, `${path}.revision`);
341
+ return revision === undefined ? baseResult : { ...baseResult, revision };
342
+ });
343
+ }
344
+ function normalizeChildResult(value, child) {
345
+ const result = requireRecord(value, `child ${child.invocation_id} result`);
346
+ requireExactKeys(result, [
347
+ 'status',
348
+ 'input_contract',
349
+ 'output_contract',
350
+ 'run_reference',
351
+ 'conclusion',
352
+ 'evidence',
353
+ 'applicability',
354
+ 'uncertainty',
355
+ 'reason'
356
+ ], `child ${child.invocation_id} result`);
357
+ if (!JUDGMENT_DAG_SUBDAG_STATUSES.includes(result.status)) {
358
+ throw new JudgmentDAGCompositionError('invalid_child_result', `child ${child.invocation_id} returned an unsupported status`, { invocation_id: child.invocation_id });
359
+ }
360
+ if (result.input_contract !== child.input_contract || result.output_contract !== child.output_contract) {
361
+ throw new JudgmentDAGCompositionError('contract_mismatch', `child ${child.invocation_id} returned a different input or output contract`, { invocation_id: child.invocation_id });
362
+ }
363
+ const runReference = parseRunReference(result.run_reference, child);
364
+ if (result.status === 'completed' && runReference === null) {
365
+ throw new JudgmentDAGCompositionError('invalid_child_result', `completed child ${child.invocation_id} must include a run reference`, { invocation_id: child.invocation_id });
366
+ }
367
+ const normalized = {
368
+ status: result.status,
369
+ input_contract: child.input_contract,
370
+ output_contract: child.output_contract,
371
+ run_reference: runReference,
372
+ conclusion: snapshotJSON(result.conclusion, `child ${child.invocation_id} result.conclusion`),
373
+ evidence: parseEvidence(result.evidence),
374
+ applicability: snapshotJSON(result.applicability, `child ${child.invocation_id} result.applicability`),
375
+ uncertainty: snapshotJSON(result.uncertainty, `child ${child.invocation_id} result.uncertainty`)
376
+ };
377
+ if (result.reason === undefined) {
378
+ return deepFreeze(normalized);
379
+ }
380
+ return deepFreeze({
381
+ ...normalized,
382
+ reason: requireString(result.reason, `child ${child.invocation_id} result.reason`)
383
+ });
384
+ }
385
+ function incompleteResult(status, child, reason) {
386
+ return deepFreeze({
387
+ status,
388
+ input_contract: child.input_contract,
389
+ output_contract: child.output_contract,
390
+ run_reference: null,
391
+ conclusion: null,
392
+ evidence: [],
393
+ applicability: { status: 'not_run' },
394
+ uncertainty: { status: 'blocked' },
395
+ reason
396
+ });
397
+ }
398
+ function parsePort(value) {
399
+ const port = requireRecord(value, 'request.port');
400
+ requireExactKeys(port, ['execute'], 'request.port');
401
+ if (typeof port.execute !== 'function') {
402
+ invalidContract('request.port.execute must be a function');
403
+ }
404
+ return port;
405
+ }
406
+ function parseSnapshotReader(value) {
407
+ const reader = requireRecord(value, 'request.snapshot_reader');
408
+ requireExactKeys(reader, ['read'], 'request.snapshot_reader');
409
+ if (typeof reader.read !== 'function') {
410
+ invalidContract('request.snapshot_reader.read must be a function');
411
+ }
412
+ return reader;
413
+ }
414
+ function parseDAGResolver(value) {
415
+ const resolver = requireRecord(value, 'request.dag_resolver');
416
+ requireExactKeys(resolver, ['resolve'], 'request.dag_resolver');
417
+ if (typeof resolver.resolve !== 'function') {
418
+ invalidContract('request.dag_resolver.resolve must be a function');
419
+ }
420
+ return resolver;
421
+ }
422
+ function parseContractValidator(value) {
423
+ const validator = requireRecord(value, 'request.contract_validator');
424
+ requireExactKeys(validator, ['validate'], 'request.contract_validator');
425
+ if (typeof validator.validate !== 'function') {
426
+ invalidContract('request.contract_validator.validate must be a function');
427
+ }
428
+ return validator;
429
+ }
430
+ function parseArtifactReader(value) {
431
+ const reader = requireRecord(value, 'request.artifact_reader');
432
+ requireExactKeys(reader, ['read'], 'request.artifact_reader');
433
+ if (typeof reader.read !== 'function') {
434
+ invalidContract('request.artifact_reader.read must be a function');
435
+ }
436
+ return reader;
437
+ }
438
+ function parseRequest(value) {
439
+ const request = requireRecord(value, 'request');
440
+ requireExactKeys(request, [
441
+ 'run_id',
442
+ 'composition',
443
+ 'question',
444
+ 'input',
445
+ 'problem_snapshot',
446
+ 'fixed_conditions',
447
+ 'delegation',
448
+ 'snapshot_reader',
449
+ 'dag_resolver',
450
+ 'contract_validator',
451
+ 'artifact_reader',
452
+ 'port'
453
+ ], 'request');
454
+ const composition = createJudgmentDAGCompositionDefinition(request.composition);
455
+ const validation = validateTopology(composition);
456
+ const artifactReader = request.artifact_reader === undefined
457
+ ? undefined
458
+ : parseArtifactReader(request.artifact_reader);
459
+ return {
460
+ run_id: requireString(request.run_id, 'request.run_id'),
461
+ composition,
462
+ question: requireString(request.question, 'request.question'),
463
+ input: snapshotJSON(request.input, 'request.input'),
464
+ problem_snapshot: parseProblemSnapshotReference(request.problem_snapshot, 'request.problem_snapshot'),
465
+ fixed_conditions: snapshotJSON(request.fixed_conditions, 'request.fixed_conditions'),
466
+ delegation: parseDelegation(request.delegation, composition.scope),
467
+ snapshot_reader: parseSnapshotReader(request.snapshot_reader),
468
+ dag_resolver: parseDAGResolver(request.dag_resolver),
469
+ contract_validator: parseContractValidator(request.contract_validator),
470
+ ...(artifactReader === undefined ? {} : { artifact_reader: artifactReader }),
471
+ port: parsePort(request.port),
472
+ validation
473
+ };
474
+ }
475
+ function parseVersionResolution(value, path) {
476
+ const resolution = requireRecord(value, path);
477
+ requireExactKeys(resolution, ['dag', 'input_contract', 'output_contract'], path);
478
+ return deepFreeze({
479
+ dag: parseVersionReference(resolution.dag, `${path}.dag`),
480
+ input_contract: requireString(resolution.input_contract, `${path}.input_contract`),
481
+ output_contract: requireString(resolution.output_contract, `${path}.output_contract`)
482
+ });
483
+ }
484
+ async function resolveDAGReferences(parsed) {
485
+ const resolve = async (role, dag, invocationId) => {
486
+ let rawResolution;
487
+ try {
488
+ rawResolution = await parsed.dag_resolver.resolve({
489
+ role,
490
+ ...(invocationId === undefined ? {} : { invocation_id: invocationId }),
491
+ dag
492
+ });
493
+ }
494
+ catch {
495
+ throw new JudgmentDAGCompositionError('dag_unavailable', `${role} DAG ${dag.id}@${dag.version} could not be resolved`, invocationId === undefined ? {} : { invocation_id: invocationId });
496
+ }
497
+ try {
498
+ return parseVersionResolution(rawResolution, `${role} DAG resolution`);
499
+ }
500
+ catch {
501
+ throw new JudgmentDAGCompositionError('dag_unavailable', `${role} DAG ${dag.id}@${dag.version} returned an invalid resolution`, invocationId === undefined ? {} : { invocation_id: invocationId });
502
+ }
503
+ };
504
+ const parentResolution = await resolve('parent', parsed.composition.parent_dag);
505
+ if (!equalVersionReference(parentResolution.dag, parsed.composition.parent_dag)) {
506
+ throw new JudgmentDAGCompositionError('dag_mismatch', 'parent DAG resolver returned a different version');
507
+ }
508
+ for (const child of parsed.composition.children) {
509
+ const resolution = await resolve('child', child.dag, child.invocation_id);
510
+ if (!equalVersionReference(resolution.dag, child.dag)) {
511
+ throw new JudgmentDAGCompositionError('dag_mismatch', `child ${child.invocation_id} DAG resolver returned a different version`, { invocation_id: child.invocation_id });
512
+ }
513
+ if (resolution.input_contract !== child.input_contract ||
514
+ resolution.output_contract !== child.output_contract) {
515
+ throw new JudgmentDAGCompositionError('contract_mismatch', `child ${child.invocation_id} DAG version has a different input or output contract`, { invocation_id: child.invocation_id });
516
+ }
517
+ try {
518
+ await parsed.contract_validator.validate({
519
+ role: 'child',
520
+ invocation_id: child.invocation_id,
521
+ dag: child.dag,
522
+ input_contract: resolution.input_contract,
523
+ output_contract: resolution.output_contract
524
+ });
525
+ }
526
+ catch {
527
+ throw new JudgmentDAGCompositionError('contract_mismatch', `child ${child.invocation_id} input/output contract was rejected`, { invocation_id: child.invocation_id });
528
+ }
529
+ }
530
+ }
531
+ async function readProblemSnapshot(parsed) {
532
+ let rawResult;
533
+ try {
534
+ rawResult = await parsed.snapshot_reader.read({
535
+ mode: 'read',
536
+ reference_resolution: 'current',
537
+ reference: parsed.problem_snapshot
538
+ });
539
+ }
540
+ catch {
541
+ throw new JudgmentDAGCompositionError('snapshot_unavailable', 'the selected JudgmentProblem snapshot could not be read');
542
+ }
543
+ try {
544
+ const result = requireRecord(rawResult, 'snapshot_reader result');
545
+ requireExactKeys(result, ['reference_resolution', 'status', 'reference', 'snapshot'], 'snapshot_reader result');
546
+ if (result.status !== 'resolved' || result.reference_resolution !== 'current') {
547
+ throw new Error('snapshot is not resolved');
548
+ }
549
+ const reference = parseProblemSnapshotReference(result.reference, 'snapshot_reader result.reference');
550
+ if (!equalProblemSnapshotReference(reference, parsed.problem_snapshot)) {
551
+ throw new Error('snapshot reference does not match the requested snapshot');
552
+ }
553
+ const snapshot = snapshotJSON(result.snapshot, 'snapshot_reader result.snapshot');
554
+ const snapshotRecord = requireRecord(snapshot, 'snapshot_reader result.snapshot');
555
+ if (snapshotRecord.snapshot_version !== 'judgment-problem-snapshot.v1' ||
556
+ snapshotRecord.problem_id !== parsed.problem_snapshot.problem_id ||
557
+ snapshotRecord.revision !== parsed.problem_snapshot.revision) {
558
+ throw new Error('snapshot identity does not match the requested snapshot');
559
+ }
560
+ return deepFreeze(snapshot);
561
+ }
562
+ catch {
563
+ throw new JudgmentDAGCompositionError('snapshot_unavailable', 'the snapshot reader returned an invalid or mismatched JudgmentProblem snapshot');
564
+ }
565
+ }
566
+ async function verifyArtifactReadback(result, child, reader) {
567
+ const runReference = result.run_reference;
568
+ if (runReference?.artifact_id === undefined)
569
+ return;
570
+ if (reader === undefined) {
571
+ throw new JudgmentDAGCompositionError('artifact_readback_failed', `child ${child.invocation_id} returned an artifact without a readback adapter`, { invocation_id: child.invocation_id });
572
+ }
573
+ let rawArtifact;
574
+ try {
575
+ rawArtifact = await reader.read({
576
+ artifact_id: runReference.artifact_id,
577
+ expected_run_id: runReference.run_id,
578
+ expected_dag: child.dag
579
+ });
580
+ }
581
+ catch {
582
+ throw new JudgmentDAGCompositionError('artifact_readback_failed', `child ${child.invocation_id} artifact could not be read back`, { invocation_id: child.invocation_id });
583
+ }
584
+ try {
585
+ const artifact = requireRecord(rawArtifact, `child ${child.invocation_id} artifact`);
586
+ if (requireString(artifact.run_id, `child ${child.invocation_id} artifact.run_id`) !== runReference.run_id) {
587
+ throw new Error('artifact run identity does not match the child result');
588
+ }
589
+ const artifactDAG = requireRecord(artifact.dag, `child ${child.invocation_id} artifact.dag`);
590
+ const artifactDAGReference = {
591
+ id: requireString(artifactDAG.id, `child ${child.invocation_id} artifact.dag.id`),
592
+ version: requireString(artifactDAG.version, `child ${child.invocation_id} artifact.dag.version`)
593
+ };
594
+ if (!equalVersionReference(artifactDAGReference, child.dag)) {
595
+ throw new Error('artifact DAG identity does not match the child result');
596
+ }
597
+ }
598
+ catch {
599
+ throw new JudgmentDAGCompositionError('artifact_readback_failed', `child ${child.invocation_id} artifact readback did not match the child run`, { invocation_id: child.invocation_id });
600
+ }
601
+ }
602
+ function childByInvocation(composition) {
603
+ return new Map(composition.children.map((child) => [child.invocation_id, child]));
604
+ }
605
+ /**
606
+ * Execute only the explicitly declared evaluation port for each child.
607
+ * Resource reservation, deploys, external sends, and arbitrary host-code
608
+ * isolation remain outside this OSS boundary.
609
+ */
610
+ export async function executeJudgmentDAGComposition(request) {
611
+ const parsed = parseRequest(request);
612
+ const childrenById = childByInvocation(parsed.composition);
613
+ // Preflight every child before the first port call. A later capability
614
+ // violation therefore cannot leave an earlier child partially evaluated.
615
+ for (const child of parsed.composition.children) {
616
+ if (!hasCapabilities(parsed.delegation.capabilities, child.required_capabilities)) {
617
+ const missing = child.required_capabilities.filter((capability) => !parsed.delegation.capabilities.includes(capability));
618
+ throw new JudgmentDAGCompositionError('capability_violation', `child ${child.invocation_id} requires undelegated capabilities: ${missing.join(', ')}`, { invocation_id: child.invocation_id });
619
+ }
620
+ }
621
+ // Resolve the selected problem snapshot and every declared DAG version before
622
+ // the first evaluation port call. The snapshot adapter owns current lookup
623
+ // and authorization; the coordinator only accepts the exact locator and
624
+ // identity it was given.
625
+ await readProblemSnapshot(parsed);
626
+ await resolveDAGReferences(parsed);
627
+ const childRecords = new Map();
628
+ for (const invocationId of parsed.validation.execution_order) {
629
+ const child = childrenById.get(invocationId);
630
+ if (child === undefined) {
631
+ throw new JudgmentDAGCompositionError('invalid_contract', `execution order references unknown invocation ${invocationId}`, { invocation_id: invocationId });
632
+ }
633
+ const dependencyResults = child.depends_on.map((dependencyId) => {
634
+ const dependency = childRecords.get(dependencyId);
635
+ if (dependency === undefined) {
636
+ throw new JudgmentDAGCompositionError('invalid_contract', `dependency ${dependencyId} has not been recorded before ${invocationId}`, { invocation_id: invocationId, dependency_id: dependencyId });
637
+ }
638
+ return {
639
+ invocation_id: dependency.invocation_id,
640
+ result: dependency.result
641
+ };
642
+ });
643
+ const delegation = {
644
+ scope: parsed.delegation.scope,
645
+ capabilities: child.required_capabilities
646
+ };
647
+ const blockedDependency = dependencyResults.find((dependency) => dependency.result.status !== 'completed');
648
+ let result;
649
+ if (blockedDependency !== undefined) {
650
+ result = incompleteResult('held', child, `dependency ${blockedDependency.invocation_id} is ${blockedDependency.result.status}`);
651
+ }
652
+ else {
653
+ const childRequest = deepFreeze({
654
+ mode: 'evaluation',
655
+ parent_run_id: parsed.run_id,
656
+ composition: {
657
+ id: parsed.composition.composition_id,
658
+ version: parsed.composition.composition_version
659
+ },
660
+ invocation_id: child.invocation_id,
661
+ dag: child.dag,
662
+ question: child.question,
663
+ input: parsed.input,
664
+ problem_snapshot: parsed.problem_snapshot,
665
+ fixed_conditions: parsed.fixed_conditions,
666
+ delegation,
667
+ dependency_results: dependencyResults
668
+ });
669
+ let rawResult;
670
+ let executorFailed = false;
671
+ try {
672
+ rawResult = await parsed.port.execute(childRequest);
673
+ }
674
+ catch {
675
+ executorFailed = true;
676
+ }
677
+ if (executorFailed) {
678
+ result = incompleteResult('failed', child, 'evaluation port failed');
679
+ }
680
+ else {
681
+ // Keep result validation outside the executor catch. A malformed or
682
+ // mismatched result is a contract error, not a successful child.
683
+ result = normalizeChildResult(rawResult, child);
684
+ await verifyArtifactReadback(result, child, parsed.artifact_reader);
685
+ }
686
+ }
687
+ const childRecord = {
688
+ invocation_id: child.invocation_id,
689
+ dag: child.dag,
690
+ question: child.question,
691
+ input_contract: child.input_contract,
692
+ output_contract: child.output_contract,
693
+ input: parsed.input,
694
+ problem_snapshot: parsed.problem_snapshot,
695
+ fixed_conditions: parsed.fixed_conditions,
696
+ delegation,
697
+ dependency_invocation_ids: child.depends_on,
698
+ dependency_results: dependencyResults,
699
+ result
700
+ };
701
+ childRecords.set(invocationId, deepFreeze(childRecord));
702
+ }
703
+ const children = parsed.validation.execution_order.map((invocationId) => {
704
+ const child = childRecords.get(invocationId);
705
+ if (child === undefined) {
706
+ throw new JudgmentDAGCompositionError('invalid_contract', `child ${invocationId} was not recorded`, { invocation_id: invocationId });
707
+ }
708
+ return child;
709
+ });
710
+ const status = children.some((child) => child.result.status === 'failed')
711
+ ? 'failed'
712
+ : children.some((child) => child.result.status === 'held')
713
+ ? 'held'
714
+ : 'completed';
715
+ return deepFreeze({
716
+ run_id: parsed.run_id,
717
+ composition: {
718
+ id: parsed.composition.composition_id,
719
+ version: parsed.composition.composition_version
720
+ },
721
+ parent_dag: parsed.composition.parent_dag,
722
+ question: parsed.question,
723
+ input: parsed.input,
724
+ problem_snapshot: parsed.problem_snapshot,
725
+ fixed_conditions: parsed.fixed_conditions,
726
+ delegation: parsed.delegation,
727
+ execution_order: parsed.validation.execution_order,
728
+ status,
729
+ children
730
+ });
731
+ }