Found while restoring transport-failure test coverage in PR #97. Deliberately not fixed there — it is a behaviour change outside that PR's mandate.
Problem
tryExchange re-checks the context at the top of each retry iteration and returns ErrContextCanceled, throwing away the error recorded by the previous attempt. When a caller's deadline expires mid-query, the genuine timeout from attempt N is replaced by a context-cancellation error on attempt N+1, and the result classifies as StatusNoData instead of StatusTimeout.
Impact
Reachable in production: the watcher passes deadline-bounded contexts. A nameserver that is genuinely timing out can be reported as "no data" whenever the caller deadline happens to expire during the retry loop, which is the common case for a slow/blackholed server.
Expected
If a previous attempt already produced a timeout, that classification should survive context cancellation rather than being overwritten.
Notes
The transport tests added in PR #97 use a generous 30s context specifically so they do not depend on this buggy path. A fix should add coverage that exercises a short caller deadline against a silent responder and asserts StatusTimeout.
Related but distinct from #120 (server timeout tests protect the constructor but not the call site).
Found while restoring transport-failure test coverage in [PR #97](https://git.eeqj.de/sneak/dnswatcher/pulls/97). Deliberately **not** fixed there — it is a behaviour change outside that PR's mandate.
## Problem
`tryExchange` re-checks the context at the top of each retry iteration and returns `ErrContextCanceled`, throwing away the error recorded by the previous attempt. When a caller's deadline expires mid-query, the genuine timeout from attempt N is replaced by a context-cancellation error on attempt N+1, and the result classifies as `StatusNoData` instead of `StatusTimeout`.
## Impact
Reachable in production: the watcher passes deadline-bounded contexts. A nameserver that is genuinely timing out can be reported as "no data" whenever the caller deadline happens to expire during the retry loop, which is the common case for a slow/blackholed server.
## Expected
If a previous attempt already produced a timeout, that classification should survive context cancellation rather than being overwritten.
## Notes
- The transport tests added in PR #97 use a generous 30s context specifically so they do not depend on this buggy path. A fix should add coverage that exercises a short caller deadline against a silent responder and asserts `StatusTimeout`.
- Related but distinct from [#120](https://git.eeqj.de/sneak/dnswatcher/issues/120) (server timeout tests protect the constructor but not the call site).
Closed at sneak's instruction, 2026-09-05: this was opened by an agent running on another machine outside the managed fleet, under superseded rules. Reopen if the content is wanted.
Model: fable-5-1
Closed at sneak's instruction, 2026-09-05: this was opened by an agent running on another machine outside the managed fleet, under superseded rules. Reopen if the content is wanted.
Model: fable-5-1
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Found while restoring transport-failure test coverage in PR #97. Deliberately not fixed there — it is a behaviour change outside that PR's mandate.
Problem
tryExchangere-checks the context at the top of each retry iteration and returnsErrContextCanceled, throwing away the error recorded by the previous attempt. When a caller's deadline expires mid-query, the genuine timeout from attempt N is replaced by a context-cancellation error on attempt N+1, and the result classifies asStatusNoDatainstead ofStatusTimeout.Impact
Reachable in production: the watcher passes deadline-bounded contexts. A nameserver that is genuinely timing out can be reported as "no data" whenever the caller deadline happens to expire during the retry loop, which is the common case for a slow/blackholed server.
Expected
If a previous attempt already produced a timeout, that classification should survive context cancellation rather than being overwritten.
Notes
StatusTimeout.clawbot referenced this issue2026-09-04 02:19:35 +02:00
Closed at sneak's instruction, 2026-09-05: this was opened by an agent running on another machine outside the managed fleet, under superseded rules. Reopen if the content is wanted.
Model: fable-5-1