Skip to content

feat: add in-process Rampart PII redaction plugin - #558

Draft
afourniernv wants to merge 93 commits into
NVIDIA:mainfrom
afourniernv:feat/pii-worker-provider
Draft

feat: add in-process Rampart PII redaction plugin#558
afourniernv wants to merge 93 commits into
NVIDIA:mainfrom
afourniernv:feat/pii-worker-provider

Conversation

@afourniernv

@afourniernv afourniernv commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Overview

Add pii_rampart, a separate first-party PII redaction plugin that runs the pinned nationaldesignstudio/rampart ONNX model inside the Relay Rust process.

The existing pii_redaction plugin remains deterministic. pii_rampart owns 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.

  • I confirm this contribution is my own work, or I have the right to submit it under this project's license.
  • I searched existing issues and open pull requests, and this does not duplicate existing work.

Details

  • Add an independent pii_rampart component kind with its own configuration, registration lifecycle, and Rust/Python/Node/Go helpers.
  • Load and optimize the pinned Rampart ONNX graph in-process with tract-onnx. Activation requires an absolute local snapshot path and verifies SHA-256 digests for the graph, config, vocabulary, and tokenizer metadata.
  • Keep model acquisition out of Relay. There is no download path, network dependency, or model file in this PR.
  • Implement the pinned BERT tokenizer in Rust, including normalization, WordPiece splitting, special tokens, and original UTF-8 byte offsets.
  • Apply Rampart's required deterministic prefilter for SSNs, Luhn-valid cards, email addresses, URLs, and IP/MAC addresses. Structured values become typed sentinels before tokenization; model spans are projected back to original UTF-8 byte offsets and merged with score-1 deterministic detections.
  • Require explicit JSON-pointer selectors. Only selected observability strings reach the model; provider/tool callback arguments and return values are not changed.
  • Validate model output before applying confidence, excluded-label, and replacement policy. Model errors, malformed spans, payload-limit failures, and bounded-admission failures fail closed for affected selected fields. Codec failures omit the observable LLM body rather than applying normalized selectors to raw data.
  • Run sanitizer CPU work on a dedicated per-activation executor with up to three workers, limited by host parallelism. At most 16 operations are admitted; admitted operations wait asynchronously for a worker for up to 500 ms. This isolates inference from both Tokio executor threads and Tokio's shared blocking pool.
  • Keep sanitization in the existing awaited middleware boundary. Managed calls wait at the observability checkpoint, preserving sanitizer ordering and guaranteeing subscribers see the sanitized event. A detached background publication queue was prototyped and rejected here because it changes core event-delivery semantics and dropped most selected bodies under burst load while accumulating detached tasks.
  • Bound each ONNX call to at most 512 padded tokens. There is no cross-request batching or model instance per request.
  • Register the component in the CLI, FFI, Python, and Node hosts, and add configuration helpers and tests for Python, Node, and Go.
  • Keep tract-onnx and the direct rayon dependency behind the crate's rampart feature. Rayon was already present transitively through Tract; the lockfile adds no new package.
  • Document pinned snapshot provisioning, explicit selectors, activation, concurrency, and binding registration in the crate README.
  • Keep the docs site, examples, worker SDK, and worker protocol unchanged. Benchmark code, output, and model files are not included in the repository.

Real-model concurrency validation on an Apple M4 Pro used the pinned snapshot through public managed OpenAI, Anthropic, tool, event, and streaming paths:

  • Claude-style fan-out, 5 agents x 5 turns plus 3 tools: three runs completed in 4.57-4.71 s with 668-683 ms p95 sanitizer latency and 0/200 fail-closed bodies.
  • Codex-style workload, 10 turns plus 6 parallel tools: completed in 6.322 s with 512 ms p95 sanitizer latency and no fail-closed bodies.
  • Sixteen concurrent streaming calls: completed in 496 ms with 0/32 request/response bodies failing closed.
  • Deliberate saturation, 32 concurrent 8 KiB inputs: completed in 1.902 s; 52/64 bodies failed closed after hitting the bounded wait. This is the intended overload behavior rather than unbounded queue growth.
  • With Tokio's only blocking-pool thread deliberately occupied, Rampart remained isolated at 22 ms p50 / 26 ms p95 with no failures. The prior spawn_blocking path reached about 501 ms p50 and failed 12/16 calls in the same condition.
  • One hundred activation/teardown cycles completed without a hang, stale callback, or failed call. Observed maximum RSS was approximately 90 MB in the concurrency run.

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-files
  • cargo clippy --workspace --all-targets -- -D warnings
  • just test-python (616 passed)
  • just test-node (347 passed)
  • just test-go
  • cargo test -p nemo-relay-pii-redaction --all-features (144 passed)
  • cargo test -p nemo-relay-pii-redaction --no-default-features (105 passed)
  • Real pinned-model fan-out, streaming, saturation, blocking-pool isolation, cancellation, and 100-cycle lifecycle smoke

just test-rust passed every compiled unit and integration suite, including 1,085 core tests and 144 PII tests. Its final core doctest failed on the pre-existing nemo_relay::Result example in crates/core/src/api/runtime/scope_stack.rs; the same invalid example is present on main and is unrelated to this change.

Where should the reviewer start?

