Skip to content

fix(pii): post-merge review fixes + live NER e2e for the privacy-filter tier#10401

Open
richiejp wants to merge 2 commits into
mudler:masterfrom
richiejp:fix/pii-ner-tier-engine
Open

fix(pii): post-merge review fixes + live NER e2e for the privacy-filter tier#10401
richiejp wants to merge 2 commits into
mudler:masterfrom
richiejp:fix/pii-ner-tier-engine

Conversation

@richiejp

Copy link
Copy Markdown
Collaborator

Description

A bunch of fixes and an e2e test for NER

Notes for Reviewers

Follow-up to the NER tier engine (#10360), already on master. This carries
only the incremental review fixes and tests that postdate that merge — the
feature itself is not re-introduced.

Review fixes:

  • openai_completion.go: remove the dead elem >= 0 conjunct in applyAnyText
    (the elem < 0 guard above already returns).
  • application.go: collapse ResolvePIIPolicy's inline re-implementation of
    PIIIsEnabled to a single cfg.PIIIsEnabled() call (sole source of the
    "explicit pii.enabled wins, else cloud-proxy default" rule) and return true
    past the !enabled guard where it is provable.
  • pattern.go: hoist the triple appConfig != nil && EnableTracing check in
    patternDetector.Detect into one local.
  • grammar.go: MaxQuantifier was 4096, but Go's regexp/syntax rejects repeat
    bounds above 1000 at Parse time, so walk()'s {n,m} guard could never fire —
    dead code shadowed by the parser. Lower it to 512 so a bound in (512,1000]
    is rejected here with an actionable error; >1000 still fails closed via
    Parse. Specs pin the relationship so the guard can't silently revert.
  • PatternListEditor.jsx: clamp a directly-typed negative min_len to >=0 and
    force the DOM value back when clamping (min={0} only constrained the spinner,
    so a negative reached saved config and silently disabled the length filter).

Tests:

  • piipattern_test.go: MaxQuantifier guard specs (must stay live, not dead).
  • model-config.spec.js: assert the min_len clamp, and that entity_actions
    collapses a duplicate group to a single row (map semantics; regression guard
    against emitting an array that drops a row on save).
  • tests/e2e-backends: token_classify capability driving the TokenClassify gRPC
    RPC against the backend image, asserting byte-correct, UTF-8 rune-aligned
    spans (entity.Text == text[start:end]) at threshold 0. Verified on CPU via
    make test-extra-backend-privacy-filter (3/3 specs).
  • Makefile: test-extra-backend-privacy-filter wrapper.
  • tests/e2e: e2e_pii_ner_test.go drives /api/pii/analyze + /api/pii/redact
    (mask + block) through the full HTTP -> detector -> redactor path; gated on
    PII_NER_MODEL_GGUF so the default suite is unaffected.
  • .github/workflows/tests-pii-ner-e2e.yml: path-filtered / nightly CI job
    running the container harness on CPU.

Assisted-by: Claude:claude-opus-4-8 [Claude Code]
Signed-off-by: Richard Palethorpe io@richiejp.com

Signed commits

  • Yes, I signed my commits.

richiejp added 2 commits June 19, 2026 10:58
…er tier

Follow-up to the NER tier engine (mudler#10360), already on master. This carries
only the incremental review fixes and tests that postdate that merge — the
feature itself is not re-introduced.

Review fixes:
- openai_completion.go: remove the dead `elem >= 0` conjunct in applyAnyText
  (the `elem < 0` guard above already returns).
- application.go: collapse ResolvePIIPolicy's inline re-implementation of
  PIIIsEnabled to a single cfg.PIIIsEnabled() call (sole source of the
  "explicit pii.enabled wins, else cloud-proxy default" rule) and return true
  past the !enabled guard where it is provable.
- pattern.go: hoist the triple `appConfig != nil && EnableTracing` check in
  patternDetector.Detect into one local.
- grammar.go: MaxQuantifier was 4096, but Go's regexp/syntax rejects repeat
  bounds above 1000 at Parse time, so walk()'s {n,m} guard could never fire —
  dead code shadowed by the parser. Lower it to 512 so a bound in (512,1000]
  is rejected here with an actionable error; >1000 still fails closed via
  Parse. Specs pin the relationship so the guard can't silently revert.
- PatternListEditor.jsx: clamp a directly-typed negative min_len to >=0 and
  force the DOM value back when clamping (min={0} only constrained the spinner,
  so a negative reached saved config and silently disabled the length filter).

Tests:
- piipattern_test.go: MaxQuantifier guard specs (must stay live, not dead).
- model-config.spec.js: assert the min_len clamp, and that entity_actions
  collapses a duplicate group to a single row (map semantics; regression guard
  against emitting an array that drops a row on save).
- tests/e2e-backends: token_classify capability driving the TokenClassify gRPC
  RPC against the backend image, asserting byte-correct, UTF-8 rune-aligned
  spans (entity.Text == text[start:end]) at threshold 0. Verified on CPU via
  `make test-extra-backend-privacy-filter` (3/3 specs).
- Makefile: test-extra-backend-privacy-filter wrapper.
- tests/e2e: e2e_pii_ner_test.go drives /api/pii/analyze + /api/pii/redact
  (mask + block) through the full HTTP -> detector -> redactor path; gated on
  PII_NER_MODEL_GGUF so the default suite is unaffected.
- .github/workflows/tests-pii-ner-e2e.yml: path-filtered / nightly CI job
  running the container harness on CPU.

Assisted-by: Claude:claude-opus-4-8 [Claude Code]
Signed-off-by: Richard Palethorpe <io@richiejp.com>
GGUF conversions of OpenMed/privacy-filter-nemotron — a fine-grained English
PII token-classifier (55 categories / 221 BIOES classes), fine-tuned from
openai/privacy-filter on NVIDIA's Nemotron-PII dataset. Sibling to the existing
privacy-filter-multilingual entry, trading language breadth for category depth.

- privacy-filter-nemotron: F16 reference artifact (~2.8 GB).
- privacy-filter-nemotron-q8: Q8_0 quant (~1.64 GB) for RAM-constrained / edge
  use; description notes the size/speed tradeoff and to validate on your own
  data (a single dropped span is a PII leak).

Both run on the privacy-filter backend with known_usecases [token_classify] and
a default mask policy (min_score 0.5); operators add per-category entity_actions
as needed. sha256s taken from the HF repo's LFS object ids.

Assisted-by: Claude:claude-opus-4-8 [Claude Code]
Signed-off-by: Richard Palethorpe <io@richiejp.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant