Replay-safe execution for a synthetic AI-agent tool action. Built with FastAPI, PostgreSQL 16, and Psycopg 3.
Autonomous AI agents inevitably retry tool calls when encountering transient network timeouts, worker restarts, or orchestration hiccups. Without an atomic idempotency ledger, every replay causes duplicate execution of underlying side effects (duplicate notifications, double billing, or corrupted system state).
RelayGuard demonstrates production-aware replay protection for a single synthetic AI-agent action (POST /v1/actions, action type: publish_update).
┌─────────────────────────────────────────────────────────────┐
│ AI AGENT CALLER │
│ POST /v1/actions │
│ { "idempotency_key": "...", "action_type": "...", ... } │
└──────────────────────────────┬──────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ RELAYGUARD API GATEWAY │
│ 1. Strict Pydantic validation (unknown fields forbidden) │
│ 2. Compute canonical SHA-256 payload hash │
│ 3. Single PostgreSQL transaction: │
│ • Claim key via INSERT ... ON CONFLICT DO NOTHING │
│ • If claimed: inspect stored hash under FOR UPDATE │
│ - Matching: return cached result (replayed: true) │
│ - Conflict: HTTP 409 Conflict │
│ • If new: execute synthetic effect & commit ledger │
└──────────────────────────────┬──────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ POSTGRESQL STORAGE │
│ • actions: idempotency_key (PK), payload_hash, result │
│ • effects: effect_id (PK), idempotency_key (UNIQUE, FK) │
└─────────────────────────────────────────────────────────────┘
- Baseline Implementation: Intentionally defective. Writes a new synthetic effect to
baseline_effectson every request, completely ignoring the key. - Fixed Implementation: Persists the action record and synthetic effect atomically in PostgreSQL. Returns stored results on exact replay; rejects key reuse with different content with HTTP 409 Conflict.
No external network calls, payments, or third-party APIs are contacted. This is a local synthetic demonstration.
- Python 3.11+
- Docker Desktop with Docker Compose (or local PostgreSQL 16+)
Create your local .env file from the provided development template before starting the database container:
Windows PowerShell:
Copy-Item .env.example .envmacOS / Linux:
cp .env.example .envImportant
Clean-Clone Verification: In a clean clone with no undeclared DATABASE_URL environment variable already set in your shell session, copying .env.example to .env ensures that app.config resolves the database host port correctly without requiring manual variable exports. If DATABASE_URL is completely absent, app.config fails fast with an explicit error directing you to .env.example.
The default .env sets DATABASE_URL=postgresql://relayguard:relayguard_dev_password@localhost:5434/relayguard, matching Docker Compose host port 5434 (which avoids collisions with any native PostgreSQL running on port 5432). If you use a native PostgreSQL service on port 5432, update DATABASE_URL in .env to point to port 5432.
docker compose up -d --wait dbThe database container runs with an automated healthcheck.
Windows PowerShell:
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install -r requirements.txtmacOS / Linux:
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txtpython -m pytest -vVerifies 10 automated test scenarios against real PostgreSQL:
- Baseline defect reproduction (10 requests
$\rightarrow$ 10 duplicate effects) - Exact replay deduplication (10 requests
$\rightarrow$ exactly 1 effect, 1 fresh, 9 cached) - Payload conflict rejection (HTTP 409 on content mismatch)
- Strict Pydantic input validation & extra-field rejection (HTTP 422)
- Concurrency safety under race conditions (10 concurrent worker threads
$\rightarrow$ 1 effect) - Transactional rollback atomicity (database trigger fault injection and recovery)
- Operational health check verification (
GET /healthz) - Multi-action repeatability and key isolation
- Database unavailability error masking (returns HTTP 503 without leaking credentials)
- Connection URL credential redaction verification
python -m scripts.measureSends 100 identical requests to the defective baseline and 100 to the fixed implementation, reporting effect counts, prevented duplicates (99), and local wall-clock timings.
To execute a live end-to-end demonstration covering health checks, replay deduplication, conflict rejection, 10-thread parallel race testing, and baseline contrast:
Windows PowerShell:
.\run_presentation.ps1Any Platform:
python -m scripts.demo_liveuvicorn app.main:app --reloadOpen interactive Swagger UI at: http://127.0.0.1:8000/docs
curl -X POST http://127.0.0.1:8000/v1/actions \
-H "Content-Type: application/json" \
-d '{
"idempotency_key": "update-demo-0001",
"action_type": "publish_update",
"content": "Synthetic customer update for the RelayGuard demo."
}'-
First call:
HTTP 200$\rightarrow$ {"status": "completed", "replayed": false, "effect_id": 1} -
Exact repeat:
HTTP 200$\rightarrow$ {"status": "completed", "replayed": true, "effect_id": 1} -
Different content with same key:
HTTP 409 Conflict$\rightarrow$ "Idempotency key was already used with a different payload."
To stop the PostgreSQL container and reset data:
docker compose down -v| File / Folder | Purpose |
|---|---|
compose.yaml |
Docker Compose specification for development PostgreSQL 16 |
.env.example |
Development-only environment template (no secrets committed) |
app/main.py |
Fixed replay-safe FastAPI service implementation |
app/baseline.py |
Clearly labelled, intentionally defective baseline service |
app/storage.py |
Psycopg 3 PostgreSQL schema management & connection handling |
app/config.py |
Fail-fast environment configuration parser |
tests/test_replay_protection.py |
Automated test suite (concurrency, atomicity, conflict, validation) |
scripts/measure.py |
100-request before/after measurement tool |
docs/ADR-001-idempotency-storage.md |
Architecture Decision Record comparing 4 storage options |
docs/AI_REVIEW_EVIDENCE.md |
AI code review analysis evaluating check-then-act vulnerabilities |
docs/TEST_REPORT.md |
Full captured test outputs and benchmark evidence |
docs/LOOM_SCRIPT.md |
5-minute timed video script and shot list |
HANDOFF.md |
Next-engineer onboarding guide and exercise |
problem.md |
Problem brief and affected user analysis |
intent.md |
Problem selection scoring rubric & non-goals |
directive.md |
Working directive with acceptance criteria and results appendix |
security.md |
Security protocols, threat model matrix, and production roadmap |