Where: faircode/detect.py's _token_matches (prefix matching for keywords of 4+ chars).
The gap: a previous issue (#372) documented and tested classify_name("birth_state") resolving to "age" as an intentional keyword-precedence case. This is a different, unaddressed failure mode: plain prefix matching on a single-word token produces genuine false positives that were never a precedence question at all - the word itself just happens to start with a demographic keyword. Verified directly:
>>> from faircode.detect import classify_name
>>> classify_name('raceway')
'race'
>>> classify_name('statement')
'geography'
>>> classify_name('stateless')
'geography'
>>> classify_name('countryside')
'geography'
>>> classify_name('citycenter')
'geography'
>>> classify_name('regional_manager')
'geography'
None of these column names have anything to do with race or geography - _token_matches matches because "raceway".startswith("race"), "statement".startswith("state"), etc., and _tokens() only splits on separators/camelCase, so a single lowercase compound word stays one token.
Why it matters: a genuinely non-demographic column (raceway_id in a motorsports dataset, financial_statement, regional_manager) gets auto-detected and profiled as a protected attribute, skewing every downstream score/flag - the opposite failure mode from the false-negative cases test_classify_rejects_false_positives already guards (Agency_Text, Language, LegalStatus).
Suggested fix: tighten _token_matches so a prefix match on a 4+ char keyword only counts when the remainder of the token is empty or itself starts a recognizable word boundary (e.g. digit or the token ending exactly at the keyword), rather than matching an arbitrary lowercase suffix - or move ambiguous stems like race/state/city/region to exact-match-only.
Where:
faircode/detect.py's_token_matches(prefix matching for keywords of 4+ chars).The gap: a previous issue (#372) documented and tested
classify_name("birth_state")resolving to"age"as an intentional keyword-precedence case. This is a different, unaddressed failure mode: plain prefix matching on a single-word token produces genuine false positives that were never a precedence question at all - the word itself just happens to start with a demographic keyword. Verified directly:None of these column names have anything to do with race or geography -
_token_matchesmatches because"raceway".startswith("race"),"statement".startswith("state"), etc., and_tokens()only splits on separators/camelCase, so a single lowercase compound word stays one token.Why it matters: a genuinely non-demographic column (
raceway_idin a motorsports dataset,financial_statement,regional_manager) gets auto-detected and profiled as a protected attribute, skewing every downstream score/flag - the opposite failure mode from the false-negative casestest_classify_rejects_false_positivesalready guards (Agency_Text,Language,LegalStatus).Suggested fix: tighten
_token_matchesso a prefix match on a 4+ char keyword only counts when the remainder of the token is empty or itself starts a recognizable word boundary (e.g. digit or the token ending exactly at the keyword), rather than matching an arbitrary lowercase suffix - or move ambiguous stems likerace/state/city/regionto exact-match-only.