Repository navigation
feat(detection): add regex entity detection - #265
lipikaramaswamy wants to merge 6 commits into
Conversation
[High impact] The PR appears safe to merge, with no new actionable findings. SummaryAdds regex detection alongside GLiNER and LLM detection.
|
|
/nvskills-ci |
|
The overall direction makes sense, and regex plus GLiNER as independent Data Designer columns feels like a solid first step toward layered detection. I don't think this PR needs to build the full multi-detector framework. Keeping the public regex API and focusing here on correct two-source behavior seems like the right scope. Could we capture a follow-up issue or design for the general framework? I'd include a shared candidate/outcome shape with multiple origins, one independently schedulable column per detector, generic fan-in, overlap resolution after validation, and per-detector preparation, resource, timeout, and failure contracts. A useful acceptance test would be adding a dummy third detector without changing fan-in, while producing identical results regardless of completion order. That follow-up could also replace the currently missing multi-pole design referenced by this plan. |
|
/nvskills-ci |
There was a problem hiding this comment.
agent (review-pr): Request changes — correctness fixes and integration work remain
local human-driven agent review found a few more bits, in addition to the outstanding comments:
-
Medium: URL validation accepts malformed hosts.
regex_detection.py:_validate_url()accepts any IDNA-encodable host containing a dot, includinghttp://-bad.comandhttp://999.999.999.999/path, withvalidate_with_llm=False. These false positives reduce detection precision and can cause unnecessary replacement of text. Define the intended hostname policy, validate IP-shaped hosts withipaddress, and validate DNS-style labels before accepting them. -
Low: callable serialization succeeds but produces an unusable configuration.
RegexRuleserializes a callable asmodule:qualname, but restored configurations cannot resolve that representation. Direct callables are documented as in-process only; serialization should fail clearly at that boundary instead of emitting a value that later fails as an unknown validator. -
Previously reported:
CASE\Kstill permits a zero-width match.
Configuration accepts the pattern, then runtime matching produces(4, 4)and drops the row. Width analysis needs to account forcore.Keep. -
Previously reported: generated files still lack SPDX headers.
Signing regeneration removed headers fromBENCHMARK.mdandskill-card.md, and the copyright check still fails. Fix the generator before restoring the headers. The restored files will have different hashes, so regenerate and signskill.oms.sigafter their final contents are settled.
The PR also conflicts with current main across detection code, configuration, tests, interface code, and skill artifacts. This is an integration gate. Conflict resolution must preserve both regex detection and the newer entity-exclusion behavior.
Local validation at 49ea1652: 1341 passed; format and type checks passed; copyright check failed on the two generated Markdown files.
Prompts for managed agents
Agents 1–3 own the fixes below; Agent 4 owns final integration. Each agent should preserve other agents’ changes and report the files changed, validation results, and any unresolved issues.
Agent 1 — URL validation
Fix built-in URL host validation in src/anonymizer/engine/detection/regex_detection.py. Reproduce acceptance of http://-bad.com and http://999.999.999.999/path, and establish the current underscore-host behavior, using BuiltinRegex(label="url", validate_with_llm=False). Define the intended hostname policy, validate IP-shaped hosts with ipaddress, and validate DNS-style labels consistently with IDNA support. Preserve valid Unicode domains, bracketed IPv6 hosts, ports, balanced delimiters, and exact offsets. Add focused positive and negative tests. Keep changes scoped to URL validation.
Agent 2 — regex configuration boundaries
Fix two configuration issues without enabling arbitrary imports. First, reject patterns such as r"CASE\K" during RegexRule validation by accounting for regex._regex_core.Keep semantics; retain the runtime zero-width backstop. Second, make JSON serialization of direct callable validators fail clearly, preserving the documented rule that only registered entry-point names are portable. Add tests covering RegexRule and Detect JSON round trips with registered names, serialization failures for top-level callables, and \K validation. Preserve validator trust boundaries.
Agent 3 — generated skill artifacts
Identify why NVSkills regeneration removes repository SPDX headers from skills/anonymizer/BENCHMARK.md and skills/anonymizer/skill-card.md. Fix the producing template or generation step so future runs retain the headers, then regenerate both files. Renew skills/anonymizer/skill.oms.sig only after the final bytes are stable, and run the copyright and skill-package checks. Coordinate with Agent 4 so any artifact changes during integration are followed by regeneration and signing.
Agent 4 — rebase and integration
Integrate the fixes and rebase PR 265 onto current main, resolving conflicts semantically. Preserve both regex detection and the newer entity-exclusion/denylist behavior through AnonymizerConfig, interface plumbing, detection workflow columns, postprocessing, and tests. Regenerate signed skill artifacts after source conflicts are resolved, and coordinate final signing with Agent 3. Run make test, make format-check, make typecheck, and make copyright-check. Report any remaining conflicts or failed checks without discarding either feature to complete the merge.
|
Addressed review items 1–3 in dd5bf2e:
Focused tests and the full 1,352-test suite pass; formatting, lint, and type checks pass. |
|
Merge-resolution note on
Added integration coverage for excluded custom-regex labels and locally accepted regex matches at both the pre-augmentation and finalization boundaries. The merged suite passes locally (1,467 tests), and the Python 3.11/3.12/3.13 CI jobs pass. @memadi tagging you for visibility since you authored the excluded-labels change. The merge keeps its original early filtering behavior and extends the safety-net filtering to the new regex routes. |
binaryaaron
left a comment
There was a problem hiding this comment.
agent (
review-pr): Three reproducible correctness issues remain.
Verified against 39c31515. The stale-decision replay issue is fixed, including a passing regression. Three additional correctness issues remain reproducible: normalized entity identity, regex precedence through augmentation, and export checks on excluded rules. These need bounded internal fixes; no public API changes are required. The existing custom-column suite passes (52 tests), but four targeted cases still fail across these three findings.
memadi-nv
left a comment
There was a problem hiding this comment.
Left one nice-to-have suggestion, and two medium-priority issues that I think is better to be addressed before merge. Overall, the implementation looks good. Thanks, Lipika!
39c3151 to
605460b
Compare
| ResolvedRegexRule( | ||
| rule_id="nemo-anonymizer.url.v1", | ||
| label="url", | ||
| pattern=rf"(?i)(?<![A-Za-z0-9_+./:@-])(?:(?:{'|'.join(_URL_SCHEMES)})://|www\.)[^\s<>\"']+", |
There was a problem hiding this comment.
The new start boundary rejects URLs immediately after an ASCII colon, such as url:https://example.org/private/alice. These matched before this change. With BuiltinRegex(label="url", detect_additional_matches=False), the models cannot recover the missed URL, so it remains unredacted. Distinguish unsupported scheme prefixes from ordinary prose or key-value separators instead of rejecting every preceding colon.
There was a problem hiding this comment.
Pushed a deliberately narrow fix in 0937044e: a standalone, case-insensitive url: / URL: prefix can precede any supported network scheme or www. form without a space. The lookbehind excludes the prefix from the matched span, so offsets and redaction affect only the URL. Tests cover case variants, all supported locator forms, both LLM-validation settings, and exported offline preview/create through final redaction. myurl:, _url:, custom:url:, git+https://, and s3://www... remain rejected.
Scope decision: this is NOT a blanket allowance for preceding colons. Visit:https://... and custom:https://... remain outside the built-in's conservative scope; whitespace or a custom rule is required, and the limitation is documented. It fixes the reported url:https://... example but is narrower than your general prose/key-value request, so I am leaving the thread open for agreement on that policy.
Verification at 0937044e: 629 relevant config/public-API/skill/matcher/lifecycle/export/candidate/admission tests passed with the PR's locked dependencies; normal commit hooks, including aggregate make check and DCO, passed. This is local deterministic regression evidence, not a new model benchmark.
Luna-only benchmark results and interpretationResults at commit Comparison and coverageBoth arms returned all 617/617 annotated records across the seven workloads below. The only intended configuration change was The following counts measure full annotated-target character coverage by final replacement spans, irrespective of predicted label. They are not label-aware recall or precision.
There were 16 target-coverage gains and 21 losses, rather than five identical records simply becoming worse. These totals include non-regex labels; fresh stochastic validation/augmentation can change those independently of the regex flag. Both annotated FTP URL targets had accepted regex URL coverage with validation OFF and remained covered as URLs with validation ON (2/2 in each arm). Offline checks passed for source-text identity, exact source-span consistency and actual Annotate replacement application on the paired records; there were no skipped replacement spans. These mechanical checks do not prove semantic boundary correctness. SWE is separate and has no gold targets: the OFF arm returned 95/100, with five failed deliveries; the ON arm was still running at the reporting snapshot. SWE is excluded from the coverage table. Failed deliveries are not counted as privacy leaks. What the contextual audit foundThe annotated cohort produced the same 274 regex candidate occurrences in both arms: 150 emails, 47 card-shaped numbers, 48 URLs, 21 IPv4, four IPv6 and four MAC addresses. These are candidate counts, not unique values or necessarily distinct final spans; overlap reconciliation can suppress nested candidates. LLM validation rejected 14 email candidates and reclassified three card-shaped candidates to A single Codex-agent source-context audit found that all 14 rejected email candidates included an underlying contact email plus adjacent text. For example, a synthetic dialogue can contain Under a strict, context-interpreted email-boundary rubric, exact agreement was 125/150 OFF versus 125/136 accepted ON. However, this is not independently human-verified precision, and it is not universal correctness: separator-free text can be ambiguous, and interpreting dialogue markers or multilingual boundaries is a user-policy decision. We should not infer a general fix from dataset-specific speaker names, a domain-ending shortlist, or ASCII-only restrictions. The important end-to-end trade-off is that rejecting the larger candidate did not reliably preserve its sensitive portion: 12 of the 14 underlying email occurrences were uncovered in the final ON output. Two were recovered elsewhere under an The broader review also found a URL candidate including closing citation punctuation and card-shaped candidates representing other identifier types. Many recognized URLs were public/generic references: being a correctly recognized URL does not establish that it should be anonymized under a privacy-sensitive-only policy. Limits and takeawayRAT annotations are selective; unannotated predictions are not automatically false positives. Boundary judgments depend on the chosen policy, ambiguous cases remain unresolved, and this was a single-agent audit rather than independent adjudication. There is no regex-disabled baseline here, so this comparison does not establish the overall benefit of adding regex detection. Takeaway: the optional contextual validation path can reject or reclassify format-valid candidates, but keep/drop decisions can trade coverage for narrower interpretation. Report that trade-off explicitly; do not claim universal precision improvement or add dataset-specific boundary heuristics based on this cohort alone. Raw texts, identifiers and responses remain private. |
Build regex detection on PR #305. Preserve bounded matching, local validators, per-rule admission routes and regex-only labels while using the shared observation admission and reconciliation path. Keep rule claims independent until admission and require exact accepted regex evidence for model-derived regex-only labels. Do not restore value propagation or replay validator decisions during finalization. Signed-off-by: lipikaramaswamy <lramaswamy@nvidia.com>
Signed-off-by: lipikaramaswamy <lramaswamy@nvidia.com>
Signed-off-by: lipikaramaswamy <lramaswamy@nvidia.com>
Signed-off-by: lipikaramaswamy <lramaswamy@nvidia.com>
Signed-off-by: Lipika Ramaswamy <lipika.ramaswamy@gmail.com>
Signed-off-by: Lipika Ramaswamy <lipika.ramaswamy@gmail.com>
0937044 to
57bf32a
Compare
Related Issue
Fixes #262.
Plan Document
Hybrid regex entity detection plan
Summary
Adds regex-based entity detection as a first-class detection source alongside GLiNER and LLM detection.
Detect.regex_rulesconfiguration surface for built-in customization and user-defined rules.Type of Change
Contributor Checklist
type(scope): description).Validation
TMPDIR=/tmp make test— 1312 passed, 1 warning.make format-check— passed.ty checkfor changed files — passed.make docs-buildfrom a clean worktree at this commit — passed.Documentation and Artifacts
make docs-buildpasses locally.PR stack
Merge/review order: #305 → #267 → #335.
main.After a parent is squash-merged, restack the remaining child commits onto the updated parent/
mainand retarget their PRs as appropriate. These links describe dependency order, not approval or CI status.