Commit 28256282b7 for bind

commit 28256282b7226f2f78c0d64463613e78e8c9bd5e
Merge: 4246025b59 93eb1cd924
Author: Štěpán Balážik <stepan@isc.org>
Date:   Thu Sep 24 07:40:20 2026 +0000

    chg: test: Declare asyncserver response handler matching with composable matchers

    `isctest/asyncserver.py` had grown past 2000 lines, mixing the servers with the DNSSEC provers, the response handlers, the actions and the control commands, and every new helper landed next to the servers. It is now a package: the root keeps the architecture (the servers and the abstract handler, action and command classes), each concrete set lives in its own submodule, and the custom servers import names from the module defining them, so an import header says which part of the framework a server uses.

    Matching was spread over two mechanisms: hand-written `match()` methods, which hide the criteria in a method body, and the declarative `QnameHandler`/`QnameQtypeHandler`/`DomainHandler` bases, which fix one combination each and cannot be composed. Combining a matching base with an answering base meant multiple inheritance with both sides defining `match()`, as noted in [the review of !12526](https://gitlab.isc.org/isc-projects/bind9/-/merge_requests/12526#note_737170): `class SigAxfrHandler(QnameQtypeHandler, AxfrHandler)` answers the right queries only because the MRO happens to pick `QnameQtypeHandler.match()` over `AxfrHandler.match()`. And, [from !12525](https://gitlab.isc.org/isc-projects/bind9/-/merge_requests/12525#note_737181), a `QnameHandler` subclass could be given a `qtypes` attribute that silently did nothing. Both mechanisms are replaced by a `matcher` attribute a handler declares, built from small matchers (`Qname`, `Qtype`, `Domain`, `Protocol`, `Edns`, label tests, `Once`) combined with `&`, `|` and `~`: a handler derives from what it answers with and declares what it answers to, and there is one place to look. A matcher is data: the server logs it when it picks a handler, a handler can read what it was declared with back (`matcher.of(Qname).qnames`), and the stateful cases (`Domain.matched_domain`, the first-query and transfer-state flags) keep their state in the matcher instead of in flags flipped from matching code. Criteria specific to one test (the reclimit name shape, a zone lookup) are matchers local to that server. With every handler converted, the `match()` method and the three declarative bases are removed.

    Merge branch 'stepan/asyncserver-matchers' into 'main'

    See merge request isc-projects/bind9!12725