Selector
An immutable description of one accessibility node.
Build one with the top-level functions (text, res, desc, ...), narrow it with the methods below and combine selectors with and / or; each call returns a new selector. Bind it with App.element for package ownership or Screen.element for whatever is visible. Mutations require exactly one match.
A Selector builds the server API's tap.v1.Selector, a small expression tree that the server forwards to the driver unchanged, so anything built here is validated identically by the server and the driver; render shows that tree, and exceptions quote it. Building a selector performs no I/O; each terminal action resolves it again.
Functions
Both must hold on the same node: text("Add") and clickable(). The result keeps this selector's scope and match choice; other must not carry its own match choice (first/at) or a different scope, because a node predicate cannot express either and silently dropping them would target a different element.
Also require this widget class name.
An element matching other somewhere below this one. The result keeps other's match choice and this selector's scope. This selector must not carry a match choice itself: the ancestor is a bare predicate, so list.at(2).descendant(x) would otherwise search under every list. Narrow the ancestor with predicates instead, or pick among the results (list.descendant(x).at(2)).
Keep matching this node, but only when an ancestor matches other.
This element must have a descendant matching other: res("card").hasDescendant(text("Play")).
Require isLongClickable == value.
Require isScrollable == value.