Start with crates/pii-redaction/src/rampart/mod.rs for the independent plugin boundary, then prefilter.rs for the pinned model's structured-input contract, model.rs for model ownership, tokenizer.rs for offset fidelity, and sanitizer.rs for 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

    • Added the optional Rampart PII redaction plugin for detecting and redacting sensitive information.
    • Added configuration for selectors, scoring, replacements, batching, codecs, policies, and processing limits.
    • Added Rampart PII support across CLI, Node.js, Python, and Go integrations.
    • Added editor support for configuring, enabling, disabling, and persisting settings.
  • Documentation

    • Added setup, model provisioning, configuration, and runtime behavior guidance.
  • Tests

    • Added coverage for configuration, validation, redaction, detection, and integrations.

@copy-pr-bot

copy-pr-bot Bot commented Jul 26, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 438fce0d-4c3b-4503-99f1-6e34f8156ce3

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Changes

Rampart 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

Layer / File(s) Summary
Detector and plugin contract
crates/pii-redaction/src/rampart/*, crates/pii-redaction/Cargo.toml
Adds configuration validation, tokenization, structured PII prefiltering, verified model loading, and ONNX inference.
Sanitizer callbacks
crates/pii-redaction/src/rampart/sanitizer.rs, crates/pii-redaction/src/builtin.rs
Adds bounded executor admission, codec-aware redaction, fail-closed behavior, and asynchronous sanitizer callbacks.
Host and CLI integration
crates/ffi/src/api/plugin.rs, crates/python/src/lib.rs, crates/node/src/api/mod.rs, crates/cli/src/server/mod.rs, crates/cli/src/plugins/*
Registers Rampart during host initialization and adds CLI editing, persistence, summaries, schema handling, and registration errors.
Language APIs
crates/node/pii_rampart.*, go/nemo_relay/pii_rampart*, python/nemo_relay/pii_rampart.*, python/nemo_relay/__init__.*
Adds configuration types, component builders, metadata constants, validation helpers, package exports, and type declarations.
Validation and supporting updates
crates/node/tests/pii_rampart_tests.mjs, go/nemo_relay/pii_rampart*_test.go, python/tests/test_pii_rampart_plugin.py, crates/cli/tests/coverage/shared/plugins_tests.rs, Cargo.toml, ATTRIBUTIONS-Rust.md, .gitattributes
Adds cross-language and CLI coverage, enables the Rampart feature, refreshes attribution metadata, and marks generated files.

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
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 35.23% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title follows Conventional Commits format, uses an allowed lowercase type, clearly describes the change, and is 49 characters without a trailing period.
Description check ✅ Passed The description includes all required template sections, completed confirmations, detailed changes, reviewer guidance, and a valid related-issue action keyword.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added size:XXL PR is very large Feature a new feature lang:go PR changes/introduces Go code lang:js PR changes/introduces Javascript/Typescript code lang:python PR changes/introduces Python code lang:rust PR changes/introduces Rust code labels Jul 26, 2026
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>
@afourniernv
afourniernv force-pushed the feat/pii-worker-provider branch from b73ac66 to 385c241 Compare July 27, 2026 00:03
@willkill07 willkill07 added this to the 0.7 milestone Jul 27, 2026
Signed-off-by: Alex Fournier <afournier@nvidia.com>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
@afourniernv afourniernv changed the title feat: add worker-backed PII local models feat: add worker-backed PII detection Jul 27, 2026
@afourniernv
afourniernv marked this pull request as ready for review July 27, 2026 18:39
@afourniernv
afourniernv requested review from a team as code owners July 27, 2026 18:39
@afourniernv afourniernv changed the title feat: add worker-backed PII detection feat: run local PII models through gRPC workers Jul 27, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 win

Merge push_registration into push_contract_registration to remove duplication.

Both functions build an identical Registration except for the contract field. Python's SDK already unifies this via a single _push_registration(..., *, contract: str = "") (see python/plugin/src/nemo_relay_plugin/_api.py lines 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_inference to self.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

📥 Commits

Reviewing files that changed from the base of the PR and between 42c7655 and 7541bec.

📒 Files selected for processing (60)
  • crates/cli/src/server/mod.rs
  • crates/core/src/lib.rs
  • crates/core/src/plugin.rs
  • crates/core/src/plugin/dynamic/host.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/core/src/plugin/worker_inference.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/tests/unit/worker_inference_tests.rs
  • crates/node/pii_redaction.d.ts
  • crates/node/pii_redaction.js
  • crates/node/tests/pii_redaction_tests.mjs
  • crates/pii-redaction/Cargo.toml
  • crates/pii-redaction/README.md
  • crates/pii-redaction/src/builtin.rs
  • crates/pii-redaction/src/component.rs
  • crates/pii-redaction/src/local.rs
  • crates/pii-redaction/tests/unit/component_tests.rs
  • crates/pii-redaction/tests/unit/local_tests.rs
  • crates/pii-redaction/tests/worker_detection_tests.rs
  • crates/pii-redaction/workers/rampart/MANIFEST.in
  • crates/pii-redaction/workers/rampart/README.md
  • crates/pii-redaction/workers/rampart/THIRD_PARTY_NOTICES.md
  • crates/pii-redaction/workers/rampart/config.schema.json
  • crates/pii-redaction/workers/rampart/nemo_relay_pii_rampart/__init__.py
  • crates/pii-redaction/workers/rampart/nemo_relay_pii_rampart/detector.py
  • crates/pii-redaction/workers/rampart/nemo_relay_pii_rampart/prefetch.py
  • crates/pii-redaction/workers/rampart/nemo_relay_pii_rampart/py.typed
  • crates/pii-redaction/workers/rampart/nemo_relay_pii_rampart/worker.py
  • crates/pii-redaction/workers/rampart/pyproject.toml
  • crates/pii-redaction/workers/rampart/relay-plugin.toml
  • crates/pii-redaction/workers/rampart/tests/test_detector.py
  • crates/pii-redaction/workers/rampart/tests/test_worker.py
  • crates/worker-proto/README.md
  • crates/worker-proto/proto/nemo/relay/worker/v1/plugin_worker.proto
  • crates/worker-proto/tests/proto_tests.rs
  • crates/worker/README.md
  • crates/worker/src/lib.rs
  • crates/worker/tests/worker_sdk_tests.rs
  • docs/about-nemo-relay/release-notes/index.mdx
  • docs/build-plugins/dynamic-plugins/grpc-worker/grpc-worker-protocol.mdx
  • docs/build-plugins/dynamic-plugins/grpc-worker/python/about.mdx
  • docs/build-plugins/dynamic-plugins/grpc-worker/rust/about.mdx
  • docs/configure-plugins/pii-redaction/about.mdx
  • docs/configure-plugins/pii-redaction/configuration.mdx
  • go/nemo_relay/pii_redaction.go
  • go/nemo_relay/pii_redaction/pii_redaction.go
  • go/nemo_relay/pii_redaction/pii_redaction_test.go
  • go/nemo_relay/pii_redaction_test.go
  • justfile
  • python/nemo_relay/pii_redaction.py
  • python/nemo_relay/pii_redaction.pyi
  • python/plugin/README.md
  • python/plugin/src/nemo_relay_plugin/__init__.py
  • python/plugin/src/nemo_relay_plugin/_api.py
  • python/tests/plugin/test_public_api_docstrings.py
  • python/tests/plugin/test_worker_sdk.py
  • python/tests/test_pii_redaction_plugin.py

Comment thread crates/pii-redaction/src/component.rs Outdated
Comment thread crates/pii-redaction/src/local.rs Outdated
Comment thread crates/pii-redaction/tests/unit/component_tests.rs Outdated
Comment thread crates/pii-redaction/tests/worker_detection_tests.rs Outdated
Comment thread crates/pii-redaction/tests/worker_detection_tests.rs Outdated
Comment thread docs/build-plugins/dynamic-plugins/grpc-worker/python/about.mdx Outdated
Comment thread docs/configure-plugins/pii-redaction/configuration.mdx Outdated
Comment thread docs/configure-plugins/pii-redaction/configuration.mdx Outdated
Comment thread go/nemo_relay/pii_redaction/pii_redaction_test.go Outdated
Comment thread python/plugin/README.md Outdated
Signed-off-by: Alex Fournier <afournier@nvidia.com>

@ericevans-nv ericevans-nv left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
@afourniernv

Copy link
Copy Markdown
Contributor Author

/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>
@afourniernv
afourniernv marked this pull request as ready for review August 3, 2026 17:58
@afourniernv

Copy link
Copy Markdown
Contributor Author

/ok to test 121f563

@willkill07

Copy link
Copy Markdown
Member

/ok to test 207fa57

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 win

Add blank lines around the License heading.

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.md around 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

📥 Commits

Reviewing files that changed from the base of the PR and between 79a861d and 207fa57.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (22)
  • ATTRIBUTIONS-Rust.md
  • Cargo.toml
  • crates/cli/src/plugins/prompt.rs
  • crates/cli/src/server/mod.rs
  • crates/cli/tests/coverage/shared/plugins_tests.rs
  • crates/node/package.json
  • crates/node/pii_rampart.d.ts
  • crates/node/pii_rampart.js
  • crates/node/src/api/mod.rs
  • crates/node/tests/pii_rampart_tests.mjs
  • crates/pii-redaction/Cargo.toml
  • crates/pii-redaction/README.md
  • crates/pii-redaction/src/rampart/mod.rs
  • crates/pii-redaction/src/rampart/model.rs
  • crates/pii-redaction/src/rampart/sanitizer.rs
  • crates/pii-redaction/src/rampart/tokenizer.rs
  • go/nemo_relay/pii_rampart.go
  • go/nemo_relay/pii_rampart/pii_rampart.go
  • go/nemo_relay/pii_rampart/pii_rampart_test.go
  • go/nemo_relay/pii_rampart_test.go
  • python/nemo_relay/__init__.py
  • python/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__.py
  • crates/cli/src/plugins/prompt.rs
  • crates/node/src/api/mod.rs
  • crates/cli/tests/coverage/shared/plugins_tests.rs
  • crates/cli/src/server/mod.rs
  • crates/pii-redaction/src/rampart/tokenizer.rs
  • crates/pii-redaction/src/rampart/model.rs
  • crates/pii-redaction/src/rampart/sanitizer.rs
  • crates/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}: Use Json = serde_json::Value in Rust-facing runtime APIs where the existing code expects JSON payloads.
Use Result<T> with FlowError in 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__.py
  • crates/cli/src/plugins/prompt.rs
  • crates/node/tests/pii_rampart_tests.mjs
  • crates/node/src/api/mod.rs
  • crates/cli/tests/coverage/shared/plugins_tests.rs
  • crates/cli/src/server/mod.rs
  • crates/pii-redaction/src/rampart/tokenizer.rs
  • crates/node/pii_rampart.js
  • crates/pii-redaction/src/rampart/model.rs
  • crates/pii-redaction/src/rampart/sanitizer.rs
  • crates/pii-redaction/src/rampart/mod.rs
  • crates/node/pii_rampart.d.ts
python/nemo_relay/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Python wrapper modules live under python/nemo_relay/, and the native extension is built from crates/python with maturin.

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 pass ty type 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 prefixed nemo_relay_, Go PascalCase, Node.js camelCase, and Python snake_case.

Files:

  • python/nemo_relay/__init__.py
  • go/nemo_relay/pii_rampart/pii_rampart_test.go
  • crates/cli/src/plugins/prompt.rs
  • crates/node/src/api/mod.rs
  • crates/cli/tests/coverage/shared/plugins_tests.rs
  • crates/cli/src/server/mod.rs
  • crates/pii-redaction/src/rampart/tokenizer.rs
  • crates/node/pii_rampart.js
  • go/nemo_relay/pii_rampart.go
  • crates/pii-redaction/src/rampart/model.rs
  • go/nemo_relay/pii_rampart/pii_rampart.go
  • crates/pii-redaction/src/rampart/sanitizer.rs
  • crates/pii-redaction/src/rampart/mod.rs
  • crates/node/pii_rampart.d.ts
  • go/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__.py
  • python/nemo_relay/__init__.pyi
  • go/nemo_relay/pii_rampart/pii_rampart_test.go
  • crates/node/src/api/mod.rs
  • go/nemo_relay/pii_rampart.go
  • go/nemo_relay/pii_rampart/pii_rampart.go
  • go/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__.py
  • python/nemo_relay/__init__.pyi
  • go/nemo_relay/pii_rampart/pii_rampart_test.go
  • go/nemo_relay/pii_rampart.go
  • go/nemo_relay/pii_rampart/pii_rampart.go
  • go/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 crate tests/ trees, and Python SDK tests belong under python/tests.

Files:

  • python/nemo_relay/__init__.py
  • crates/cli/src/plugins/prompt.rs
  • crates/node/src/api/mod.rs
  • crates/cli/src/server/mod.rs
  • crates/pii-redaction/src/rampart/tokenizer.rs
  • crates/pii-redaction/src/rampart/model.rs
  • crates/pii-redaction/src/rampart/sanitizer.rs
  • crates/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, use maintain-dynamic-plugins and 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, prefer uv run pre-commit run --files <changed files...>.
Before review or handoff, run uv run pre-commit run --all-files.

Files:

  • python/nemo_relay/__init__.py
  • python/nemo_relay/__init__.pyi
  • Cargo.toml
  • go/nemo_relay/pii_rampart/pii_rampart_test.go
  • crates/cli/src/plugins/prompt.rs
  • crates/node/tests/pii_rampart_tests.mjs
  • crates/node/src/api/mod.rs
  • crates/cli/tests/coverage/shared/plugins_tests.rs
  • crates/pii-redaction/Cargo.toml
  • crates/node/package.json
  • crates/cli/src/server/mod.rs
  • crates/pii-redaction/src/rampart/tokenizer.rs
  • crates/node/pii_rampart.js
  • go/nemo_relay/pii_rampart.go
  • crates/pii-redaction/README.md
  • crates/pii-redaction/src/rampart/model.rs
  • ATTRIBUTIONS-Rust.md
  • go/nemo_relay/pii_rampart/pii_rampart.go
  • crates/pii-redaction/src/rampart/sanitizer.rs
  • crates/pii-redaction/src/rampart/mod.rs
  • crates/node/pii_rampart.d.ts
  • go/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; resolve header_env values 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 and just test-rust when event fields change; run just test-python, just test-go, and just test-node when binding-native configuration or lifecycle changes.

Files:

  • python/nemo_relay/__init__.py
  • go/nemo_relay/pii_rampart/pii_rampart_test.go
  • crates/cli/src/plugins/prompt.rs
  • crates/node/src/api/mod.rs
  • crates/cli/tests/coverage/shared/plugins_tests.rs
  • crates/cli/src/server/mod.rs
  • crates/pii-redaction/src/rampart/tokenizer.rs
  • crates/node/pii_rampart.js
  • go/nemo_relay/pii_rampart.go
  • crates/pii-redaction/src/rampart/model.rs
  • go/nemo_relay/pii_rampart/pii_rampart.go
  • crates/pii-redaction/src/rampart/sanitizer.rs
  • crates/pii-redaction/src/rampart/mod.rs
  • crates/node/pii_rampart.d.ts
  • go/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__.py
  • go/nemo_relay/pii_rampart/pii_rampart_test.go
  • crates/cli/src/plugins/prompt.rs
  • crates/node/src/api/mod.rs
  • crates/cli/tests/coverage/shared/plugins_tests.rs
  • crates/cli/src/server/mod.rs
  • crates/pii-redaction/src/rampart/tokenizer.rs
  • crates/node/pii_rampart.js
  • go/nemo_relay/pii_rampart.go
  • crates/pii-redaction/src/rampart/model.rs
  • go/nemo_relay/pii_rampart/pii_rampart.go
  • crates/pii-redaction/src/rampart/sanitizer.rs
  • crates/pii-redaction/src/rampart/mod.rs
  • crates/node/pii_rampart.d.ts
  • go/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__.py
  • go/nemo_relay/pii_rampart/pii_rampart_test.go
  • crates/node/pii_rampart.js
  • go/nemo_relay/pii_rampart.go
  • crates/pii-redaction/README.md
  • ATTRIBUTIONS-Rust.md
  • go/nemo_relay/pii_rampart/pii_rampart.go
  • crates/node/pii_rampart.d.ts
  • go/nemo_relay/pii_rampart_test.go
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/__init__.py
  • python/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 as release/<major>.<minor>.

Keep Rust package names and workspace metadata in Cargo.toml internally consistent across the project.

OpenTelemetry and OpenInference dependencies must be unconditional rather than Cargo feature-gated.

Files:

  • Cargo.toml
  • crates/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.toml
  • crates/pii-redaction/Cargo.toml
Cargo.toml

📄 CodeRabbit inference engine (.agents/skills/update-project-version/SKILL.md)

In Cargo.toml, treat [workspace.package].version as the source of truth for the Rust workspace and Python build versioning, and keep workspace.dependencies.nemo-relay.version, workspace.dependencies.nemo-relay-adaptive.version, workspace.dependencies.nemo-relay-pii-redaction.version, workspace.dependencies.nemo-relay-ffi.version, and workspace.dependencies.nemo-relay-cli.version aligned when the workspace version changes.

Files:

  • Cargo.toml
go/nemo_relay/**/*.go

