# Adapter Integration Contract
This document defines the boundaries, responsibilities, and architectural contracts for any external system integrating with `nexir-mvcc-core`.
The core kernel enforces correctness, determinism, isolation, and transaction bounds. It relies entirely on the adapter to provide logical time, ordered mutation application, durable storage, replay handling, and crash recovery.
## 1. Timestamp Source
The core accepts timestamps blindly; it does not invoke `SystemTime` or any wall clock.
- The Adapter must provide **deterministic and monotonic timestamps** for affected keys.
- Timestamps do not strictly need to be globally monotonic unless the Adapter chooses that constraint, but they *must* be monotonic per written key.
- For log-ordered systems, timestamps may be derived mathematically from the log index and operation ordinal.
## 2. Mutation Path Selection
The Adapter is responsible for translating user/network commands into the cheapest safe execution path:
- **`DirectPhysicalBatch`**: For blind writes (e.g., standard `SET` or `DEL`).
- **`VersionGuardedBatch`**: For read-modify-write (RMW) and conditional writes (e.g., `INCR`, `SET NX`).
- **`Intent` Path**: For transaction-window/provisional-lock operations.
*Note: Distributed cross-shard transaction orchestration remains outside the scope of MVCC Core V1.*
## 3. Storage Atomicity
The core relies absolutely on the Adapter's underlying `Backend` for atomic durability.
- Single-key and multi-key intent commits both flow through `commit_intents_batch`; durable adapters must implement it as one atomic storage transition that creates committed versions and removes matching intents together.
- `put_committed_batch` must be handled as a strictly all-or-nothing operation by the durable storage layer.
- Intent operations must be atomic at the storage level. Durable adapters **must** execute `put_intents_batch`, `commit_intents_batch`, and `remove_intents_batch` as strict atomic transactions.
- The core cannot repair a backend that violates atomic success during power loss. If the backend lies about durability, the core cannot detect it.
## 4. Idempotency and Replay
Because ordered apply systems may retry operations after failovers, restarts, or timeouts, the adapter is responsible for strict idempotency.
- The Adapter must maintain idempotency records keyed by an external mutation ID or log identity.
- Replayed applications must return the exact same semantic result to the caller without applying the physical mutation twice.
- The core primitives are deterministic but **do not** own or manage replay caches.
## 5. Guard Semantics
When utilizing the `VersionGuardedBatch` path:
- For RMW commands, every written key derived from a read **must** have a corresponding read guard attached to the batch by the Adapter.
- Guard validation happens at a deterministic time during batch apply.
- If a guard fails (e.g., due to a stale read), it must produce a deterministic conflict/retry signal.
## 6. Latches vs. Locks
The boundary between fast in-memory latches and persistent intent locks must be respected:
- **Durable logical locks** are explicitly managed as MVCC intents by the core.
- **In-memory latches** (e.g., mutexes guarding data structures or command queues) belong entirely to the adapter/runtime.
- **Strict Rule**: Latches must be short-lived. They must *never* be held across network calls, consensus rounds, or client wait boundaries.
## 7. Failure and Recovery
The Adapter holds the burden of proving robust failure recovery:
- The Adapter must prove replay determinism after a crash and restart.
- The Adapter must definitively prove atomic storage behavior boundaries.
- Snapshots generated by the Adapter must consistently bundle MVCC committed versions, active intents, idempotency records, and last-applied metadata in the same snapshot.
## 8. Concurrency Ownership
- The adapter owns concurrency.
- For each ordered write domain, mutation apply must be serialized into the MVCC engine.
- Concurrent client requests may race before ordering, but committed apply order must be deterministic.
- The MVCC core should not be wrapped in a shared Mutex/RwLock as a default architecture.
- If the adapter uses a Mutex/RwLock for prototype simplicity, it must be documented as non-final.
- Read-serving strategy must be explicitly chosen by the adapter:
- serialized through apply owner,
- snapshot/clone based,
- or served from a durable snapshot using the same visibility rules.
- Active read tracking for GC safe points belongs to the adapter.
---
## Apply Outcome Contract (Adapter Conceptual API)
The core emits specific typed errors (e.g., `BatchError` or `CommitError`). The Adapter is expected to map these granular core states into a higher-level state machine concept for network/client consumption.
Conceptually, the Adapter should map outcomes into an enum like this:
```rust
enum ApplyOutcome {
Applied,
AlreadyApplied,
ConflictRetry,
InvalidRequest,
BackendError,
}
```
> **Note**: This enum is not currently part of the core public API. A future adapter crate may define it, or the core may expose it later if multiple adapters require a shared result type. `AlreadyApplied` is strictly an adapter-level result because the idempotency/replay cache lives entirely outside the MVCC library.
### Conceptual Mapping
| `Ok(())` | `Applied` |
| Idempotency cache hit (Adapter Layer) | `AlreadyApplied` |
| `BatchError::GuardFailedNewerVersion` | `ConflictRetry` |
| `BatchError::GuardFailedVersionMismatch` | `ConflictRetry` |
| `BatchError::GuardFailedValueMismatch` | `ConflictRetry` |
| `BatchError::KeyLocked` | `ConflictRetry` (or general transaction conflict) |
| `BatchError::CommitTsTooOld` | `InvalidRequest` (or signals a timestamp generation/replay bug in the adapter) |
| `BatchError::InvalidCommitTimestamp` | `InvalidRequest` |
| `BatchError::DuplicateKeyInBatch` | `InvalidRequest` |
| `BatchError::NoReadGuards` | `InvalidRequest` |
| `BatchError::Backend` | `BackendError` |
| `CommitError::CommitTsTooOld` | `InvalidRequest` (signals a timestamp generation/replay bug in the adapter) |
| `CommitError::*` variants | Adapter-defined commit failure categories |