Move Disposition enum and inflight acquisition logic into a standalone
acquire_inflight() function. Rewrite 4 tests that were exercising tokio
primitives to call the real coalescing code path instead.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Followers in the inflight coalescing path now log as COALESCED instead
of RECURSIVE, making it visible in the dashboard when queries were
deduplicated vs independently resolved. Adds 10 tests covering
InflightGuard cleanup, broadcast mechanics, and concurrent handle_query
coalescing through a mock TCP DNS server.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When multiple queries for the same (domain, qtype) arrive concurrently
and all miss the cache, only the first triggers recursive resolution.
Subsequent queries wait on a broadcast channel for the result.
Prevents thundering herd where N concurrent cache misses each
independently walk the full NS chain, compounding timeouts.
Uses InflightGuard (Drop impl) to guarantee map cleanup on
panic/cancellation — prevents permanent SERVFAIL poisoning.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>