📄 CodeRabbit inference engine (.agents/skills/test-go-binding/SKILL.md)

go/nemo_relay/**/*.go: Format changed Go packages with cd go/nemo_relay && go fmt ./...
Run Go tests with just test-go to build and test the NeMo Relay Go binding
Use just build-go when you want an explicit build-only pass or need the artifact for other work
Use just ci=true test-go when you need the CI-style coverage and JUnit path
On macOS, set DYLD_LIBRARY_PATH to the ../../target/release directory before running the raw go test command directly

Use PascalCase for public Go APIs.

Files:

  • go/nemo_relay/pii_rampart/pii_rampart_test.go
  • go/nemo_relay/pii_rampart.go
  • go/nemo_relay/pii_rampart/pii_rampart.go
  • go/nemo_relay/pii_rampart_test.go
**/*.go

📄 CodeRabbit inference engine (CONTRIBUTING.md)

When changing the experimental Go binding, format Go code with gofmt and keep go vet ./... passing.

Files:

  • go/nemo_relay/pii_rampart/pii_rampart_test.go
  • go/nemo_relay/pii_rampart.go
  • go/nemo_relay/pii_rampart/pii_rampart.go
  • go/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.go
  • crates/cli/src/plugins/prompt.rs
  • crates/node/src/api/mod.rs
  • crates/cli/tests/coverage/shared/plugins_tests.rs
  • crates/cli/src/server/mod.rs
  • crates/pii-redaction/src/rampart/tokenizer.rs
  • crates/node/pii_rampart.js
  • go/nemo_relay/pii_rampart.go
  • crates/pii-redaction/src/rampart/model.rs
  • go/nemo_relay/pii_rampart/pii_rampart.go
  • crates/pii-redaction/src/rampart/sanitizer.rs
  • crates/pii-redaction/src/rampart/mod.rs
  • crates/node/pii_rampart.d.ts
  • go/nemo_relay/pii_rampart_test.go
go/nemo_relay/**

📄 CodeRabbit inference engine (.agents/skills/maintain-optimizer/SKILL.md)

Keep shared plugin helpers in go/nemo_relay aligned with plugin registration, composition, and lifecycle behavior.

Files:

  • go/nemo_relay/pii_rampart/pii_rampart_test.go
  • go/nemo_relay/pii_rampart.go
  • go/nemo_relay/pii_rampart/pii_rampart.go
  • go/nemo_relay/pii_rampart_test.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/pii_rampart_test.go
  • go/nemo_relay/pii_rampart.go
  • go/nemo_relay/pii_rampart/pii_rampart.go
  • go/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.go
  • crates/node/tests/pii_rampart_tests.mjs
  • crates/cli/tests/coverage/shared/plugins_tests.rs
  • go/nemo_relay/pii_rampart_test.go
**/*.rs

