Check the store for (principal, key, payload) and return whether the
caller should replay, reject, or execute fresh.
On miss, the store writes an in-flight placeholder atomically via
the backend's putIfAbsent. Only the caller that wins the claim gets
miss; parallel callers with the same key see in-flight and should
retry the check after a brief delay. The returned payloadHash MUST
be passed back to save() to avoid double-hashing.
Save a successful execution's response to the cache, replacing the in-flight placeholder written at check time.
Release the in-flight claim written at check time — used by the middleware when the handler fails, so a retry can re-execute rather than replay a cached error.
OptionalsaveShort-TTL cache for an error envelope that the handler is guaranteed to reproduce on re-execution (currently: strict-mode response VALIDATION_ERROR driven by handler drift).
Optional on the interface so custom store implementations aren't
forced to migrate — when absent, the dispatcher falls back to
release() (the pre-#758 behavior). Stores backed by
createIdempotencyStore always include it.
Retry-storm guard, not a spec replay. Without it, a drifted handler
under strict validation + a retrying buyer produces unbounded
re-execution (release-on-error lets every retry hit the handler again
with the same drift). Caching for TRANSIENT_ERROR_TTL_SECONDS (10s)
short-circuits retries within the buyer's typical backoff window.
Operational note — DoS primitive. A drifted handler reachable by
a hostile buyer is a cache-fill vector: every fresh idempotency_key
writes a new 10s-TTL entry, cheap because the handler fails fast.
Alert on sustained VALIDATION_ERROR rates per principal — they
indicate either a broken handler (deploy regression) or a buyer
probing for drift. Steady-state VALIDATION_ERROR should be zero.
Dev-experience note — TTL opacity. After deploying a handler fix,
same-key retries within the 10s window still replay the cached error
before the fix takes effect. Iterative handler authors should use a
fresh idempotency_key to bypass the cache during development.
OptionalprobeProbe the backend at server startup. Delegates to backend.probe() if
the backend implements it; otherwise resolves immediately. Wire into
serve() via readinessCheck: () => store.probe() so the server
never accepts traffic with a broken pool.
Capability fragment for get_adcp_capabilities — tells buyers the
replay window so they can reason about retry safety. Pass to
createAdcpServer via capabilities.idempotency.
Release backend resources (close pools, clear timers).
OptionalclearDrop every cached entry without releasing backend resources.
Present only when the configured backend supports it (e.g.,
memoryBackend). Production-leaning backends leave this undefined
so an accidental production call can't flush the cache.
Only invoked from AdcpServer.compliance.reset() — do not call from
production code paths.
The replay window in seconds (already bounds-checked at construction).