@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.
package/README.md CHANGED
@@ -1,341 +1,512 @@
1
- # @x12i/graphenix-executable-format
2
-
3
- Strict **X12i executable graph profile** built on [`@x12i/graphenix-core`](../core), with deterministic model configuration cases validated against [`@x12i/ai-profiles`](https://www.npmjs.com/package/@x12i/ai-profiles).
4
-
5
- Graphenix core defines the structural graph format. This package defines the X12i executable lifecycle: authoring graphs, compiled executable plans, execution traces, model inheritance, fallback, and the studio adapter.
6
-
7
- ## Install
8
-
9
- ```bash
10
- npm install @x12i/graphenix-executable-format @x12i/graphenix-core
11
- ```
12
-
13
- `@x12i/ai-profiles` is installed automatically as a dependency (profile registry and `profileChoice` key validation).
14
-
15
- ## Relationship
16
-
17
- ```txt
18
- @x12i/graphenix-core
19
- generic graph document format (2.0.0)
20
-
21
- @x12i/ai-profiles
22
- profile/choice registry (cheap/default, vol/pro, deep/openai_deep, …)
23
-
24
- @x12i/graphenix-executable-format
25
- strict runnable profile + compile + trace
26
- ```
27
-
28
- A valid authoring graph is always a valid Graphenix document, but not every Graphenix document is executable.
29
-
30
- ## Lifecycle artifacts
31
-
32
- ```txt
33
- AuthoringGraphDocument ← Studio saves this (source of truth)
34
- ↓ compileExecutablePlan()
35
- ExecutableGraphPlan ← Engine consumes this
36
- ↓ executeGraph()
37
- GraphExecutionTrace ← Append-only run evidence
38
- ```
39
-
40
- | Artifact | Purpose | Saved? | Used by engine? |
41
- | -------- | ------- | -----: | --------------: |
42
- | **AuthoringGraphDocument** | Human/studio source of truth | Yes | No, not directly |
43
- | **ExecutableGraphPlan** | Normalized, deterministic, run-ready plan | Optional cache / per run | Yes |
44
- | **GraphExecutionTrace** | What happened during one run | Yes, append-only | No |
45
-
46
- ## Extension namespace
47
-
48
- ```txt
49
- graph.metadata.extensions["x12i.executable/v1"]
50
- ```
51
-
52
- ## Key rule: deterministic cases
53
-
54
- ```txt
55
- Cases may choose stronger or weaker AI profiles.
56
- AI may not choose the case.
57
- ```
58
-
59
- Allowed case selectors:
60
-
61
- ```txt
62
- runtime.mode = "simulate"
63
- runtime.input.riskLevel = "high"
64
- runtime.environment = "prod"
65
- runtime.input.analysisDepth = "deep"
66
- ```
67
-
68
- Forbidden:
69
-
70
- ```txt
71
- Ask AI whether input is high risk, then pick a model case
72
- LLM classification as a case condition
73
- semanticMatch / function / script selectors
74
- node.output.* / ai.* / executionMemory.ai.*
75
- ```
76
-
77
- ## Profile choice format
78
-
79
- Use explicit `profile/choice` composite keys from `@x12i/ai-profiles`:
80
-
81
- ```json
82
- {
83
- "kind": "profileChoice",
84
- "key": "vol/default"
85
- }
86
- ```
87
-
88
- Examples: `cheap/default`, `sum/default`, `vol/default`, `vol/pro`, `deep/openai_deep`.
89
-
90
- Rejected:
91
-
92
- ```txt
93
- kind: "profile" with bare names (economy, balanced)
94
- bare keys (cheap, default, strong)
95
- vendor slugs as profileChoice (openai/gpt-4o-mini unknown key)
96
- ```
97
-
98
- Direct concrete model (separate from profiles):
99
-
100
- ```json
101
- {
102
- "kind": "model",
103
- "provider": "openai",
104
- "modelId": "gpt-4o-mini"
105
- }
106
- ```
107
-
108
- `profileChoice` is **not** resolved to vendor/model during normalization — only at invocation/planning via `@x12i/ai-profiles`.
109
-
110
- ## Model configuration cases
111
-
112
- ### Graph-level (`modelConfig`)
113
-
114
- Authoring form may use `default` shorthand or explicit `cases[]`:
115
-
116
- ```json
117
- {
118
- "version": "graph-model-config/v1",
119
- "cases": [
120
- {
121
- "id": "default",
122
- "modelConfig": {
123
- "preActionModel": { "kind": "profileChoice", "key": "cheap/default" },
124
- "skillModel": { "kind": "profileChoice", "key": "vol/default" },
125
- "postActionModel": { "kind": "profileChoice", "key": "cheap/default" }
126
- }
127
- },
128
- {
129
- "id": "simulate",
130
- "when": { "path": "runtime.mode", "op": "eq", "value": "simulate" },
131
- "modelConfig": {
132
- "preActionModel": { "kind": "profileChoice", "key": "cheap/default" },
133
- "skillModel": { "kind": "profileChoice", "key": "sum/default" },
134
- "postActionModel": { "kind": "profileChoice", "key": "cheap/default" }
135
- }
136
- }
137
- ]
138
- }
139
- ```
140
-
141
- Rules:
142
-
143
- - Evaluate conditional cases in order; select the first match.
144
- - If none match, use case `id: "default"`.
145
- - Exactly one default graph case required.
146
- - Every graph case must define the full triplet: `preActionModel`, `skillModel`, `postActionModel`.
147
-
148
- ### Node-level (`taskConfiguration.modelConfig`)
149
-
150
- Node cases may be partial when `inherit: true`. Missing slots inherit from the **selected graph case**.
151
-
152
- ```json
153
- {
154
- "inherit": true,
155
- "cases": [
156
- {
157
- "id": "high-risk-input",
158
- "when": {
159
- "path": "runtime.input.riskLevel",
160
- "op": "eq",
161
- "value": "high"
162
- },
163
- "modelConfig": {
164
- "skillModel": { "kind": "profileChoice", "key": "deep/openai_deep" }
165
- }
166
- }
167
- ]
168
- }
169
- ```
170
-
171
- ## Case condition DSL
172
-
173
- ```ts
174
- type CaseCondition =
175
- | { all: CaseCondition[] }
176
- | { any: CaseCondition[] }
177
- | { not: CaseCondition }
178
- | {
179
- path: string;
180
- op: "eq" | "neq" | "in" | "notIn" | "exists" | "notExists"
181
- | "gt" | "gte" | "lt" | "lte" | "matches";
182
- value?: string | number | boolean | null | string[] | number[];
183
- };
184
- ```
185
-
186
- Allowed path roots: `runtime.mode`, `runtime.environment`, `runtime.job.*`, `runtime.input.*`, `runtime.variables.*`, `runtime.flags.*`, `runtime.context.*`, `graph.id`, `graph.revision`.
187
-
188
- ## Validate authoring graph
189
-
190
- ```ts
191
- import {
192
- validateAuthoringGraph,
193
- validateExecutableGraph,
194
- createMinimalExecutableGraph
195
- } from "@x12i/graphenix-executable-format";
196
- import { validateGraph } from "@x12i/graphenix-core";
197
-
198
- const doc = createMinimalExecutableGraph();
199
-
200
- validateGraph(doc); // Graphenix structure
201
- validateAuthoringGraph(doc); // authoring profile semantics
202
- validateExecutableGraph(doc); // alias for authoring validation
203
- ```
204
-
205
- ## Normalize and preview resolution
206
-
207
- ```ts
208
- import {
209
- normalizeExecutableGraph,
210
- resolveNodeAiPlan,
211
- explainNodeInheritance,
212
- buildDeterministicCaseContext,
213
- evaluateCaseCondition,
214
- validateCaseCondition
215
- } from "@x12i/graphenix-executable-format";
216
-
217
- const normalized = normalizeExecutableGraph(doc); // non-mutating
218
-
219
- const context = buildDeterministicCaseContext(doc, {
220
- mode: "live",
221
- input: { analysisDepth: "deep", riskLevel: "high" }
222
- });
223
-
224
- const plan = resolveNodeAiPlan(normalized, "node:professional-answer", context);
225
- console.log(explainNodeInheritance(plan));
226
- // Graph case selected: deep-live
227
- // Node case selected: high-risk-input
228
- // ...
229
- ```
230
-
231
- ## Compile executable plan
232
-
233
- ```ts
234
- import {
235
- compileExecutablePlan,
236
- validateExecutablePlan,
237
- buildRuntimeObject
238
- } from "@x12i/graphenix-executable-format";
239
-
240
- const runtime = buildRuntimeObject({
241
- jobId: "wg-1780698714844-8q8izhb",
242
- mode: "live",
243
- input: { analysisDepth: "deep" }
244
- });
245
-
246
- const plan = compileExecutablePlan(authoringGraph, runtime, {
247
- profileRegistry: { version: "3.2.0" },
248
- environment: "prod"
249
- });
250
-
251
- validateExecutablePlan(plan);
252
- ```
253
-
254
- Flow inside `compileExecutablePlan`:
255
-
256
- ```txt
257
- validateAuthoringExecutableGraph()
258
- normalizeExecutableGraph()
259
- assertNormalizedExecutableGraph()
260
- selectGraphModelCase() resolveNodeAiPlan() per task node
261
- buildNodeExecutionUnits()
262
- ```
263
-
264
- The engine should consume only `ExecutableGraphPlan`.
265
-
266
- ## Studio engine adapter
267
-
268
- ```ts
269
- import { buildGraphExecutionRequestFromStudioExecute } from "@x12i/graphenix-executable-format";
270
-
271
- const { plan, runtime } = buildGraphExecutionRequestFromStudioExecute(
272
- studioRequest,
273
- { agentId: "agent-1" }
274
- );
275
- ```
276
-
277
- The engine receives only `{ plan, runtime }`. Credentials and request-level model defaults are never copied.
278
-
279
- ## Model inheritance and fallback
280
-
281
- - Graph-level `modelConfig` is **required** with a complete model triplet per case.
282
- - Node overrides may be partial; missing slots inherit from the **selected graph case**.
283
- - Fallback is same-slot only: `node.skillModel → graph.skillModel` from the selected graph case (never cross-slot, another case, or runtime defaults).
284
-
285
- ## Execution trace
286
-
287
- ```ts
288
- import {
289
- createExecutionTrace,
290
- appendExecutionEvent,
291
- validateExecutionTrace
292
- } from "@x12i/graphenix-executable-format";
293
-
294
- const trace = createExecutionTrace(plan, runtime);
295
- const withStart = appendExecutionEvent(trace, {
296
- id: "evt:1",
297
- ts: new Date().toISOString(),
298
- level: "info",
299
- type: "graph.started",
300
- message: "Graph execution started."
301
- });
302
-
303
- validateExecutionTrace(withStart, plan.nodePlans);
304
- ```
305
-
306
- ## Public APIs (case selection)
307
-
308
- | API | Purpose |
309
- | --- | ------- |
310
- | `validateCaseCondition(condition)` | Validate deterministic `when` DSL |
311
- | `evaluateCaseCondition(condition, context)` | Evaluate against runtime/graph context |
312
- | `selectGraphModelCase(modelConfig, context)` | Pick graph case |
313
- | `selectNodeModelCase(nodeModelConfig, context)` | Pick node case |
314
- | `resolveNodeAiPlan(doc, nodeId, context)` | Full resolved plan with `caseSelection` |
315
- | `isProfileChoiceKeyFormat(key)` | From `@x12i/ai-profiles` |
316
- | `isKnownProfileChoice(key)` | Bundled registry lookup |
317
-
318
- ## Node kinds
319
-
320
- | Kind | Purpose |
321
- | ---- | ------- |
322
- | `x12i:task` | Run a skill with optional per-node model overrides and pre/post actions |
323
- | `x12i:finalizer` | Produce final graph output |
324
-
325
- ## Development
326
-
327
- From monorepo root:
328
-
329
- ```bash
330
- npm install
331
- npm run build --workspace=@x12i/graphenix-executable-format
332
- npm run test --workspace=@x12i/graphenix-executable-format
333
- ```
334
-
335
- ## Schema
336
-
337
- Profile JSON Schema fragment: `schema/graphenix-executable-format-1.0.0.schema.json` (structural subset; full semantics enforced by TypeScript validators).
338
-
339
- ## Implementation report
340
-
341
- See [`docs/IMPLEMENTATION-REPORT.md`](./docs/IMPLEMENTATION-REPORT.md) for the full CR/FR gap analysis and acceptance test matrix.
1
+ # @x12i/graphenix-executable-format
2
+
3
+ **Umbrella package** re-exports the full Graphenix executable lifecycle for prototypes and all-in-one installs.
4
+
5
+ For production, depend on [lifecycle packages](#package-family) directly (design-only clients should not pull in plan-compiler or trace-format).
6
+
7
+ **Canonical vocabulary:** [GLOSSARY.md](../../GLOSSARY.md) · **Format scope:** [FORMAT-SCOPE.md](../../docs/FORMAT-SCOPE.md)
8
+
9
+ **Naming:** `@x12i/*` is the **npm scope only**. JSON documents use `graphenix.*` identifiers and plain node kinds (`task`, `finalizer`) — never `x12i` in saved payloads.
10
+
11
+ ---
12
+
13
+ ## Who should use this
14
+
15
+ | Role | Prefer umbrella? | Prefer direct packages |
16
+ | ---- | :--------------: | ---------------------- |
17
+ | Prototype / spike | **Yes** | |
18
+ | Graph designer / editor | No | `@x12i/graphenix-authoring-format` + `@x12i/graphenix-case-format` |
19
+ | Compiler / execution prep | No | `@x12i/graphenix-plan-compiler` + `@x12i/graphenix-plan-format` |
20
+ | Execution engine | No | `@x12i/graphenix-plan-format` + `@x12i/graphenix-trace-format` |
21
+ | Backend host | No | `@x12i/graphenix-execute-envelope` |
22
+
23
+ ---
24
+
25
+ ## Install
26
+
27
+ ```bash
28
+ npm install @x12i/graphenix-executable-format @x12i/graphenix-core
29
+ ```
30
+
31
+ Built on [`@x12i/graphenix-core`](../core), with deterministic model cases validated against [`@x12i/ai-profiles`](https://www.npmjs.com/package/@x12i/ai-profiles).
32
+
33
+ ---
34
+
35
+ ## Full lifecycle (four phases)
36
+
37
+ Reference domain: **`graph:content-pipeline`** parallel research → content package.
38
+ Fixture: `createContentPipelineReferenceGraph()` from this package (re-exported from authoring-format).
39
+
40
+ ```txt
41
+ ┌─ DESIGN ─────────────────────────────────────────────────────────────┐
42
+ AuthoringGraphDocument + ConceptDocument (shadow, optional) │
43
+ validateGraph + validateAuthoringGraph + validateConceptDocument │
44
+ └───────────────────────────────┬──────────────────────────────────────┘
45
+ │ compileExecutablePlan(authoring, runtime)
46
+ ┌─ COMPILE ─────────────────────▼──────────────────────────────────────┐
47
+ │ ExecutableGraphPlan │
48
+ │ validateExecutablePlan │
49
+ └───────────────────────────────┬──────────────────────────────────────┘
50
+ │ engine runs executionUnits[] in order
51
+ ┌─ EXECUTE + TRACE ─────────────▼──────────────────────────────────────┐
52
+ GraphExecutionTrace (append-only) │
53
+ │ validateExecutionTrace │
54
+ └──────────────────────────────────────────────────────────────────────┘
55
+ ```
56
+
57
+ | Phase | Artifact | Validate with | Finalization brief |
58
+ | ----- | -------- | ------------- | ------------------ |
59
+ | Design | `AuthoringGraphDocument` | `validateGraph`, `validateAuthoringGraph` | [GRAPH-FORMAT-FINALIZATION.md](../../docs/GRAPH-FORMAT-FINALIZATION.md) |
60
+ | Design (shadow) | `ConceptDocument` | `validateConceptDocument` | [concept-document.md](../../docs/concept-document.md) |
61
+ | Compile | `ExecutableGraphPlan` | `validateExecutablePlan` | [COMPILE-FORMAT-FINALIZATION.md](../../docs/COMPILE-FORMAT-FINALIZATION.md) |
62
+ | Execute + trace | `GraphExecutionTrace` | `validateExecutionTrace` | [EXECUTE-TRACE-FORMAT-FINALIZATION.md](../../docs/EXECUTE-TRACE-FORMAT-FINALIZATION.md) |
63
+
64
+ **Role guides:** [docs/roles/README.md](../../docs/roles/README.md)
65
+
66
+ ---
67
+
68
+ ## Package family
69
+
70
+ ```txt
71
+ @x12i/graphenix-core
72
+
73
+
74
+ @x12i/graphenix-executable-contracts
75
+
76
+ ├── @x12i/graphenix-case-format
77
+ ├── @x12i/graphenix-executable-profile-format
78
+ ├── @x12i/graphenix-task-node-format
79
+ ├── @x12i/graphenix-authoring-format
80
+ ├── @x12i/graphenix-plan-format
81
+ └── @x12i/graphenix-trace-format
82
+
83
+
84
+ @x12i/graphenix-plan-compiler
85
+
86
+
87
+ @x12i/graphenix-execute-envelope (optional host adapter)
88
+
89
+ @x12i/graphenix-executable-format ← this package (re-exports all above)
90
+ ```
91
+
92
+ | Package | Phase | README |
93
+ | ------- | ----- | ------ |
94
+ | `@x12i/graphenix-executable-contracts` | Shared types | [executable-contracts/README.md](../executable-contracts/README.md) |
95
+ | `@x12i/graphenix-case-format` | Design | [case-format/README.md](../case-format/README.md) |
96
+ | `@x12i/graphenix-task-node-format` | Design | [task-node-format/README.md](../task-node-format/README.md) |
97
+ | `@x12i/graphenix-executable-profile-format` | Design | [executable-profile-format/README.md](../executable-profile-format/README.md) |
98
+ | `@x12i/graphenix-authoring-format` | Design | [authoring-format/README.md](../authoring-format/README.md) |
99
+ | `@x12i/graphenix-plan-compiler` | Compile | [plan-compiler/README.md](../plan-compiler/README.md) |
100
+ | `@x12i/graphenix-plan-format` | Compile + execute input | [plan-format/README.md](../plan-format/README.md) |
101
+ | `@x12i/graphenix-execute-envelope` | Execute prep | [execute-envelope/README.md](../execute-envelope/README.md) |
102
+ | `@x12i/graphenix-trace-format` | Execute + observability | [trace-format/README.md](../trace-format/README.md) |
103
+
104
+ ---
105
+
106
+ ## JSON identifiers (format payloads)
107
+
108
+ | Field | Value |
109
+ | ----- | ----- |
110
+ | Task node `kind` | `"task"` |
111
+ | Finalizer node `kind` | `"finalizer"` |
112
+ | Task `parameters.profile` | `"graphenix.task-node/v1"` |
113
+ | Finalizer `parameters.profile` | `"graphenix.finalizer-node/v1"` |
114
+ | Executable extension key | `"graphenix.executable/v1"` |
115
+ | Plan `format` | `"graphenix.executable-plan/v1"` or `v2` |
116
+ | Trace `format` | `"graphenix.execution-trace/v1"` or `v2` |
117
+ | Concept `formatVersion` | `"graphenix.concept/v1"` |
118
+
119
+ ---
120
+
121
+ ## Phase 1 — Design (authoring)
122
+
123
+ ### Task run phases (vocabulary)
124
+
125
+ One task node = one `runTask` wave: **prePhase → mainPhase → postPhase**.
126
+ See [GLOSSARY §1–§5](../../GLOSSARY.md).
127
+
128
+ **Explicit rule:** `aiTaskStrategies.pre: "synthesis"` (PRE-phase utility strategy) ≠ `aiTaskProfile.inputSynthesis.enabled` (skill input synthesis profile → plan `pipelinePhase`). Do not use “Synthesis PRE”.
129
+
130
+ ### Two-tier validation
131
+
132
+ ```ts
133
+ import { validateGraph } from "@x12i/graphenix-core";
134
+ import {
135
+ validateAuthoringGraph,
136
+ validateConceptDocument,
137
+ createContentPipelineReferenceGraph
138
+ } from "@x12i/graphenix-executable-format";
139
+
140
+ const doc = createContentPipelineReferenceGraph();
141
+
142
+ validateGraph(doc);
143
+ validateAuthoringGraph(doc);
144
+
145
+ validateConceptDocument({
146
+ formatVersion: "graphenix.concept/v1",
147
+ graphId: doc.id,
148
+ name: doc.name,
149
+ graphConcept: {
150
+ primaryIntentStatement: "Turn a campaign brief into a structured content package."
151
+ }
152
+ });
153
+ ```
154
+
155
+ ### Authoring task node (JSON excerpt)
156
+
157
+ ```json
158
+ {
159
+ "id": "node:audience-insights",
160
+ "kind": "task",
161
+ "layout": { "x": 120, "y": 200 },
162
+ "parameters": {
163
+ "profile": "graphenix.task-node/v1",
164
+ "nodeType": "task",
165
+ "skillKey": "professional-answer",
166
+ "taskConfiguration": {
167
+ "executionStrategies": [],
168
+ "aiTaskStrategies": {
169
+ "pre": "synthesis",
170
+ "preInputStrategy": "execution-memory-only"
171
+ }
172
+ }
173
+ }
174
+ }
175
+ ```
176
+
177
+ ### Phase model profiles (extension)
178
+
179
+ ```json
180
+ "metadata": {
181
+ "extensions": {
182
+ "graphenix.executable/v1": {
183
+ "profileVersion": "1.0.0",
184
+ "modelConfig": {
185
+ "version": "graph-model-config/v1",
186
+ "cases": [{
187
+ "id": "default",
188
+ "modelConfig": {
189
+ "preActionModel": { "kind": "profileChoice", "key": "cheap/default" },
190
+ "skillModel": { "kind": "profileChoice", "key": "vol/default" },
191
+ "postActionModel": { "kind": "profileChoice", "key": "cheap/default" }
192
+ }
193
+ }]
194
+ }
195
+ }
196
+ }
197
+ }
198
+ ```
199
+
200
+ ### Design APIs
201
+
202
+ | API | Purpose |
203
+ | --- | ------- |
204
+ | `validateAuthoringGraph` | Executable profile + full task-node body |
205
+ | `validateConceptDocument` | Studio shadow document |
206
+ | `validateCaseCondition` / `evaluateCaseCondition` | Deterministic `when` DSL |
207
+ | `selectGraphModelCase` / `selectNodeModelCase` | Case preview at design time |
208
+ | `resolveNodeAiPlan` / `explainNodeInheritance` | Preview slot resolution |
209
+ | `normalizeExecutableGraph` | Canonical model config (non-mutating) |
210
+ | `stripDesignOnlyFieldsFromGraph` | Remove `node.layout` before plan embed |
211
+ | `createMinimalExecutableGraph` | One task + finalizer |
212
+ | `createContentPipelineReferenceGraph` | Canonical reference graph |
213
+ | `addTaskNode`, `setGraphModelConfig`, … | CRUD helpers |
214
+
215
+ ### Deterministic cases (summary)
216
+
217
+ ```txt
218
+ Cases may choose stronger or weaker AI profiles.
219
+ AI may not choose the case.
220
+ ```
221
+
222
+ Allowed selectors: `runtime.mode`, `runtime.input.*`, `runtime.environment`, `graph.id`, …
223
+ Forbidden: `ai.*`, `node.output.*`, `semanticMatch`, LLM-based conditions.
224
+
225
+ Full DSL: [case-format/README.md](../case-format/README.md).
226
+
227
+ ---
228
+
229
+ ## Phase 2 — Compile (authoring → plan)
230
+
231
+ ### Design plan mapping
232
+
233
+ | Authoring (design) | Plan execution unit | Run phase |
234
+ | ------------------ | ------------------- | --------- |
235
+ | `aiTaskStrategies.pre` | `externalPreUtility` | prePhase |
236
+ | `skillKey` + plain MAIN | `mainSkill` | mainPhase |
237
+ | `aiTaskProfile.inputSynthesis` | `pipelinePhase` | mainPhase |
238
+ | `aiTaskStrategies.post` | `externalPostUtility` | postPhase |
239
+ | Phase model profiles | `modelSlot` + `modelSelection` on each unit | per phase |
240
+
241
+ Content pipeline reference tasks: PRE synthesis + MAIN only (no POST unless design declares it).
242
+
243
+ ### Compile flow
244
+
245
+ ```ts
246
+ import {
247
+ createContentPipelineReferenceGraph,
248
+ compileExecutablePlan,
249
+ validateExecutablePlan,
250
+ buildRuntimeObject
251
+ } from "@x12i/graphenix-executable-format";
252
+
253
+ const authoring = createContentPipelineReferenceGraph();
254
+ const runtime = buildRuntimeObject({
255
+ jobId: "job-001",
256
+ mode: "live",
257
+ input: { priority: "normal" }
258
+ });
259
+
260
+ const plan = compileExecutablePlan(authoring, runtime, {
261
+ profileRegistry: { package: "@x12i/ai-profiles", version: "3.2.0" },
262
+ environment: "prod"
263
+ });
264
+
265
+ const result = validateExecutablePlan(plan);
266
+ if (!result.valid) throw new Error("Invalid plan");
267
+ ```
268
+
269
+ Internal pipeline:
270
+
271
+ ```txt
272
+ validateAuthoringExecutableGraph()
273
+ normalizeExecutableGraph()
274
+ stripDesignOnlyFieldsFromGraph() ← node.layout removed
275
+ assertNormalizedExecutableGraph()
276
+ selectGraphModelCase() → resolveNodeAiPlan() per task node
277
+ buildNodeExecutionUnits() ← PRE / MAIN / POST from aiTaskStrategies
278
+ buildFinalizerPlans()
279
+ validateExecutablePlan() ← recommended before handoff
280
+ ```
281
+
282
+ ### Compiled plan (JSON excerpt v2)
283
+
284
+ ```json
285
+ {
286
+ "format": "graphenix.executable-plan/v2",
287
+ "source": { "graphId": "graph:content-pipeline" },
288
+ "nodePlans": {
289
+ "node:audience-insights": {
290
+ "executionUnits": [
291
+ {
292
+ "unitKind": "externalPreUtility",
293
+ "order": 0,
294
+ "strategyKey": "synthesis",
295
+ "modelSlot": "preActionModel"
296
+ },
297
+ {
298
+ "unitKind": "mainSkill",
299
+ "order": 1,
300
+ "skillKey": "professional-answer",
301
+ "modelSlot": "skillModel"
302
+ }
303
+ ]
304
+ }
305
+ }
306
+ }
307
+ ```
308
+
309
+ ### Compile APIs
310
+
311
+ | API | Purpose |
312
+ | --- | ------- |
313
+ | `compileExecutablePlan` | Authoring + runtime → plan |
314
+ | `validateExecutablePlan` | Validate v1 or v2 plan |
315
+ | `buildDeterministicCaseContext` | Freeze pre-run context |
316
+ | `buildGraphExecutionRequestFromStudioExecute` | Host adapter: request → `{ plan, runtime }` |
317
+
318
+ Details: [plan-compiler/README.md](../plan-compiler/README.md) · [plan-format/README.md](../plan-format/README.md)
319
+
320
+ ---
321
+
322
+ ## Phase 3 Execute (engine)
323
+
324
+ The engine consumes **only** `{ plan, runtime }`. It never reads authoring graphs.
325
+
326
+ ### Execution order
327
+
328
+ For each task node in topological order:
329
+
330
+ 1. `validateExecutablePlan(plan)` on receipt
331
+ 2. PRE-phase units (`externalPreUtility`) → MAIN (`mainSkill`, `pipelinePhase`, …) → POST if present
332
+ 3. Each unit uses frozen `modelSelection` from the plan — no case re-selection at runtime
333
+
334
+ ### Execute APIs (from this package)
335
+
336
+ | API | Package origin |
337
+ | --- | -------------- |
338
+ | `validateExecutablePlan` | plan-format |
339
+ | `createExecutionTrace` | trace-format |
340
+ | `appendExecutionEvent` | trace-format |
341
+
342
+ Details: [docs/roles/execution-engine.md](../../docs/roles/execution-engine.md)
343
+
344
+ ---
345
+
346
+ ## Phase 4 — Trace (evidence)
347
+
348
+ Traces are **append-only** and bound to `planHash`.
349
+
350
+ ```ts
351
+ import {
352
+ createExecutionTrace,
353
+ appendExecutionEvent,
354
+ validateExecutionTrace,
355
+ deriveGraphStatus,
356
+ summarizeExecutionTrace
357
+ } from "@x12i/graphenix-executable-format";
358
+
359
+ const trace = createExecutionTrace(plan, runtime);
360
+
361
+ appendExecutionEvent(trace, {
362
+ id: "evt:1",
363
+ ts: new Date().toISOString(),
364
+ level: "info",
365
+ type: "graph.started",
366
+ message: "Graph execution started."
367
+ });
368
+
369
+ appendExecutionEvent(trace, {
370
+ id: "evt:2",
371
+ ts: new Date().toISOString(),
372
+ level: "info",
373
+ type: "node.started",
374
+ nodeId: "node:audience-insights"
375
+ });
376
+
377
+ appendExecutionEvent(trace, {
378
+ id: "evt:3",
379
+ ts: new Date().toISOString(),
380
+ level: "info",
381
+ type: "unit.started",
382
+ nodeId: "node:audience-insights",
383
+ unitId: "unit:node:audience-insights:pre:0",
384
+ unitKind: "externalPreUtility"
385
+ });
386
+
387
+ validateExecutionTrace(trace, plan.nodePlans);
388
+ const status = deriveGraphStatus(trace);
389
+ ```
390
+
391
+ ### Trace header (JSON excerpt)
392
+
393
+ ```json
394
+ {
395
+ "format": "graphenix.execution-trace/v1",
396
+ "traceId": "trace:job-001",
397
+ "jobId": "job-001",
398
+ "source": { "graphId": "graph:content-pipeline", "graphHash": "sha256:…" },
399
+ "plan": { "planId": "plan:abc123", "planHash": "sha256:…" },
400
+ "events": []
401
+ }
402
+ ```
403
+
404
+ Details: [trace-format/README.md](../trace-format/README.md) · [docs/roles/observability.md](../../docs/roles/observability.md)
405
+
406
+ ---
407
+
408
+ ## Validation tiers (summary)
409
+
410
+ | When | Call |
411
+ | ---- | ---- |
412
+ | Authoring save | `validateGraph` + `validateAuthoringGraph` |
413
+ | Concept save | `validateConceptDocument` |
414
+ | After compile | `validateExecutablePlan` |
415
+ | After run | `validateExecutionTrace(trace, plan.nodePlans)` |
416
+
417
+ ---
418
+
419
+ ## End-to-end example (umbrella import)
420
+
421
+ ```ts
422
+ import { validateGraph } from "@x12i/graphenix-core";
423
+ import {
424
+ createContentPipelineReferenceGraph,
425
+ validateAuthoringGraph,
426
+ compileExecutablePlan,
427
+ validateExecutablePlan,
428
+ buildRuntimeObject,
429
+ createExecutionTrace,
430
+ appendExecutionEvent,
431
+ validateExecutionTrace
432
+ } from "@x12i/graphenix-executable-format";
433
+
434
+ // Design
435
+ const authoring = createContentPipelineReferenceGraph();
436
+ validateGraph(authoring);
437
+ validateAuthoringGraph(authoring);
438
+
439
+ // Compile
440
+ const runtime = buildRuntimeObject({ jobId: "job-001", mode: "live", input: {} });
441
+ const plan = compileExecutablePlan(authoring, runtime);
442
+ validateExecutablePlan(plan);
443
+
444
+ // Execute + trace (engine loop abbreviated)
445
+ const trace = createExecutionTrace(plan, runtime);
446
+ appendExecutionEvent(trace, {
447
+ id: "evt:1",
448
+ ts: new Date().toISOString(),
449
+ level: "info",
450
+ type: "graph.completed",
451
+ message: "Done."
452
+ });
453
+ validateExecutionTrace(trace, plan.nodePlans);
454
+ ```
455
+
456
+ ---
457
+
458
+ ## Profile choice format
459
+
460
+ ```json
461
+ { "kind": "profileChoice", "key": "vol/default" }
462
+ ```
463
+
464
+ Examples: `cheap/default`, `vol/default`, `vol/pro`, `deep/openai_deep`.
465
+ Rejected: bare aliases, `kind: "profile"`, vendor slugs as profileChoice keys.
466
+
467
+ `profileChoice` resolves at compile/plan time via `@x12i/ai-profiles` — not during normalization.
468
+
469
+ ---
470
+
471
+ ## Model inheritance and fallback
472
+
473
+ - Graph-level `modelConfig` is **required** with full triplet per case (`preActionModel`, `skillModel`, `postActionModel`).
474
+ - Node overrides may be partial when `inherit: true`.
475
+ - Fallback is **same-slot only** on the selected graph case — never cross-slot or runtime defaults.
476
+
477
+ ---
478
+
479
+ ## Node kinds
480
+
481
+ | `kind` | `parameters.profile` | Purpose |
482
+ | ------ | -------------------- | ------- |
483
+ | `task` | `graphenix.task-node/v1` | Skill + phase utility strategies |
484
+ | `finalizer` | `graphenix.finalizer-node/v1` | Graph output (`finalizerType`: `aggregate`, `compose`, …) |
485
+
486
+ Design-only: `node.layout` — stripped at compile, never on plan.
487
+
488
+ ---
489
+
490
+ ## Development
491
+
492
+ From monorepo root:
493
+
494
+ ```bash
495
+ npm install
496
+ npm run build --workspace=@x12i/graphenix-executable-format
497
+ npm run test --workspace=@x12i/graphenix-executable-format
498
+ ```
499
+
500
+ ## Schema
501
+
502
+ Profile JSON Schema fragment: `schema/graphenix-executable-format-1.0.0.schema.json` (structural subset; full semantics enforced by TypeScript validators).
503
+
504
+ ## Further reading
505
+
506
+ | Doc | Topic |
507
+ | --- | ----- |
508
+ | [GLOSSARY.md](../../GLOSSARY.md) | Phase vocabulary |
509
+ | [FORMAT-SCOPE.md](../../docs/FORMAT-SCOPE.md) | Compliance + strict profiles |
510
+ | [NAMING.md](../../docs/NAMING.md) | npm `@x12i/*` vs JSON `graphenix.*` |
511
+ | [PUBLISHING.md](../../PUBLISHING.md) | npm publish order |
512
+ | [docs/IMPLEMENTATION-REPORT.md](./docs/IMPLEMENTATION-REPORT.md) | Acceptance test matrix |