📄 CodeRabbit inference engine (.agents/skills/prepare-pr/SKILL.md)

**/*.rs: Any Rust change must run just test-rust
Any Rust change must run cargo fmt --all
Any Rust change must run cargo clippy --workspace --all-targets -- -D warnings

**/*.rs: Run cargo fmt --all for all FFI work since it is Rust work
Run just test-rust to validate FFI changes
Run cargo clippy --workspace --all-targets -- -D warnings to enforce strict linting on FFI work

When Rust files changed as part of Go work, also run cargo fmt --all, just test-rust, and cargo clippy --workspace --all-targets -- -D warnings

**/*.rs: Run cargo fmt --all when Rust files are changed as part of Node work
Run cargo clippy --workspace --all-targets -- -D warnings when Rust files are changed as part of Node work
Run just test-rust when Rust files are changed as part of Node work

When changing the core Rust runtime or Rust-facing API surface, format Rust code with cargo fmt (rustfmt defaults), keep cargo clippy -- -D warnings clean, and satisfy cargo deny check per deny.toml.

**/*.rs: If any Rust code changed, always run just test-rust.
If any Rust code changed, also run cargo fmt --all.
If any Rust code changed, also run cargo clippy --workspace --all-targets -- -D warnings.
For Rust changes headed for review, run cargo fmt --all and cargo clippy --workspace --all-targets -- -D warnings even if relying on pre-commit.

