How Apache Maka Ensures Data Integrity and Replayability After a Crash
Apache Maka treats the Runtime Event Log as the single source of truth, using an append‑only ledger and two‑phase tool execution boundaries to survive crashes without data loss or duplicated side‑effects.
Every operation in Apache Maka is recorded as an immutable fact, enabling the system to reconstruct exact execution history after unexpected termination. By combining durable storage in SQLite with a layered authority model, Maka guarantees that data integrity and replayability after a crash are maintained through rigorous log replay and workspace verification.
The Immutable Append‑Only Runtime Event Log
At the core of Maka’s safety guarantees is the Runtime Event Log, an append‑only ledger that serves as the canonical record of every model interaction, tool invocation, and permission decision.
Each entry is defined as a RuntimeEvent in packages/core/src/runtime-event.ts. The schema includes a unique UUID, timestamps, role information, author identity, and an optional partial flag for streaming chunks. Partial events are later superseded by non‑partial events, ensuring the history remains clean and ordered. Because the log is strictly append‑only, facts survive process termination, power loss, or host crashes without corruption.
Durable Fact Boundaries and Two‑Phase Tool Execution
Maka implements a two‑step transaction protocol to isolate side‑effects from commit points. This separation is enforced by SQLite transactions in packages/storage/src/sqlite-runtime-store.ts and orchestrated in packages/runtime/src/tool-runtime.ts.
Phase T1 (Dispatch): When a tool is invoked, the runtime first persists a toolDispatch fact containing the canonical arguments hash and operation ID. This confirms the tool may have started and marks the beginning of the side‑effect window.
Phase T2 (Outcome): After the tool completes, the runtime writes a function_response event and updates the toolDispatch record with the final outcome. This guarantees the side‑effect has completed and the result is visible to the model.
This T1/T2 split creates three well‑defined crash states:
- No T1: The tool never started; safe to ignore.
- T1 only: The tool may have run externally, requiring the RecoveryResolver to decide whether to replay, reconcile, or park the operation.
- T1 + T2: The tool completed; the result is immutable and safe to replay.
Crash Recovery and the Recovery Resolver
After a restart, the SessionManager loads the immutable prefix of the log and delegates classification to the RecoveryResolver in packages/runtime/src/recovery-resolver.ts. The resolver categorizes each incomplete operation according to the crash contract defined in docs/architecture/runtime-resume-architecture.md:
completed: Both T1 and T2 facts are present.definitely_not_dispatched: No T1 fact exists.indeterminate: Only T1 is present, requiring external reconciliation.corruption: Conflicting facts trigger a fail‑closed response.
Phase 0 of recovery reads the committed prefix and produces a replay‑safe plan. Phase 1 creates a fresh Run only if the plan proves that every tool operation has reached a terminal state (completed or definitely_not_dispatched). The new run receives fresh IDs (runId, invocationId, turnId) but references the high‑water mark of the old log, ensuring the model provider receives exactly the same history it saw before the crash. This flow is orchestrated by packages/runtime/src/runtime-resume.ts and packages/runtime/src/continuation-safety.ts.
Workspace Identity Verification
To prevent replaying history against a filesystem that has diverged, Maka verifies workspace identity during recovery. The runtime reads a workspace UUID from .maka-workspace.json via WorkspaceIdentity in packages/storage/src/workspace-identity.ts and compares it against the stored identity in the opening fact. A mismatch aborts continuation and forces a park, ensuring the system never silently continues with inconsistent external state.
Atomic Recovery Bundles for Indeterminate States
For operations that crash after T1 but before T2, Maka supports recovery bundles (toolRecovery) that atomically record the observed external state and a decision (completed or parked). These bundles are written within the same SQLite transaction that persists the toolDispatch fact, as documented in Phase 3A of the runtime resume architecture. This atomicity prevents torn states where the log and external reality disagree.
Inspecting the Log and Planning a Safe Continuation
The following example demonstrates how to load the durable store, inspect events, and determine if continuation is safe:
import { RuntimeEvent } from '@maka/core';
import { SqliteRuntimeStore } from '@maka/storage';
import { RecoveryResolver } from '@maka/runtime';
// Open the durable store (SQLite)
const store = new SqliteRuntimeStore('/path/to/workspace/.maka/runtime.sqlite');
// Load all events for a given invocation
const events: RuntimeEvent[] = await store.readEventsForInvocation('inv-123');
// Phase 0 – build a safe-replay plan
const resolver = new RecoveryResolver(events);
const plan = resolver.buildSafeReplayPlan(); // returns `completed | park`
if (plan === 'completed') {
// Phase 1 – claim a new continuation
const continuation = await store.createContinuation({
sourceInvocationId: 'inv-123',
sourceRunId: 'run-45',
highWater: resolver.highWaterMark,
});
// Now you can send `continuation` to the model provider
} else {
console.warn('Cannot safely resume – inspection required');
}
Summary
- Immutable Ledger: All facts are stored as
RuntimeEventobjects in an append‑only log, ensuring history survives crashes. - Two‑Phase Safety: The T1/T2 boundary separates dispatch from outcome, allowing precise classification of incomplete operations.
- Deterministic Replay: The RecoveryResolver in
packages/runtime/src/recovery-resolver.tsanalyzes the log prefix to prove safety before creating new runs. - Workspace Verification: The
WorkspaceIdentitycheck inpackages/storage/src/workspace-identity.tsprevents resumption against mutated filesystems. - Atomic Recovery: Recovery bundles are committed atomically with their associated
toolDispatchfacts viapackages/storage/src/sqlite-runtime-store.ts.
Frequently Asked Questions
How does Maka prevent duplicate tool execution after a crash?
Maka prevents duplicates through the T1/T2 boundary protocol. When only T1 (dispatch) is present after a crash, the RecoveryResolver marks the operation as indeterminate and either reconciles externally or parks the session. If T2 (outcome) is present, the operation is marked completed and replayed from the log without re‑executing the tool.
What happens if the workspace files change during a crash?
If the workspace UUID stored in .maka-workspace.json does not match the identity recorded in the opening fact, the runtime forces a park. This mechanism in packages/storage/src/workspace-identity.ts ensures that Maka never replays history against a filesystem that has diverged from the recorded state.
Can Maka recover from partial writes or log corruption?
Yes. The RecoveryResolver detects corruption states where conflicting facts exist in the log, triggering a fail‑closed response. Additionally, because packages/storage/src/sqlite-runtime-store.ts uses SQLite transactions for all writes, including atomic recovery bundles, the system maintains consistency even if the process terminates mid‑write.
Where is the crash recovery logic implemented in the source code?
The primary recovery logic resides in packages/runtime/src/recovery-resolver.ts (classification), packages/runtime/src/runtime-resume.ts (orchestration), and packages/storage/src/sqlite-runtime-store.ts (persistence). The architectural specification is documented in docs/architecture/runtime-resume-architecture.md.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →