docs: require configuration-path tests for new recognizers - #2211
docs: require configuration-path tests for new recognizers#2211omri374 wants to merge 7 commits into
Conversation
Recognizers are tested by constructing them in Python. Nothing tests the path users take, which is enabling them in a registry YAML. 61 of the 86 entries in default_recognizers.yaml ship disabled, so their constructors are never exercised from configuration at all. Enabling every entry in isolation shows three that raise on construction (UsMbiRecognizer, KrBrnRecognizer, KrDriverLicenseRecognizer: __init__ rejects the 'name' key the loader passes), and 31 that load nothing because their languages are excluded by the top-level supported_languages filter, silently. Adds a required configuration-path test, plus guidance drawn from recurring review findings: enabled-by-default framed as false-positive surface rather than geography, score bands matching the codebase, substring context matching, exact score assertions, lookalike negatives, and a backward-compatibility section. Also corrects the SSN test example, which used 123-45-6789 as a true positive. That value is on the recognizer's sample-SSN denylist and returns no results.
Coverage report (presidio-anonymizer)Click to see where and how coverage changed
This report was generated by python-coverage-comment-action |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Coverage report (presidio-structured)Click to see where and how coverage changed
This report was generated by python-coverage-comment-action |
||||||||||||||||||||||||
Coverage report (presidio-cli)Click to see where and how coverage changed
This report was generated by python-coverage-comment-action |
||||||||||||||||||||||||
Clarified scoring criteria for strong patterns in the instructions.
There was a problem hiding this comment.
Pull request overview
Updates the repository’s Copilot contributor guidance for Presidio recognizers to require configuration-path testing (enabling recognizers via YAML and loading through RecognizerRegistryProvider) and to align recognizer/testing guidance with current loader behavior and maintainer practices.
Changes:
- Adds a new requirement that new recognizers include at least one test which enables the recognizer in a YAML registry config and asserts detection through
RecognizerRegistryProvider. - Refines recognizer design/testing guidance (score bands, thresholds vs hard context requirements, substring context matching behavior, and exact-score assertions).
- Fixes the SSN documentation example to avoid denylisted sample SSNs and adds troubleshooting/backward-compatibility guidance.
Coverage report (presidio-image-redactor)Click to see where and how coverage changed
This report was generated by python-coverage-comment-action |
||||||||||||||||||||||||||||||||||||
Coverage report (presidio-analyzer)Click to see where and how coverage changed
The report is truncated to 25 files out of 79. To see the full report, please visit the workflow summary page. This report was generated by python-coverage-comment-action |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.
Suppressed comments (5)
.github/copilot-instructions.md:65
- The repo already has a non-full-name country directory (
presidio_analyzer/predefined_recognizers/country_specific/thai/), so stating that onlyus/ukare exceptions is inaccurate and can confuse contributors. Either listthaias an existing exception or relax the rule to match current layout.
Directory names are the full lowercase country name (`south_africa`, `philippines`,
`canada`), not the ISO country code. The only exceptions are the pre-existing `us`
and `uk` directories. Do not add new abbreviated directories.
.github/copilot-instructions.md:108
- The
LemmaContextAwareEnhancerconstructor parameter iscontext_matching_mode, notmatching_mode; using the wrong name here will lead to incorrect guidance/snippets.
**Context words are matched as substrings.** `LemmaContextAwareEnhancer` defaults to
`matching_mode="substring"`, so short context words fire on unrelated tokens.
.github/copilot-instructions.md:69
- This language-code guidance conflicts with current code/config:
default_recognizers.yamlincludeskrinsupported_languagesfor Korean recognizers andKrPassportRecognizerdefaultssupported_language="kr". Clarify thatkris a legacy literal tag and that ISO 639-1 (ko) should be used to avoid recognizers being filtered out when users pass standard language codes.
Language codes are different: `supported_language` and the YAML `supported_languages`
key take ISO 639-1 language codes (`ko` for Korean), not country codes (`kr`). A
mismatch here produces a recognizer that never loads.
.github/copilot-instructions.md:100
UsBankRecognizeruses score 0.05 for its 8-17 digit pattern, which falls in the table’s “very weak” band; calling it a “weak score” here is misleading given the new score-band guidance. Consider stating the exact score instead to keep the example consistent.
Compare against existing recognizers before choosing: `UsPassportRecognizer` uses
0.05 for nine bare digits, `UsBankRecognizer` uses a weak score for 8-17 digits.
.github/copilot-instructions.md:202
- The configuration-path test example references an undefined
nlp_enginevariable, so it won’t run as written. Defining a lightweight engine (e.g.,NoOpNlpEngine) in the snippet makes it copy/pasteable and avoids requiring spaCy model downloads for pattern-only recognizers.
registry = RecognizerRegistryProvider(
conf_file=conf
).create_recognizer_registry()
analyzer = AnalyzerEngine(registry=registry, nlp_engine=nlp_engine)
Replaces the enabled-by-default criteria, which used the presence of a checksum as a gate. Most patterns have no checksum: about 40% of the predefined PatternRecognizer subclasses do not override validate_result, and that is the right choice when the entity has no verifiable structure. Coincidental matches are also not the problem. A generic pattern scored at 0.05 costs nothing, because a threshold removes it while context or validation can still lift a real match. The disqualifier for shipping enabled is a coincidental match that arrives at a score no threshold can separate from a true positive. Adds a section covering the hooks as a generic capability: True replaces the score with MAX_SCORE, False drops the result, None leaves the pattern score alone. Spells out that a check which is only mandatory across part of the entity's range can promote but never invalidate, so it inflates coincidental matches to full confidence while genuine lookalikes keep the base score. The previous wording compressed this into one unclear sentence.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.
Suppressed comments (1)
.github/copilot-instructions.md:65
- The guidance says the only abbreviated country-specific directory names are
usanduk, but the current codebase also includescountry_specific/thai/(e.g.,th_tnin_recognizer.py), so the statement is inaccurate and could mislead contributors.
Directory names are the full lowercase country name (`south_africa`, `philippines`,
`canada`), not the ISO country code. The only exceptions are the pre-existing `us`
and `uk` directories. Do not add new abbreviated directories.
59a7f1e to
f594c3d
Compare
Adds a repo-local code review skill that captures the recognizer testing, scoring, and backward-compatibility practices established in PR #2211. The skill classifies a diff (recognizer change vs. shared-class change) and applies matching checklists. Its load-bearing rule: any PR adding or changing a recognizer must include a configuration-path test that loads the recognizer through RecognizerRegistryProvider and asserts detection, since predefined recognizers ship enabled: false and are otherwise never exercised on the path users actually take. A references file provides the test template and the full list of defects the test catches. Also covers score-band calibration, validate_result promotion pitfalls, context-substring matching, exact-score/lookalike-negative test requirements, and backward-compatibility review for changes to shared library classes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013ck825cANTDYre5UCfmpYE
Adds .github/instructions/recognizer-review.instructions.md, a review-only, path-scoped GitHub Copilot custom-instructions file. It applies to recognizer sources, default_recognizers.yaml, and recognizer tests, and directs Copilot code review to require a RecognizerRegistryProvider configuration-path test, check construction-path agreement and backward compatibility, and enforce the score-calibration, validate_result, context-word, and test-quality rules captured in the recognizer-pr-review skill. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013ck825cANTDYre5UCfmpYE
- Use context_matching_mode (the actual LemmaContextAwareEnhancer constructor parameter) instead of matching_mode. - Correct the directory-naming note: thai/ (and us/uk) are pre-existing short forms not to imitate, rather than claiming only us/uk are exceptions. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013ck825cANTDYre5UCfmpYE
Change Description
Adds a required configuration-path test for new recognizers, and corrects several pieces of guidance that do not match current maintainer practice or current behavior.
Why
Recognizers are tested by constructing them in Python. Nothing tests the path users take, which is flipping
enabled: truein a registry YAML.default_recognizers.yamlenabled: falseEnabling every entry in isolation, with the entry's own languages, surfaces defects that Python-only tests cannot see:
The loader passes the YAML
namekey to the constructor. These three classes do not accept it, so enabling any of them raises and takes down construction of the whole registry. Reproduced throughRecognizerRegistryProvider.AzureAILanguageRecognizerandKrPassportRecognizershare the gap but are not reachable from the shipped config.Two more in the same family:
supported_languagesis["en"]. Settingenabled: trueon any of them loads nothing, with no error or warning.KrPassportRecognizerdefaults tosupported_language="kr". Its four siblings useko, and the YAML lists both codes for those siblings.What changed
New requirement
RecognizerRegistryProvideradd_recognizer(), configuration)Corrected guidance
(weak)/(very weak)in the pattern namepresidio-structuredneeds context-free detectionmemberfires onrememberandauthonauthor. Context is also prefix-only by defaultBug fix in the docs
123-45-6789as a true positive. That value is on the recognizer's sample-SSN denylist and returns no results, so the example as written fails. The "False positive prevention" case using the same value passed for the wrong reason. Replaced with456-78-9012and moved the denylisted value to the true-negative groupFollow-ups, not in this PR
name: Optional[str] = Nonein its constructor. Small and separable.CHANGELOG.md, but open and merged PRs do. Either a CI check should enforce it or the rule should be dropped, since an unenforced rule teaches contributors to skim the file. Left unchanged here because the decision is yours.Checklist