Files:

  • crates/cli/src/plugins/prompt.rs
  • crates/node/src/api/mod.rs
  • crates/cli/tests/coverage/shared/plugins_tests.rs
  • crates/cli/src/server/mod.rs
  • crates/pii-redaction/src/rampart/tokenizer.rs
  • crates/pii-redaction/src/rampart/model.rs
  • crates/pii-redaction/src/rampart/sanitizer.rs
  • crates/pii-redaction/src/rampart/mod.rs
crates/node/**/*.{js,mjs,cjs,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use camelCase for Node.js public APIs.

Files:

  • crates/node/tests/pii_rampart_tests.mjs
  • crates/node/pii_rampart.js
  • crates/node/pii_rampart.d.ts
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.mjs
  • crates/node/src/api/mod.rs
  • crates/node/package.json
  • crates/node/pii_rampart.js
  • crates/node/pii_rampart.d.ts
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/package.json
  • crates/node/pii_rampart.js
  • crates/node/pii_rampart.d.ts
crates/node/package.json

📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)

Keep the Node package metadata in crates/node/package.json consistent with the package name, versioning, and publish surface.

Keep the crates/node/package.json package version aligned with the workspace-root package-lock.json, and keep its dependencies["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 spell NVIDIA in all caps. Do not use Nvidia, nvidia, nVidia, nVIDIA, or NV.
Use an NVIDIA before a noun because the name starts with an 'en' sound.
Do not add a registered trademark symbol after NVIDIA when 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 with NVIDIA on 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 with s, not an apostrophe, such as GPUs.
In headings, common acronyms can remain abbreviated. Spell out the term in the first or second sentence of the body.
Common terms such as CPU, GPU, PC, API, and UI usually do not need to be spelled out for developer audiences.

Files:

  • crates/pii-redaction/README.md
  • ATTRIBUTIONS-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.md
  • ATTRIBUTIONS-Rust.md
**/*.{md,rst,txt}

📄 CodeRabbit inference engine (.agents/skills/review-doc-style/assets/nvidia-style-guide.md)

Spell NVIDIA in all caps. Do not use Nvidia, nvidia, or NV.

Files:

  • crates/pii-redaction/README.md
  • ATTRIBUTIONS-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.
Use can for possibility and reserve may for permission.
Use after for temporal relationships instead of once.
Prefer refer to over see when 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
  • ATTRIBUTIONS-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.md
  • ATTRIBUTIONS-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 as RELEASING.md, not as user-facing docs pages or CHANGELOG.md
Keep stable user-facing wrappers at scripts/ 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, and grpc-v1 protocol details on separate pages

If links in documentation change, run just docs-linkcheck.

Files:

  • crates/pii-redaction/README.md
  • ATTRIBUTIONS-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.md
  • ATTRIBUTIONS-Rust.md
crates/node/**/*.{ts,tsx,d.ts}

📄 CodeRabbit inference engine (.agents/skills/test-node-binding/SKILL.md)

Use npm run check:docstrings --workspace=nemo-relay-node to validate public API docstring checks when surface docs changed

Files:

  • 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.go
  • go/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.go
  • go/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 Quality

Run the documentation link checker.

Because Line 220 adds a new external link, run just docs-linkcheck before handoff.

As per coding guidelines, run just docs-linkcheck when 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 Quality

Keep the current dependency declarations. tempfile = "3" is present, and unicode_categories 0.1.1 has no RustSec advisory. Its age alone does not require a change.

			> Likely an incorrect or invalid review comment.

Comment thread crates/node/pii_rampart.js
Comment thread crates/pii-redaction/src/rampart/mod.rs
Comment thread crates/pii-redaction/src/rampart/mod.rs
Comment thread crates/pii-redaction/src/rampart/mod.rs
Comment thread crates/pii-redaction/src/rampart/model.rs
Comment thread crates/pii-redaction/src/rampart/sanitizer.rs
Comment thread crates/pii-redaction/src/rampart/sanitizer.rs
Comment thread crates/pii-redaction/src/rampart/sanitizer.rs
Comment thread crates/pii-redaction/src/rampart/tokenizer.rs
Comment thread go/nemo_relay/pii_rampart_test.go
Signed-off-by: Alex Fournier <afournier@nvidia.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 207fa57 and 9d59ce6.

📒 Files selected for processing (10)
  • crates/node/pii_rampart.js
  • crates/node/tests/pii_rampart_tests.mjs
  • crates/pii-redaction/README.md
  • crates/pii-redaction/src/rampart/mod.rs
  • crates/pii-redaction/src/rampart/model.rs
  • crates/pii-redaction/src/rampart/sanitizer.rs
  • go/nemo_relay/pii_rampart.go
  • go/nemo_relay/pii_rampart_test.go
  • python/nemo_relay/pii_rampart.py
  • python/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.py
  • python/nemo_relay/pii_rampart.py
  • crates/pii-redaction/src/rampart/mod.rs
  • crates/pii-redaction/src/rampart/sanitizer.rs
  • crates/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}: Use Json = serde_json::Value in Rust-facing runtime APIs where the existing code expects JSON payloads.
