npm.io
2.17.0 • Published 2 weeks ago

@x12i/graphenix-plan-format

Licence
MIT
Version
2.17.0
Deps
2
Size
262 kB
Vulns
0
Weekly
0

@x12i/graphenix-plan-format

ExecutableGraphPlan format — validates the engine-facing artifact produced by @x12i/graphenix-plan-compiler.

Defines and checks what a correct compiled plan looks like: resolved phase model profiles, ordered execution units per run phase, finalizer plans, embedded normalized graph snapshot, and forbidden runtime fields.

This package does not compile from authoring graphs — it only validates plan documents. Use @x12i/graphenix-plan-compiler to produce plans.

Canonical vocabulary: GLOSSARY.md at monorepo root.
Finalization brief: COMPILE-FORMAT-FINALIZATION.md · execute/trace: EXECUTE-TRACE-FORMAT-FINALIZATION.md.
When task run phases or plan-phase terms change, update this README and GLOSSARY.md §5 together.


Who should use this

Role Use this package?
Execution engine Yes — validate plan before run
Compiler / execution prep Yes — validate output before handoff
Run history / observability Yes — bind traces to validated plan shape
Graph designer / Studio Only if showing compile preview
Authoring-only services No — use @x12i/graphenix-authoring-format

Install

npm install @x12i/graphenix-plan-format

Types (ExecutableGraphPlan, ExecutableGraphPlanV2, ExecutionUnitPlanV2, …) live in @x12i/graphenix-executable-contracts.


Lifecycle position

AuthoringGraphDocument
        │  compileAuthoringGraphToExecutablePlan()  (static — no runtime)
        │  compileExecutablePlanV2(authoring, runtime)  (execute path only)
        ▼
ExecutableGraphPlan              ← THIS PACKAGE validates

Execute contract: validateExecutablePlanV2 requires complete nodePlans[].modelSlots for AI tasks (job ⊕ node merge happens at compile — execute must not re-read partial node taskConfiguration.modelConfig).


Task run phases (runtime topology)

One task node invocation is three run phases (GLOSSARY §1):

Run phase Meaning Typical plan units
prePhase Optional utility work before the skill externalPreUtility (v2) / preAction (v1)
mainPhase Skill / MAIN execution mainSkill, pipelinePhase, localSkill (v2) / skill (v1)
postPhase Optional utility work after the skill externalPostUtility (v2) / postAction (v1)

This is phase topology — not model choice and not catalog action ids.

Design → plan mapping (do not conflate)

Authoring declares phase utility strategies on the task node. The compiler expands them into plan execution units:

prePhase.strategyKey (design: aiTaskStrategies.pre)
        │  compile
        ▼
PRE-phase execution units (plan: externalPreUtility / preAction)

mainPhase.executionStrategies + skill input synthesis profile (design)
        │  compile
        ▼
MAIN-phase execution units (plan: mainSkill, pipelinePhase, …)

postPhase.strategyKey (design: aiTaskStrategies.post)
        │  compile
        ▼
POST-phase execution units (plan: externalPostUtility / postAction)
Design (authoring) Plan (this package) Glossary
aiTaskStrategies.pre PRE-phase units with strategyKey / actionKey PRE-phase utility strategy → plan PRE-phase action list
executionStrategies, aiTaskProfile.inputSynthesis mainSkill, pipelinePhase, … MAIN-phase wrappers / skill input synthesis profile
aiTaskStrategies.post POST-phase units POST-phase utility strategy → plan POST-phase action list
preActions[] / postActions[] (optional on design) Same shape at plan layer Plan-phase action lists — not synonyms for aiTaskStrategies.pre

Explicit rule: strategyKey: "synthesis" (PRE-phase utility) ≠ inputSynthesis.enabled (MAIN skill input synthesis profile). The plan may contain pipelinePhase units from the latter without any PRE-phase utility unit.

PRE synthesis (2.4.0): inputsConfig and smartInput.paths are MAIN only. PRE invokeContract.reads / unitParams.memoryPaths come from aiTaskProfile.inputSynthesis.sources or are empty ([]) for runtime default trio. When sources is authored, reads and memoryPaths must be identical.

Each execution unit carries a phase model profile binding (GLOSSARY §4):

modelSlot Run phase
preActionModel PRE-phase model profile
skillModel MAIN-phase model profile
postActionModel POST-phase model profile
finalizerModel Finalizer (graph output)

Utility strategy = what runs. Model profile = which AI profile runs it.


Plan document shape

v1 — graphenix.executable-plan/v1
ExecutableGraphPlan
  ├─ format, planId, createdAt
  ├─ source (graphId, graphHash, …)
  ├─ profileRegistry (@x12i/ai-profiles version)
  ├─ runtimeBinding (jobId, mode, environment, hashes)
  ├─ graph — embedded NormalizedExecutableGraphDocument
  ├─ caseSelection — graph + per-node selected cases
  ├─ nodePlans[nodeId]
  │     ├─ selectedCases, modelSlots (preActionModel / skillModel / postActionModel)
  │     └─ executionUnits[] — ordered preAction → skill → postAction
  └─ finalizerPlans (if applicable)

