# Migrating to Activix v4

> **On Activix v5+**, the correlation field was renamed from **`identity`** to **`runContext`**. See [MIGRATION-v5.md](./MIGRATION-v5.md). The examples below use the v4 name.

## Breaking changes

1. **`structure` is required** on every activity row. It must include **`outer.input`**, **`outer.output`** (key required; value may be `null` until done), and **`outer.metadata`** (object, may be `{}`).
2. Optional **`structure.inner`** with the same three keys when you model an internal phase.
3. **Integrator-controlled fields** (`activityId`, `status`, `startTime`, `endTime`, `duration`, `createdAt`, `updatedAt`, `error`, etc.) are **ignored** if sent; Activix sets lifecycle fields.
4. **In-memory and playground stores** no longer auto-add **`createdAt`** / **`updatedAt`** on documents (use Activix time fields only).
5. **`completeRecord`** always sets **`endTime`** / **`duration`** from **`Date.now()`** (caller-supplied end times are stripped).

## Flat document → `structure`

**Before (example):**

```json
{
  "model": "openai/gpt-4o-mini",
  "type": "synthesis",
  "systemPrompt": "...",
  "userPrompt": "...",
  "outputPreview": "...",
  "identity": { "sessionId": "..." }
}
```

**After:**

```json
{
  "identity": { "sessionId": "...", "jobId": "optional-here" },
  "structure": {
    "outer": {
      "input": { "systemPrompt": "...", "userPrompt": "..." },
      "output": "full text or null while running",
      "metadata": {
        "model": "openai/gpt-4o-mini",
        "type": "synthesis",
        "cost": { "amount": 0.0012, "currency": "USD", "unit": "tokens" }
      }
    }
  }
}
```

Move correlation ids into **`identity`**; move domain labels into **`metadata`**; put boundary payloads in **`input`** / **`output`**.

## Code changes

```ts
import { Activix, activixStructure, activixTier } from '@x12i/activix';

await ax.startRecord({
  identity: { sessionId: upstreamSessionId, jobId: 'job-1' },
  structure: activixStructure(
    activixTier(
      { prompts: { system: '...', user: '...' } },
      null,
      { model: 'openai/gpt-4o-mini', type: 'synthesis' }
    )
  ),
});

await ax.completeRecord(activityId, {
  structure: { outer: { output: finalText } },
});
```

## Queries

Prefer querying nested paths, e.g. **`identity.jobId`**, **`structure.outer.metadata.type`**, instead of old top-level duplicates.