Use Result<T> with FlowError in 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.py
  • crates/node/tests/pii_rampart_tests.mjs
  • crates/node/pii_rampart.js
  • python/nemo_relay/pii_rampart.py
  • crates/pii-redaction/src/rampart/mod.rs
  • crates/pii-redaction/src/rampart/sanitizer.rs
  • crates/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 pass ty type checking.
Add the SPDX license header to all Python source files using the # comment form.

Files:

  • python/tests/test_pii_rampart_plugin.py
  • python/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 prefixed nemo_relay_, Go PascalCase, Node.js camelCase, and Python snake_case.

Files:

  • python/tests/test_pii_rampart_plugin.py
  • go/nemo_relay/pii_rampart_test.go
  • crates/node/pii_rampart.js
  • go/nemo_relay/pii_rampart.go
  • python/nemo_relay/pii_rampart.py
  • crates/pii-redaction/src/rampart/mod.rs
  • crates/pii-redaction/src/rampart/sanitizer.rs
  • crates/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 crate tests/ trees, and Python SDK tests belong under python/tests.

Files:

  • python/tests/test_pii_rampart_plugin.py
  • python/nemo_relay/pii_rampart.py
  • crates/pii-redaction/src/rampart/mod.rs
  • crates/pii-redaction/src/rampart/sanitizer.rs
  • crates/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.asyncio to any test; async tests are automatically detected and run by the async runner.
