The previous fix was too blunt: under OR it sent NO constraint tree at
all, so "library = ebooks" stopped narrowing the author menu the
moment an OR-connected author rule appeared. The user spec is subtler:
library = ebooks AND (author = Lewis Carroll OR author = ?)
→ the menu shows EBOOK authors, with Lewis Carroll OFF the list.
suggestTree now walks root → edited rule and builds one conjunctive
chain:
- ALL-group siblings stay (AND narrows: the ebook scope persists);
- ANY-group siblings drop — they are independent alternatives under
OR and must not narrow;
- EXCEPT a same-field ANY sibling, whose picked values NEGATE into
the chain (contains → not_contains, is → is_not, in → not_in): the
picked value leaves the menu, everything else in scope stays;
- an ALREADY-NEGATED sibling picks nothing to take off, so it drops
rather than flipping positive (a positive flip would narrow);
- a field without a negation twin falls back to dropping;
- incomplete rules never constrain (not filters yet), and the edited
rule itself never constrains its own menu.
Pins: the user's exact tree (ebook scope kept + Lewis Carroll negated
off), the root-OR variant (different-field sibling drops, same-field
negates), the twinless fallback, plus the existing AND/OR cases —
34 filter-builder vitest cases green, container filter slice green
(TestFilterSuggestionsUnderRules unaffected: the server contract is
unchanged, only which qf the client composes).