feat: add in-process Rampart PII redaction plugin - #558
Conversation
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Enterprise Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughChangesRampart PII support adds an ONNX detector, structured prefilter, bounded asynchronous sanitizer, plugin registration, CLI editor integration, and Node, Go, and Python APIs. Host initialization paths register the component and expose configuration validation helpers. Rampart PII plugin
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant Host
participant PluginRegistry
participant RampartDetector
participant RampartSanitizer
participant Guardrail
Host->>PluginRegistry: register Rampart PII component
PluginRegistry->>RampartDetector: verify and load model artifacts
PluginRegistry->>RampartSanitizer: create sanitizer
PluginRegistry->>Guardrail: register surface callbacks
Guardrail->>RampartSanitizer: sanitize selected payload
RampartSanitizer->>RampartDetector: detect text batch
RampartDetector-->>RampartSanitizer: return scored spans
RampartSanitizer-->>Guardrail: return redacted payload
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Signed-off-by: Alex Fournier <afournier@nvidia.com>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
b73ac66 to
385c241
Compare
Signed-off-by: Alex Fournier <afournier@nvidia.com>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
There was a problem hiding this comment.
Actionable comments posted: 11
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
crates/worker/src/lib.rs (1)
676-705: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winMerge
push_registrationintopush_contract_registrationto remove duplication.Both functions build an identical
Registrationexcept for thecontractfield. Python's SDK already unifies this via a single_push_registration(..., *, contract: str = "")(seepython/plugin/src/nemo_relay_plugin/_api.pylines 1288-1310); the Rust SDK diverging into two near-duplicate helpers risks future drift (e.g., a new field added to one but not the other).♻️ Proposed refactor
- fn push_registration( - &mut self, - name: &str, - surface: RegistrationSurface, - priority: i32, - break_chain: bool, - ) { - self.handlers.registrations.push(Registration { - local_name: name.into(), - surface: surface as i32, - priority, - break_chain, - contract: String::new(), - }); - } - - fn push_contract_registration( - &mut self, - name: &str, - surface: RegistrationSurface, - contract: &str, - ) { - self.handlers.registrations.push(Registration { - local_name: name.into(), - surface: surface as i32, - priority: 0, - break_chain: false, - contract: contract.into(), - }); - } + fn push_registration( + &mut self, + name: &str, + surface: RegistrationSurface, + priority: i32, + break_chain: bool, + ) { + self.push_contract_registration(name, surface, priority, break_chain, ""); + } + + fn push_contract_registration( + &mut self, + name: &str, + surface: RegistrationSurface, + priority: i32, + break_chain: bool, + contract: &str, + ) { + self.handlers.registrations.push(Registration { + local_name: name.into(), + surface: surface as i32, + priority, + break_chain, + contract: contract.into(), + }); + }Then update the call in
register_worker_inferencetoself.push_contract_registration(name, RegistrationSurface::WorkerInference, 0, false, contract);.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/worker/src/lib.rs` around lines 676 - 705, Merge push_registration into push_contract_registration by giving push_contract_registration priority and break_chain parameters, with contract supplied as the final argument and defaulting to an empty string where appropriate. Remove the duplicate helper, update all callers including register_worker_inference to pass the unified arguments, and preserve existing Registration field values.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@crates/pii-redaction/src/component.rs`:
- Around line 960-962: Update is_valid_json_pointer_pattern to validate wildcard
segments according to JsonPointerPattern::matches: reject any path segment that
contains '*' unless the entire segment is exactly "*". Preserve existing JSON
Pointer validation for all other segments and continue accepting standalone
wildcard segments.
In `@crates/pii-redaction/src/local.rs`:
- Around line 732-740: The empty-paths branch in llm_sanitize_request_callback
must sanitize request headers as well as request.content, preserving the
intended pointer prefixes for the headers and content roots. Reuse the existing
request/header sanitization behavior used by sanitize_raw_request or the builtin
flow, and ensure the broad-coverage path returns a request with sanitized header
values.
In `@crates/pii-redaction/tests/unit/component_tests.rs`:
- Around line 1916-1921: Update the table-driven assertion in the
validate_plugin_config test loop to include failure context identifying the
current config/field/message case and the produced diagnostics. Preserve the
existing matching condition while supplying a descriptive assertion message so
failures reveal which case failed and the actual report contents.
In `@crates/pii-redaction/tests/worker_detection_tests.rs`:
- Around line 54-58: Remove the duplicate “/message” selector from either
target_paths or target_path_patterns in the test configuration, keeping it in
only one collection so the test expresses a single intent.
- Around line 268-285: Update the fail-closed assertion in the worker exit test
around the event emitted by “worker-pii-exit” to use a message value that the
healthy fixture worker does not redact, while retaining the expected redaction
for “unselected” if applicable. Ensure the assertion can only pass when the
crashed batch is handled fail-closed, rather than matching normal “PRIVATE”
detection behavior.
In `@crates/pii-redaction/workers/rampart/README.md`:
- Around line 134-136: Update the Runtime Bounds section in the README by adding
a complete introductory sentence before the existing bullet list; leave the
documented limits unchanged and ensure the lead-in grammatically introduces the
list.
In `@docs/build-plugins/dynamic-plugins/grpc-worker/python/about.mdx`:
- Line 168: Rename the “Register worker inference” heading to “Register Worker
Inference” in docs/build-plugins/dynamic-plugins/grpc-worker/python/about.mdx at
lines 168-168 and docs/build-plugins/dynamic-plugins/grpc-worker/rust/about.mdx
at lines 71-71, preserving the existing heading structure.
In `@docs/configure-plugins/pii-redaction/configuration.mdx`:
- Around line 424-431: The omission guidance following the “Path Semantics”
section is outdated. Update the paragraph describing manual LLM calls with
normalized target_paths and no active or fallback codec to state that payloads
are sanitized using the configured raw paths and emitted, matching the
early-return behavior in builtin and local redaction flows; preserve the
documented fail-closed contract.
- Around line 329-331: Add a complete introductory sentence immediately before
the TOML code block following the sanitizer registration-rejection paragraph,
clearly describing what the configuration example demonstrates. Keep the
existing TOML content unchanged.
In `@go/nemo_relay/pii_redaction/pii_redaction_test.go`:
- Around line 47-62: Extend the validation condition in the NewComponentSpec
test to assert that spec.Config.Local.Backend matches the configured backend
value from the test setup. Keep the existing configuration assertions unchanged
and include the backend check alongside the other Local fields.
In `@python/plugin/README.md`:
- Around line 108-125: Update the Worker Inference example to establish that ctx
is a PluginContext available inside WorkerPlugin.register, either by showing the
enclosing register method or explicitly stating that scope. Keep the
register_worker_inference usage and handler behavior unchanged.
---
Outside diff comments:
In `@crates/worker/src/lib.rs`:
- Around line 676-705: Merge push_registration into push_contract_registration
by giving push_contract_registration priority and break_chain parameters, with
contract supplied as the final argument and defaulting to an empty string where
appropriate. Remove the duplicate helper, update all callers including
register_worker_inference to pass the unified arguments, and preserve existing
Registration field values.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: b6f7fc1b-5518-49b8-af16-dd1759b6fa64
📒 Files selected for processing (60)
crates/cli/src/server/mod.rscrates/core/src/lib.rscrates/core/src/plugin.rscrates/core/src/plugin/dynamic/host.rscrates/core/src/plugin/dynamic/worker.rscrates/core/src/plugin/worker_inference.rscrates/core/tests/fixtures/worker_plugin/src/main.rscrates/core/tests/integration/worker_plugin_tests.rscrates/core/tests/unit/dynamic_worker_tests.rscrates/core/tests/unit/plugin_tests.rscrates/core/tests/unit/worker_inference_tests.rscrates/node/pii_redaction.d.tscrates/node/pii_redaction.jscrates/node/tests/pii_redaction_tests.mjscrates/pii-redaction/Cargo.tomlcrates/pii-redaction/README.mdcrates/pii-redaction/src/builtin.rscrates/pii-redaction/src/component.rscrates/pii-redaction/src/local.rscrates/pii-redaction/tests/unit/component_tests.rscrates/pii-redaction/tests/unit/local_tests.rscrates/pii-redaction/tests/worker_detection_tests.rscrates/pii-redaction/workers/rampart/MANIFEST.incrates/pii-redaction/workers/rampart/README.mdcrates/pii-redaction/workers/rampart/THIRD_PARTY_NOTICES.mdcrates/pii-redaction/workers/rampart/config.schema.jsoncrates/pii-redaction/workers/rampart/nemo_relay_pii_rampart/__init__.pycrates/pii-redaction/workers/rampart/nemo_relay_pii_rampart/detector.pycrates/pii-redaction/workers/rampart/nemo_relay_pii_rampart/prefetch.pycrates/pii-redaction/workers/rampart/nemo_relay_pii_rampart/py.typedcrates/pii-redaction/workers/rampart/nemo_relay_pii_rampart/worker.pycrates/pii-redaction/workers/rampart/pyproject.tomlcrates/pii-redaction/workers/rampart/relay-plugin.tomlcrates/pii-redaction/workers/rampart/tests/test_detector.pycrates/pii-redaction/workers/rampart/tests/test_worker.pycrates/worker-proto/README.mdcrates/worker-proto/proto/nemo/relay/worker/v1/plugin_worker.protocrates/worker-proto/tests/proto_tests.rscrates/worker/README.mdcrates/worker/src/lib.rscrates/worker/tests/worker_sdk_tests.rsdocs/about-nemo-relay/release-notes/index.mdxdocs/build-plugins/dynamic-plugins/grpc-worker/grpc-worker-protocol.mdxdocs/build-plugins/dynamic-plugins/grpc-worker/python/about.mdxdocs/build-plugins/dynamic-plugins/grpc-worker/rust/about.mdxdocs/configure-plugins/pii-redaction/about.mdxdocs/configure-plugins/pii-redaction/configuration.mdxgo/nemo_relay/pii_redaction.gogo/nemo_relay/pii_redaction/pii_redaction.gogo/nemo_relay/pii_redaction/pii_redaction_test.gogo/nemo_relay/pii_redaction_test.gojustfilepython/nemo_relay/pii_redaction.pypython/nemo_relay/pii_redaction.pyipython/plugin/README.mdpython/plugin/src/nemo_relay_plugin/__init__.pypython/plugin/src/nemo_relay_plugin/_api.pypython/tests/plugin/test_public_api_docstrings.pypython/tests/plugin/test_worker_sdk.pypython/tests/test_pii_redaction_plugin.py
Signed-off-by: Alex Fournier <afournier@nvidia.com>
There was a problem hiding this comment.
You could refine local_model to resolve an integration-provided callback. The PII middleware would execute that callback with the selected text and detector settings, then receive the detected spans, labels, and confidence scores. The integration could implement the callback using any model, runtime, or transport it chooses, while the PII component continues to own field selection, detection validation, policy, and redaction.
Signed-off-by: Alex Fournier <afournier@nvidia.com> # Conflicts: # Cargo.toml
|
/ok to test 1e37b71 |
Signed-off-by: Alex Fournier <afournier@nvidia.com>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
|
/ok to test 121f563 |
|
/ok to test 207fa57 |
There was a problem hiding this comment.
Actionable comments posted: 10
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
ATTRIBUTIONS-Rust.md (1)
28878-28880: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick winAdd blank lines around the
Licenseheading.At line 28879, add one blank line before and after the heading. This resolves the reported MD022 warnings.
Proposed fix
**License Type(s)**: Apache-2.0 + ### License: https://spdx.org/licenses/Apache-2.0.html +</details> <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.In
@ATTRIBUTIONS-Rust.mdaround lines 28878 - 28880, In the Apache-2.0
attribution entry, add one blank line before and after the “### License:
https://spdx.org/licenses/Apache-2.0.html” heading, preserving the surrounding
license content and formatting.</details> <!-- cr-comment:v1:21087021b162c078c947d653 --> _Source: Linters/SAST tools_ </blockquote></details> </blockquote></details>🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. Inline comments: In `@crates/node/pii_rampart.js`: - Around line 29-47: Remove the earlier model_path property from the returned configuration object, while retaining the final model_path: modelPath assignment after ...config. Update the object in the relevant configuration-returning function without changing other defaults. In `@crates/pii-redaction/src/rampart/mod.rs`: - Around line 667-767: Move the #[cfg(test)] tests from the rampart module into the crate’s tests/ tree, preserving coverage for valid_config, validation, registration, and component-spec behavior. Expose the required rampart symbols through the crate root or appropriate public(crate) interfaces, including RampartPiiPlugin, parse_config, and config_value_violations, so integration tests can access them without retaining tests under src. Apply the same relocation to the corresponding test modules in sanitizer.rs, model.rs, and tokenizer.rs. - Around line 483-489: Use supported_codec_names() as the single source of truth for codec choices. Update the ConfigViolation message, editor codec enum, and codec_schema enum values to derive their names from that shared list instead of hardcoding the three codecs, while preserving validation behavior. - Around line 262-271: Update plugin_already_registered_error to return the typed PluginError::Conflict variant, preserving its existing duplicate-registration message. In register_rampart_pii_component, replace the message-based “already registered” match guard with a match on PluginError::Conflict(_) while continuing to ignore that case and propagate other errors. In `@crates/pii-redaction/src/rampart/model.rs`: - Around line 475-497: Document the interaction between inference_batch_size and MAX_PADDED_TOKENS_PER_BATCH next to the inference_batch_size field in the Rampart configuration, explaining that the padded-token limit may produce smaller batches than the configured maximum. Keep the existing inference_batches behavior unchanged unless implementing the requested alternative of scaling the token budget with the configured batch size. In `@crates/pii-redaction/src/rampart/sanitizer.rs`: - Around line 569-575: Move the has_selected_string pre-check inside the async work dispatched by tool_sanitize_callback, and add a fixed traversal budget to has_selected_string and event_fields_have_selected_strings. Track visited nodes (including category_profile conversion) and return true when the limit is reached so uncertain or oversized payloads proceed to the existing bounded executor instead of performing unbounded work on the Tokio runtime thread. - Around line 856-1646: Extend the tests around collect_strings and replace_strings to verify index alignment when an oversized string at MAX_TEXT_BYTES appears between two eligible strings, ensuring only the intended values are sanitized or fail closed. Add a JSON-pointer test using a key containing "/" or "~" to validate compile_json_pointer and traversal through escape_json_pointer_segment preserve escaped pointer semantics. - Around line 648-655: Update llm_sanitize_request_callback and llm_sanitize_response_callback to perform the same selector pre-check as tool_sanitize_callback before calling backend.admit. Check request raw content together with headers, and check the response payload directly; return the original payload unchanged when no selected path matches, while preserving admission and inference for matching payloads. Keep codec-path checks based on their normalized decoded shapes. In `@crates/pii-redaction/src/rampart/tokenizer.rs`: - Around line 214-223: The tokenization path around next_special_token and RampartTokenizer::encode must make split_special_tokens explicit so special-token literals embedded in content are treated as ordinary text rather than control-token IDs. Preserve the intended control-token behavior when splitting is enabled, and add a regression test covering adjacent PII whose score remains above min_score so sanitize_batch does not leave the original text unchanged. In `@go/nemo_relay/pii_rampart_test.go`: - Around line 11-49: Cover both validation APIs with matching tests: in go/nemo_relay/pii_rampart_test.go lines 11-49, add valid and invalid-configuration assertions for ValidateRampartPiiConfig, including invalid selector or path diagnostics; in go/nemo_relay/pii_rampart/pii_rampart_test.go lines 8-28, add the same outcome checks for ValidateConfig. Ensure the tests exercise successful validation and verify the expected errors for invalid selectors or paths, including JSON conversion and facade forwarding behavior. --- Outside diff comments: In `@ATTRIBUTIONS-Rust.md`: - Around line 28878-28880: In the Apache-2.0 attribution entry, add one blank line before and after the “### License: https://spdx.org/licenses/Apache-2.0.html” heading, preserving the surrounding license content and formatting.🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Enterprise
Run ID:
5fae45ff-7aef-4eb2-8d27-6b57192f0c0a⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock📒 Files selected for processing (22)
ATTRIBUTIONS-Rust.mdCargo.tomlcrates/cli/src/plugins/prompt.rscrates/cli/src/server/mod.rscrates/cli/tests/coverage/shared/plugins_tests.rscrates/node/package.jsoncrates/node/pii_rampart.d.tscrates/node/pii_rampart.jscrates/node/src/api/mod.rscrates/node/tests/pii_rampart_tests.mjscrates/pii-redaction/Cargo.tomlcrates/pii-redaction/README.mdcrates/pii-redaction/src/rampart/mod.rscrates/pii-redaction/src/rampart/model.rscrates/pii-redaction/src/rampart/sanitizer.rscrates/pii-redaction/src/rampart/tokenizer.rsgo/nemo_relay/pii_rampart.gogo/nemo_relay/pii_rampart/pii_rampart.gogo/nemo_relay/pii_rampart/pii_rampart_test.gogo/nemo_relay/pii_rampart_test.gopython/nemo_relay/__init__.pypython/nemo_relay/__init__.pyi📜 Review details
⏰ Context from checks skipped due to timeout. (2)
- GitHub Check: Check / Run
- GitHub Check: Preview docs
🧰 Additional context used
📓 Path-based instructions (35)
**/*.{rs,py}
📄 CodeRabbit inference engine (AGENTS.md)
Follow binding naming conventions in Rust and Python: use
snake_case.Files:
python/nemo_relay/__init__.pycrates/cli/src/plugins/prompt.rscrates/node/src/api/mod.rscrates/cli/tests/coverage/shared/plugins_tests.rscrates/cli/src/server/mod.rscrates/pii-redaction/src/rampart/tokenizer.rscrates/pii-redaction/src/rampart/model.rscrates/pii-redaction/src/rampart/sanitizer.rscrates/pii-redaction/src/rampart/mod.rs**/*.{rs,py,js,mjs,cjs,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{rs,py,js,mjs,cjs,ts,tsx}: UseJson = serde_json::Valuein Rust-facing runtime APIs where the existing code expects JSON payloads.
UseResult<T>withFlowErrorin core runtime paths, and keep errors explicit and binding-appropriate at the wrapper layer.
Keep async behavior on the existing tokio-based model; bindings should preserve callback and future lifetimes rather than blocking or hiding async work unexpectedly.Files:
python/nemo_relay/__init__.pycrates/cli/src/plugins/prompt.rscrates/node/tests/pii_rampart_tests.mjscrates/node/src/api/mod.rscrates/cli/tests/coverage/shared/plugins_tests.rscrates/cli/src/server/mod.rscrates/pii-redaction/src/rampart/tokenizer.rscrates/node/pii_rampart.jscrates/pii-redaction/src/rampart/model.rscrates/pii-redaction/src/rampart/sanitizer.rscrates/pii-redaction/src/rampart/mod.rscrates/node/pii_rampart.d.tspython/nemo_relay/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
Python wrapper modules live under
python/nemo_relay/, and the native extension is built fromcrates/pythonwithmaturin.Files:
python/nemo_relay/__init__.py**/*.py
📄 CodeRabbit inference engine (CONTRIBUTING.md)
**/*.py: When changing the Python wrapper package, tests, or docs tooling, lint with Ruff (E,F,W,I), format with Ruff formatter (120-character lines, double quotes), and passtytype checking.
Add the SPDX license header to all Python source files using the#comment form.Files:
python/nemo_relay/__init__.py**/*.{rs,py,go,js,ts,c,h}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Use language-appropriate naming conventions: Rust
snake_case, C FFI exports prefixednemo_relay_, GoPascalCase, Node.jscamelCase, and Pythonsnake_case.Files:
python/nemo_relay/__init__.pygo/nemo_relay/pii_rampart/pii_rampart_test.gocrates/cli/src/plugins/prompt.rscrates/node/src/api/mod.rscrates/cli/tests/coverage/shared/plugins_tests.rscrates/cli/src/server/mod.rscrates/pii-redaction/src/rampart/tokenizer.rscrates/node/pii_rampart.jsgo/nemo_relay/pii_rampart.gocrates/pii-redaction/src/rampart/model.rsgo/nemo_relay/pii_rampart/pii_rampart.gocrates/pii-redaction/src/rampart/sanitizer.rscrates/pii-redaction/src/rampart/mod.rscrates/node/pii_rampart.d.tsgo/nemo_relay/pii_rampart_test.go{crates/python/src/py_api/mod.rs,python/nemo_relay/**/*.py,python/nemo_relay/**/*.pyi,go/nemo_relay/**/*.go,crates/node/src/api/**/*.rs}
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Update the language-native bindings for every exposed surface in Python, Go, and Node.js.
Files:
python/nemo_relay/__init__.pypython/nemo_relay/__init__.pyigo/nemo_relay/pii_rampart/pii_rampart_test.gocrates/node/src/api/mod.rsgo/nemo_relay/pii_rampart.gogo/nemo_relay/pii_rampart/pii_rampart.gogo/nemo_relay/pii_rampart_test.go{python/nemo_relay/**/*.py,python/nemo_relay/**/*.pyi,go/nemo_relay/**/*.go}
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Update language wrapper helpers such as Python wrapper modules, Python type stubs, and Go shorthand packages when the new behavior belongs in those helper layers.
Files:
python/nemo_relay/__init__.pypython/nemo_relay/__init__.pyigo/nemo_relay/pii_rampart/pii_rampart_test.gogo/nemo_relay/pii_rampart.gogo/nemo_relay/pii_rampart/pii_rampart.gogo/nemo_relay/pii_rampart_test.go{crates/**/src/**/*.rs,python/**/*.py}
📄 CodeRabbit inference engine (.agents/skills/maintain-dynamic-plugins/SKILL.md)
Do not add tests under
src; Rust tests belong in cratetests/trees, and Python SDK tests belong underpython/tests.Files:
python/nemo_relay/__init__.pycrates/cli/src/plugins/prompt.rscrates/node/src/api/mod.rscrates/cli/src/server/mod.rscrates/pii-redaction/src/rampart/tokenizer.rscrates/pii-redaction/src/rampart/model.rscrates/pii-redaction/src/rampart/sanitizer.rscrates/pii-redaction/src/rampart/mod.rs**/*
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
**/*: Format changed files with the language-native formatter before the final lint/test pass.
If dynamic plugin behavior changed, usemaintain-dynamic-pluginsand include the native SDK, worker protocol, Python SDK, docs, packaging, and Codecov surfaces in the validation plan.
If code changes alter APIs, bindings, commands, paths, packaging behavior, observability/adaptive semantics, or documented best practices, update any dependent maintainer or consumer skills in the same branch.
During iteration, preferuv run pre-commit run --files <changed files...>.
Before review or handoff, runuv run pre-commit run --all-files.Files:
python/nemo_relay/__init__.pypython/nemo_relay/__init__.pyiCargo.tomlgo/nemo_relay/pii_rampart/pii_rampart_test.gocrates/cli/src/plugins/prompt.rscrates/node/tests/pii_rampart_tests.mjscrates/node/src/api/mod.rscrates/cli/tests/coverage/shared/plugins_tests.rscrates/pii-redaction/Cargo.tomlcrates/node/package.jsoncrates/cli/src/server/mod.rscrates/pii-redaction/src/rampart/tokenizer.rscrates/node/pii_rampart.jsgo/nemo_relay/pii_rampart.gocrates/pii-redaction/README.mdcrates/pii-redaction/src/rampart/model.rsATTRIBUTIONS-Rust.mdgo/nemo_relay/pii_rampart/pii_rampart.gocrates/pii-redaction/src/rampart/sanitizer.rscrates/pii-redaction/src/rampart/mod.rscrates/node/pii_rampart.d.tsgo/nemo_relay/pii_rampart_test.go**/*.{rs,py,go,js,ts}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
If a language surface changed, always run that language's test target even when Rust core did not change.
**/*.{rs,py,go,js,ts}: When observability configuration or lifecycle is exposed, keep FFI and Python, Go, and Node.js binding-native config objects and subscriber/exporter methods aligned in logical knobs and semantics.
Require every OpenTelemetry endpoint to have a type and nonblank destination; resolveheader_envvalues at activation and reject missing, blank, or duplicate headers.
Concatenate layered ATOF sink, ATIF storage, and OpenTelemetry endpoint lists with higher-precedence entries first.
Preserve correct handling of mark events, start/end events, orphan cases, and span or trajectory fields derived from intended event data.
Run affected Rust tests andjust test-rustwhen event fields change; runjust test-python,just test-go, andjust test-nodewhen binding-native configuration or lifecycle changes.Files:
python/nemo_relay/__init__.pygo/nemo_relay/pii_rampart/pii_rampart_test.gocrates/cli/src/plugins/prompt.rscrates/node/src/api/mod.rscrates/cli/tests/coverage/shared/plugins_tests.rscrates/cli/src/server/mod.rscrates/pii-redaction/src/rampart/tokenizer.rscrates/node/pii_rampart.jsgo/nemo_relay/pii_rampart.gocrates/pii-redaction/src/rampart/model.rsgo/nemo_relay/pii_rampart/pii_rampart.gocrates/pii-redaction/src/rampart/sanitizer.rscrates/pii-redaction/src/rampart/mod.rscrates/node/pii_rampart.d.tsgo/nemo_relay/pii_rampart_test.go**/*.{rs,py,js,ts,tsx,go,java,kt,swift}
📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)
Add tests covering registration and duplicate names, deregistration and missing names, priority ordering, callback failure policy, scope-local inheritance and cleanup, event payload semantics, immutable mark and scope fields, and parity across affected bindings.
Files:
python/nemo_relay/__init__.pygo/nemo_relay/pii_rampart/pii_rampart_test.gocrates/cli/src/plugins/prompt.rscrates/node/src/api/mod.rscrates/cli/tests/coverage/shared/plugins_tests.rscrates/cli/src/server/mod.rscrates/pii-redaction/src/rampart/tokenizer.rscrates/node/pii_rampart.jsgo/nemo_relay/pii_rampart.gocrates/pii-redaction/src/rampart/model.rsgo/nemo_relay/pii_rampart/pii_rampart.gocrates/pii-redaction/src/rampart/sanitizer.rscrates/pii-redaction/src/rampart/mod.rscrates/node/pii_rampart.d.tsgo/nemo_relay/pii_rampart_test.go**/*.{md,mdx,py,go,js,ts}
📄 CodeRabbit inference engine (.agents/skills/maintain-observability/SKILL.md)
Examples and documentation must use each exporter's documented flush/deregister order before shutdown.
Files:
python/nemo_relay/__init__.pygo/nemo_relay/pii_rampart/pii_rampart_test.gocrates/node/pii_rampart.jsgo/nemo_relay/pii_rampart.gocrates/pii-redaction/README.mdATTRIBUTIONS-Rust.mdgo/nemo_relay/pii_rampart/pii_rampart.gocrates/node/pii_rampart.d.tsgo/nemo_relay/pii_rampart_test.gopython/nemo_relay/**/*
⚙️ CodeRabbit configuration file
python/nemo_relay/**/*: Review Python wrapper changes for typed API consistency, contextvars-based scope isolation, async behavior, and parity with the native extension.
Stubs and runtime implementations should stay aligned.Files:
python/nemo_relay/__init__.pypython/nemo_relay/__init__.pyi**/Cargo.toml
📄 CodeRabbit inference engine (.agents/skills/prepare-code-freeze/SKILL.md)
Confirm or infer the target release version from
upstream/main:Cargo.toml. Derive the release branch asrelease/<major>.<minor>.Keep Rust package names and workspace metadata in
Cargo.tomlinternally consistent across the project.OpenTelemetry and OpenInference dependencies must be unconditional rather than Cargo feature-gated.
Files:
Cargo.tomlcrates/pii-redaction/Cargo.toml**/*.toml
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Add the SPDX license header to all TOML files using the
#comment form.Files:
Cargo.tomlcrates/pii-redaction/Cargo.tomlCargo.toml
📄 CodeRabbit inference engine (.agents/skills/update-project-version/SKILL.md)
In
Cargo.toml, treat[workspace.package].versionas the source of truth for the Rust workspace and Python build versioning, and keepworkspace.dependencies.nemo-relay.version,workspace.dependencies.nemo-relay-adaptive.version,workspace.dependencies.nemo-relay-pii-redaction.version,workspace.dependencies.nemo-relay-ffi.version, andworkspace.dependencies.nemo-relay-cli.versionaligned when the workspace version changes.Files:
Cargo.tomlgo/nemo_relay/**/*.go
📄 CodeRabbit inference engine (.agents/skills/test-go-binding/SKILL.md)
go/nemo_relay/**/*.go: Format changed Go packages withcd go/nemo_relay && go fmt ./...
Run Go tests withjust test-goto build and test the NeMo Relay Go binding
Usejust build-gowhen you want an explicit build-only pass or need the artifact for other work
Usejust ci=true test-gowhen you need the CI-style coverage and JUnit path
On macOS, setDYLD_LIBRARY_PATHto the../../target/releasedirectory before running the rawgo testcommand directlyUse
PascalCasefor public Go APIs.Files:
go/nemo_relay/pii_rampart/pii_rampart_test.gogo/nemo_relay/pii_rampart.gogo/nemo_relay/pii_rampart/pii_rampart.gogo/nemo_relay/pii_rampart_test.go**/*.go
📄 CodeRabbit inference engine (CONTRIBUTING.md)
When changing the experimental Go binding, format Go code with
gofmtand keepgo vet ./...passing.Files:
go/nemo_relay/pii_rampart/pii_rampart_test.gogo/nemo_relay/pii_rampart.gogo/nemo_relay/pii_rampart/pii_rampart.gogo/nemo_relay/pii_rampart_test.go**/*.{rs,go,js,ts}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Add the SPDX license header to all Rust, Go, JavaScript, and TypeScript source files using the corresponding
//comment form.Files:
go/nemo_relay/pii_rampart/pii_rampart_test.gocrates/cli/src/plugins/prompt.rscrates/node/src/api/mod.rscrates/cli/tests/coverage/shared/plugins_tests.rscrates/cli/src/server/mod.rscrates/pii-redaction/src/rampart/tokenizer.rscrates/node/pii_rampart.jsgo/nemo_relay/pii_rampart.gocrates/pii-redaction/src/rampart/model.rsgo/nemo_relay/pii_rampart/pii_rampart.gocrates/pii-redaction/src/rampart/sanitizer.rscrates/pii-redaction/src/rampart/mod.rscrates/node/pii_rampart.d.tsgo/nemo_relay/pii_rampart_test.gogo/nemo_relay/**
📄 CodeRabbit inference engine (.agents/skills/maintain-optimizer/SKILL.md)
Keep shared plugin helpers in
go/nemo_relayaligned with plugin registration, composition, and lifecycle behavior.Files:
go/nemo_relay/pii_rampart/pii_rampart_test.gogo/nemo_relay/pii_rampart.gogo/nemo_relay/pii_rampart/pii_rampart.gogo/nemo_relay/pii_rampart_test.gogo/nemo_relay/**/*
⚙️ CodeRabbit configuration file
go/nemo_relay/**/*: Review Go binding changes for cgo memory ownership, race safety, callback cleanup, idiomatic exported APIs, and parity with Rust/FFI behavior.
Any API change should include focused Go tests and consider race-test behavior.Files:
go/nemo_relay/pii_rampart/pii_rampart_test.gogo/nemo_relay/pii_rampart.gogo/nemo_relay/pii_rampart/pii_rampart.gogo/nemo_relay/pii_rampart_test.go{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}
⚙️ CodeRabbit configuration file
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}: Tests should cover the behavior promised by the changed API surface, including error paths and cross-request isolation where relevant.
Prefer assertions on lifecycle events, scope stacks, middleware ordering, and binding parity over shallow smoke tests.Files:
go/nemo_relay/pii_rampart/pii_rampart_test.gocrates/node/tests/pii_rampart_tests.mjscrates/cli/tests/coverage/shared/plugins_tests.rsgo/nemo_relay/pii_rampart_test.go**/*.rs
📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)
**/*.rs: Any Rust change must runjust test-rust
Any Rust change must runcargo fmt --all
Any Rust change must runcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allfor all FFI work since it is Rust work
Runjust test-rustto validate FFI changes
Runcargo clippy --workspace --all-targets -- -D warningsto enforce strict linting on FFI workWhen Rust files changed as part of Go work, also run
cargo fmt --all,just test-rust, andcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allwhen Rust files are changed as part of Node work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files are changed as part of Node work
Runjust test-rustwhen Rust files are changed as part of Node workWhen changing the core Rust runtime or Rust-facing API surface, format Rust code with
cargo fmt(rustfmt defaults), keepcargo clippy -- -D warningsclean, and satisfycargo deny checkperdeny.toml.
**/*.rs: If any Rust code changed, always runjust test-rust.
If any Rust code changed, also runcargo fmt --all.
If any Rust code changed, also runcargo clippy --workspace --all-targets -- -D warnings.
For Rust changes headed for review, runcargo fmt --allandcargo clippy --workspace --all-targets -- -D warningseven if relying on pre-commit.Files:
crates/cli/src/plugins/prompt.rscrates/node/src/api/mod.rscrates/cli/tests/coverage/shared/plugins_tests.rscrates/cli/src/server/mod.rscrates/pii-redaction/src/rampart/tokenizer.rscrates/pii-redaction/src/rampart/model.rscrates/pii-redaction/src/rampart/sanitizer.rscrates/pii-redaction/src/rampart/mod.rscrates/node/**/*.{js,mjs,cjs,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use
camelCasefor Node.js public APIs.Files:
crates/node/tests/pii_rampart_tests.mjscrates/node/pii_rampart.jscrates/node/pii_rampart.d.tscrates/{python,ffi,node}/**/*
⚙️ CodeRabbit configuration file
crates/{python,ffi,node}/**/*: Treat binding changes as public API changes. Check for parity with the other language bindings, FFI ownership/lifetime safety,
callback error propagation, stable type conversion, and consistent async/stream semantics.
Flag changes that update one binding without corresponding tests or documentation for the same surface elsewhere.Files:
crates/node/tests/pii_rampart_tests.mjscrates/node/src/api/mod.rscrates/node/package.jsoncrates/node/pii_rampart.jscrates/node/pii_rampart.d.tscrates/node/**/*.{js,ts,jsx,tsx,json}
📄 CodeRabbit inference engine (.agents/skills/test-node-binding/SKILL.md)
Format changed Node files with
npm run format --workspace=nemo-relay-nodeFiles:
crates/node/package.jsoncrates/node/pii_rampart.jscrates/node/pii_rampart.d.tscrates/node/package.json
📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)
Keep the Node package metadata in
crates/node/package.jsonconsistent with the package name, versioning, and publish surface.Keep the
crates/node/package.jsonpackage version aligned with the workspace-rootpackage-lock.json, and keep itsdependencies["nemo-relay-node"]entry aligned when the Node package version changes.Files:
crates/node/package.json**/*.{md,rst,html,txt}
📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-brand-terminology.md)
**/*.{md,rst,html,txt}: Always spellNVIDIAin all caps. Do not useNvidia,nvidia,nVidia,nVIDIA, orNV.
Usean NVIDIAbefore a noun because the name starts with an 'en' sound.
Do not add a registered trademark symbol afterNVIDIAwhen referring to the company.
Use trademark symbols with product names only when the document type or legal guidance requires them.
Verify official capitalization, spacing, and hyphenation for product names.
Precede NVIDIA product names withNVIDIAon first mention when it is natural and accurate.
Do not rewrite product names for grammar or title-case rules.
Preserve third-party product names according to the owner's spelling.
Include the company name and full model qualifier on first use when it helps identify the model.
Preserve the official capitalization and punctuation of model names.
Use shorter family names only after the full name is established.
Spell out a term on first use and put the acronym in parentheses unless the acronym is widely understood by the intended audience.
Use the acronym on later mentions after it has been defined.
For long documents, reintroduce the full term if readers might lose context.
Form plurals of acronyms withs, not an apostrophe, such asGPUs.
In headings, common acronyms can remain abbreviated. Spell out the term in the first or second sentence of the body.
Common terms such asCPU,GPU,PC,API, andUIusually do not need to be spelled out for developer audiences.Files:
crates/pii-redaction/README.mdATTRIBUTIONS-Rust.md**/*.{md,rst,html}
📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-brand-terminology.md)
Link the first mention of a product name when the destination helps the reader.
Files:
crates/pii-redaction/README.mdATTRIBUTIONS-Rust.md**/*.{md,rst,txt}
📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-guide.md)
Spell
NVIDIAin all caps. Do not useNvidia,nvidia, orNV.Files:
crates/pii-redaction/README.mdATTRIBUTIONS-Rust.md**/*.{md,rst}
📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-guide.md)
**/*.{md,rst}: Format commands, code elements, expressions, package names, file names, and paths as inline code.
Use descriptive link text. Avoid raw URLs and weak anchors such as "here" or "read more."
Use title case consistently for technical documentation headings.
Introduce code blocks, lists, tables, and images with complete sentences.
Write procedures as imperative steps. Keep steps parallel and split long procedures into smaller tasks.
Prefer active voice, present tense, short sentences, contractions, and plain English.
Usecanfor possibility and reservemayfor permission.
Useafterfor temporal relationships instead ofonce.
Preferrefer tooverseewhen the wording points readers to another resource.
Avoid culture-specific idioms, unnecessary Latinisms, jokes, and marketing exaggeration in technical docs.
Spell out months in body text, avoid ordinal dates, and use clear time zones.
Spell out whole numbers from zero through nine unless they are technical values, parameters, versions, or UI values.
Use numerals for 10 or greater and include commas in thousands.
Do not add trademark symbols to learning-oriented docs unless the source, platform, or legal guidance explicitly requires them.Files:
crates/pii-redaction/README.mdATTRIBUTIONS-Rust.md**/*.md
📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-technical-docs.md)
**/*.md: Use title case consistently in technical documentation headings
Avoid quotation marks, ampersands, and exclamation marks in headings
Keep product, event, research, and whitepaper names in their official title case
Use title case for table headers
Do not force social-media sentence case into technical docs
Format code elements, commands, parameters, package names, and expressions in monospace
Format directories, file names, and paths in monospace using backticks
Use angle brackets inside monospace for variables inside paths, such as/home/<username>/.login
Format error messages and strings in quotation marks, keeping literal code strings in code formatting when clearer
Format UI buttons, menus, fields, and labels in bold
Use angle brackets between UI labels for menu paths, such as File > Save As
Use italics for new terms on first use, sparingly and only when introducing the term
Use italics for publication titles
Format keyboard shortcuts in plain text, such as Press Ctrl+Alt+Delete
Use owner/repo link text for GitHub repositories, preferring[NVIDIA/NeMo](link)over prose references like 'the GitHub repo'
Introduce every code block with a complete sentence
Do not make a code block complete the grammar of the previous sentence
Do not continue a sentence after a code block
Use syntax highlighting when the format supports it for code blocks
Avoid the word 'snippet' unless the surrounding docs already use it as a term of art
Keep inline method, function, and class references consistent with nearby docs, omitting empty parentheses for prose readability when no call is shown
Use descriptive anchor text that matches the destination title when possible for links
Avoid raw URLs in running text
Avoid generic anchor text such as 'here,' 'this page,' and 'read more'
Include acronyms in link text when a linked term includes an acronym
Do not link long sentences or multiple sentences
Avoid links that pull readers away from a procedure unless the link is a p...Files:
crates/pii-redaction/README.mdATTRIBUTIONS-Rust.md**/*.{md,mdx}
📄 CodeRabbit inference engine (AGENTS.md)
Update
README.md,fern/, package READMEs, and binding-support notes when public behavior, package names, examples, or supported bindings change.
**/*.{md,mdx}: Prefer the documented public API, not internal shortcuts
Keep package names, repo references, and build commands current
Keep release-process and release-notes guidance in repo-maintainer docs such asRELEASING.md, not as user-facing docs pages orCHANGELOG.md
Keep stable user-facing wrappers atscripts/root in docs and examples; only point at namespaced helper paths when documenting internal maintenance work
When detailed dynamic plugin guides exist, keep Rust native plugin examples, Python worker plugin examples, andgrpc-v1protocol details on separate pagesIf links in documentation change, run
just docs-linkcheck.Files:
crates/pii-redaction/README.mdATTRIBUTIONS-Rust.md**/*.{md,markdown,mdx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Add the SPDX license header to all Markdown/MDX documentation files using the HTML comment block form.
Files:
crates/pii-redaction/README.mdATTRIBUTIONS-Rust.mdcrates/node/**/*.{ts,tsx,d.ts}
📄 CodeRabbit inference engine (.agents/skills/test-node-binding/SKILL.md)
Use
npm run check:docstrings --workspace=nemo-relay-nodeto validate public API docstring checks when surface docs changedFiles:
crates/node/pii_rampart.d.ts🧠 Learnings (5)
📚 Learning: 2026-07-28T20:33:25.156Z
Learnt from: willkill07 Repo: NVIDIA/NeMo-Relay PR: 572 File: go/nemo_relay/adaptive_runtime_test.go:214-238 Timestamp: 2026-07-28T20:33:25.156Z Learning: When adding/adjusting Go unit tests for `BuildCacheRequestFacts` (request-ID validation and related request parsing), set `CacheRequestFactsInput.Provider` to a valid provider in all tests that are intended to isolate request-ID behavior—because `BuildCacheRequestFacts` does not validate `Provider`. Then add separate test coverage for malformed `AnnotatedRequest` JSON so JSON parsing failures are not conflated with `Provider`-related inputs.Applied to files:
go/nemo_relay/pii_rampart/pii_rampart_test.gogo/nemo_relay/pii_rampart_test.go📚 Learning: 2026-07-28T23:57:11.641Z
Learnt from: willkill07 Repo: NVIDIA/NeMo-Relay PR: 570 File: crates/node/src/api/mod.rs:3265-3282 Timestamp: 2026-07-28T23:57:11.641Z Learning: In the Node.js binding, `flushSubscribers()` is Promise-based/async and must be awaited. Any session-close or teardown path (e.g., the OpenClaw live smoke session-close flow) must await `flushSubscribers()` before continuing to live ATIF export assertions and before teardown, so queued subscriber delivery fully completes and tests/assertions observe the final state.Applied to files:
crates/node/src/api/mod.rs📚 Learning: 2026-08-03T17:55:34.521Z
Learnt from: afourniernv Repo: NVIDIA/NeMo-Relay PR: 558 File: crates/node/pii_rampart.js:50-59 Timestamp: 2026-08-03T17:55:34.521Z Learning: In Node.js helper modules under `crates/node`, use `ComponentSpec` as the public component-wrapper API name, including for wrappers such as `plugin`, `adaptive`, `observability`, `model_pricing`, `pii_redaction`, and equivalent modules like `pii_rampart`. This established API name takes precedence over the general camelCase public API guideline for consistency.Applied to files:
crates/node/pii_rampart.js📚 Learning: 2026-08-03T17:55:44.657Z
Learnt from: afourniernv Repo: NVIDIA/NeMo-Relay PR: 558 File: go/nemo_relay/pii_rampart.go:42-62 Timestamp: 2026-08-03T17:55:44.657Z Learning: In the Rampart PII configuration constructors `NewRampartPiiConfig` and `NewConfig`, treat the returned configuration as incomplete until callers set `TargetPaths` or `TargetPathPatterns`. Both selector lists must not remain empty before validation or activation, because the Rust validator rejects configurations without a target field.Applied to files:
go/nemo_relay/pii_rampart.gogo/nemo_relay/pii_rampart/pii_rampart.go📚 Learning: 2026-05-07T18:04:44.387Z
Learnt from: mnajafian-nv Repo: NVIDIA/NeMo-Flow PR: 67 File: integrations/openclaw/src/modules.ts:1-2 Timestamp: 2026-05-07T18:04:44.387Z Learning: In NVIDIA/NeMo-Flow, TypeScript source files should use `//` line comments for SPDX headers (e.g., `// SPDX-FileCopyrightText: ...` and `// SPDX-License-Identifier: ...`) rather than C-style block comments (`/* ... */`). The repo’s copyright checker enforces this mapping, so `//` SPDX headers in `.ts` files should not be flagged as a style violation.Applied to files:
crates/node/pii_rampart.d.ts🪛 Biome (2.5.5)
crates/node/pii_rampart.js
[error] 31-31: This property is later overwritten by an object member with the same name.
(lint/suspicious/noDuplicateObjectKeys)
🪛 markdownlint-cli2 (0.23.1)
ATTRIBUTIONS-Rust.md
[warning] 28879-28879: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Above(MD022, blanks-around-headings)
[warning] 28879-28879: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below(MD022, blanks-around-headings)
🔇 Additional comments (31)
crates/pii-redaction/README.md (7)
9-15: LGTM!Also applies to: 44-45
69-74: LGTM!
210-218: LGTM!Also applies to: 221-237
219-220: 📐 Maintainability & Code QualityRun the documentation link checker.
Because Line 220 adds a new external link, run
just docs-linkcheckbefore handoff.As per coding guidelines, run
just docs-linkcheckwhen links in Markdown change.Source: Coding guidelines
239-274: LGTM!
275-290: LGTM!
292-302: LGTM!Cargo.toml (1)
36-36: LGTM!crates/node/src/api/mod.rs (1)
78-78: LGTM!Also applies to: 127-128
crates/cli/src/server/mod.rs (3)
30-37: LGTM!Also applies to: 866-866, 880-880, 892-892, 917-919, 949-951
416-419: LGTM!Also applies to: 432-455
871-872: LGTM!Also applies to: 885-886, 899-900, 928-934, 960-1001
crates/cli/src/plugins/prompt.rs (3)
14-193: LGTM!
195-303: LGTM!
305-1270: LGTM!crates/cli/tests/coverage/shared/plugins_tests.rs (3)
322-432: LGTM!Also applies to: 619-841
1463-1516: LGTM!
1908-1997: LGTM!Also applies to: 2102-2351, 2414-2503, 3125-3144
crates/node/package.json (1)
52-55: LGTM!crates/node/pii_rampart.d.ts (1)
1-49: LGTM!crates/node/pii_rampart.js (1)
1-28: LGTM!Also applies to: 50-81
go/nemo_relay/pii_rampart.go (1)
1-92: LGTM!go/nemo_relay/pii_rampart/pii_rampart.go (1)
1-41: LGTM!python/nemo_relay/__init__.py (1)
20-20: LGTM!Also applies to: 241-241, 572-572
python/nemo_relay/__init__.pyi (1)
35-35: LGTM!crates/node/tests/pii_rampart_tests.mjs (1)
1-72: LGTM!crates/pii-redaction/src/rampart/mod.rs (1)
227-259: LGTM!Also applies to: 285-340, 342-424, 426-563
crates/pii-redaction/src/rampart/tokenizer.rs (1)
103-157: LGTM!Also applies to: 160-181, 183-212, 225-244, 246-266
crates/pii-redaction/src/rampart/model.rs (1)
128-194: LGTM!Also applies to: 196-279, 281-323, 325-372, 374-424, 427-473, 499-539, 541-578, 580-642
crates/pii-redaction/src/rampart/sanitizer.rs (1)
136-173: LGTM!Also applies to: 175-220, 221-258, 260-375, 377-452, 454-527, 736-777, 842-854
crates/pii-redaction/Cargo.toml (1)
27-33: 📐 Maintainability & Code QualityKeep the current dependency declarations.
tempfile = "3"is present, andunicode_categories0.1.1 has no RustSec advisory. Its age alone does not require a change.> Likely an incorrect or invalid review comment.
Signed-off-by: Alex Fournier <afournier@nvidia.com>
…nto feat/pii-worker-provider
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@crates/pii-redaction/src/rampart/mod.rs`:
- Around line 707-727: Extend bounds_the_configurable_window_budget to cover the
lower boundary by setting max_windows_per_payload to 0 and asserting
validate_rampart_pii_config reports an error for that field, while preserving
the existing default and upper-bound assertions.
In `@crates/pii-redaction/src/rampart/model.rs`:
- Around line 66-73: Rename DetectionError::into_plugin_error to bind it
explicitly to warmup handling, such as into_warmup_error, and update the load
call site accordingly; keep the existing PayloadLimit message and Model error
propagation unchanged.
In `@crates/pii-redaction/src/rampart/sanitizer.rs`:
- Around line 1331-1389: Extend
model_window_limit_fails_closed_for_every_surface with a codec-decoded response
case using PayloadLimitedDetector and sanitize_response_with_codec. Assert that
the call returns Err(SanitizeError::PayloadLimit), covering the
sanitize_serializable propagation path while preserving the existing raw request
and response assertions.
- Around line 367-391: Remove the identity `selected` index vector from
`sanitize_texts` and update `sanitize_batch` to iterate over `texts` directly.
Validate each `detection.text_index` against `texts.len()` before indexing,
while preserving the existing payload-limit, model-error, replacement, and
result behaviors.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Enterprise
Run ID: c88e3d02-6b7b-446b-9640-95469f5d4dd1
📒 Files selected for processing (10)
crates/node/pii_rampart.jscrates/node/tests/pii_rampart_tests.mjscrates/pii-redaction/README.mdcrates/pii-redaction/src/rampart/mod.rscrates/pii-redaction/src/rampart/model.rscrates/pii-redaction/src/rampart/sanitizer.rsgo/nemo_relay/pii_rampart.gogo/nemo_relay/pii_rampart_test.gopython/nemo_relay/pii_rampart.pypython/tests/test_pii_rampart_plugin.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (31)
**/*.{rs,py}
📄 CodeRabbit inference engine (AGENTS.md)
Follow binding naming conventions in Rust and Python: use
snake_case.
Files:
python/tests/test_pii_rampart_plugin.pypython/nemo_relay/pii_rampart.pycrates/pii-redaction/src/rampart/mod.rscrates/pii-redaction/src/rampart/sanitizer.rscrates/pii-redaction/src/rampart/model.rs
**/*.{rs,py,js,mjs,cjs,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{rs,py,js,mjs,cjs,ts,tsx}: UseJson = serde_json::Valuein Rust-facing runtime APIs where the existing code expects JSON payloads.
UseResult<T>withFlowErrorin core runtime paths, and keep errors explicit and binding-appropriate at the wrapper layer.
Keep async behavior on the existing tokio-based model; bindings should preserve callback and future lifetimes rather than blocking or hiding async work unexpectedly.
Files:
python/tests/test_pii_rampart_plugin.pycrates/node/tests/pii_rampart_tests.mjscrates/node/pii_rampart.jspython/nemo_relay/pii_rampart.pycrates/pii-redaction/src/rampart/mod.rscrates/pii-redaction/src/rampart/sanitizer.rscrates/pii-redaction/src/rampart/model.rs
**/*.py
📄 CodeRabbit inference engine (CONTRIBUTING.md)
**/*.py: When changing the Python wrapper package, tests, or docs tooling, lint with Ruff (E,F,W,I), format with Ruff formatter (120-character lines, double quotes), and passtytype checking.
Add the SPDX license header to all Python source files using the#comment form.
Files:
python/tests/test_pii_rampart_plugin.pypython/nemo_relay/pii_rampart.py
**/*.{rs,py,go,js,ts,c,h}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Use language-appropriate naming conventions: Rust
snake_case, C FFI exports prefixednemo_relay_, GoPascalCase, Node.jscamelCase, and Pythonsnake_case.
Files:
python/tests/test_pii_rampart_plugin.pygo/nemo_relay/pii_rampart_test.gocrates/node/pii_rampart.jsgo/nemo_relay/pii_rampart.gopython/nemo_relay/pii_rampart.pycrates/pii-redaction/src/rampart/mod.rscrates/pii-redaction/src/rampart/sanitizer.rscrates/pii-redaction/src/rampart/model.rs
{crates/**/src/**/*.rs,python/**/*.py}
📄 CodeRabbit inference engine (.agents/skills/maintain-dynamic-plugins/SKILL.md)
Do not add tests under
src; Rust tests belong in cratetests/trees, and Python SDK tests belong underpython/tests.
Files:
python/tests/test_pii_rampart_plugin.pypython/nemo_relay/pii_rampart.pycrates/pii-redaction/src/rampart/mod.rscrates/pii-redaction/src/rampart/sanitizer.rscrates/pii-redaction/src/rampart/model.rs
python/tests/**/*.py
📄 CodeRabbit inference engine (.agents/skills/test-python-binding/SKILL.md)
python/tests/**/*.py: Pytest is used to run tests.
Do not add@pytest.mark.asyncioto any test; async tests are automatically detected and run by the async runner.
Do not add a-> Nonereturn type annotation to test functions.
When mocking a class, do not define a new class; useunittest.mock.MagicMockorunittest.mock.AsyncMock, with thespecconstructor argument when necessary.
Name mocked classes with themockprefix, notfake.
Prefer pytest fixtures over helper methods.
Do not repeat fixtures; if a fixture is needed in multiple test files, place it in aconftest.pyfile.
When creating a fixture, use@pytest.fixture(name="<fixture_name>"[, scope="<scope>"])and define the fixture function asdef <fixture_name>_fixture() -> <return_type>:; only specifyscopewhen it is notfunction.
Preferpytest.mark.parametrizeover creating individual tests for different input types.
Files:
python/tests/test_pii_rampart_plugin.py
**/*
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
**/*: Format changed files with the language-native formatter before the final lint/test pass.
If dynamic plugin behavior changed, usemaintain-dynamic-pluginsand include the native SDK, worker protocol, Python SDK, docs, packaging, and Codecov surfaces in the validation plan.
If code changes alter APIs, bindings, commands, paths, packaging behavior, observability/adaptive semantics, or documented best practices, update any dependent maintainer or consumer skills in the same branch.
During iteration, preferuv run pre-commit run --files <changed files...>.
Before review or handoff, runuv run pre-commit run --all-files.
Files:
python/tests/test_pii_rampart_plugin.pycrates/node/tests/pii_rampart_tests.mjsgo/nemo_relay/pii_rampart_test.gocrates/node/pii_rampart.jsgo/nemo_relay/pii_rampart.gopython/nemo_relay/pii_rampart.pycrates/pii-redaction/README.mdcrates/pii-redaction/src/rampart/mod.rscrates/pii-redaction/src/rampart/sanitizer.rscrates/pii-redaction/src/rampart/model.rs
**/*.{rs,py,go,js,ts}
📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)
If a language surface changed, always run that language's test target even when Rust core did not change.
**/*.{rs,py,go,js,ts}: When observability configuration or lifecycle is exposed, keep FFI and Python, Go, and Node.js binding-native config objects and subscriber/exporter methods aligned in logical knobs and semantics.
Require every OpenTelemetry endpoint to have a type and nonblank destination; resolveheader_envvalues at activation and reject missing, blank, or duplicate headers.
Concatenate layered ATOF sink, ATIF storage, and OpenTelemetry endpoint lists with higher-precedence entries first.
Preserve correct handling of mark events, start/end events, orphan cases, and span or trajectory fields derived from intended event data.
Run affected Rust tests andjust test-rustwhen event fields change; runjust test-python,just test-go, andjust test-nodewhen binding-native configuration or lifecycle changes.
Files:
python/tests/test_pii_rampart_plugin.pygo/nemo_relay/pii_rampart_test.gocrates/node/pii_rampart.jsgo/nemo_relay/pii_rampart.gopython/nemo_relay/pii_rampart.pycrates/pii-redaction/src/rampart/mod.rscrates/pii-redaction/src/rampart/sanitizer.rscrates/pii-redaction/src/rampart/model.rs
**/*.{rs,py,js,ts,tsx,go,java,kt,swift}
📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)
Add tests covering registration and duplicate names, deregistration and missing names, priority ordering, callback failure policy, scope-local inheritance and cleanup, event payload semantics, immutable mark and scope fields, and parity across affected bindings.
Files:
python/tests/test_pii_rampart_plugin.pygo/nemo_relay/pii_rampart_test.gocrates/node/pii_rampart.jsgo/nemo_relay/pii_rampart.gopython/nemo_relay/pii_rampart.pycrates/pii-redaction/src/rampart/mod.rscrates/pii-redaction/src/rampart/sanitizer.rscrates/pii-redaction/src/rampart/model.rs
**/*.{md,mdx,py,go,js,ts}
📄 CodeRabbit inference engine (.agents/skills/maintain-observability/SKILL.md)
Examples and documentation must use each exporter's documented flush/deregister order before shutdown.
Files:
python/tests/test_pii_rampart_plugin.pygo/nemo_relay/pii_rampart_test.gocrates/node/pii_rampart.jsgo/nemo_relay/pii_rampart.gopython/nemo_relay/pii_rampart.pycrates/pii-redaction/README.md
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}
⚙️ CodeRabbit configuration file
{crates/**/tests/**,python/tests/**,go/nemo_relay/**/*_test.go}: Tests should cover the behavior promised by the changed API surface, including error paths and cross-request isolation where relevant.
Prefer assertions on lifecycle events, scope stacks, middleware ordering, and binding parity over shallow smoke tests.
Files:
python/tests/test_pii_rampart_plugin.pycrates/node/tests/pii_rampart_tests.mjsgo/nemo_relay/pii_rampart_test.go
crates/node/**/*.{js,mjs,cjs,ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use
camelCasefor Node.js public APIs.
Files:
crates/node/tests/pii_rampart_tests.mjscrates/node/pii_rampart.js
crates/{python,ffi,node}/**/*
⚙️ CodeRabbit configuration file
crates/{python,ffi,node}/**/*: Treat binding changes as public API changes. Check for parity with the other language bindings, FFI ownership/lifetime safety,
callback error propagation, stable type conversion, and consistent async/stream semantics.
Flag changes that update one binding without corresponding tests or documentation for the same surface elsewhere.
Files:
crates/node/tests/pii_rampart_tests.mjscrates/node/pii_rampart.js
go/nemo_relay/**/*.go
📄 CodeRabbit inference engine (.agents/skills/test-go-binding/SKILL.md)
go/nemo_relay/**/*.go: Format changed Go packages withcd go/nemo_relay && go fmt ./...
Run Go tests withjust test-goto build and test the NeMo Relay Go binding
Usejust build-gowhen you want an explicit build-only pass or need the artifact for other work
Usejust ci=true test-gowhen you need the CI-style coverage and JUnit path
On macOS, setDYLD_LIBRARY_PATHto the../../target/releasedirectory before running the rawgo testcommand directlyUse
PascalCasefor public Go APIs.
Files:
go/nemo_relay/pii_rampart_test.gogo/nemo_relay/pii_rampart.go
**/*.go
📄 CodeRabbit inference engine (CONTRIBUTING.md)
When changing the experimental Go binding, format Go code with
gofmtand keepgo vet ./...passing.
Files:
go/nemo_relay/pii_rampart_test.gogo/nemo_relay/pii_rampart.go
**/*.{rs,go,js,ts}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Add the SPDX license header to all Rust, Go, JavaScript, and TypeScript source files using the corresponding
//comment form.
Files:
go/nemo_relay/pii_rampart_test.gocrates/node/pii_rampart.jsgo/nemo_relay/pii_rampart.gocrates/pii-redaction/src/rampart/mod.rscrates/pii-redaction/src/rampart/sanitizer.rscrates/pii-redaction/src/rampart/model.rs
{crates/python/src/py_api/mod.rs,python/nemo_relay/**/*.py,python/nemo_relay/**/*.pyi,go/nemo_relay/**/*.go,crates/node/src/api/**/*.rs}
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Update the language-native bindings for every exposed surface in Python, Go, and Node.js.
Files:
go/nemo_relay/pii_rampart_test.gogo/nemo_relay/pii_rampart.gopython/nemo_relay/pii_rampart.py
{python/nemo_relay/**/*.py,python/nemo_relay/**/*.pyi,go/nemo_relay/**/*.go}
📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)
Update language wrapper helpers such as Python wrapper modules, Python type stubs, and Go shorthand packages when the new behavior belongs in those helper layers.
Files:
go/nemo_relay/pii_rampart_test.gogo/nemo_relay/pii_rampart.gopython/nemo_relay/pii_rampart.py
go/nemo_relay/**
📄 CodeRabbit inference engine (.agents/skills/maintain-optimizer/SKILL.md)
Keep shared plugin helpers in
go/nemo_relayaligned with plugin registration, composition, and lifecycle behavior.
Files:
go/nemo_relay/pii_rampart_test.gogo/nemo_relay/pii_rampart.go
go/nemo_relay/**/*
⚙️ CodeRabbit configuration file
go/nemo_relay/**/*: Review Go binding changes for cgo memory ownership, race safety, callback cleanup, idiomatic exported APIs, and parity with Rust/FFI behavior.
Any API change should include focused Go tests and consider race-test behavior.
Files:
go/nemo_relay/pii_rampart_test.gogo/nemo_relay/pii_rampart.go
crates/node/**/*.{js,ts,jsx,tsx,json}
📄 CodeRabbit inference engine (.agents/skills/test-node-binding/SKILL.md)
Format changed Node files with
npm run format --workspace=nemo-relay-node
Files:
crates/node/pii_rampart.js
python/nemo_relay/**/*.py
📄 CodeRabbit inference engine (AGENTS.md)
Python wrapper modules live under
python/nemo_relay/, and the native extension is built fromcrates/pythonwithmaturin.
Files:
python/nemo_relay/pii_rampart.py
python/nemo_relay/**/*
⚙️ CodeRabbit configuration file
python/nemo_relay/**/*: Review Python wrapper changes for typed API consistency, contextvars-based scope isolation, async behavior, and parity with the native extension.
Stubs and runtime implementations should stay aligned.
Files:
python/nemo_relay/pii_rampart.py
**/*.{md,rst,html,txt}
📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-brand-terminology.md)
**/*.{md,rst,html,txt}: Always spellNVIDIAin all caps. Do not useNvidia,nvidia,nVidia,nVIDIA, orNV.
Usean NVIDIAbefore a noun because the name starts with an 'en' sound.
Do not add a registered trademark symbol afterNVIDIAwhen referring to the company.
Use trademark symbols with product names only when the document type or legal guidance requires them.
Verify official capitalization, spacing, and hyphenation for product names.
Precede NVIDIA product names withNVIDIAon first mention when it is natural and accurate.
Do not rewrite product names for grammar or title-case rules.
Preserve third-party product names according to the owner's spelling.
Include the company name and full model qualifier on first use when it helps identify the model.
Preserve the official capitalization and punctuation of model names.
Use shorter family names only after the full name is established.
Spell out a term on first use and put the acronym in parentheses unless the acronym is widely understood by the intended audience.
Use the acronym on later mentions after it has been defined.
For long documents, reintroduce the full term if readers might lose context.
Form plurals of acronyms withs, not an apostrophe, such asGPUs.
In headings, common acronyms can remain abbreviated. Spell out the term in the first or second sentence of the body.
Common terms such asCPU,GPU,PC,API, andUIusually do not need to be spelled out for developer audiences.
Files:
crates/pii-redaction/README.md
**/*.{md,rst,html}
📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-brand-terminology.md)
Link the first mention of a product name when the destination helps the reader.
Files:
crates/pii-redaction/README.md
**/*.{md,rst,txt}
📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-guide.md)
Spell
NVIDIAin all caps. Do not useNvidia,nvidia, orNV.
Files:
crates/pii-redaction/README.md
**/*.{md,rst}
📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-guide.md)
**/*.{md,rst}: Format commands, code elements, expressions, package names, file names, and paths as inline code.
Use descriptive link text. Avoid raw URLs and weak anchors such as "here" or "read more."
Use title case consistently for technical documentation headings.
Introduce code blocks, lists, tables, and images with complete sentences.
Write procedures as imperative steps. Keep steps parallel and split long procedures into smaller tasks.
Prefer active voice, present tense, short sentences, contractions, and plain English.
Usecanfor possibility and reservemayfor permission.
Useafterfor temporal relationships instead ofonce.
Preferrefer tooverseewhen the wording points readers to another resource.
Avoid culture-specific idioms, unnecessary Latinisms, jokes, and marketing exaggeration in technical docs.
Spell out months in body text, avoid ordinal dates, and use clear time zones.
Spell out whole numbers from zero through nine unless they are technical values, parameters, versions, or UI values.
Use numerals for 10 or greater and include commas in thousands.
Do not add trademark symbols to learning-oriented docs unless the source, platform, or legal guidance explicitly requires them.
Files:
crates/pii-redaction/README.md
**/*.md
📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-technical-docs.md)
**/*.md: Use title case consistently in technical documentation headings
Avoid quotation marks, ampersands, and exclamation marks in headings
Keep product, event, research, and whitepaper names in their official title case
Use title case for table headers
Do not force social-media sentence case into technical docs
Format code elements, commands, parameters, package names, and expressions in monospace
Format directories, file names, and paths in monospace using backticks
Use angle brackets inside monospace for variables inside paths, such as/home/<username>/.login
Format error messages and strings in quotation marks, keeping literal code strings in code formatting when clearer
Format UI buttons, menus, fields, and labels in bold
Use angle brackets between UI labels for menu paths, such as File > Save As
Use italics for new terms on first use, sparingly and only when introducing the term
Use italics for publication titles
Format keyboard shortcuts in plain text, such as Press Ctrl+Alt+Delete
Use owner/repo link text for GitHub repositories, preferring[NVIDIA/NeMo](link)over prose references like 'the GitHub repo'
Introduce every code block with a complete sentence
Do not make a code block complete the grammar of the previous sentence
Do not continue a sentence after a code block
Use syntax highlighting when the format supports it for code blocks
Avoid the word 'snippet' unless the surrounding docs already use it as a term of art
Keep inline method, function, and class references consistent with nearby docs, omitting empty parentheses for prose readability when no call is shown
Use descriptive anchor text that matches the destination title when possible for links
Avoid raw URLs in running text
Avoid generic anchor text such as 'here,' 'this page,' and 'read more'
Include acronyms in link text when a linked term includes an acronym
Do not link long sentences or multiple sentences
Avoid links that pull readers away from a procedure unless the link is a p...
Files:
crates/pii-redaction/README.md
**/*.{md,mdx}
📄 CodeRabbit inference engine (AGENTS.md)
Update
README.md,fern/, package READMEs, and binding-support notes when public behavior, package names, examples, or supported bindings change.
**/*.{md,mdx}: Prefer the documented public API, not internal shortcuts
Keep package names, repo references, and build commands current
Keep release-process and release-notes guidance in repo-maintainer docs such asRELEASING.md, not as user-facing docs pages orCHANGELOG.md
Keep stable user-facing wrappers atscripts/root in docs and examples; only point at namespaced helper paths when documenting internal maintenance work
When detailed dynamic plugin guides exist, keep Rust native plugin examples, Python worker plugin examples, andgrpc-v1protocol details on separate pagesIf links in documentation change, run
just docs-linkcheck.
Files:
crates/pii-redaction/README.md
**/*.{md,markdown,mdx}
📄 CodeRabbit inference engine (CONTRIBUTING.md)
Add the SPDX license header to all Markdown/MDX documentation files using the HTML comment block form.
Files:
crates/pii-redaction/README.md
**/*.rs
📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)
**/*.rs: Any Rust change must runjust test-rust
Any Rust change must runcargo fmt --all
Any Rust change must runcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allfor all FFI work since it is Rust work
Runjust test-rustto validate FFI changes
Runcargo clippy --workspace --all-targets -- -D warningsto enforce strict linting on FFI workWhen Rust files changed as part of Go work, also run
cargo fmt --all,just test-rust, andcargo clippy --workspace --all-targets -- -D warnings
**/*.rs: Runcargo fmt --allwhen Rust files are changed as part of Node work
Runcargo clippy --workspace --all-targets -- -D warningswhen Rust files are changed as part of Node work
Runjust test-rustwhen Rust files are changed as part of Node workWhen changing the core Rust runtime or Rust-facing API surface, format Rust code with
cargo fmt(rustfmt defaults), keepcargo clippy -- -D warningsclean, and satisfycargo deny checkperdeny.toml.
**/*.rs: If any Rust code changed, always runjust test-rust.
If any Rust code changed, also runcargo fmt --all.
If any Rust code changed, also runcargo clippy --workspace --all-targets -- -D warnings.
For Rust changes headed for review, runcargo fmt --allandcargo clippy --workspace --all-targets -- -D warningseven if relying on pre-commit.
Files:
crates/pii-redaction/src/rampart/mod.rscrates/pii-redaction/src/rampart/sanitizer.rscrates/pii-redaction/src/rampart/model.rs
🧠 Learnings (3)
📚 Learning: 2026-07-28T20:33:25.156Z
Learnt from: willkill07
Repo: NVIDIA/NeMo-Relay PR: 572
File: go/nemo_relay/adaptive_runtime_test.go:214-238
Timestamp: 2026-07-28T20:33:25.156Z
Learning: When adding/adjusting Go unit tests for `BuildCacheRequestFacts` (request-ID validation and related request parsing), set `CacheRequestFactsInput.Provider` to a valid provider in all tests that are intended to isolate request-ID behavior—because `BuildCacheRequestFacts` does not validate `Provider`. Then add separate test coverage for malformed `AnnotatedRequest` JSON so JSON parsing failures are not conflated with `Provider`-related inputs.
Applied to files:
go/nemo_relay/pii_rampart_test.go
📚 Learning: 2026-08-03T17:55:34.521Z
Learnt from: afourniernv
Repo: NVIDIA/NeMo-Relay PR: 558
File: crates/node/pii_rampart.js:50-59
Timestamp: 2026-08-03T17:55:34.521Z
Learning: In Node.js helper modules under `crates/node`, use `ComponentSpec` as the public component-wrapper API name, including for wrappers such as `plugin`, `adaptive`, `observability`, `model_pricing`, `pii_redaction`, and equivalent modules like `pii_rampart`. This established API name takes precedence over the general camelCase public API guideline for consistency.
Applied to files:
crates/node/pii_rampart.js
📚 Learning: 2026-08-03T17:55:44.657Z
Learnt from: afourniernv
Repo: NVIDIA/NeMo-Relay PR: 558
File: go/nemo_relay/pii_rampart.go:42-62
Timestamp: 2026-08-03T17:55:44.657Z
Learning: In the Rampart PII configuration constructors `NewRampartPiiConfig` and `NewConfig`, treat the returned configuration as incomplete until callers set `TargetPaths` or `TargetPathPatterns`. Both selector lists must not remain empty before validation or activation, because the Rust validator rejects configurations without a target field.
Applied to files:
go/nemo_relay/pii_rampart.go
🔇 Additional comments (22)
crates/pii-redaction/README.md (2)
220-220: 📐 Maintainability & Code QualityRun the documentation link check.
Run
just docs-linkcheckbefore merge to validate the added Hugging Face documentation link.As per coding guidelines, if links in documentation change, run
just docs-linkcheck.Source: Coding guidelines
301-301: LGTM!Also applies to: 303-310
crates/node/pii_rampart.js (1)
43-43: LGTM!python/nemo_relay/pii_rampart.py (1)
40-40: LGTM!python/tests/test_pii_rampart_plugin.py (1)
23-23: LGTM!go/nemo_relay/pii_rampart_test.go (1)
21-23: LGTM!crates/node/tests/pii_rampart_tests.mjs (1)
18-18: LGTM!go/nemo_relay/pii_rampart.go (1)
59-59: 🗄️ Data Integrity & IntegrationNo constructor mismatch exists.
pii_rampart.NewConfigdelegates tonemo_relay.NewRampartPiiConfig, so it usesMaxWindowsPerPayload: 4.> Likely an incorrect or invalid review comment.crates/pii-redaction/src/rampart/mod.rs (3)
45-45: LGTM!
551-556: LGTM!
647-649: 🗄️ Data Integrity & IntegrationNo default mismatch remains. All bindings use 4, and the Rust
serdedefault supplies 4 to the generated JSON Schema.> Likely an incorrect or invalid review comment.crates/pii-redaction/src/rampart/model.rs (3)
212-218: LGTM!
274-275: LGTM!Also applies to: 290-291
305-305: 🗄️ Data Integrity & IntegrationNo documentation change is needed. The README documents the four overlapping 512-token windows, the maximum configurable budget of 16, and the whole-surface fail-closed behavior when limits are exceeded.
> Likely an incorrect or invalid review comment.crates/pii-redaction/src/rampart/sanitizer.rs (8)
32-32: LGTM!Also applies to: 49-57, 95-103
225-259: LGTM!
267-301: LGTM!
393-397: LGTM!Also applies to: 405-412, 428-440
453-517: LGTM!
633-643: LGTM!Also applies to: 658-681, 706-733
751-775: LGTM!Also applies to: 871-877
889-937: LGTM!Also applies to: 995-1101, 1112-1117, 1762-1777
Signed-off-by: Alex Fournier <afournier@nvidia.com>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
Current-head production benchmarkReran the Rampart validation on commit This head adds a bounded, content-addressed decision cache and field-level model-budget fallback:
Real Claude Code and Codex trafficI rebuilt the actual Relay CLI and ran cold direct calls plus tool-heavy sessions through Anthropic Messages and OpenAI Responses at the default four-window budget.
For comparison, the equivalent pre-cache harness retained only 1/5 Anthropic request bodies and 0/11 OpenAI Responses request bodies even with a 16-window budget. Synthetic production matrixThe 16-window run gives the direct comparison with the prior benchmark.
The soak retained all 2,400 LLM bodies with zero canary leaks and zero fail-closed bodies. Tokio heartbeat p99 was 0.449 ms, heartbeat max was 0.901 ms, and max RSS was 231.3 MB. Repeated-field timings separate the first cold inference from later exact cache hits:
At the default four-window budget, the 8 KiB field took 434.048 ms cold. The 16 KiB field was rejected field-by-field in 1.506 ms rather than spending second-scale inference time or removing the full envelope. Redaction quality stayed unchanged on 210 balanced AI4Privacy rows across seven languages:
Validation on this head:
The practical limit remains explicit: a unique cold field that exceeds its configured model-window budget is replaced in observability. Repeated coding-agent instructions, tool schemas, and history no longer repeatedly consume that budget or cause the whole request body to disappear. |
|
/ok to test 1866014 |
Signed-off-by: Alex Fournier <afournier@nvidia.com>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
|
/ok to test be1725e |
Overview
Add
pii_rampart, a separate first-party PII redaction plugin that runs the pinnednationaldesignstudio/rampartONNX model inside the Relay Rust process.The existing
pii_redactionplugin remains deterministic.pii_rampartowns its model-backed configuration and lifecycle without adding a generic inference surface or changing the gRPC worker protocol.This PR builds on the async primary-middleware boundary introduced by #571. Rampart uses that boundary to await sanitization without running tokenization or ONNX inference on Tokio executor threads or Tokio's shared blocking pool.
Details
pii_rampartcomponent kind with its own configuration, registration lifecycle, and Rust/Python/Node/Go helpers.tract-onnx. Activation requires an absolute local snapshot path and verifies SHA-256 digests for the graph, config, vocabulary, and tokenizer metadata.tract-onnxand the directrayondependency behind the crate'srampartfeature. Rayon was already present transitively through Tract; the lockfile adds no new package.Real-model concurrency validation on an Apple M4 Pro used the pinned snapshot through public managed OpenAI, Anthropic, tool, event, and streaming paths:
spawn_blockingpath reached about 501 ms p50 and failed 12/16 calls in the same condition.The main package-size cost remains unchanged. A minimal unstripped release binary grew from 4,307,520 bytes without Rampart to 36,344,480 bytes with it. Prior local package builds produced a 17,693,724-byte Python wheel and a 16,717,279-byte Node tarball.
Validation:
uv run pre-commit run --all-filescargo clippy --workspace --all-targets -- -D warningsjust test-python(616 passed)just test-node(347 passed)just test-gocargo test -p nemo-relay-pii-redaction --all-features(144 passed)cargo test -p nemo-relay-pii-redaction --no-default-features(105 passed)just test-rustpassed every compiled unit and integration suite, including 1,085 core tests and 144 PII tests. Its final core doctest failed on the pre-existingnemo_relay::Resultexample incrates/core/src/api/runtime/scope_stack.rs; the same invalid example is present onmainand is unrelated to this change.Where should the reviewer start?
Start with
crates/pii-redaction/src/rampart/mod.rsfor the independent plugin boundary, thenprefilter.rsfor the pinned model's structured-input contract,model.rsfor model ownership,tokenizer.rsfor offset fidelity, andsanitizer.rsfor the dedicated executor, bounded admission, selection, and fail-closed behavior.The key tradeoff is explicit: running in-process avoids a separate deployment and IPC path, but it adds roughly 32 MB to an unstripped release binary and gives up process-level crash isolation. Calls await sanitization for up to the bounded deadline; sustained overload favors privacy and bounded resource use by redacting or omitting selected observability content rather than growing an unbounded queue.
Related Issues: (use one of the action keywords Closes / Fixes / Resolves / Relates to)
Summary by CodeRabbit
New Features
Documentation
Tests