Do not add a -> None return type annotation to test functions.
When mocking a class, do not define a new class; use unittest.mock.MagicMock or unittest.mock.AsyncMock, with the spec constructor argument when necessary.
Name mocked classes with the mock prefix, not fake.
Prefer pytest fixtures over helper methods.
Do not repeat fixtures; if a fixture is needed in multiple test files, place it in a conftest.py file.
When creating a fixture, use @pytest.fixture(name="<fixture_name>"[, scope="<scope>"]) and define the fixture function as def <fixture_name>_fixture() -> <return_type>:; only specify scope when it is not function.
Prefer pytest.mark.parametrize over 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, use maintain-dynamic-plugins and 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, prefer uv run pre-commit run --files <changed files...>.
Before review or handoff, run uv run pre-commit run --all-files.

Files:

  • python/tests/test_pii_rampart_plugin.py
  • crates/node/tests/pii_rampart_tests.mjs
  • go/nemo_relay/pii_rampart_test.go
  • crates/node/pii_rampart.js
  • go/nemo_relay/pii_rampart.go
  • python/nemo_relay/pii_rampart.py
  • crates/pii-redaction/README.md
  • crates/pii-redaction/src/rampart/mod.rs
  • crates/pii-redaction/src/rampart/sanitizer.rs
  • crates/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; resolve header_env values 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 and just test-rust when event fields change; run just test-python, just test-go, and just test-node when binding-native configuration or lifecycle changes.

Files:

  • python/tests/test_pii_rampart_plugin.py
  • go/nemo_relay/pii_rampart_test.go
  • crates/node/pii_rampart.js
  • go/nemo_relay/pii_rampart.go
  • python/nemo_relay/pii_rampart.py
  • crates/pii-redaction/src/rampart/mod.rs
  • crates/pii-redaction/src/rampart/sanitizer.rs
  • crates/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.py
  • go/nemo_relay/pii_rampart_test.go
  • crates/node/pii_rampart.js
  • go/nemo_relay/pii_rampart.go
  • python/nemo_relay/pii_rampart.py
  • crates/pii-redaction/src/rampart/mod.rs
  • crates/pii-redaction/src/rampart/sanitizer.rs
  • crates/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.py
  • go/nemo_relay/pii_rampart_test.go
  • crates/node/pii_rampart.js
  • go/nemo_relay/pii_rampart.go
  • python/nemo_relay/pii_rampart.py
  • crates/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.py
  • crates/node/tests/pii_rampart_tests.mjs
  • go/nemo_relay/pii_rampart_test.go
