@cfxlabsinc/b2b-services
    Preparing search index...
    RuleCondition:
        | {
            field: MatcherField;
            operator: "is"
            | "is_not";
            value: string | number | boolean;
        }
        | {
            field: MatcherField;
            operator: "is_one_of"
            | "is_not_one_of"
            | "contains_any"
            | "contains_none";
            value: string[];
        }
        | { field: MatcherField; operator: "is_set"
        | "is_not_set" }
        | {
            field: MatcherField;
            operator: "gt" | "gte" | "lt" | "lte";
            value: string | number;
        }
        | {
            field: MatcherField;
            operator: "between";
            value: [string | number, string | number];
        }
        | {
            field: MatcherField;
            operator: "starts_with"
            | "ends_with"
            | "contains_substring";
            value: string;
        }

    A single condition within a rule matcher. Value shape is operator-dependent so callers can't construct a nonsensical between with one bound, or is_set with a value. Scalars allow the JSON primitives that round-trip cleanly through jsonb (string | number | boolean); comparison operators stay on the numeric-coercible subset. Set-membership operators take string[] so b2b.rule_match can compare via jsonb containment without losing type fidelity — callers stringify booleans/numbers at write time (e.g. ["true", "false"], ["100", "200"]).