Summary
SafeHarborFinding.match_count conflates two different things: a header match
and each value match are both counted via the same _record(...) increment.
For a column whose name matches (e.g. email) and whose cells match, a dataset
of N rows reports match_count == N + 1 (one for the header, one per value).
Why it matters
Reviewers reading column 'email' - 11 hit(s) on a 10-row file are surprised by
the off-by-one, and the number is ambiguous: is it rows, or rows+header? For
audit evidence the count should be unambiguous.
Suggested fix
Track header detection separately from value detection on the finding, e.g. a
boolean matched_by_header plus a value_match_count, or simply do not
increment match_count for the header-only signal. Either way, document the
semantics of match_count in the SafeHarborFinding docstring and reflect the
choice in the SARIF message text.
Repro
from deidproof.core import safe_harbor_scan
rows = [{"email": f"u{i}@x.co"} for i in range(10)]
f = [x for x in safe_harbor_scan(rows, ["email"]) if x.rule_id == "S6"][0]
print(f.match_count) # -> 11 (10 values + 1 header)
Summary
SafeHarborFinding.match_countconflates two different things: a header matchand each value match are both counted via the same
_record(...)increment.For a column whose name matches (e.g.
email) and whose cells match, a datasetof N rows reports
match_count == N + 1(one for the header, one per value).Why it matters
Reviewers reading
column 'email' - 11 hit(s)on a 10-row file are surprised bythe off-by-one, and the number is ambiguous: is it rows, or rows+header? For
audit evidence the count should be unambiguous.
Suggested fix
Track header detection separately from value detection on the finding, e.g. a
boolean
matched_by_headerplus avalue_match_count, or simply do notincrement
match_countfor the header-only signal. Either way, document thesemantics of
match_countin theSafeHarborFindingdocstring and reflect thechoice in the SARIF message text.
Repro