Summary
Expand engine explain so CompiledDetection::ArrayMatch (and element-scoped Conditional bodies) record per-member and per-predicate traces, including nested array scopes, while keeping the production evaluator untouched and the explain verdict identical to eval.
Motivation
Shipped #270 collapses array object-scope into an opaque DetectionTrace::Other leaf (PASS/FAIL array_match "field" Quantifier). Authors debugging #159 array-matching rules cannot see which member or predicate decided the quantifier, and nested scopes (rules[any].ip[all]|...) stay equally opaque. Production eval already walks members; explain never records that walk.
Proposed approach
- Factor relative-field /
element_field / array-item helpers shared by the compiler and explain so binding cannot drift.
- Replace the opaque
Other path with DetectionTrace::ArrayMatch, ArrayMemberTrace, and DetectionTrace::Conditional for extended bodies; recurse for nested ArrayMatch.
- Non-short-circuiting recording walk; quantifier verdict from the full member list; keep
explain_rule(...).matched == evaluate(...).is_some().
- Truncation cap 32 per
ArrayMatch node: failing members first, then matching, then index order; set truncated/omitted when capped.
- CLI human tree with
member[i] and nested array_match; JSON/NDJSON full tree; CSV/TSV summary-only for array nodes in v1.
- Land on
feat/explain-array-match with docs, rsigma-eval README, and CHANGELOG (not the docs overhaul branch).
Out of scope
- Changing production
matched_fields / --match-detail for arrays.
- Exploding CSV/TSV into full nested paths.
- Convert backends or lint rules.
Tasks
References
- Shipped array matching and explain/introspect toolkit
crates/rsigma-eval/src/explain/mod.rs, crates/rsigma-eval/src/compiler/mod.rs
crates/rsigma-cli/src/commands/explain.rs, crates/rsigma-cli/tests/cli_explain.rs
Summary
Expand
engine explainsoCompiledDetection::ArrayMatch(and element-scopedConditionalbodies) record per-member and per-predicate traces, including nested array scopes, while keeping the production evaluator untouched and the explain verdict identical to eval.Motivation
Shipped #270 collapses array object-scope into an opaque
DetectionTrace::Otherleaf (PASS/FAIL array_match "field" Quantifier). Authors debugging #159 array-matching rules cannot see which member or predicate decided the quantifier, and nested scopes (rules[any].ip[all]|...) stay equally opaque. Production eval already walks members; explain never records that walk.Proposed approach
element_field/ array-item helpers shared by the compiler and explain so binding cannot drift.Otherpath withDetectionTrace::ArrayMatch,ArrayMemberTrace, andDetectionTrace::Conditionalfor extended bodies; recurse for nestedArrayMatch.explain_rule(...).matched == evaluate(...).is_some().ArrayMatchnode: failing members first, then matching, then index order; settruncated/omittedwhen capped.member[i]and nestedarray_match; JSON/NDJSON full tree; CSV/TSV summary-only for array nodes in v1.feat/explain-array-matchwith docs,rsigma-evalREADME, and CHANGELOG (not the docs overhaul branch).Out of scope
matched_fields/--match-detailfor arrays.Tasks
References
crates/rsigma-eval/src/explain/mod.rs,crates/rsigma-eval/src/compiler/mod.rscrates/rsigma-cli/src/commands/explain.rs,crates/rsigma-cli/tests/cli_explain.rs