Follow-up to #183 (RFC 9421 request signing). The signing module ships `InMemoryReplayStore` for single-process verifiers. Multi-instance deployments (load-balanced FastAPI, autoscaled workers) need a shared store so a nonce accepted by one instance cannot be replayed on another within the signature's validity window.
What's needed
- `adcp.signing.RedisReplayStore` implementing the existing `ReplayStore` Protocol (`seen`, `remember`, `at_capacity`).
- TTL honored via Redis key expiration (`SET ... PX ...`).
- Per-keyid cap tracked via a sorted set or counter (`ZCARD`/`INCR` pattern) — spec cap recommendation is 1M entries.
- Key naming that isolates tenants: `adcp:replay:{keyid}:{nonce}`.
- Optional dep via `[redis]` extra in `pyproject.toml` (using `redis-py`).
Why separate
The Protocol surface is already defined and the in-memory implementation passes all 28 conformance vectors. A Redis adapter is operational infra, not protocol work — cleaner as a follow-up with its own integration test suite (against a real Redis via `testcontainers` or a mock).
Out of scope
- Memcached / DynamoDB / etc. adapters — Redis is the dominant ad-tech choice; others can follow the same Protocol.
Follow-up to #183 (RFC 9421 request signing). The signing module ships `InMemoryReplayStore` for single-process verifiers. Multi-instance deployments (load-balanced FastAPI, autoscaled workers) need a shared store so a nonce accepted by one instance cannot be replayed on another within the signature's validity window.
What's needed
Why separate
The Protocol surface is already defined and the in-memory implementation passes all 28 conformance vectors. A Redis adapter is operational infra, not protocol work — cleaner as a follow-up with its own integration test suite (against a real Redis via `testcontainers` or a mock).
Out of scope