feat: PII Replacement V3-MVP mode - #672
Draft
nina-xu wants to merge 27 commits into
Draft
Conversation
Contributor
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Enterprise Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
nina-xu
force-pushed
the
nina-xu/pii-repl-v3-alt-config
branch
from
July 27, 2026 15:05
cf11160 to
4eb987c
Compare
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
nina-xu
force-pushed
the
nina-xu/pii-repl-v3-alt-config
branch
from
July 31, 2026 00:49
49c38bd to
baaf407
Compare
Signed-off-by: nina-xu <19981858+nina-xu@users.noreply.github.com>
…uctured columns. Write auto-discovered plans to pii_replacement_plan.yaml and omit null fields. In MVP mode, skip free-text column scanning when no replaceable structured PII is detected because there is nothing to propagate. Signed-off-by: nina-xu <19981858+nina-xu@users.noreply.github.com>
…persona only condition persona-sourced fields Signed-off-by: nina-xu <19981858+nina-xu@users.noreply.github.com>
Signed-off-by: nina-xu <19981858+nina-xu@users.noreply.github.com>
Signed-off-by: nina-xu <19981858+nina-xu@users.noreply.github.com>
Signed-off-by: nina-xu <19981858+nina-xu@users.noreply.github.com>
Signed-off-by: nina-xu <19981858+nina-xu@users.noreply.github.com>
Signed-off-by: nina-xu <19981858+nina-xu@users.noreply.github.com>
Signed-off-by: nina-xu <19981858+nina-xu@users.noreply.github.com>
Signed-off-by: nina-xu <19981858+nina-xu@users.noreply.github.com>
Signed-off-by: nina-xu <19981858+nina-xu@users.noreply.github.com>
Signed-off-by: nina-xu <19981858+nina-xu@users.noreply.github.com>
… the config Signed-off-by: nina-xu <19981858+nina-xu@users.noreply.github.com>
Signed-off-by: nina-xu <19981858+nina-xu@users.noreply.github.com>
Signed-off-by: nina-xu <19981858+nina-xu@users.noreply.github.com>
Signed-off-by: nina-xu <19981858+nina-xu@users.noreply.github.com>
Signed-off-by: nina-xu <19981858+nina-xu@users.noreply.github.com>
Signed-off-by: nina-xu <19981858+nina-xu@users.noreply.github.com>
Signed-off-by: nina-xu <19981858+nina-xu@users.noreply.github.com>
Signed-off-by: nina-xu <19981858+nina-xu@users.noreply.github.com>
Signed-off-by: nina-xu <19981858+nina-xu@users.noreply.github.com>
… issues Signed-off-by: nina-xu <19981858+nina-xu@users.noreply.github.com>
nina-xu
force-pushed
the
nina-xu/pii-repl-v3-alt-config
branch
from
July 31, 2026 18:31
d4d85dd to
5b7b975
Compare
Signed-off-by: nina-xu <19981858+nina-xu@users.noreply.github.com>
Signed-off-by: nina-xu <19981858+nina-xu@users.noreply.github.com>
Signed-off-by: nina-xu <19981858+nina-xu@users.noreply.github.com>
Signed-off-by: nina-xu <19981858+nina-xu@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR replaces the old NER / GLiNER / Jinja
data_editorPII stack with a tabular, plan-driven replacer. Detection is heuristic (column names + value patterns); replacement is deterministic given a plan, seed, and persona backend. There is no GPU NER and no LLM in this release.What users experience
When
replace_piiis enabled (the default), the pipeline still runs PII replacement on the training dataframe before training. The mechanism is new:--validatepreflight).pii_replacement_plan.yamlinto the run directory so the discovered (or used) plan can be edited and reused.Turning it off is unchanged in spirit:
replace_pii: null,--no-replace-pii, or.with_replace_pii(enable=False).Config shape (
replace_pii)Old step/NER/classify YAML (
PiiReplacerConfig) is gone. The new top-level object isReplacePiiConfig:replacement_plan"auto_discovery"(default), a path to a plan YAML, or an inline plan (config file only)replacement.locale/seedperson.backendmanaged(default, pre-generated personas),faker, or internal-onlypgmperson.managed_assets_path/sdg_pgms_srcdiscovery.replace_group_keydata.group_training_examples_byis set, that column is forced onto the plan as a standaloneunique_identifierllm_enhancementtrueraisesNotImplementedErrorat apply time (preflight warns)A plan has:
scope:record|group|dataframe— how widely one original value keeps the same synthetic valuepersona_backed_columns: named personas; columns filled from one synthetic identity; optionalmatch_persona_by(gender/ethnic_background) columns that are read onlystandalone_columns_to_replace: IDs, cards, free text, etc., replaced independentlyEach column entry is
column_name+entity_type+ optionalpatterns(formats for writing values).Important rule: the engine follows entity type, not YAML section. Putting an ID under a persona does not make it persona-sourced; putting a name only under standalone means it will not share a synthetic person with other name columns. Preflight/apply emit warnings for those mismatches; they do not rewrite the plan.
Discovery (auto plan)
With
replacement_plan: auto_discovery, discovery:free_text.scopetogroupifgroup_training_examples_byis set, elsedataframe.date/ datetime / time / duration) as identified, not replaced — logged, omitted from the plan.patternsfrom observed value shapes (names/emails as persona placeholders; DOB as strftime; IDs/phones as character templates). IPv4/IPv6 get no templates.No LLM or NER model is used.
Replacement (exact apply behavior)
Persona-sourced (from one synthetic identity when listed under a persona): names, email, street address, SSN, national ID. Phone is persona-sourced only under
pgm; undermanaged/fakerit is rebuilt from the column’s format like other identifiers.Entity-driven (stable original→synthetic map, standalone path always): unique IDs, cards, API keys, IPs, DOB (age-preserving perturbation keeping format), and non-
pgmphones.Free text: does not replace the whole cell; substitutes values already replaced elsewhere in the row (plus name tokens for partial mentions like “Dr. Smith”). Word-boundary matching; original punctuation variants are normalized for matching.
Persona backends:
managed— sampledatasets/{locale}.parquetunderNSS_MANAGED_ASSETS_PATHor~/.data-designer/managed-assets; missing assets fall back to Faker with a warning.faker— Faker personas; locale must be supported.pgm— localsdg_pgmscheckout; no fallback;en_USonly; only backend that supplies persona phone numbers.match_persona_byconditions which persona is drawn (e.g. sex→gender for name agreement). Condition columns are never replaced.After apply, column stats for the evaluation report record transform methods (
personas/Faker/PGM,pattern,perturbation,propagation).Validation and preflight
User-supplied plans are checked in preflight (
PiiPlanValidityCheck) so--validatecatches bad plans without running replacement. Errors include unknown/duplicate columns, missingentity_type,entity_type: date, patterns that don’t match values or don’t apply to that entity, group scope without a group key, and persona/matcher conflicts. Auto-discovered plans are validated when replacement runs, not in that preflight check. Separate config checks cover Faker locale, managed assets presence (warning), and PGM source (error).What was removed
NemoPII/data_editor(including Jinja/Faker template execution).replace_piistep/classify/NER config.GenExpression,GenFaker, etc.) that depended on that engine.fragment.pyand NER metadata on field features.Typed
ActionExecutoractions (distributions, UUID, date constraints, etc.) remain but are not on the default PII path.Net behavioral change vs
mainpii_replacement_plan.yamlround-tripDefault runs still replace PII automatically; the plan file in the run dir is the main new control surface for audit and override.
Testing Plan
Paths below assume datasets live in
/root/datasetsand configs in/root/configs. Artifacts land undersafe-synthesizer-artifacts/<config>---<dataset>/<timestamp>/(plan aspii_replacement_plan.yaml, transformed data asdataset/transformed_training.csvwhen PII changed anything).For PII-only checks, prefer the SDK
TabularPiiReplacersnippets (no GPU/train). Use CLI--validatefor plan/preflight, and a tiny TinyLlama run only when you need end-to-end artifact wiring.Dataset map
/root/datasets/telco_churn.csvCustomerID,Name,Gender, city/state/zipfull_name+match_persona_bygender; ID patterns (CUST-…); dataframe scope/root/datasets/patient_events.csvpatient_id, names,date_of_birth,sex,provider_name,notes/detailsgroup_training_examples_by=patient_id; DOB perturbation; dual personas (patient + provider); free-text propagation/root/datasets/bike_sales.csvBirthDate+Gendermatch_persona_by/root/datasets/crm/Contact.csv/root/datasets/pii_dataset_no_label.csvorpersonal_bios.csvtextbio that mentions them/root/datasets/call_transcripts.csvtranscript)/root/datasets/EHR.csv/root/datasets/clinc_oos.csv1. Auto-discovery smoke (CLI)
Tiny config (
/root/configs/quick-tinyllama-pii.yamlor equivalent) + Faker so managed assets are not required:Check: run dir contains
pii_replacement_plan.yaml. For patient events, expectscope: group, patient + provider personas,patient_idas standaloneunique_identifier,notes/detailsasfree_text, and DOB present. For telco, expectscope: dataframe,Nameunder a persona withGenderinmatch_persona_by,CustomerIDstandalone.PII-only SDK equivalent:
2. Plan round-trip (edit → reuse)
pii_replacement_plan.yamlout of the run dir.provider_nameunder its own persona, add/adjustpatterns, or forcescope.safe-synthesizer run \ --config /root/configs/quick-tinyllama.yaml \ --data-source /root/datasets/patient_events.csv \ --data__group_training_examples_by patient_id \ --replace_pii__replacement_plan /path/to/edited_pii_replacement_plan.yaml \ --replace_pii__person__backend faker \ --emit_telemetry falseOr inline in a config (see
/root/configs/new-pii-repl.yaml/quick-tinyllama-pii.yaml):Check: dropped columns stay original; persona columns share one identity within scope; preflight/
--validaterejects bad column names and bad patterns.3. Preflight /
--validate(no replacement apply)Also exercise:
scope: groupwithoutdata.group_training_examples_bypii_plan_group_scope_invalidentity_type: dateon a columnpii_plan_entity_type_invalidllm_enhancement: trueperson.backend: faker+ bogus localepii_faker_locale_invalidbackend: managedpii_managed_assets_missingwarning; apply falls back to Faker4. Consistency scope
Use patient_events (many rows per
patient_id):group(default when group key set)data.group_training_examples_by: patient_id+ auto plandataframescope: dataframe(or no group key on telco/bike)recordscope: recordon a small slice with duplicate namesfirst_namerepeats; also assert free-text notes agree with that row’s structured name (regression for H2)For standalone IDs/phones under
scope: group|record, today’s code keeps a dataframe-wide map (H1) — assert current behavior, then re-assert after the fix.5. Free-text propagation
Best datasets: patient_events (
notesmentioning clinical context; provider honorifics) and pii_dataset_no_label / personal_bios (textrepeatsname/email/phone/address).safe-synthesizer run \ --config /root/configs/quick-tinyllama.yaml \ --data-source /root/datasets/pii_dataset_no_label.csv \ --replace_pii__person__backend faker \ --replace_pii__replacement__seed 42 \ --training__num_input_records_to_sample 200 \ --emit_telemetry falseCheck: in
transformed_training.csv, structuredname/email/phonechange and the same originals disappear fromtext. Partial mentions (Dr. <Last>) follow when onlyfull_nameis planned. Case variants (SmithvsSMITH) — document current case-sensitive behavior (M1), then retest after fix.Negative control:
call_transcripts.csvorclinc_oos.csv— plan should have little/no structured PII; free-text scan skipped or empty; transcripts largely unchanged.6. Persona backends
Check on bike_sales:
FirstName/LastName/AddressLine1/PhoneNumber/BirthDatereplaced;Genderunchanged but conditions names; phone is not persona-tied under managed/faker (entity-driven / pattern). Withpgm(if/root/sdg-pgms/srcpresent), phone may come from the persona — only backend that does.7. Gender / ethnicity conditioning
After replacement, spot-check that synthetic given names are plausible for the row’s
Gender/sex(Faker male/female generators). Ethnicity conditioning needs a column mapped viamatch_persona_by: ethnic_background(e.g. EHRethnicityor patientracein an edited plan).8. Disable PII / no-op paths
safe-synthesizer run --config /root/configs/quick-tinyllama.yaml \ --data-source /root/datasets/telco_churn.csv \ --no-replace-pii \ --emit_telemetry falseCheck: no
pii_replacement_plan.yaml(or PII stage skipped); training CSV equals source holdout.9. End-to-end SDK customization
Check CRM Contact:
FirstName/LastName/Email/Phone/MailingStreetreplaced consistently as one persona;Idstandalone.10. Suggested matrix (quick vs deep)
patient_idtext/notes--validatebad plan--validatereplacement_planpathquick-tinyllama.yamlWhat to inspect after each run
pii_replacement_plan.yaml— scope, personas, matchers, patterns, free_text columnsdataset/transformed_training.csvvsdataset/training.csv— columns changed, referential consistency within scopepersonas,pattern,perturbation,propagation) when a full run completesPre-Review Checklist
Ensure that the following pass:
mise run format && mise run checkor via prek validation.mise run testpasses locallymise run test:e2epasses locallymise run test:ci-containerpasses locally (recommended)/syncon this PR to trigger a run (auto-triggers on ready-for-review)Pre-Merge Checklist
Other Notes