v1 unit kinds: preAction | skill | postAction | finalizer.

v2 — graphenix.executable-plan/v2 (preferred for new engines)
ExecutableGraphPlanV2
  ├─ format, planId, createdAt, planHash
  ├─ source, profileRegistry, runtimeBinding, runtimeExpectations
  ├─ normalizedGraph — embedded or ref
  ├─ policies (directModelPolicy, fallback, trace, …)
  ├─ nodeIndex[], deferredGates[]
  ├─ nodePlans[nodeId] — NodeExecutionPlan
  │     ├─ invokeContract (pipeline snapshot from authoring)
  │     ├─ modelSlots, selectedCases
  │     └─ executionUnits[] — ordered by run phase
  └─ finalizerPlans[nodeId] — FinalizerExecutionPlan

v2 unit kinds include:

unitKind Typical run phase invokeMode
externalPreUtility prePhase externalRunTask
mainSkill mainPhase mainRunTask
pipelinePhase mainPhase (wrapper / synthesis inside MAIN) pipelinePhase
localSkill mainPhase local
externalPostUtility postPhase externalRunTask
finalizer graph output finalizer
validation, mapping, callGraph special none / …

Each ExecutionUnitPlanV2 exposes: unitId, nodeId, unitKind, invokeMode, order, actionKey, strategyKey, skillKey, modelSlot, modelSelection, modelSource, invokeContract, retry/fallback/trace policies, and sourcePath (JSON pointer into embedded graph).


Per-task node plan (diagram)

NodeExecutionPlan (one task node, one runTask wave)
│
├─ prePhase units[]     externalPreUtility / preAction
│       modelSlot: preActionModel
│
├─ mainPhase units[]    mainSkill | pipelinePhase | localSkill
│       modelSlot: skillModel (pipelinePhase may share MAIN profile)
│
└─ postPhase units[]    externalPostUtility / postAction
        modelSlot: postActionModel

Order is strict: PRE units → MAIN units → POST units. Validators reject missing MAIN skill, duplicate orders, and slot/kind mismatches.


Examples (JSON)

v2 plan header (minimal)
{
  "format": "graphenix.executable-plan/v2",
  "planId": "plan:abc123",
  "createdAt": "2026-06-06T12:00:00.000Z",
  "planHash": "sha256:…",
  "source": {
    "graphId": "graph:content-pipeline",
    "graphRevision": "1.0.0",
    "graphHash": "sha256:…",
    "formatVersion": "2.0.0"
  },
  "profileRegistry": {
    "package": "@x12i/ai-profiles",
    "version": "3.2.0",
    "registryHash": "sha256:…"
  },
  "runtimeBinding": {
    "jobId": "job-001",
    "mode": "live",
    "environment": "prod",
    "sourceGraphHash": "sha256:…",
    "profileRegistryHash": "sha256:…"
  }
}
v2 nodePlans — PRE + MAIN execution units (content pipeline)

Compiled from authoring aiTaskStrategies.pre: "synthesis" + executionStrategies: [] on node:audience-insights. No POST units unless design declares aiTaskStrategies.post:

"nodePlans": {
  "node:audience-insights": {
    "nodeId": "node:audience-insights",
    "nodeType": "task",
    "executionClass": "aiTask",
    "skillKey": "professional-answer",
    "selectedCases": {
      "graphModelCaseId": "default"
    },
    "modelSlots": {
      "preActionModel": {
        "selection": { "kind": "profileChoice", "key": "cheap/default" },
        "source": "graphCase"
      },
      "skillModel": {
        "selection": { "kind": "profileChoice", "key": "vol/default" },
        "source": "graphCase"
      }
    },
    "executionUnits": [
      {
        "unitId": "unit:node:audience-insights:pre:0",
        "nodeId": "node:audience-insights",
        "unitKind": "externalPreUtility",
        "invokeMode": "externalRunTask",
        "order": 0,
        "strategyKey": "synthesis",
        "actionKey": "synthesis",
        "modelSlot": "preActionModel",
        "modelSelection": { "kind": "profileChoice", "key": "cheap/default" },
        "sourcePath": "/graph/nodes/node:audience-insights/parameters/taskConfiguration/aiTaskStrategies/pre"
      },
      {
        "unitId": "unit:node:audience-insights:main:1",
        "nodeId": "node:audience-insights",
        "unitKind": "mainSkill",
        "invokeMode": "mainRunTask",
        "order": 1,
        "skillKey": "professional-answer",
        "modelSlot": "skillModel",
        "modelSelection": { "kind": "profileChoice", "key": "vol/default" },
        "sourcePath": "/graph/nodes/node:audience-insights/parameters/skillKey"
      }
    ],
    "sourcePath": "/graph/nodes/node:audience-insights"
  }
}
v2 nodePlans — PRE / MAIN / POST

When authoring declares aiTaskStrategies.post, the compiler appends POST-phase units (same mapping as PRE via externalPostUtility).

