This requires a decision.
In filter.go, filterOpNegContains and filterOpNegGlob both return false when the field is absent:
goif seg.filterOp == filterOpNegContains {
fv := fieldValue(v, seg.name)
if fv == nil {
return false // <-- surprising
}
Semantically, [Tags!~devops] reads as "Tags does not contain devops". If the element doesn't have a Tags field at all, most users would expect that to be true (it certainly doesn't contain devops). Today it's treated as false — absent fields fail negative filters.
This matters for mixed-type slices where some element types have the field and others don't. ..[Status!=retired] on a slice of heterogeneous records silently drops records that don't even have a Status field.
Before changing anything, write tests for:
[Tags!~devops] with an element missing the Tags field — should match (absence means no devops tag)
[Status!=retired] with an element missing Status — should match
Corresponding positive cases: [Tags~devops] with absent Tags — should NOT match (already correct)
[Status=active] with absent Status — should NOT match (already correct)
Confirm the negative cases fail today. Decide and document: does "absent = negative filter passes" apply to ALL negative forms (!!, !=, !~)? Currently !! does match-on-absence. Make != and !~ consistent with !!. Update the README to state this invariant explicitly: "negative filters (!!, !=, !~) treat missing fields as matching; positive filters treat missing fields as non-matching."
This requires a decision.