crates/node/**/*.{js,mjs,cjs,ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use camelCase for Node.js public APIs.

Files:

  • crates/node/tests/pii_rampart_tests.mjs
  • crates/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.mjs
  • crates/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 with cd go/nemo_relay && go fmt ./...
Run Go tests with just test-go to build and test the NeMo Relay Go binding
Use just build-go when you want an explicit build-only pass or need the artifact for other work
Use just ci=true test-go when you need the CI-style coverage and JUnit path
On macOS, set DYLD_LIBRARY_PATH to the ../../target/release directory before running the raw go test command directly

Use PascalCase for public Go APIs.

Files:

  • go/nemo_relay/pii_rampart_test.go
  • go/nemo_relay/pii_rampart.go
**/*.go

📄 CodeRabbit inference engine (CONTRIBUTING.md)

When changing the experimental Go binding, format Go code with gofmt and keep go vet ./... passing.

Files:

  • go/nemo_relay/pii_rampart_test.go
  • go/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.go
  • crates/node/pii_rampart.js
  • go/nemo_relay/pii_rampart.go
  • crates/pii-redaction/src/rampart/mod.rs
  • crates/pii-redaction/src/rampart/sanitizer.rs
  • crates/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.go
  • go/nemo_relay/pii_rampart.go
  • python/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.go
  • go/nemo_relay/pii_rampart.go
  • python/nemo_relay/pii_rampart.py
go/nemo_relay/**

📄 CodeRabbit inference engine (.agents/skills/maintain-optimizer/SKILL.md)

Keep shared plugin helpers in go/nemo_relay aligned with plugin registration, composition, and lifecycle behavior.

Files:

  • go/nemo_relay/pii_rampart_test.go
  • go/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.go
  • go/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 from crates/python with maturin.

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 spell NVIDIA in all caps. Do not use Nvidia, nvidia, nVidia, nVIDIA, or NV.
Use an NVIDIA before a noun because the name starts with an 'en' sound.
Do not add a registered trademark symbol after NVIDIA when 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 with NVIDIA on 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 with s, not an apostrophe, such as GPUs.
In headings, common acronyms can remain abbreviated. Spell out the term in the first or second sentence of the body.
Common terms such as CPU, GPU, PC, API, and UI usually 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 NVIDIA in all caps. Do not use Nvidia, nvidia, or NV.

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.
Use can for possibility and reserve may for permission.
Use after for temporal relationships instead of once.
Prefer refer to over see when 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 as RELEASING.md, not as user-facing docs pages or CHANGELOG.md
Keep stable user-facing wrappers at scripts/ 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, and grpc-v1 protocol details on separate pages

If 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 run just test-rust
Any Rust change must run cargo fmt --all
Any Rust change must run cargo clippy --workspace --all-targets -- -D warnings

**/*.rs: Run cargo fmt --all for all FFI work since it is Rust work
Run just test-rust to validate FFI changes
Run cargo clippy --workspace --all-targets -- -D warnings to enforce strict linting on FFI work

When Rust files changed as part of Go work, also run cargo fmt --all, just test-rust, and cargo clippy --workspace --all-targets -- -D warnings

**/*.rs: Run cargo fmt --all when Rust files are changed as part of Node work
Run cargo clippy --workspace --all-targets -- -D warnings when Rust files are changed as part of Node work
Run just test-rust when Rust files are changed as part of Node work

When changing the core Rust runtime or Rust-facing API surface, format Rust code with cargo fmt (rustfmt defaults), keep cargo clippy -- -D warnings clean, and satisfy cargo deny check per deny.toml.

**/*.rs: If any Rust code changed, always run just test-rust.
If any Rust code changed, also run cargo fmt --all.
If any Rust code changed, also run cargo clippy --workspace --all-targets -- -D warnings.
For Rust changes headed for review, run cargo fmt --all and cargo clippy --workspace --all-targets -- -D warnings even if relying on pre-commit.

Files:

  • crates/pii-redaction/src/rampart/mod.rs
  • crates/pii-redaction/src/rampart/sanitizer.rs
  • crates/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 Quality

Run the documentation link check.

Run just docs-linkcheck before 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 & Integration

No constructor mismatch exists. pii_rampart.NewConfig delegates to nemo_relay.NewRampartPiiConfig, so it uses MaxWindowsPerPayload: 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 & Integration

No default mismatch remains. All bindings use 4, and the Rust serde default 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 & Integration

No 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

Comment thread crates/pii-redaction/src/rampart/mod.rs
Comment thread crates/pii-redaction/src/rampart/model.rs
Comment thread crates/pii-redaction/src/rampart/sanitizer.rs Outdated
Comment thread crates/pii-redaction/src/rampart/sanitizer.rs
Signed-off-by: Alex Fournier <afournier@nvidia.com>
Signed-off-by: Alex Fournier <afournier@nvidia.com>
@afourniernv

afourniernv commented Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

Current-head production benchmark

Reran the Rampart validation on commit be1725e4 using a release build on an Apple M4 Pro (14 logical CPUs, 48 GiB RAM) and the pinned, hash-verified Q4 model snapshot. The harness and model files remained temporary and are not part of the branch.

This head adds a bounded, content-addressed decision cache and field-level model-budget fallback:

  • Cache keys are SHA-256 digests. Cached values contain only keep/redact/fail-closed decisions and byte ranges, never selected or sanitized text.
  • The cache is bounded to 4,096 entries and 4 MiB of decision ranges per plugin activation.
  • Exact strings are deduplicated within a payload and across later calls. Cache hits do not consume the per-payload unique-text or model-window budget.
  • If a group exceeds the model budget, Rampart splits it until each field can be evaluated. An individually oversized field fails closed without removing the surrounding request, response, tool payload, or event.
  • Transient model/output failures are not cached. Budget-driven field omission is warning-logged without field content.

Real Claude Code and Codex traffic

I 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.

  • 15/15 LLM starts and 15/15 LLM ends retained their observable bodies: 4/4 Anthropic and 11/11 OpenAI Responses on each side.
  • 36/36 tool scopes retained their observable bodies across Bash, Glob, Grep, and Read.
  • All 37 lifecycle UUID groups were structurally valid.
  • Zero synthetic privacy-canary leaks were present in 1,263 emitted events.
  • Cold Codex instructions between 8.2 and 17.8 KiB exceeded the individual four-window budget and were replaced field-by-field; the request envelopes and all other fields remained available.

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 matrix

The 16-window run gives the direct comparison with the prior benchmark.

Workload Throughput p50 p95 p99
Repeated sequential request/response 3,538.92 calls/s 0.275 ms 0.361 ms 0.372 ms
Eight-way agent fan-out with 5 ms provider delay 1,243.78 calls/s 6.228 ms 6.798 ms 6.926 ms
1,200-call soak at concurrency 8 5,952.93 calls/s 1.206 ms 1.737 ms 2.225 ms

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:

Selected field Cold Warm p50
64 B 4.346 ms 0.213 ms
256 B 10.560 ms 0.198 ms
1 KiB 42.322 ms 0.226 ms
8 KiB 446.440 ms 0.564 ms
16 KiB 924.273 ms 0.304 ms

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:

  • 1,124/1,128 modeled sensitive spans redacted: 99.645%.
  • Wilson 95% interval: 99.092%-99.862%.
  • 460/460 intentionally unmodeled public terms retained.
  • The same four misses remained: one SOCIALNUM, two CITY spans, and one questionable BUILDINGNUM annotation.

Validation on this head:

  • just test-rust
  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo fmt --all
  • uv run pre-commit run --all-files
  • Focused Rampart suite: 160/160 passed

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.

@afourniernv

Copy link
Copy Markdown
Contributor Author

/ok to test 1866014

@afourniernv
afourniernv marked this pull request as draft August 3, 2026 21:52
@afourniernv

Copy link
Copy Markdown
Contributor Author

/ok to test be1725e

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Feature a new feature lang:go PR changes/introduces Go code lang:js PR changes/introduces Javascript/Typescript code lang:python PR changes/introduces Python code lang:rust PR changes/introduces Rust code size:XXL PR is very large

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants