@x12i/graphenix-executable-format 1.0.0 → 2.0.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.
@@ -1,62 +1,55 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const strict_1 = __importDefault(require("node:assert/strict"));
7
- const node_test_1 = require("node:test");
8
- const graphenix_core_1 = require("@x12i/graphenix-core");
9
- const api_js_1 = require("../api.js");
10
- const minimal_executable_graph_js_1 = require("../fixtures/minimal-executable-graph.js");
11
- const graphenix_core_2 = require("@x12i/graphenix-core");
12
- const constants_js_1 = require("../constants.js");
1
+ import assert from "node:assert/strict";
2
+ import { describe, it } from "node:test";
3
+ import { validateGraph } from "@x12i/graphenix-core";
4
+ import { assertExecutableGraph, validateExecutableGraph, validateStudioExecuteRequest, validateRuntimeObject, buildGraphExecutionRequestFromStudioExecute, resolveNodeAiPlan, explainNodeInheritance, resolveNodeModelSlot, normalizeExecutableGraph, validateCaseCondition, evaluateCaseCondition, isProfileChoiceKeyFormat, isKnownProfileChoice, buildDeterministicCaseContext, compileExecutablePlan, validateExecutablePlan, validateAuthoringGraph, createExecutionTrace, appendExecutionEvent, validateExecutionTrace, buildRuntimeObject, createMinimalExecutableGraph, createPlainGraphenixGraph } from "../api.js";
5
+ import { EXECUTABLE_PROFILE_NAMESPACE } from "@x12i/graphenix-executable-contracts";
13
6
  function setGraphModelConfig(doc, modelConfig) {
14
7
  const next = structuredClone(doc);
15
- const ext = next.graph.metadata.extensions[constants_js_1.EXECUTABLE_PROFILE_NAMESPACE];
8
+ const ext = next.graph.metadata.extensions[EXECUTABLE_PROFILE_NAMESPACE];
16
9
  ext.modelConfig = modelConfig;
17
10
  return next;
18
11
  }
