Anonymizer currently uses DataDesigner CustomColumnConfig for private pipeline steps. This works in-process, but custom functions serialize poorly and complicate distributed execution. The goal is to make Anonymizer workflows portable when nemo-anonymizer is installed, without exposing implementation details as user-facing API.
Remove CustomColumnConfig from production Anonymizer workflow builders and replace it with Anonymizer-owned plugin column configs that DataDesigner can discover through entry points.
Use anonymizer.engine.workflow_columns for the implementation package.
Rationale:
- It describes the Anonymizer concept, not the host engine.
- It avoids names like
dd_plugins. - It keeps these classes internal to the Anonymizer engine while still allowing DataDesigner to load them by entry point.
Entry point names should use the Anonymizer domain:
[project.entry-points."data_designer.plugins"]
anonymizer-detection-transform = "anonymizer.engine.workflow_columns.detection.plugins:detection_transform_plugin"
anonymizer-chunked-validation = "anonymizer.engine.workflow_columns.detection.plugins:chunked_validation_plugin"Use one installable package, nemo-anonymizer, with multiple DataDesigner plugin entry points. Each entry point exposes one Plugin object. This gives us one package with multiple submodules, rather than one distribution per plugin.
Do not create a 1:1 plugin for every current helper function unless it is clearer. Prefer a small set of role-based column types:
- Detection transforms for parse, validation prep, merge, and finalize operations.
- Chunked validation for model-backed validation.
- Rewrite transforms for prompt prep, extraction, metrics, and postprocess operations.
- Rewrite model-call columns for evaluator and repair calls that need parser context or dynamic model aliases.
Keep the existing pure helper functions as implementation cores. The plugin generators should adapt DataDesigner row input to those helpers, not rewrite the business logic.
Moving custom columns into plugins does not by itself remove the need for a chat-completions-compatible NER endpoint. The current detector remains an LLMTextColumnConfig, so DataDesigner routes it through chat completion generation.
To remove the extra chat completions head on NER models, the detector call itself must become an Anonymizer workflow column that talks to a native NER endpoint or client. That is a separate design slice because it needs a stable endpoint contract, provider configuration, and response normalization.
Move the detection workflow off custom columns first.
Tasks:
- Add
src/anonymizer/engine/workflow_columns/. - Add detection plugin configs and generators:
DetectionTransformConfigChunkedValidationConfig
- Add DataDesigner entry points in
pyproject.toml. - Replace detection
CustomColumnConfigusage inEntityDetectionWorkflow. - Keep
chunked_validate_row(...)as the core validator implementation. - Add a serialization test that builds the detection workflow and confirms config JSON contains no serialized function names.
Validation:
.venv/bin/ruff check src/anonymizer/engine/detection src/anonymizer/engine/workflow_columns tests/engine/test_detection_workflow.py tests/engine/test_chunked_validation.py
.venv/bin/pytest tests/engine/test_detection_postprocess.py tests/engine/test_chunked_validation.py tests/engine/test_detection_workflow.pyExit criteria:
- Detection behavior is unchanged.
- Detection builder configs serialize without custom generator functions.
- No production detection workflow path instantiates
CustomColumnConfig.
Move rewrite, evaluation, repair, and final judge postprocess columns.
Tasks:
- Add rewrite plugin configs and generators:
RewriteTransformConfigRewriteEvaluatorCallConfigRewriteRepairCallConfigFinalJudgeTransformConfig
- Replace custom columns in:
domain_classification.pyqa_generation.pyrewrite_generation.pyevaluate.pyrepair.pyfinal_judge.py
- Preserve current parser-context behavior in evaluator columns.
- Add tests that workflow column lists contain plugin configs, not
CustomColumnConfig.
Validation:
.venv/bin/ruff check src/anonymizer/engine/rewrite src/anonymizer/engine/workflow_columns tests/engine/test_rewrite_workflow.py
.venv/bin/pytest tests/engine/test_domain_classification.py tests/engine/test_qa_generation.py tests/engine/test_rewrite_generation.py tests/engine/test_evaluate.py tests/engine/test_repair.py tests/engine/test_final_judge.py tests/engine/test_rewrite_workflow.pyExit criteria:
- Rewrite behavior is unchanged.
- Repair loop still runs only on failing rows.
- Evaluator calls still enforce expected QA IDs.
- Rewrite builder configs serialize without custom generator functions.
Make the new path hard to regress.
Tasks:
- Add a test that production code under
src/anonymizer/engineno longer createsCustomColumnConfig. - Add export tests for distributed builder factories.
- Update any docs or comments that describe custom columns as the distributed limitation.
- Bump the DataDesigner dependency only when the needed plugin and serialization behavior is available in the supported release.
- Consider a native detector workflow column if we want NER models to avoid chat-completions-compatible serving.
Validation:
.venv/bin/ruff check .
.venv/bin/ruff format --check .
.venv/bin/pytest tests/engine tests/interfaceExit criteria:
- Runtime Anonymizer workflows use Anonymizer plugin columns only.
- Serialized configs are portable across machines where
nemo-anonymizeris installed. - Tests prevent reintroducing custom columns into production workflow builders.
- Should plugin configs live under
anonymizer.engine.workflow_columnsor a shorteranonymizer.workflow_columnsnamespace? - Should
DetectionTransformConfiguse an operation enum, or should parse, prep, merge, and finalize each get a distinct config class? - Which DataDesigner release should become the minimum supported version for this migration?
- Is native NER transport in scope for this migration, or should it be a separate provider/client project?