Documentation Index
Fetch the complete documentation index at: https://docs.manthan.systems/llms.txt
Use this file to discover all available pages before exploring further.
What is replay protection?
Replay protection ensures that identical signals cannot produce two separate governed decisions using the same replay store. Each execution_fingerprint can only be consumed once - ever.
This is essential for governed decisions that cause consequential state transitions: approving a payment, escalating a case, deploying infrastructure. The governance runtime enforces single-use execution at the atomic level.
How it works
Parmana uses a two-phase commit protocol for replay protection:
- Compute the
execution_fingerprint - sha256(canonicalize(signals))
- Reserve the fingerprint in the replay store (phase 1)
- Evaluate the policy and sign the decision
- Confirm the fingerprint in the replay store (phase 2)
If the store is unavailable at step 2, execution is blocked - fail-closed by design. If it fails at step 4, the caller receives an error and must not retry automatically.
A second call with the same signals throws INV-013:
[INV-013@replay] Replay detected: execution_fingerprint <hash> has already been consumed
MemoryReplayStore vs RedisReplayStore
| MemoryReplayStore | RedisReplayStore |
|---|
| Persistence | In-process only | Persists across restarts |
| Multi-process | No | Yes |
| Use case | Development and testing | Production |
| Setup | None | Redis instance |
MemoryReplayStore emits a warning when NODE_ENV=production. It loses all replay protection state on process restart and does not work across multiple processes. Use RedisReplayStore in production.
RedisReplayStore setup
import { RedisReplayStore } from "@parmanasystems/core";
const store = new RedisReplayStore({
host: process.env.REDIS_HOST,
port: parseInt(process.env.REDIS_PORT ?? "6379"),
});
What the fingerprint covers
The execution_fingerprint is derived from the canonicalized signals only - not from timestamps, trace IDs, or request metadata:
const execution_fingerprint = sha256(canonicalize(signals));
This means:
- Same signals = same fingerprint = replay rejected
- Different signals = different fingerprint = new execution
- Key ordering and whitespace do not affect the fingerprint
INV-013 in practice
Replay detection is intentional, not an error in your code. Common causes:
| Cause | Fix |
|---|
| Client retrying a failed request with the same signals | Use idempotency at the application layer; don’t re-execute with the same signals |
| Testing with the same signals repeatedly | Use new MemoryReplayStore() per test to reset state |
| Distributed nodes sharing a MemoryReplayStore | Switch to RedisReplayStore |
Error codes
| Code | Meaning |
|---|
INV-013 | Replay detected - execution_fingerprint already consumed |
See also