Description
PR #733 P3.6/P3.7 remain in services/dns_resolver.py:285-525 and collectors/clients.py:1545-1620. with_timeout uses the same sentinel for timeout and arbitrary exceptions, so lookup_timeouts counts non-timeout failures. queue_peak_depth reports the bounded handoff queue and saturates at max_concurrent_lookups, hiding the producer backlog and racing across concurrent batches. Separate failure causes and expose a queue/backlog measure whose value changes with real pending work.
Acceptance Criteria
- #1 Only actual deadline expiry increments the DNS timeout counter
- #2 Resolver exceptions have a separate bounded outcome signal
- #3 Queue or backlog metrics distinguish a small batch from a fleet-sized pending batch
- #4 Concurrent resolve_multiple calls cannot reset or corrupt each others measurements
Definition of Done
- #1 make check (uv run ruff check . && uv run ruff format –check . && uv run mypy . && uv run pytest -v)
- #2 make docgen, when metrics, config, endpoints or collectors changed — CI fails the build on generated-docs drift
- #3 Grafana queries in grafana/dashboards/*.json and grafana/alerts/ updated, if a metric or label name changed
Implementation Plan
Wave 1 L5: separate DNS failure causes and concurrency-safe backlog accounting alongside the privacy audit; root integrates and finalizes.
Final Summary
Implemented and verified in 7327153. DNS timeout/failure and producer backlog signals are exclusive and overlap-safe; full gates passed.