# @x12i/graphenix-executable-contracts

Shared **contracts** for the Graphenix executable graph lifecycle: TypeScript types, constants, error codes, and lightweight utilities.

No validators, compilers, or adapters — only the shared vocabulary other lifecycle packages build on.

**Naming policy:** [NAMING.md](../../docs/NAMING.md) — npm scope `@x12i/*` vs JSON identifiers `graphenix.*`.

## Who should use this

| Role | Use this package? |
| ---- | ----------------- |
| Library author needing types only | **Yes** |
| Graph designer / Studio | Prefer `@x12i/graphenix-authoring-format` |
| Engine | Prefer `@x12i/graphenix-plan-format` + `@x12i/graphenix-trace-format` |

## Install

```bash
npm install @x12i/graphenix-executable-contracts @x12i/graphenix-core
```

## Type index (primary)

| Domain | Key types / constants |
| ------ | --------------------- |
| Authoring | `AuthoringGraphDocument`, `GraphProjectDocument` |
| Plan v2 | `ExecutableGraphPlanV2`, `NodeExecutionPlan`, `ExecutionUnitPlan`, `EXECUTABLE_PLAN_FORMAT_V2` |
| Plan v1 | `ExecutableGraphPlan`, `EXECUTABLE_PLAN_FORMAT` (legacy) |
| Trace v2 | `GraphExecutionTraceV2`, `TraceEvent`, `EXECUTION_TRACE_FORMAT_V2` |
| Trace v1 | `GraphExecutionTrace`, `EXECUTION_TRACE_FORMAT` (legacy) |
| Runtime | `GraphRuntimeObject`, `StudioExecuteRequest` |
| Model config | `AiModelSelection`, `CaseCondition`, `ModelConfigTriplet` |
| Units | `ExecutionUnitKindV2`, `InvokeContract`, `ModelSlot` |
| Fact-guard | `FactGuardStepConfig`, `AuditFactGuardConfig`, `AuthoringFactGuardConfig`, `FACT_GUARD_POLICY_IDS` |

## Example

```ts
import {
  EXECUTABLE_PLAN_FORMAT_V2,
  EXECUTION_TRACE_FORMAT_V2,
  type ExecutableGraphPlanV2,
  type GraphExecutionTraceV2,
  type NodeExecutionPlan,
  type CaseCondition,
  type AiModelSelection,
  execError
} from "@x12i/graphenix-executable-contracts";
```

## Key exports

- **Constants** — format ids, `TASK_NODE_KIND`, `AI_MODEL_SLOTS`, profile namespace
- **Types** — authoring graph, executable plan, execution trace, case conditions, model config, runtime
- **Utilities** — `isRecord`, `execError`, `getExecutableProfile`, `isExecutableTaskNode`, …
- **Hashing** — `sha256Hash`, `defaultHashFunction`
- **Schema** — `schema/graphenix-executable-format-1.0.0.schema.json` (published with package)

## Dependencies

- Peer: `@x12i/graphenix-core` ^2.4.0

## Error codes (synthesis)

| Code | When |
| ---- | ---- |
| `LEGACY_PRE_INPUT_STRATEGY` | Authoring still has `preInputStrategy` / `synthesisInputStrategy` (warn on normalize; reject `preInputStrategy` on validate) |
| `LEGACY_SYNTHESIS_INPUT_STRATEGY_ON_PLAN` | Plan unit has `unitParams.synthesisInputStrategy` — **remove**; re-compile (validation fails until removed) |

Empty `invokeContract.reads` and `unitParams.memoryPaths` on PRE synthesis units is **valid** — runtime applies `DEFAULT_PRE_SYNTHESIS_READ_PATHS` (`jobVariables`, `taskVariables`, `input`). Layer-1 hints (narrix, webScope) are not PRE read scope.

## Synthesis `unitParams` (plan wire)

PRE synthesis `externalPreUtility` units carry paths only:

```json
{
  "memoryPaths": [],
  "autoEnableContext": true
}
```

When `aiTaskProfile.inputSynthesis.sources` is authored, compiler emits identical paths on `invokeContract.reads` and `memoryPaths`. When omitted, both are `[]` and ai-tasks applies the default trio at runtime.

No plan field for synthesis template key — runtime resolves from skill catalog. Future explicit per-node override (multi-template skills, P2 FR): `invokeContract.synthesisContextStrategyKey` (not `synthesisInputStrategy`).

## Related packages

Part of the [Graphenix Format](https://github.com/x12i/graphenix-format) monorepo. Lifecycle status: [GAP-ANALYSIS.md](../../docs/GAP-ANALYSIS.md).