19
- (0, node_test_1.describe)("graphenix base validation", () => {
20
- (0, node_test_1.it)("valid executable graph passes Graphenix validateGraph()", () => {
21
- const doc = (0, minimal_executable_graph_js_1.createMinimalExecutableGraph)();
22
- const result = (0, graphenix_core_1.validateGraph)(doc);
23
- strict_1.default.equal(result.valid, true);
12
+ describe("graphenix base validation", () => {
13
+ it("valid executable graph passes Graphenix validateGraph()", () => {
14
+ const doc = createMinimalExecutableGraph();
15
+ const result = validateGraph(doc);
16
+ assert.equal(result.valid, true);
24
17
  });
25
18
  });
26
- (0, node_test_1.describe)("executable profile validation", () => {
27
- (0, node_test_1.it)("valid executable graph passes assertExecutableGraph()", () => {
28
- const doc = (0, minimal_executable_graph_js_1.createMinimalExecutableGraph)();
29
- strict_1.default.doesNotThrow(() => (0, api_js_1.assertExecutableGraph)(doc));
30
- });
31
- (0, node_test_1.it)("plain Graphenix graph without executable profile fails", () => {
32
- const doc = (0, minimal_executable_graph_js_1.createPlainGraphenixGraph)();
33
- const result = (0, api_js_1.validateExecutableGraph)(doc);
34
- strict_1.default.equal(result.valid, false);
35
- strict_1.default.ok(result.errors.some((e) => e.code === "EXECUTABLE_PROFILE_MISSING"));
36
- });
37
- (0, node_test_1.it)("graph-level modelConfig is required", () => {
38
- const doc = (0, minimal_executable_graph_js_1.createMinimalExecutableGraph)();
39
- const ext = doc.graph.metadata.extensions[constants_js_1.EXECUTABLE_PROFILE_NAMESPACE];
19
+ describe("executable profile validation", () => {
20
+ it("valid executable graph passes assertExecutableGraph()", () => {
21
+ const doc = createMinimalExecutableGraph();
22
+ assert.doesNotThrow(() => assertExecutableGraph(doc));
23
+ });
24
+ it("plain Graphenix graph without executable profile fails", () => {
25
+ const doc = createPlainGraphenixGraph();
26
+ const result = validateExecutableGraph(doc);
27
+ assert.equal(result.valid, false);
28
+ assert.ok(result.errors.some((e) => e.code === "EXECUTABLE_PROFILE_MISSING"));
29
+ });
30
+ it("graph-level modelConfig is required", () => {
31
+ const doc = createMinimalExecutableGraph();
32
+ const ext = doc.graph.metadata.extensions[EXECUTABLE_PROFILE_NAMESPACE];
40
33
  delete ext.modelConfig;
41
- const result = (0, api_js_1.validateExecutableGraph)(doc);
42
- strict_1.default.equal(result.valid, false);
43
- strict_1.default.ok(result.errors.some((e) => e.code === "GRAPH_MODEL_CONFIG_MISSING"));
34
+ const result = validateExecutableGraph(doc);
35
+ assert.equal(result.valid, false);
36
+ assert.ok(result.errors.some((e) => e.code === "GRAPH_MODEL_CONFIG_MISSING"));
44
37
  });
45
38
  });
46
- (0, node_test_1.describe)("model inheritance", () => {
47
- (0, node_test_1.it)("node with no modelConfig inherits all slots", () => {
48
- const doc = (0, minimal_executable_graph_js_1.createMinimalExecutableGraph)();
49
- const plan = (0, api_js_1.resolveNodeAiPlan)(doc, "node:professional-answer");
50
- strict_1.default.equal(plan.slots.preActionModel.inherited, true);
51
- strict_1.default.equal(plan.slots.skillModel.inherited, true);
52
- strict_1.default.equal(plan.slots.postActionModel.inherited, true);
53
- strict_1.default.match((0, api_js_1.explainNodeInheritance)(plan), /graph case default/);
54
- });
55
- (0, node_test_1.it)("node may override only skillModel", () => {
56
- const doc = (0, minimal_executable_graph_js_1.createMinimalExecutableGraph)();
39
+ describe("model inheritance", () => {
40
+ it("node with no modelConfig inherits all slots", () => {
41
+ const doc = createMinimalExecutableGraph();
42
+ const plan = resolveNodeAiPlan(doc, "node:professional-answer");
43
+ assert.equal(plan.slots.preActionModel.inherited, true);
44
+ assert.equal(plan.slots.skillModel.inherited, true);
45
+ assert.equal(plan.slots.postActionModel.inherited, true);
46
+ assert.match(explainNodeInheritance(plan), /graph case default/);
47
+ });
48
+ it("node may override only skillModel", () => {
49
+ const doc = createMinimalExecutableGraph();
57
50
  const taskNode = doc.graph.nodes.find((n) => n.id === "node:professional-answer");
58
51
  const params = taskNode.parameters;
59
- strict_1.default.ok(params && params.nodeType === "task");
52
+ assert.ok(params && params.nodeType === "task");
60
53
  taskNode.parameters = {
61
54
  ...params,
62
55
  taskConfiguration: {
@@ -67,14 +60,14 @@ function setGraphModelConfig(doc, modelConfig) {
67
60
  }
68
61
  }
69
62
  };
70
- const plan = (0, api_js_1.resolveNodeAiPlan)(doc, "node:professional-answer");
71
- strict_1.default.equal(plan.slots.skillModel.inherited, false);
72
- strict_1.default.equal(plan.slots.preActionModel.inherited, true);
63
+ const plan = resolveNodeAiPlan(doc, "node:professional-answer");
64
+ assert.equal(plan.slots.skillModel.inherited, false);
65
+ assert.equal(plan.slots.preActionModel.inherited, true);
73
66
  });
74
67
  });
75
- (0, node_test_1.describe)("model fallback", () => {
76
- (0, node_test_1.it)("fallback uses graph same-slot only", () => {
77
- const resolved = (0, api_js_1.resolveNodeModelSlot)({
68
+ describe("model fallback", () => {
69
+ it("fallback uses graph same-slot only", () => {
70
+ const resolved = resolveNodeModelSlot({
78
71
  slot: "skillModel",
79
72
  graphSelection: { kind: "profileChoice", key: "vol/default" },
80
73
  nodeSelection: {
@@ -95,33 +88,33 @@ function setGraphModelConfig(doc, modelConfig) {
95
88
  graphCaseId: "default",
96
89
  nodeId: "node:test"
97
90
  });
98
- strict_1.default.equal(resolved.source, "fallbackToGraphDefault");
99
- strict_1.default.equal(resolved.selected.kind === "profileChoice" ? resolved.selected.key : "", "vol/default");
91
+ assert.equal(resolved.source, "fallbackToGraphDefault");
92
+ assert.equal(resolved.selected.kind === "profileChoice" ? resolved.selected.key : "", "vol/default");
100
93
  });
101
- (0, node_test_1.it)("fallback does not use runtime or request model defaults", () => {
102
- const runtime = (0, api_js_1.validateRuntimeObject)({
94
+ it("fallback does not use runtime or request model defaults", () => {
95
+ const runtime = validateRuntimeObject({
103
96
  jobId: "job-1",
104
97
  job: { id: "job-1", jobId: "job-1" },
105
98
  graphDefaultModel: { kind: "profileChoice", key: "cheap/default" }
106
99
  });
107
- strict_1.default.equal(runtime.valid, false);
100
+ assert.equal(runtime.valid, false);
108
101
  });
109
102
  });
110
- (0, node_test_1.describe)("studio adapter", () => {
111
- (0, node_test_1.it)("studio request with graphDefaultModel fails", () => {
112
- const doc = (0, minimal_executable_graph_js_1.createMinimalExecutableGraph)();
113
- const result = (0, api_js_1.validateStudioExecuteRequest)({
103
+ describe("studio adapter", () => {
104
+ it("studio request with graphDefaultModel fails", () => {
105
+ const doc = createMinimalExecutableGraph();
106
+ const result = validateStudioExecuteRequest({
114
107
  mode: "graph",
115
108
  jobId: "job-1",
116
109
  graph: doc,
117
110
  graphDefaultModel: {}
118
111
  });
119
- strict_1.default.equal(result.valid, false);
120
- strict_1.default.ok(result.errors.some((e) => e.code === "STUDIO_GRAPH_DEFAULT_MODEL_FORBIDDEN"));
112
+ assert.equal(result.valid, false);
113
+ assert.ok(result.errors.some((e) => e.code === "STUDIO_GRAPH_DEFAULT_MODEL_FORBIDDEN"));
121
114
  });
122
- (0, node_test_1.it)("studio adapter outputs compiled { plan, runtime }", () => {
123
- const doc = (0, minimal_executable_graph_js_1.createMinimalExecutableGraph)();
124
- const ext = doc.graph.metadata.extensions[constants_js_1.EXECUTABLE_PROFILE_NAMESPACE];
115
+ it("studio adapter outputs compiled { plan, runtime }", () => {
116
+ const doc = createMinimalExecutableGraph();
117
+ const ext = doc.graph.metadata.extensions[EXECUTABLE_PROFILE_NAMESPACE];
125
118
  ext.modelConfig = {
126
119
  version: "graph-model-config/v1",
127
120
  default: {
@@ -139,87 +132,56 @@ function setGraphModelConfig(doc, modelConfig) {
139
132
  },
140
133
  openrouterApiKey: "secret-should-not-copy"
141
134
  };
142
- const execution = (0, api_js_1.buildGraphExecutionRequestFromStudioExecute)(request, {
135
+ const execution = buildGraphExecutionRequestFromStudioExecute(request, {
143
136
  agentId: "agent-1"
144
137
  });
145
- strict_1.default.equal(execution.runtime.jobId, "job-123");
146
- strict_1.default.equal(execution.plan.source.graphId, doc.id);
147
- strict_1.default.equal(execution.plan.format, "x12i.graphenix.executable-plan/v1");
148
- strict_1.default.equal("openrouterApiKey" in execution.runtime, false);
149
- strict_1.default.equal("openrouterApiKey" in execution.plan, false);
150
- const profile = execution.plan.graph.graph.metadata?.extensions?.[constants_js_1.EXECUTABLE_PROFILE_NAMESPACE];
151
- strict_1.default.equal(profile?.modelConfig?.cases?.[0]?.id, "default");
152
- strict_1.default.equal((0, api_js_1.validateExecutablePlan)(execution.plan).valid, true);
138
+ assert.equal(execution.runtime.jobId, "job-123");
139
+ assert.equal(execution.plan.source.graphId, doc.id);
140
+ assert.equal(execution.plan.format, "graphenix.executable-plan/v1");
141
+ assert.equal("openrouterApiKey" in execution.runtime, false);
142
+ assert.equal("openrouterApiKey" in execution.plan, false);
143
+ const profile = execution.plan.graph.graph.metadata?.extensions?.[EXECUTABLE_PROFILE_NAMESPACE];
144
+ assert.equal(profile?.modelConfig?.cases?.[0]?.id, "default");
145
+ assert.equal(validateExecutablePlan(execution.plan).valid, true);
153
146
  });
154
147
  });
155
- (0, node_test_1.describe)("runtime validation", () => {
156
- (0, node_test_1.it)("credentials are never copied into runtime", () => {
157
- const result = (0, api_js_1.validateRuntimeObject)({
148
+ describe("runtime validation", () => {
149
+ it("credentials are never copied into runtime", () => {
150
+ const result = validateRuntimeObject({
158
151
  jobId: "job-1",
159
152
  job: { id: "job-1", jobId: "job-1" },
160
153
  credentials: { token: "x" }
161
154
  });
162
- strict_1.default.equal(result.valid, false);
155
+ assert.equal(result.valid, false);
163
156
  });
164
- (0, node_test_1.it)("runtime modelConfig is rejected", () => {
165
- const result = (0, api_js_1.validateRuntimeObject)({
157
+ it("runtime modelConfig is rejected", () => {
158
+ const result = validateRuntimeObject({
166
159
  jobId: "job-1",
167
160
  job: { id: "job-1", jobId: "job-1" },
168
161
  modelConfig: {}
169
162
  });
170
- strict_1.default.equal(result.valid, false);
163
+ assert.equal(result.valid, false);
171
164
  });
172
165
  });
173
- (0, node_test_1.describe)("migration", () => {
174
- (0, node_test_1.it)("legacy graph migrates into valid Graphenix executable document", () => {
175
- const migrated = (0, api_js_1.migrateLegacyGraphModelObjectToGraphenixExecutable)({
176
- id: "graph:legacy",
177
- version: "0.1.0",
178
- nodes: [
179
- {
180
- id: "node:a",
181
- kind: "task",
182
- skillKey: "demo"
183
- }
184
- ],
185
- edges: [],
186
- modelConfig: {
187
- version: "graph-model-config/v1",
188
- cases: [
189
- {
190
- id: "default",
191
- modelConfig: {
192
- preActionModel: { kind: "profile", profile: "economy" },
193
- skillModel: { kind: "profile", profile: "balanced" },
194
- postActionModel: { kind: "profile", profile: "economy" }
195
- }
196
- }
197
- ]
198
- }
199
- });
200
- strict_1.default.equal(migrated.formatVersion, graphenix_core_2.GRAPHENIX_FORMAT_VERSION);
201
- strict_1.default.doesNotThrow(() => (0, api_js_1.assertExecutableGraph)(migrated));
202
- });
203
- });
204
- (0, node_test_1.describe)("node kinds", () => {
205
- (0, node_test_1.it)("task nodes must use kind x12i:task", () => {
206
- const doc = (0, minimal_executable_graph_js_1.createMinimalExecutableGraph)();
166
+ describe("node kinds", () => {
167
+ it("task nodes must use kind task", () => {
168
+ const doc = createMinimalExecutableGraph();
207
169
  doc.graph.nodes[0].kind = "task:wrong";
208
- const result = (0, api_js_1.validateExecutableGraph)(doc);
209
- strict_1.default.ok(result.errors.some((e) => e.code === "TASK_NODE_INVALID"));
170
+ const result = validateExecutableGraph(doc);
171
+ assert.ok(result.errors.some((e) => e.code === "TASK_NODE_INVALID"));
210
172
  });
211
173
  });
212
- (0, node_test_1.describe)("deterministic cases", () => {
213
- (0, node_test_1.it)("AC-001: runtime.mode eq simulate is accepted", () => {
214
- const errors = (0, api_js_1.validateCaseCondition)({
174
+ describe("deterministic cases", () => {
175
+ it("AC-001: runtime.mode eq simulate is accepted", () => {
176
+ const errors = validateCaseCondition({
215
177
  path: "runtime.mode",
216
178
  op: "eq",
217
179
  value: "simulate"
218
180
  });
219
- strict_1.default.equal(errors.length, 0);
181
+ assert.equal(errors.length, 0);
220
182
  });
221
- (0, node_test_1.it)("AC-007/008: first matching case is selected, else default", () => {
222
- const doc = setGraphModelConfig((0, minimal_executable_graph_js_1.createMinimalExecutableGraph)(), {
183
+ it("AC-007/008: first matching case is selected, else default", () => {
184
+ const doc = setGraphModelConfig(createMinimalExecutableGraph(), {
223
185
  version: "graph-model-config/v1",
224
186
  cases: [
225
187
  {
@@ -241,12 +203,12 @@ function setGraphModelConfig(doc, modelConfig) {
241
203
  }
242
204
  ]
243
205
  });
244
- const context = (0, api_js_1.buildDeterministicCaseContext)(doc, { mode: "simulate" });
245
- const plan = (0, api_js_1.resolveNodeAiPlan)(doc, "node:professional-answer", context);
246
- strict_1.default.equal(plan.graphCaseId, "simulate");
206
+ const context = buildDeterministicCaseContext(doc, { mode: "simulate" });
207
+ const plan = resolveNodeAiPlan(doc, "node:professional-answer", context);
208
+ assert.equal(plan.graphCaseId, "simulate");
247
209
  });
248
- (0, node_test_1.it)("AC-009/010: default case requirements", () => {
249
- const noDefault = (0, api_js_1.validateExecutableGraph)(setGraphModelConfig((0, minimal_executable_graph_js_1.createMinimalExecutableGraph)(), {
210
+ it("AC-009/010: default case requirements", () => {
211
+ const noDefault = validateExecutableGraph(setGraphModelConfig(createMinimalExecutableGraph(), {
250
212
  version: "graph-model-config/v1",
251
213
  cases: [
252
214
  {
@@ -260,51 +222,51 @@ function setGraphModelConfig(doc, modelConfig) {
260
222
  }
261
223
  ]
262
224
  }));
263
- strict_1.default.ok(noDefault.errors.some((e) => e.code === "CASE_SELECTION_DEFAULT_MISSING"));
225
+ assert.ok(noDefault.errors.some((e) => e.code === "CASE_SELECTION_DEFAULT_MISSING"));
264
226
  });
265
227
  });
266
- (0, node_test_1.describe)("forbidden AI selectors", () => {
267
- (0, node_test_1.it)("AC-020: ai.prompt is rejected", () => {
268
- const errors = (0, api_js_1.validateCaseCondition)({ ai: { prompt: "complex?" } });
269
- strict_1.default.ok(errors.some((e) => e.code === "CASE_CONDITION_FORBIDDEN_AI_SELECTOR"));
228
+ describe("forbidden AI selectors", () => {
229
+ it("AC-020: ai.prompt is rejected", () => {
230
+ const errors = validateCaseCondition({ ai: { prompt: "complex?" } });
231
+ assert.ok(errors.some((e) => e.code === "CASE_CONDITION_FORBIDDEN_AI_SELECTOR"));
270
232
  });
271
- (0, node_test_1.it)("AC-024: ai.classification path is rejected", () => {
272
- const errors = (0, api_js_1.validateCaseCondition)({
233
+ it("AC-024: ai.classification path is rejected", () => {
234
+ const errors = validateCaseCondition({
273
235
  path: "ai.classification.risk",
274
236
  op: "eq",
275
237
  value: "high"
276
238
  });
277
- strict_1.default.ok(errors.some((e) => e.code === "CASE_CONDITION_FORBIDDEN_PATH"));
239
+ assert.ok(errors.some((e) => e.code === "CASE_CONDITION_FORBIDDEN_PATH"));
278
240
  });
279
- (0, node_test_1.it)("AC-025: node.output path is rejected", () => {
280
- const errors = (0, api_js_1.validateCaseCondition)({
241
+ it("AC-025: node.output path is rejected", () => {
242
+ const errors = validateCaseCondition({
281
243
  path: "node.output.riskClassifier.risk",
282
244
  op: "eq",
283
245
  value: "high"
284
246
  });
285
- strict_1.default.ok(errors.some((e) => e.code === "CASE_CONDITION_FORBIDDEN_PATH"));
247
+ assert.ok(errors.some((e) => e.code === "CASE_CONDITION_FORBIDDEN_PATH"));
286
248
  });
287
249
  });
288
- (0, node_test_1.describe)("profile-choice validation", () => {
289
- (0, node_test_1.it)("AC-030/031/032: valid profileChoice keys accepted", () => {
290
- strict_1.default.equal((0, api_js_1.isProfileChoiceKeyFormat)("cheap/default"), true);
291
- strict_1.default.equal((0, api_js_1.isProfileChoiceKeyFormat)("vol/default"), true);
292
- strict_1.default.equal((0, api_js_1.isProfileChoiceKeyFormat)("deep/openai_deep"), true);
293
- strict_1.default.equal((0, api_js_1.isKnownProfileChoice)("vol/pro"), true);
294
- });
295
- (0, node_test_1.it)("AC-033/034/035/036: bare aliases rejected", () => {
250
+ describe("profile-choice validation", () => {
251
+ it("AC-030/031/032: valid profileChoice keys accepted", () => {
252
+ assert.equal(isProfileChoiceKeyFormat("cheap/default"), true);
253
+ assert.equal(isProfileChoiceKeyFormat("vol/default"), true);
254
+ assert.equal(isProfileChoiceKeyFormat("deep/openai_deep"), true);
255
+ assert.equal(isKnownProfileChoice("vol/pro"), true);
256
+ });
257
+ it("AC-033/034/035/036: bare aliases rejected", () => {
296
258
  for (const key of ["cheap", "balanced", "cheapest", "default"]) {
297
- strict_1.default.equal((0, api_js_1.isProfileChoiceKeyFormat)(key), false);
259
+ assert.equal(isProfileChoiceKeyFormat(key), false);
298
260
  }
299
261
  });
300
- (0, node_test_1.it)("AC-037/038: vendor slugs and legacy aliases rejected", () => {
262
+ it("AC-037/038: vendor slugs and legacy aliases rejected", () => {
301
263
  // Syntactically valid profile/choice shape, but not a bundled registry key.
302
- strict_1.default.equal((0, api_js_1.isProfileChoiceKeyFormat)("openai/gpt-4o-mini"), true);
303
- strict_1.default.equal((0, api_js_1.isKnownProfileChoice)("openai/gpt-4o-mini"), false);
304
- strict_1.default.equal((0, api_js_1.isProfileChoiceKeyFormat)("cheap@anthropic_cheap"), false);
264
+ assert.equal(isProfileChoiceKeyFormat("openai/gpt-4o-mini"), true);
265
+ assert.equal(isKnownProfileChoice("openai/gpt-4o-mini"), false);
266
+ assert.equal(isProfileChoiceKeyFormat("cheap@anthropic_cheap"), false);
305
267
  });
306
- (0, node_test_1.it)("AC-039: unknown choice rejected in graph validation", () => {
307
- const result = (0, api_js_1.validateExecutableGraph)(setGraphModelConfig((0, minimal_executable_graph_js_1.createMinimalExecutableGraph)(), {
268
+ it("AC-039: unknown choice rejected in graph validation", () => {
269
+ const result = validateExecutableGraph(setGraphModelConfig(createMinimalExecutableGraph(), {
308
270
  version: "graph-model-config/v1",
309
271
  cases: [
310
272
  {
@@ -317,10 +279,10 @@ function setGraphModelConfig(doc, modelConfig) {
317
279
  }
318
280
  ]
319
281
  }));
320
- strict_1.default.ok(result.errors.some((e) => e.code === "PROFILE_CHOICE_KEY_UNKNOWN"));
282
+ assert.ok(result.errors.some((e) => e.code === "PROFILE_CHOICE_KEY_UNKNOWN"));
321
283
  });
322
- (0, node_test_1.it)("deprecated kind profile is rejected", () => {
323
- const result = (0, api_js_1.validateExecutableGraph)(setGraphModelConfig((0, minimal_executable_graph_js_1.createMinimalExecutableGraph)(), {
284
+ it("deprecated kind profile is rejected", () => {
285
+ const result = validateExecutableGraph(setGraphModelConfig(createMinimalExecutableGraph(), {
324
286
  version: "graph-model-config/v1",
325
287
  cases: [
326
288
  {
@@ -333,13 +295,13 @@ function setGraphModelConfig(doc, modelConfig) {
333
295
  }
334
296
  ]
335
297
  }));
336
- strict_1.default.ok(result.errors.some((e) => e.code === "PROFILE_SELECTION_KIND_DEPRECATED"));
298
+ assert.ok(result.errors.some((e) => e.code === "PROFILE_SELECTION_KIND_DEPRECATED"));
337
299
  });
338
300
  });
339
- (0, node_test_1.describe)("normalization", () => {
340
- (0, node_test_1.it)("AC-060: graph default shorthand normalizes to cases[0].id = default", () => {
341
- const doc = (0, minimal_executable_graph_js_1.createMinimalExecutableGraph)();
342
- const ext = doc.graph.metadata.extensions[constants_js_1.EXECUTABLE_PROFILE_NAMESPACE];
301
+ describe("normalization", () => {
302
+ it("AC-060: graph default shorthand normalizes to cases[0].id = default", () => {
303
+ const doc = createMinimalExecutableGraph();
304
+ const ext = doc.graph.metadata.extensions[EXECUTABLE_PROFILE_NAMESPACE];
343
305
  ext.modelConfig = {
344
306
  version: "graph-model-config/v1",
345
307
  default: {
@@ -348,25 +310,25 @@ function setGraphModelConfig(doc, modelConfig) {
348
310
  postActionModel: { kind: "profileChoice", key: "cheap/default" }
349
311
  }
350
312
  };
351
- const normalized = (0, api_js_1.normalizeExecutableGraph)(doc);
352
- const profile = normalized.graph.metadata?.extensions?.[constants_js_1.EXECUTABLE_PROFILE_NAMESPACE];
353
- strict_1.default.equal(profile?.modelConfig?.cases?.[0]?.id, "default");
354
- strict_1.default.equal(profile?.modelConfig?.cases?.[0]?.when, undefined);
313
+ const normalized = normalizeExecutableGraph(doc);
314
+ const profile = normalized.graph.metadata?.extensions?.[EXECUTABLE_PROFILE_NAMESPACE];
315
+ assert.equal(profile?.modelConfig?.cases?.[0]?.id, "default");
316
+ assert.equal(profile?.modelConfig?.cases?.[0]?.when, undefined);
355
317
  });
356
- (0, node_test_1.it)("AC-066: normalization does not mutate source graph", () => {
357
- const doc = (0, minimal_executable_graph_js_1.createMinimalExecutableGraph)();
318
+ it("AC-066: normalization does not mutate source graph", () => {
319
+ const doc = createMinimalExecutableGraph();
358
320
  const before = structuredClone(doc);
359
- (0, api_js_1.normalizeExecutableGraph)(doc);
360
- strict_1.default.deepEqual(doc, before);
321
+ normalizeExecutableGraph(doc);
322
+ assert.deepEqual(doc, before);
361
323
  });
362
324
  });
363
- (0, node_test_1.describe)("full resolution example", () => {
364
- (0, node_test_1.it)("matches CR/FR section 12 resolution", () => {
365
- const doc = (0, minimal_executable_graph_js_1.createMinimalExecutableGraph)();
325
+ describe("full resolution example", () => {
326
+ it("matches CR/FR section 12 resolution", () => {
327
+ const doc = createMinimalExecutableGraph();
366
328
  const taskNode = doc.graph.nodes.find((n) => n.id === "node:professional-answer");
367
329
  const params = taskNode.parameters;
368
- strict_1.default.ok(params && params.nodeType === "task");
369
- const ext = doc.graph.metadata.extensions[constants_js_1.EXECUTABLE_PROFILE_NAMESPACE];
330
+ assert.ok(params && params.nodeType === "task");
331
+ const ext = doc.graph.metadata.extensions[EXECUTABLE_PROFILE_NAMESPACE];
370
332
  ext.modelConfig = {
371
333
  version: "graph-model-config/v1",
372
334
  cases: [
@@ -439,51 +401,51 @@ function setGraphModelConfig(doc, modelConfig) {
439
401
  }
440
402
  }
441
403
  };
442
- const context = (0, api_js_1.buildDeterministicCaseContext)(doc, {
404
+ const context = buildDeterministicCaseContext(doc, {
443
405
  mode: "live",
444
406
  input: { analysisDepth: "deep", riskLevel: "high" }
445
407
  });
446
- const plan = (0, api_js_1.resolveNodeAiPlan)(doc, "node:professional-answer", context);
447
- strict_1.default.equal(plan.graphCaseId, "deep-live");
448
- strict_1.default.equal(plan.nodeCaseId, "high-risk-input");
449
- strict_1.default.equal(plan.slots.preActionModel.selected.kind, "profileChoice");
408
+ const plan = resolveNodeAiPlan(doc, "node:professional-answer", context);
409
+ assert.equal(plan.graphCaseId, "deep-live");
410
+ assert.equal(plan.nodeCaseId, "high-risk-input");
411
+ assert.equal(plan.slots.preActionModel.selected.kind, "profileChoice");
450
412
  if (plan.slots.preActionModel.selected.kind === "profileChoice") {
451
- strict_1.default.equal(plan.slots.preActionModel.selected.key, "vol/default");
413
+ assert.equal(plan.slots.preActionModel.selected.key, "vol/default");
452
414
  }
453
415
  if (plan.slots.skillModel.selected.kind === "profileChoice") {
454
- strict_1.default.equal(plan.slots.skillModel.selected.key, "deep/openai_deep");
416
+ assert.equal(plan.slots.skillModel.selected.key, "deep/openai_deep");
455
417
  }
456
- strict_1.default.ok(plan.caseSelection.graph.matchedConditions.some((c) => c.includes("runtime.mode eq live")));
457
- strict_1.default.ok(plan.caseSelection.node?.matchedConditions.some((c) => c.includes("runtime.input.riskLevel eq high")));
418
+ assert.ok(plan.caseSelection.graph.matchedConditions.some((c) => c.includes("runtime.mode eq live")));
419
+ assert.ok(plan.caseSelection.node?.matchedConditions.some((c) => c.includes("runtime.input.riskLevel eq high")));
458
420
  });
459
421
  });
460
- (0, node_test_1.describe)("evaluateCaseCondition", () => {
461
- (0, node_test_1.it)("AC-004/005/006: all, any, not supported", () => {
462
- const context = (0, api_js_1.buildDeterministicCaseContext)((0, minimal_executable_graph_js_1.createMinimalExecutableGraph)(), {
422
+ describe("evaluateCaseCondition", () => {
423
+ it("AC-004/005/006: all, any, not supported", () => {
424
+ const context = buildDeterministicCaseContext(createMinimalExecutableGraph(), {
463
425
  mode: "live",
464
426
  input: { riskLevel: "high", tier: "gold" }
465
427
  });
466
- strict_1.default.equal((0, api_js_1.evaluateCaseCondition)({
428
+ assert.equal(evaluateCaseCondition({
467
429
  all: [
468
430
  { path: "runtime.mode", op: "eq", value: "live" },
469
431
  { path: "runtime.input.riskLevel", op: "eq", value: "high" }
470
432
  ]
471
433
  }, context), true);
472
- strict_1.default.equal((0, api_js_1.evaluateCaseCondition)({
434
+ assert.equal(evaluateCaseCondition({
473
435
  any: [
474
436
  { path: "runtime.input.tier", op: "eq", value: "silver" },
475
437
  { path: "runtime.input.tier", op: "eq", value: "gold" }
476
438
  ]
477
439
  }, context), true);
478
- strict_1.default.equal((0, api_js_1.evaluateCaseCondition)({
440
+ assert.equal(evaluateCaseCondition({
479
441
  not: { path: "runtime.mode", op: "eq", value: "simulate" }
480
442
  }, context), true);
481
443
  });
482
444
  });
483
- (0, node_test_1.describe)("lifecycle artifacts", () => {
484
- (0, node_test_1.it)("AC-A001/A005: authoring graph with modelConfig.default passes", () => {
485
- const doc = (0, minimal_executable_graph_js_1.createMinimalExecutableGraph)();
486
- const ext = doc.graph.metadata.extensions[constants_js_1.EXECUTABLE_PROFILE_NAMESPACE];
445
+ describe("lifecycle artifacts", () => {
446
+ it("AC-A001/A005: authoring graph with modelConfig.default passes", () => {
447
+ const doc = createMinimalExecutableGraph();
448
+ const ext = doc.graph.metadata.extensions[EXECUTABLE_PROFILE_NAMESPACE];
487
449
  ext.modelConfig = {
488
450
  version: "graph-model-config/v1",
489
451
  default: {
@@ -492,10 +454,10 @@ function setGraphModelConfig(doc, modelConfig) {
492
454
  postActionModel: { kind: "profileChoice", key: "cheap/default" }
493
455
  }
494
456
  };
495
- strict_1.default.equal((0, api_js_1.validateAuthoringGraph)(doc).valid, true);
457
+ assert.equal(validateAuthoringGraph(doc).valid, true);
496
458
  });
497
- (0, node_test_1.it)("AC-A003/A004: bare profile and kind profile fail authoring validation", () => {
498
- const bareProfile = (0, api_js_1.validateAuthoringGraph)(setGraphModelConfig((0, minimal_executable_graph_js_1.createMinimalExecutableGraph)(), {
459
+ it("AC-A003/A004: bare profile and kind profile fail authoring validation", () => {
460
+ const bareProfile = validateAuthoringGraph(setGraphModelConfig(createMinimalExecutableGraph(), {
499
461
  version: "graph-model-config/v1",
500
462
  cases: [
501
463
  {
@@ -508,8 +470,8 @@ function setGraphModelConfig(doc, modelConfig) {
508
470
  }
509
471
  ]
510
472
  }));
511
- strict_1.default.ok(bareProfile.errors.some((e) => e.code === "PROFILE_CHOICE_KEY_FORMAT_INVALID"));
512
- const kindProfile = (0, api_js_1.validateAuthoringGraph)(setGraphModelConfig((0, minimal_executable_graph_js_1.createMinimalExecutableGraph)(), {
473
+ assert.ok(bareProfile.errors.some((e) => e.code === "PROFILE_CHOICE_KEY_FORMAT_INVALID"));
474
+ const kindProfile = validateAuthoringGraph(setGraphModelConfig(createMinimalExecutableGraph(), {
513
475
  version: "graph-model-config/v1",
514
476
  cases: [
515
477
  {
@@ -522,11 +484,11 @@ function setGraphModelConfig(doc, modelConfig) {
522
484
  }
523
485
  ]
524
486
  }));
525
- strict_1.default.ok(kindProfile.errors.some((e) => e.code === "PROFILE_SELECTION_KIND_DEPRECATED"));
487
+ assert.ok(kindProfile.errors.some((e) => e.code === "PROFILE_SELECTION_KIND_DEPRECATED"));
526
488
  });
527
- (0, node_test_1.it)("AC-P001/P003/P008/P009/P010: compile produces run-bound executable plan", () => {
528
- const doc = (0, minimal_executable_graph_js_1.createMinimalExecutableGraph)();
529
- const ext = doc.graph.metadata.extensions[constants_js_1.EXECUTABLE_PROFILE_NAMESPACE];
489
+ it("AC-P001/P003/P008/P009/P010: compile produces run-bound executable plan", () => {
490
+ const doc = createMinimalExecutableGraph();
491
+ const ext = doc.graph.metadata.extensions[EXECUTABLE_PROFILE_NAMESPACE];
530
492
  ext.modelConfig = {
531
493
  version: "graph-model-config/v1",
532
494
  cases: [
@@ -549,57 +511,57 @@ function setGraphModelConfig(doc, modelConfig) {
549
511
  }
550
512
  ]
551
513
  };
552
- const runtime = (0, api_js_1.buildRuntimeObject)({
514
+ const runtime = buildRuntimeObject({
553
515
  jobId: "job-compile-1",
554
516
  mode: "simulate",
555
517
  input: { target_subnet_cidr: "10.0.0.0/24" }
556
518
  });
557
519
  const before = structuredClone(doc);
558
- const plan = (0, api_js_1.compileExecutablePlan)(doc, runtime, {
520
+ const plan = compileExecutablePlan(doc, runtime, {
559
521
  profileRegistry: { version: "3.0.0", registryHash: "sha256:profiles456" },
560
522
  environment: "prod"
561
523
  });
562
- strict_1.default.deepEqual(doc, before);
563
- strict_1.default.equal(plan.format, "x12i.graphenix.executable-plan/v1");
564
- strict_1.default.equal(plan.source.graphId, doc.id);
565
- strict_1.default.equal(plan.runtimeBinding.jobId, "job-compile-1");
566
- strict_1.default.equal(plan.caseSelection.graph.caseId, "simulate");
567
- strict_1.default.equal(plan.profileRegistry.version, "3.0.0");
568
- const profileExt = plan.graph.graph.metadata?.extensions?.[constants_js_1.EXECUTABLE_PROFILE_NAMESPACE];
569
- strict_1.default.equal("default" in (profileExt?.modelConfig ?? {}), false);
524
+ assert.deepEqual(doc, before);
525
+ assert.equal(plan.format, "graphenix.executable-plan/v1");
526
+ assert.equal(plan.source.graphId, doc.id);
527
+ assert.equal(plan.runtimeBinding.jobId, "job-compile-1");
528
+ assert.equal(plan.caseSelection.graph.caseId, "simulate");
529
+ assert.equal(plan.profileRegistry.version, "3.0.0");
530
+ const profileExt = plan.graph.graph.metadata?.extensions?.[EXECUTABLE_PROFILE_NAMESPACE];
531
+ assert.equal("default" in (profileExt?.modelConfig ?? {}), false);
570
532
  const professionalPlan = plan.nodePlans["node:professional-answer"];
571
- strict_1.default.equal(professionalPlan?.modelSlots?.skillModel?.selection.kind, "profileChoice");
572
- strict_1.default.equal((0, api_js_1.validateExecutablePlan)(plan).valid, true);
573
- });
574
- (0, node_test_1.it)("AC-E003/E006/E008: executable plan is normalized with resolved node slots", () => {
575
- const doc = (0, minimal_executable_graph_js_1.createMinimalExecutableGraph)();
576
- const runtime = (0, api_js_1.buildRuntimeObject)({ jobId: "job-plan-1" });
577
- const plan = (0, api_js_1.compileExecutablePlan)(doc, runtime);
578
- strict_1.default.equal((0, api_js_1.validateExecutablePlan)(plan).valid, true);
579
- strict_1.default.ok(plan.nodePlans["node:professional-answer"]?.modelSlots?.preActionModel);
580
- strict_1.default.equal("credentials" in plan, false);
581
- });
582
- (0, node_test_1.it)("AC-T001/T002/T011: execution trace references plan and keeps append-only events", () => {
583
- const doc = (0, minimal_executable_graph_js_1.createMinimalExecutableGraph)();
584
- const runtime = (0, api_js_1.buildRuntimeObject)({ jobId: "job-trace-1", mode: "live" });
585
- const plan = (0, api_js_1.compileExecutablePlan)(doc, runtime);
586
- const trace = (0, api_js_1.createExecutionTrace)(plan, runtime);
587
- strict_1.default.equal(trace.source.graphId, plan.source.graphId);
588
- strict_1.default.equal(trace.plan.planId, plan.planId);
589
- strict_1.default.equal(trace.status, "queued");
533
+ assert.equal(professionalPlan?.modelSlots?.skillModel?.selection.kind, "profileChoice");
534
+ assert.equal(validateExecutablePlan(plan).valid, true);
535
+ });
536
+ it("AC-E003/E006/E008: executable plan is normalized with resolved node slots", () => {
537
+ const doc = createMinimalExecutableGraph();
538
+ const runtime = buildRuntimeObject({ jobId: "job-plan-1" });
539
+ const plan = compileExecutablePlan(doc, runtime);
540
+ assert.equal(validateExecutablePlan(plan).valid, true);
541
+ assert.ok(plan.nodePlans["node:professional-answer"]?.modelSlots?.preActionModel);
542
+ assert.equal("credentials" in plan, false);
543
+ });
544
+ it("AC-T001/T002/T011: execution trace references plan and keeps append-only events", () => {
545
+ const doc = createMinimalExecutableGraph();
546
+ const runtime = buildRuntimeObject({ jobId: "job-trace-1", mode: "live" });
547
+ const plan = compileExecutablePlan(doc, runtime);
548
+ const trace = createExecutionTrace(plan, runtime);
549
+ assert.equal(trace.source.graphId, plan.source.graphId);
550
+ assert.equal(trace.plan.planId, plan.planId);
551
+ assert.equal(trace.status, "queued");
590
552
  const startedAt = "2026-06-06T12:00:01.000Z";
591
- const updated = (0, api_js_1.appendExecutionEvent)(trace, {
553
+ const updated = appendExecutionEvent(trace, {
592
554
  id: "evt:1",
593
555
  ts: startedAt,
594
556
  level: "info",
595
557
  type: "graph.started",
596
558
  message: "Graph execution started."
597
559
  });
598
- strict_1.default.equal(updated.events.length, 1);
599
- strict_1.default.notEqual(updated, trace);
600
- strict_1.default.equal((0, api_js_1.validateExecutionTrace)(updated, plan.nodePlans).valid, true);
560
+ assert.equal(updated.events.length, 1);
561
+ assert.notEqual(updated, trace);
562
+ assert.equal(validateExecutionTrace(updated, plan.nodePlans).valid, true);
601
563
  const nodeTrace = updated.nodeExecutions["node:professional-answer"];
602
- strict_1.default.ok(nodeTrace?.units["unit:node:professional-answer:skill"]);
564
+ assert.ok(nodeTrace?.units["unit:node:professional-answer:skill"]);
603
565
  });
604
566
  });
605
567
  function getTaskNode(doc, nodeId = "node:professional-answer") {
@@ -608,7 +570,7 @@ function getTaskNode(doc, nodeId = "node:professional-answer") {
608
570
  function setTaskConfiguration(doc, config) {
609
571
  const node = getTaskNode(doc);
610
572
  const params = node.parameters;
611
- strict_1.default.ok(params && params.nodeType === "task");
573
+ assert.ok(params && params.nodeType === "task");
612
574
  node.parameters = {
613
575
  ...params,
614
576
  taskConfiguration: config
@@ -616,22 +578,22 @@ function setTaskConfiguration(doc, config) {
616
578
  return doc;
617
579
  }
618
580
  function setGraphPolicies(doc, policies) {
619
- const ext = doc.graph.metadata.extensions[constants_js_1.EXECUTABLE_PROFILE_NAMESPACE];
581
+ const ext = doc.graph.metadata.extensions[EXECUTABLE_PROFILE_NAMESPACE];
620
582
  ext.policies = policies;
621
583
  return doc;
622
584
  }
623
- (0, node_test_1.describe)("execution units", () => {
624
- (0, node_test_1.it)("AC-001: task node with no preActions/postActions compiles into one skill unit", () => {
625
- const doc = (0, minimal_executable_graph_js_1.createMinimalExecutableGraph)();
626
- const runtime = (0, api_js_1.buildRuntimeObject)({ jobId: "job-units-1" });
627
- const plan = (0, api_js_1.compileExecutablePlan)(doc, runtime);
585
+ describe("execution units", () => {
586
+ it("AC-001: task node with no preActions/postActions compiles into one skill unit", () => {
587
+ const doc = createMinimalExecutableGraph();
588
+ const runtime = buildRuntimeObject({ jobId: "job-units-1" });
589
+ const plan = compileExecutablePlan(doc, runtime);
628
590
  const units = plan.nodePlans["node:professional-answer"].executionUnits;
629
- strict_1.default.equal(units.length, 1);
630
- strict_1.default.equal(units[0].unitKind, "skill");
631
- strict_1.default.equal(units[0].unitId, "unit:node:professional-answer:skill");
591
+ assert.equal(units.length, 1);
592
+ assert.equal(units[0].unitKind, "skill");
593
+ assert.equal(units[0].unitId, "unit:node:professional-answer:skill");
632
594
  });
633
- (0, node_test_1.it)("AC-002/003/004: preActions before skill and postActions after with stable order", () => {
634
- const doc = setTaskConfiguration((0, minimal_executable_graph_js_1.createMinimalExecutableGraph)(), {
595
+ it("AC-002/003/004: preActions before skill and postActions after with stable order", () => {
596
+ const doc = setTaskConfiguration(createMinimalExecutableGraph(), {
635
597
  preActions: [
636
598
  { id: "pre:a", actionKey: "prepare-input" },
637
599
  { id: "pre:b", actionKey: "normalize-input" }
@@ -641,10 +603,10 @@ function setGraphPolicies(doc, policies) {
641
603
  { id: "post:b", actionKey: "shape-response" }
642
604
  ]
643
605
  });
644
- const plan = (0, api_js_1.compileExecutablePlan)(doc, (0, api_js_1.buildRuntimeObject)({ jobId: "job-units-2" }));
606
+ const plan = compileExecutablePlan(doc, buildRuntimeObject({ jobId: "job-units-2" }));
645
607
  const units = plan.nodePlans["node:professional-answer"].executionUnits;
646
- strict_1.default.equal(units.length, 5);
647
- strict_1.default.deepEqual(units.map((unit) => [unit.order, unit.unitKind, unit.actionKey ?? unit.skillKey]), [
608
+ assert.equal(units.length, 5);
609
+ assert.deepEqual(units.map((unit) => [unit.order, unit.unitKind, unit.actionKey ?? unit.skillKey]), [
648
610
  [0, "preAction", "prepare-input"],
649
611
  [1, "preAction", "normalize-input"],
650
612
  [2, "skill", "professional-answer"],
@@ -652,31 +614,31 @@ function setGraphPolicies(doc, policies) {
652
614
  [4, "postAction", "shape-response"]
653
615
  ]);
654
616
  });
655
- (0, node_test_1.it)("AC-005/006/007: units use resolved node model slots", () => {
656
- const doc = setTaskConfiguration((0, minimal_executable_graph_js_1.createMinimalExecutableGraph)(), {
617
+ it("AC-005/006/007: units use resolved node model slots", () => {
618
+ const doc = setTaskConfiguration(createMinimalExecutableGraph(), {
657
619
  preActions: [{ id: "pre:a", actionKey: "prepare-input" }],
658
620
  postActions: [{ id: "post:a", actionKey: "validate-output" }]
659
621
  });
660
- const plan = (0, api_js_1.compileExecutablePlan)(doc, (0, api_js_1.buildRuntimeObject)({ jobId: "job-units-3" }));
622
+ const plan = compileExecutablePlan(doc, buildRuntimeObject({ jobId: "job-units-3" }));
661
623
  const nodePlan = plan.nodePlans["node:professional-answer"];
662
624
  const pre = nodePlan.executionUnits.find((unit) => unit.unitKind === "preAction");
663
625
  const skill = nodePlan.executionUnits.find((unit) => unit.unitKind === "skill");
664
626
  const post = nodePlan.executionUnits.find((unit) => unit.unitKind === "postAction");
665
- strict_1.default.equal(pre.modelSlot, "preActionModel");
627
+ assert.equal(pre.modelSlot, "preActionModel");
666
628
  if (pre.modelSelection?.kind === "profileChoice") {
667
- strict_1.default.equal(pre.modelSelection.key, "cheap/default");
629
+ assert.equal(pre.modelSelection.key, "cheap/default");
668
630
  }
669
- strict_1.default.equal(skill.modelSlot, "skillModel");
631
+ assert.equal(skill.modelSlot, "skillModel");
670
632
  if (skill.modelSelection?.kind === "profileChoice") {
671
- strict_1.default.equal(skill.modelSelection.key, "vol/default");
633
+ assert.equal(skill.modelSelection.key, "vol/default");
672
634
  }
673
- strict_1.default.equal(post.modelSlot, "postActionModel");
635
+ assert.equal(post.modelSlot, "postActionModel");
674
636
  if (post.modelSelection?.kind === "profileChoice") {
675
- strict_1.default.equal(post.modelSelection.key, "cheap/default");
637
+ assert.equal(post.modelSelection.key, "cheap/default");
676
638
  }
677
639
  });
678
- (0, node_test_1.it)("AC-008/009: node skillModel override does not affect pre/post units", () => {
679
- const doc = setTaskConfiguration((0, minimal_executable_graph_js_1.createMinimalExecutableGraph)(), {
640
+ it("AC-008/009: node skillModel override does not affect pre/post units", () => {
641
+ const doc = setTaskConfiguration(createMinimalExecutableGraph(), {
680
642
  modelConfig: {
681
643
  inherit: true,
682
644
  modelConfig: {
@@ -686,23 +648,23 @@ function setGraphPolicies(doc, policies) {
686
648
  preActions: [{ id: "pre:a", actionKey: "prepare-input" }],
687
649
  postActions: [{ id: "post:a", actionKey: "validate-output" }]
688
650
  });
689
- const plan = (0, api_js_1.compileExecutablePlan)(doc, (0, api_js_1.buildRuntimeObject)({ jobId: "job-units-4" }));
651
+ const plan = compileExecutablePlan(doc, buildRuntimeObject({ jobId: "job-units-4" }));
690
652
  const units = plan.nodePlans["node:professional-answer"].executionUnits;
691
653
  const pre = units.find((unit) => unit.unitKind === "preAction");
692
654
  const skill = units.find((unit) => unit.unitKind === "skill");
693
655
  const post = units.find((unit) => unit.unitKind === "postAction");
694
656
  if (pre.modelSelection?.kind === "profileChoice") {
695
- strict_1.default.equal(pre.modelSelection.key, "cheap/default");
657
+ assert.equal(pre.modelSelection.key, "cheap/default");
696
658
  }
697
659
  if (skill.modelSelection?.kind === "profileChoice") {
698
- strict_1.default.equal(skill.modelSelection.key, "deep/openai_deep");
660
+ assert.equal(skill.modelSelection.key, "deep/openai_deep");
699
661
  }
700
662
  if (post.modelSelection?.kind === "profileChoice") {
701
- strict_1.default.equal(post.modelSelection.key, "cheap/default");
663
+ assert.equal(post.modelSelection.key, "cheap/default");
702
664
  }
703
665
  });
704
- (0, node_test_1.it)("AC-010: action-level model override fails when policy disabled", () => {
705
- const doc = setTaskConfiguration((0, minimal_executable_graph_js_1.createMinimalExecutableGraph)(), {
666
+ it("AC-010: action-level model override fails when policy disabled", () => {
667
+ const doc = setTaskConfiguration(createMinimalExecutableGraph(), {
706
668
  preActions: [
707
669
  {
708
670
  id: "pre:a",
@@ -711,11 +673,11 @@ function setGraphPolicies(doc, policies) {
711
673
  }
712
674
  ]
713
675
  });
714
- const result = (0, api_js_1.validateAuthoringGraph)(doc);
715
- strict_1.default.ok(result.errors.some((e) => e.code === "TASK_ACTION_MODEL_OVERRIDE_FORBIDDEN"));
676
+ const result = validateAuthoringGraph(doc);
677
+ assert.ok(result.errors.some((e) => e.code === "TASK_ACTION_MODEL_OVERRIDE_FORBIDDEN"));
716
678
  });
717
- (0, node_test_1.it)("AC-011/012: action-level model override passes when policy enabled", () => {
718
- const doc = setGraphPolicies(setTaskConfiguration((0, minimal_executable_graph_js_1.createMinimalExecutableGraph)(), {
679
+ it("AC-011/012: action-level model override passes when policy enabled", () => {
680
+ const doc = setGraphPolicies(setTaskConfiguration(createMinimalExecutableGraph(), {
719
681
  preActions: [
720
682
  {
721
683
  id: "pre:a",
@@ -724,16 +686,16 @@ function setGraphPolicies(doc, policies) {
724
686
  }
725
687
  ]
726
688
  }), { allowActionLevelModelOverride: true });
727
- strict_1.default.equal((0, api_js_1.validateAuthoringGraph)(doc).valid, true);
728
- const plan = (0, api_js_1.compileExecutablePlan)(doc, (0, api_js_1.buildRuntimeObject)({ jobId: "job-units-5" }));
689
+ assert.equal(validateAuthoringGraph(doc).valid, true);
690
+ const plan = compileExecutablePlan(doc, buildRuntimeObject({ jobId: "job-units-5" }));
729
691
  const pre = plan.nodePlans["node:professional-answer"].executionUnits[0];
730
- strict_1.default.equal(pre.modelSource, "actionOverride");
692
+ assert.equal(pre.modelSource, "actionOverride");
731
693
  if (pre.modelSelection?.kind === "profileChoice") {
732
- strict_1.default.equal(pre.modelSelection.key, "vol/pro");
694
+ assert.equal(pre.modelSelection.key, "vol/pro");
733
695
  }
734
696
  });
735
- (0, node_test_1.it)("AC-013: bare profile key in action-level override fails", () => {
736
- const doc = setGraphPolicies(setTaskConfiguration((0, minimal_executable_graph_js_1.createMinimalExecutableGraph)(), {
697
+ it("AC-013: bare profile key in action-level override fails", () => {
698
+ const doc = setGraphPolicies(setTaskConfiguration(createMinimalExecutableGraph(), {
737
699
  preActions: [
738
700
  {
739
701
  id: "pre:a",
@@ -742,11 +704,11 @@ function setGraphPolicies(doc, policies) {
742
704
  }
743
705
  ]
744
706
  }), { allowActionLevelModelOverride: true });
745
- const result = (0, api_js_1.validateAuthoringGraph)(doc);
746
- strict_1.default.ok(result.errors.some((e) => e.code === "PROFILE_CHOICE_KEY_FORMAT_INVALID"));
707
+ const result = validateAuthoringGraph(doc);
708
+ assert.ok(result.errors.some((e) => e.code === "PROFILE_CHOICE_KEY_FORMAT_INVALID"));
747
709
  });
748
- (0, node_test_1.it)("AC-014/015/016: unit fallback stays on same slot only", () => {
749
- const resolvedPre = (0, api_js_1.resolveNodeModelSlot)({
710
+ it("AC-014/015/016: unit fallback stays on same slot only", () => {
711
+ const resolvedPre = resolveNodeModelSlot({
750
712
  slot: "preActionModel",
751
713
  graphSelection: { kind: "profileChoice", key: "cheap/default" },
752
714
  nodeSelection: { kind: "profileChoice", key: "vol/pro" },
@@ -762,29 +724,29 @@ function setGraphPolicies(doc, policies) {
762
724
  graphCaseId: "default",
763
725
  nodeId: "node:professional-answer"
764
726
  });
765
- strict_1.default.equal(resolvedPre.source, "fallbackToGraphDefault");
727
+ assert.equal(resolvedPre.source, "fallbackToGraphDefault");
766
728
  if (resolvedPre.selected.kind === "profileChoice") {
767
- strict_1.default.equal(resolvedPre.selected.key, "cheap/default");
729
+ assert.equal(resolvedPre.selected.key, "cheap/default");
768
730
  }
769
- const plan = (0, api_js_1.compileExecutablePlan)(setTaskConfiguration((0, minimal_executable_graph_js_1.createMinimalExecutableGraph)(), {
731
+ const plan = compileExecutablePlan(setTaskConfiguration(createMinimalExecutableGraph(), {
770
732
  preActions: [{ id: "pre:a", actionKey: "prepare-input" }],
771
733
  postActions: [{ id: "post:a", actionKey: "validate-output" }]
772
- }), (0, api_js_1.buildRuntimeObject)({ jobId: "job-units-fallback" }));
734
+ }), buildRuntimeObject({ jobId: "job-units-fallback" }));
773
735
  const units = plan.nodePlans["node:professional-answer"].executionUnits;
774
- strict_1.default.ok(units.every((unit) => unit.modelSlot !== "skillModel" || unit.unitKind === "skill"));
775
- strict_1.default.ok(units.every((unit) => unit.modelSlot !== "postActionModel" || unit.unitKind === "postAction"));
776
- strict_1.default.ok(units.every((unit) => unit.modelSlot !== "preActionModel" || unit.unitKind === "preAction"));
736
+ assert.ok(units.every((unit) => unit.modelSlot !== "skillModel" || unit.unitKind === "skill"));
737
+ assert.ok(units.every((unit) => unit.modelSlot !== "postActionModel" || unit.unitKind === "postAction"));
738
+ assert.ok(units.every((unit) => unit.modelSlot !== "preActionModel" || unit.unitKind === "preAction"));
777
739
  });
778
- (0, node_test_1.it)("AC-017/018/019: execution trace records planned units and unit fallback", () => {
779
- const doc = setTaskConfiguration((0, minimal_executable_graph_js_1.createMinimalExecutableGraph)(), {
740
+ it("AC-017/018/019: execution trace records planned units and unit fallback", () => {
741
+ const doc = setTaskConfiguration(createMinimalExecutableGraph(), {
780
742
  preActions: [{ id: "pre:a", actionKey: "prepare-input" }],
781
743
  postActions: [{ id: "post:a", actionKey: "validate-output" }]
782
744
  });
783
- const runtime = (0, api_js_1.buildRuntimeObject)({ jobId: "job-units-6" });
784
- const plan = (0, api_js_1.compileExecutablePlan)(doc, runtime);
785
- const trace = (0, api_js_1.createExecutionTrace)(plan, runtime);
745
+ const runtime = buildRuntimeObject({ jobId: "job-units-6" });
746
+ const plan = compileExecutablePlan(doc, runtime);
747
+ const trace = createExecutionTrace(plan, runtime);
786
748
  const nodeTrace = trace.nodeExecutions["node:professional-answer"];
787
- strict_1.default.equal(Object.keys(nodeTrace.units).length, 3);
749
+ assert.equal(Object.keys(nodeTrace.units).length, 3);
788
750
  const skillUnitId = "unit:node:professional-answer:skill";
789
751
  nodeTrace.units[skillUnitId] = {
790
752
  ...nodeTrace.units[skillUnitId],
@@ -811,8 +773,8 @@ function setGraphPolicies(doc, policies) {
811
773
  enabled: true,
812
774
  allowedTriggers: ["nodeModelUnavailable"]
813
775
  };
814
- strict_1.default.equal((0, api_js_1.validateExecutionTrace)(invalidFallback, invalidPolicyPlan.nodePlans).valid, false);
815
- const withEvent = (0, api_js_1.appendExecutionEvent)(trace, {
776
+ assert.equal(validateExecutionTrace(invalidFallback, invalidPolicyPlan.nodePlans).valid, false);
777
+ const withEvent = appendExecutionEvent(trace, {
816
778
  id: "evt:unit:1",
817
779
  ts: "2026-06-06T12:00:02.100Z",
818
780
  level: "info",
@@ -826,18 +788,18 @@ function setGraphPolicies(doc, policies) {
826
788
  source: "graphDefault"
827
789
  }
828
790
  });
829
- strict_1.default.equal(withEvent.events[0].type, "executionUnit.model.resolved");
791
+ assert.equal(withEvent.events[0].type, "executionUnit.model.resolved");
830
792
  });
831
- (0, node_test_1.it)("AC-020: graph, plan, and trace remain implementation-agnostic", () => {
832
- const doc = setTaskConfiguration((0, minimal_executable_graph_js_1.createMinimalExecutableGraph)(), {
793
+ it("AC-020: graph, plan, and trace remain implementation-agnostic", () => {
794
+ const doc = setTaskConfiguration(createMinimalExecutableGraph(), {
833
795
  preActions: [{ id: "pre:a", actionKey: "prepare-input" }]
834
796
  });
835
- const runtime = (0, api_js_1.buildRuntimeObject)({ jobId: "job-units-7" });
836
- const plan = (0, api_js_1.compileExecutablePlan)(doc, runtime);
837
- const trace = (0, api_js_1.createExecutionTrace)(plan, runtime);
797
+ const runtime = buildRuntimeObject({ jobId: "job-units-7" });
798
+ const plan = compileExecutablePlan(doc, runtime);
799
+ const trace = createExecutionTrace(plan, runtime);
838
800
  const serialized = JSON.stringify({ doc, plan, trace });
839
801
  for (const forbidden of ["openrouter", "anthropic-sdk", "langchain"]) {
840
- strict_1.default.equal(serialized.includes(forbidden), false);
802
+ assert.equal(serialized.includes(forbidden), false);
841
803
  }
842
804
  });
843
805
  });