# Apache Maka Model Projection Transition System: Immutability and Safe Context Updates

> Discover the Apache Maka model projection transition system. Learn how immutable records and append-only ledgers ensure safe, deterministic updates for model-visible data.

- Repository: [The Apache Software Foundation/maka](https://github.com/apache/maka)
- Tags: deep-dive
- Published: 2026-09-02

---

**The Apache Maka model projection transition system enables safe, deterministic updates to model-visible data by creating immutable transition records that replace specific projection parts while preserving an append-only event ledger.**

In **Apache Maka**, a lightweight framework for building reliable AI agents, every LLM interaction is stored as an immutable event. When model-visible data—such as a tool call result—must be changed after it has been recorded, the framework cannot simply edit the original event. Instead, Maka employs a **Model‑Projection‑Transition System** that expresses modifications as new ledger entries, maintaining both safety and replayability.

## Core Concepts of the Model Projection Transition System

The system rests on five interconnected principles that govern how context evolves over time.

| Concept | Purpose |
|---------|---------|
| **Append‑only ledger** | All runtime facts persist as `AgentRunEvent` records; history is never overwritten |
| **Projection** | A read‑only view derived from durable events, consumed by UI components and model context builders |
| **Transition record** | A `model_projection_transition_recorded` event that identifies a projection part to replace, carries replacement data, and includes the source digest for validation |
| **Deterministic reduction** | A reducer processes transition records in order, recreating the current projection state |
| **Idempotent creation** | The transition ID is content‑derived, ensuring duplicate writes produce identical records |

These concepts work together to guarantee that context updates are **safe**, **replayable**, and **concurrent‑writer aware**.

## How the Transition System Works

### Defining the Target with ModelProjectionTransitionTarget

A transition must precisely locate the projection part to replace. The `ModelProjectionTransitionTarget` interface in [`packages/core/src/model-projection-transition.ts`](https://github.com/apache/maka/blob/main/packages/core/src/model-projection-transition.ts) specifies this address:

```typescript
// packages/core/src/model-projection-transition.ts
export interface ModelProjectionTransitionTarget {
  runtimeEventId: string;
  part: 'tool_result';
  toolCallId: string;
  toolName: string;
}

```

This four‑tuple identifies: the originating event, the projection part type (`tool_result` is the only supported part currently), the specific tool call, and the tool name.

### Building a Transition Record

The `buildModelProjectionTransition` function constructs a complete transition object. It computes **SHA‑256 digests** of both the source and replacement projections, then derives a deterministic `transitionId` from the record's content:

```typescript
export function buildModelProjectionTransition(
  input: BuildModelProjectionTransitionInput,
): ModelProjectionTransition {
  const sourceProjectionDigest = durableToolResultProjectionDigest(
    decodeDurableToolResultProjection(input.sourceProjection),
  );
  // ...
  const transitionId = `mptransition-${nodeCrypto
    .createHash('sha256')
    .update(stableJsonStringify(body))
    .digest('hex')
    .slice(0, 32)}`;
  // ...
}

```

This design ensures that **identical inputs always yield the same transition ID**, making the operation naturally idempotent.

### Validating Transition Integrity

Before application, `decodeModelProjectionTransition` enforces schema compliance and validates the digest format:

```typescript
export function decodeModelProjectionTransition(
  value: unknown,
  sessionId: string,
): ModelProjectionTransition {
  if (!isModelProjectionTransition(value, sessionId)) {
    throw new Error('Invalid model projection transition');
  }
  return value;
}

```

The validator rejects malformed records early, preventing corrupt transitions from reaching the reducer.

### Computing Projection Digests

The `durableToolResultProjectionDigest` function creates stable identifiers for projection versions:

```typescript
export function durableToolResultProjectionDigest(
  projection: DurableToolResultProjection,
): `sha256:${string}` {
  return `sha256:${nodeCrypto
    .createHash('sha256')
    .update(stableJsonStringify(projection))
    .digest('hex')}`;
}

```

Digests enable **optimistic concurrency control**: a transition is accepted only if its `sourceProjectionDigest` matches the current projection's digest.

### Durable Projection Types

The `DurableToolResultProjection` type in [`packages/core/src/durable-tool-result-projection.ts`](https://github.com/apache/maka/blob/main/packages/core/src/durable-tool-result-projection.ts) defines valid replacement shapes:

```typescript
export type DurableToolResultProjection =
  | { version: 1; kind: 'text';  text: string; isError?: true }
  | { version: 1; kind: 'json';  value: DurableProjectionJson; isError?: true }
  | { version: 1; kind: 'content'; parts: DurableToolResultProjectionPart[] }
  | { version: 1; kind: 'execution_denied'; reason?: string }
  | { version: 1; kind: 'failure';
      reason: 'projection_failed';
      message: typeof DURABLE_TOOL_RESULT_PROJECTION_FAILURE_MESSAGE };

```

These variants cover text results, structured JSON, multi‑part content, explicit denials, and internal failures.

## Runtime Enforcement and Error Handling

When the Apache Maka runtime applies a transition, it validates both the target address and the source digest. Mismatched digests cause rejection, protecting against stale writes. The runtime kernel in [`packages/runtime/src/runtime-kernel.ts`](https://github.com/apache/maka/blob/main/packages/runtime/src/runtime-kernel.ts) throws descriptive errors—such as *"No active AgentRun for model projection transition"*—when infrastructure preconditions fail.

## Practical Examples

### Building a Transition Client‑Side

```typescript
import {
  buildModelProjectionTransition,
  type ModelProjectionTransitionTarget,
  type BuildModelProjectionTransitionInput,
} from '@maka/core/src/model-projection-transition.js';
import { type DurableToolResultProjection } from '@maka/core/src/durable-tool-result-projection.js';

const target: ModelProjectionTransitionTarget = {
  runtimeEventId: 'event-123',
  part: 'tool_result',
  toolCallId: 'call-456',
  toolName: 'search',
};

const source: DurableToolResultProjection = {
  version: 1,
  kind: 'text',
  text: 'Old search result',
};

const replacement: DurableToolResultProjection = {
  version: 1,
  kind: 'text',
  text: 'Corrected search result',
};

const input: BuildModelProjectionTransitionInput = {
  sessionId: 'session-abc',
  target,
  sourceProjection: source,
  replacement,
  now: Date.now(),
};

const transition = buildModelProjectionTransition(input);
console.log('Transition ID:', transition.transitionId);

```

### Validating a Received Transition

```typescript
import { decodeModelProjectionTransition } from '@maka/core/src/model-projection-transition.js';

try {
  const transition = decodeModelProjectionTransition(raw, 'session-abc');
  console.log('Valid transition for target', transition.target);
} catch (e) {
  console.error('Invalid transition record:', e);
}

```

### Applying a Transition in a Reducer

```typescript
function applyTransition(
  currentProjection: DurableToolResultProjection,
  transition: ModelProjectionTransition,
): DurableToolResultProjection {
  if (durableToolResultProjectionDigest(currentProjection) !== transition.sourceProjectionDigest) {
    throw new Error('Source projection digest mismatch');
  }
  return transition.replacement;
}

```

## Key Source Files

| File | Responsibility |
|------|---------------|
| [`packages/core/src/model-projection-transition.ts`](https://github.com/apache/maka/blob/main/packages/core/src/model-projection-transition.ts) | Transition record types, builder, validator, and digest functions |
| [`packages/core/src/durable-tool-result-projection.ts`](https://github.com/apache/maka/blob/main/packages/core/src/durable-tool-result-projection.ts) | Durable projection schema and type definitions |
| [`packages/runtime/src/runtime-kernel.ts`](https://github.com/apache/maka/blob/main/packages/runtime/src/runtime-kernel.ts) | Runtime ledger integration and validation |
| [`packages/runtime/src/ai-sdk-compaction.ts`](https://github.com/apache/maka/blob/main/packages/runtime/src/ai-sdk-compaction.ts) | Reducer implementation for context compaction |

## Why the Model Projection Transition System Matters for Context Management

- **Safety**: The model's view is always derived from validated projections; malformed transitions cannot corrupt historical context
- **Replayability**: Any session state can be reconstructed by replaying the event ledger from origin
- **Concurrency safety**: Digest‑based guards prevent lost updates when multiple writers compete
- **Precision**: Only the targeted `tool_result` section changes; unrelated session state remains untouched
- **Auditability**: Every context modification exists as an explicit, inspectable ledger entry

## Summary

The **Apache Maka model projection transition system** elegantly solves the problem of updating immutable context:

- All runtime data lives in an **append‑only ledger** of `AgentRunEvent` records
- **Projections** provide read‑only, derived views for UI and model consumption
- **Transition records** express targeted replacements with cryptographic integrity checks
- **Deterministic reduction** recreates current state by applying transitions in order
- **Idempotent, content‑derived IDs** ensure duplicate operations are harmless

This architecture makes Apache Maka's context management simultaneously **safe**, **transparent**, and **resilient to concurrency**.

## Frequently Asked Questions

### How does Apache Maka prevent corrupt updates to model context?

Apache Maka prevents corrupt updates through **digest‑based validation**. Each transition record includes a `sourceProjectionDigest` computed from the expected current projection. The runtime verifies this digest before applying any replacement. If the current projection has changed—due to another writer or stale data—the digest mismatch causes rejection, preserving data integrity.

### Can two processes safely update the same tool result simultaneously?

Yes, with **optimistic concurrency control**. Both processes read the same source projection digest and construct transitions. The first to commit succeeds; the second finds a digest mismatch and must retry with fresh data. Because transition IDs are **content‑derived**, accidental duplicate submissions are idempotent and harmless.

### What happens when a transition targets a nonexistent event?

The runtime in [`packages/runtime/src/runtime-kernel.ts`](https://github.com/apache/maka/blob/main/packages/runtime/src/runtime-kernel.ts) validates the target address during transition processing. If the referenced `runtimeEventId`, `toolCallId`, or combination does not exist, validation fails with an explicit error. The append‑only ledger structure ensures that targets, once valid, remain addressable for the session lifetime.

### How does the system support debugging and audit trails?

Every transition exists as a **first‑class ledger entry** with a deterministic, content‑derived ID. Developers can inspect the complete sequence of `model_projection_transition_recorded` events to understand exactly how context evolved. Replaying the ledger through the reducer reproduces the exact model-visible state at any historical point, enabling precise post‑hoc analysis.