v2 MAIN pipelinePhase from skill input synthesis profile (not PRE utility)

When authoring uses aiTaskProfile.inputSynthesis.enabled (not aiTaskStrategies.pre):

{
  "unitId": "unit:node:task:pipeline:0",
  "unitKind": "pipelinePhase",
  "invokeMode": "pipelinePhase",
  "order": 0,
  "modelSlot": "skillModel",
  "sourcePath": "/graph/nodes/node:task/parameters/taskConfiguration/aiTaskProfile/inputSynthesis"
}
v1 plan unit shape (legacy engines)
"executionUnits": [
  {
    "unitId": "unit:1:pre",
    "unitKind": "preAction",
    "order": 0,
    "actionKey": "synthesis",
    "modelSlot": "preActionModel",
    "modelSelection": { "kind": "profileChoice", "key": "cheap/default" }
  },
  {
    "unitId": "unit:1:skill",
    "unitKind": "skill",
    "order": 1,
    "skillKey": "professional-answer",
    "modelSlot": "skillModel",
    "modelSelection": { "kind": "profileChoice", "key": "vol/default" }
  }
]

Example (API)

import {
  validateExecutablePlan,
  validateExecutablePlanV1,
  validateExecutablePlanV2
} from "@x12i/graphenix-plan-format";
import type { ExecutableGraphPlan } from "@x12i/graphenix-executable-contracts";

const result = validateExecutablePlan(plan);
if (!result.valid) {
  console.error(result.errors.map((e) => `${e.path}: ${e.message}`));
}

// Or target a specific format version:
validateExecutablePlanV2(planV2);
validateExecutablePlanV1(planV1);

validateExecutablePlan() auto-selects v1 vs v2 from plan.format.

Typical compile + validate flow:

import { compileExecutablePlan } from "@x12i/graphenix-plan-compiler";
import { validateExecutablePlan } from "@x12i/graphenix-plan-format";

const plan = compileExecutablePlan(authoringGraph, runtime, {
  profileRegistry: { package: "@x12i/ai-profiles", version: "3.2.0" }
});

const validation = validateExecutablePlan(plan);
if (!validation.valid) throw new Error("Invalid plan");

Key exports

API Purpose
validateExecutablePlan(plan) Validate v1 or v2 (detects plan.format)
validateExecutablePlanV1(plan) Validate graphenix.executable-plan/v1 only
validateExecutablePlanV2(plan) Validate graphenix.executable-plan/v2 only

Types and constants are imported from @x12i/graphenix-executable-contracts:

Symbol Value / role
EXECUTABLE_PLAN_FORMAT "graphenix.executable-plan/v1"
EXECUTABLE_PLAN_FORMAT_V2 "graphenix.executable-plan/v2"
ExecutableGraphPlan v1 plan document
ExecutableGraphPlanV2 v2 plan document
NodeExecutionPlan Per-node v2 plan with executionUnits
ExecutionUnitPlanV2 Single v2 execution unit
ExecutionUnitPlan v1 unit (deprecated for new work)

What validation enforces

  • Plan metadata: format, planId, createdAt, source graph refs, profile registry ref
  • Embedded graph is normalized (validateNormalizedExecutableGraph via authoring-format)
  • Case selection frozen on plan — graph + node cases with explanations
  • Model slots resolved per node; profileChoice keys well-formed; direct model policy (v2)
  • Execution units: ordering, unique ids, kind modelSlot alignment, required MAIN skill
  • Optional fact-guard on sub-action unitParams (synthesis, polish, audit); enabled: true requires policyId; mainSkill forbidden — see GLOSSARY §6
  • Forbidden fields never on plan: credentials, trace events, provider responses, execution logs, …
  • v2: invokeMode matches unitKind, invoke contracts, deferred gates, finalizer plans

Validation errors use glossary-friendly paths (e.g. PRE/MAIN/POST phase model slots). Do not label plan units as “Synthesis PRE” — use PRE-phase utility strategy vs skill input synthesis profile per GLOSSARY.md.


Dependencies

Package Why
@x12i/graphenix-executable-contracts Plan and unit types, error codes
@x12i/graphenix-authoring-format Validates embedded normalized authoring graph

Peer (via compiler, not required at runtime for validation alone): @x12i/graphenix-core.


Package Role
GLOSSARY.md Canonical phase + strategy + model vocabulary
@x12i/graphenix-plan-compiler Produces plans from authoring + runtime
@x12i/graphenix-authoring-format Design authoring; phase utility strategies
@x12i/graphenix-task-node-format Task-node body validation (design layer)
@x12i/graphenix-executable-profile-format Phase model profiles on authoring graph
@x12i/graphenix-trace-format Run evidence bound to a validated plan
Compiler role guide End-to-end compile client guide

README sync policy

When documenting or changing task run phases, update these together:

Layer Package README
Design task body + utility strategies task-node-format/README.md
Phase model profiles (authoring) executable-profile-format/README.md
Compiled plan + execution units this file — include example JSON
Compile pipeline plan-compiler/README.md
Terms of record GLOSSARY.md

Keywords