Skip to content

fix(pii): preserve trusted scope metadata#531

Merged
rapids-bot[bot] merged 4 commits into
NVIDIA:release/0.6from
willkill07:fix/trajectory-context-scope-metadata
Jul 22, 2026
Merged

fix(pii): preserve trusted scope metadata#531
rapids-bot[bot] merged 4 commits into
NVIDIA:release/0.6from
willkill07:fix/trajectory-context-scope-metadata

Conversation

@willkill07

@willkill07 willkill07 commented Jul 22, 2026

Copy link
Copy Markdown
Member

Overview

Preserves trusted Relay and CLI scope-classification metadata in the trajectory_context PII-redaction preset while continuing to redact arbitrary metadata.

  • 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

  • Preserve documented direct string classification metadata and the typed boolean provider_payload_exact on Scope events only.
  • Project the trusted agent_kind value as nemo_relay.agent.kind on OpenTelemetry and OpenInference trace roots and session identity marks.
  • Keep the exception type-aware: malformed, nested, arbitrary, and content-bearing metadata remains semantically redacted.
  • Add scope, subscriber/exporter, and root-span identity regression coverage, and document the trusted-metadata contract.

Where should the reviewer start?

Start in crates/pii-redaction/src/trajectory.rs for the type-aware scope sanitizer, then crates/core/src/observability/mod.rs for the canonical agent identity projection and their focused regression tests.

Related Issues: (use one of the action keywords Closes / Fixes / Resolves / Relates to)

Summary by CodeRabbit

  • New Features
    • Enhanced trajectory-context exports in preserve mode to retain only a fixed set of approved, low-cardinality Scope metadata fields (string/boolean), while redacting private/nested and any unexpected metadata.
    • Added agent_kind projection into OpenTelemetry trace roots and session mark events.
  • Bug Fixes
    • Improved sanitization behavior for Scope metadata, including safer handling of malformed trusted metadata and redaction of session ownership fields.
  • Documentation
    • Updated the README to clarify trusted Scope-metadata preset behavior and warn against placing PII/conversational content in retained fields.

Signed-off-by: Will Killian <wkillian@nvidia.com>
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 63ebd26e-f15a-4afb-95ac-62379046b249

📥 Commits

Reviewing files that changed from the base of the PR and between dff9d99 and d1301de.

📒 Files selected for processing (1)
  • crates/pii-redaction/src/trajectory.rs
📜 Recent review details
🧰 Additional context used
📓 Path-based instructions (9)
**/*.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/trajectory.rs
**/*.{rs,py}

📄 CodeRabbit inference engine (AGENTS.md)

Follow binding naming conventions in Rust and Python: use snake_case.

Files:

  • crates/pii-redaction/src/trajectory.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:

  • crates/pii-redaction/src/trajectory.rs
**/*.{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:

  • crates/pii-redaction/src/trajectory.rs
**/*.{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:

  • crates/pii-redaction/src/trajectory.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:

  • crates/pii-redaction/src/trajectory.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:

  • crates/pii-redaction/src/trajectory.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.

Files:

  • crates/pii-redaction/src/trajectory.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:

  • crates/pii-redaction/src/trajectory.rs
🔇 Additional comments (4)
crates/pii-redaction/src/trajectory.rs (4)

14-33: LGTM!


158-197: LGTM!


329-379: LGTM!


14-379: 📐 Maintainability & Code Quality

Run the required Rust validation before handoff.

Please attach results for cargo fmt --all, cargo clippy --workspace --all-targets -- -D warnings, just test-rust, and uv run pre-commit run --all-files. As per coding guidelines, “If any Rust code changed, always run just test-rust,” “run cargo fmt --all,” “run cargo clippy --workspace --all-targets -- -D warnings,” and “Before review or handoff, run uv run pre-commit run --all-files.”

Source: Coding guidelines


Walkthrough

The trajectory sanitizer now preserves explicitly trusted Scope metadata values by field and JSON type, while redacting arbitrary or malformed metadata. Observability projection also emits agent_kind on trace roots and marks, with tests covering sanitization and span placement.

Changes

Trajectory metadata sanitization

Layer / File(s) Summary
Scope metadata sanitization
crates/pii-redaction/src/trajectory.rs, crates/pii-redaction/README.md, crates/pii-redaction/tests/unit/component_tests.rs
Adds typed trusted-field allowlists, preserves matching Scope metadata, redacts other values, documents the contract, and validates behavior across sanitization surfaces.

Agent kind observability projection

Layer / File(s) Summary
Agent kind observability projection
crates/core/src/observability/mod.rs, crates/core/tests/unit/observability/*
Projects agent_kind as nemo_relay.agent.kind on trace roots and marks, but not child spans.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title follows Conventional Commits and accurately summarizes the main change.
Description check ✅ Passed The description matches the repo template and includes overview, details, reviewer start, checklist items, and related issues.
Linked Issues check ✅ Passed The changes preserve trusted scope metadata, redact malformed/arbitrary values, project agent_kind correctly, and add matching regression/docs coverage for #528.
Out of Scope Changes check ✅ Passed The diff stays focused on trusted scope metadata preservation, observability projection, tests, and documentation with no unrelated code paths.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ 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:M PR is medium Bug issue describes bug; PR fixes bug lang:rust PR changes/introduces Rust code labels Jul 22, 2026
@willkill07 willkill07 self-assigned this Jul 22, 2026
@willkill07 willkill07 added this to the 0.6 milestone Jul 22, 2026
@github-actions

Copy link
Copy Markdown

@willkill07
willkill07 marked this pull request as ready for review July 22, 2026 13:21
@willkill07
willkill07 requested a review from a team as a code owner July 22, 2026 13:21
Comment thread crates/pii-redaction/src/trajectory.rs Outdated
@bbednarski9

Copy link
Copy Markdown
Contributor

Suggested follow-up: typed trusted metadata and canonical agent identity

For the release/0.6 contract, I think the static allowlist should be split by JSON type. This preserves the additional low-cardinality classification fields while allowing provider_payload_exact to retain its boolean value.

In crates/pii-redaction/src/trajectory.rs:

const TRUSTED_STRING_SCOPE_METADATA_FIELDS: &[&str] = &[
    "nemo_relay_scope_role",
    "agent_kind",
    "hook_event_name",
    "gateway_config_profile",
    "gateway_mode",
    "turn_source",
    "harness",
    "source",
    "identity_quality",
    "gateway_path",
    "llm_correlation_status",
    "llm_correlation_source",
    "tool_correlation_status",
    "tool_correlation_source",
    "otel.status_code",
    "fidelity_source",
];

const TRUSTED_BOOLEAN_SCOPE_METADATA_FIELDS: &[&str] = &["provider_payload_exact"];

Then make the allowlist check value-type aware:

fn sanitize_scope_metadata(value: Json, replacement: &str) -> Json {
    let Json::Object(values) = value else {
        return redact_semantic_content(value, replacement, None);
    };

    Json::Object(
        values
            .into_iter()
            .map(|(key, value)| {
                let value = if is_trusted_scope_metadata_value(&key, &value) {
                    value
                } else {
                    redact_semantic_content(value, replacement, Some(&key))
                };
                (key, value)
            })
            .collect(),
    )
}

fn is_trusted_scope_metadata_value(key: &str, value: &Json) -> bool {
    match value {
        Json::String(_) => TRUSTED_STRING_SCOPE_METADATA_FIELDS.contains(&key),
        Json::Bool(_) => TRUSTED_BOOLEAN_SCOPE_METADATA_FIELDS.contains(&key),
        _ => false,
    }
}

For the stable downstream harness key, agent_kind is already the trusted source field. Rather than adding nemo_relay.agent.kind to the metadata allowlist, project it as a canonical root-span attribute in push_session_identity_attributes in crates/core/src/observability/mod.rs:

if let Some(agent_kind) = metadata
    .and_then(|value| value.get("agent_kind"))
    .and_then(crate::json::Json::as_str)
{
    attributes.push(KeyValue::new(
        "nemo_relay.agent.kind",
        agent_kind.to_string(),
    ));
}

That helper is shared by OpenTelemetry and OpenInference and is applied to trace roots/session identity marks. otel.status_description is intentionally excluded because it is free-form error content; otel.status_code remains available for span status semantics.

I compiled this exact combination locally against the current PR head; the focused OpenTelemetry/OpenInference identity tests and the full PII-redaction suite passed.

@bbednarski9

Copy link
Copy Markdown
Contributor

Suggested regression coverage for the finalized contract

I would extend the existing trusted-metadata test and add one end-to-end ATIF hierarchy test. This covers the newly trusted strings, the trusted boolean, the deliberate exclusion of otel.status_description, value-type enforcement, canonical root projection, and actual turn/subagent reconstruction.

First, add these fields to metadata in trajectory_preset_preserves_trusted_scope_metadata_only:

"gateway_path": "/v1/responses",
"llm_correlation_status": "matched_hint",
"llm_correlation_source": "request_affinity",
"tool_correlation_status": "explicit",
"tool_correlation_source": "hook",
"otel.status_code": "ERROR",
"fidelity_source": "hermes_api_hooks_sanitized",
"provider_payload_exact": true,
"otel.status_description": "private provider error",

Add the corresponding expected values:

"gateway_path": "/v1/responses",
"llm_correlation_status": "matched_hint",
"llm_correlation_source": "request_affinity",
"tool_correlation_status": "explicit",
"tool_correlation_source": "hook",
"otel.status_code": "ERROR",
"fidelity_source": "hermes_api_hooks_sanitized",
"provider_payload_exact": true,
"otel.status_description": "[REDACTED]",

The malformed-value case should also verify that the key alone is insufficient when the JSON type is wrong:

// Input
"gateway_path": true,
"provider_payload_exact": "true",

// Expected
"gateway_path": false,
"provider_payload_exact": "[REDACTED]",

For the canonical root attribute, extend session_identity_is_projected_on_trace_roots_and_marks_only in crates/core/tests/unit/observability/otel_tests.rs:

let identity = json!({
    "session_id": "logical-session",
    "user_id": "alice",
    "agent_kind": "claude-code"
});
assert_eq!(root_attributes["nemo_relay.agent.kind"], "claude-code");
assert!(!child_attributes.contains_key("nemo_relay.agent.kind"));

Finally, add this focused ATIF regression test after sanitized_trajectory_content_never_reaches_subscribers_or_exporters:

#[test]
fn trajectory_preset_preserves_turn_and_subagent_roles_for_atif() {
    let _guard = crate::plugins::pii_redaction::test_mutex().lock().unwrap();
    reset_runtime();
    setup_isolated_thread();

    futures::executor::block_on(initialize_plugins(plugin_config(json!({
        "codec": "openai_chat",
        "profiles": [{
            "mode": "builtin",
            "priority": 80,
            "builtin": {"preset": "trajectory_context"}
        }]
    }))))
    .unwrap();

    let atif = AtifExporter::new(
        "pii-role-regression".into(),
        AtifAgentInfo {
            name: "test-agent".into(),
            version: "1".into(),
            model_name: None,
            tool_definitions: None,
            extra: None,
        },
    );
    register_subscriber("pii-role-regression-atif", atif.subscriber()).unwrap();

    let session = push_scope(
        PushScopeParams::builder()
            .name("claude-code-session")
            .scope_type(ScopeType::Agent)
            .metadata(json!({
                "nemo_relay_scope_role": "session",
                "agent_kind": "claude-code"
            }))
            .build(),
    )
    .unwrap();
    let turn = push_scope(
        PushScopeParams::builder()
            .name("claude-code-turn")
            .scope_type(ScopeType::Agent)
            .metadata(json!({"nemo_relay_scope_role": "turn"}))
            .build(),
    )
    .unwrap();
    let subagent = push_scope(
        PushScopeParams::builder()
            .name("claude-code-subagent")
            .scope_type(ScopeType::Agent)
            .metadata(json!({
                "nemo_relay_scope_role": "subagent",
                "session_id": "child-session"
            }))
            .build(),
    )
    .unwrap();
    let child_llm = push_scope(
        PushScopeParams::builder()
            .name("child-llm")
            .scope_type(ScopeType::Llm)
            .input(json!({
                "messages": [{"role": "user", "content": "[REDACTED]"}]
            }))
            .build(),
    )
    .unwrap();
    pop_scope(
        PopScopeParams::builder()
            .handle_uuid(&child_llm.uuid)
            .output(json!({"content": "[REDACTED]"}))
            .build(),
    )
    .unwrap();
    for handle in [&subagent, &turn, &session] {
        pop_scope(PopScopeParams::builder().handle_uuid(&handle.uuid).build()).unwrap();
    }

    crate::api::subscriber::flush_subscribers().unwrap();
    let trajectory = serde_json::to_value(atif.export().unwrap()).unwrap();

    assert_eq!(
        trajectory["subagent_trajectories"][0]["trajectory_id"],
        subagent.uuid.to_string()
    );
    assert_eq!(
        trajectory["steps"][0]["observation"]["results"][0]
            ["subagent_trajectory_ref"][0]["trajectory_id"],
        subagent.uuid.to_string()
    );

    deregister_subscriber("pii-role-regression-atif").unwrap();
    clear_plugin_configuration().unwrap();
}

I mutation-tested the ATIF case by removing nemo_relay_scope_role from the trusted list: it then failed because the turn was classified as the embedded child instead of the actual subagent. With the full proposed implementation, formatting passed and all 88 PII-redaction tests passed.

Signed-off-by: Will Killian <wkillian@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: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/pii-redaction/tests/unit/component_tests.rs (1)

1887-1899: 🎯 Functional Correctness | 🔵 Trivial | 🏗️ Heavy lift

Assert trusted field/value associations structurally.

output.contains(key) && output.contains(value) can pass when an exporter drops the field but emits the same key or value elsewhere; true is especially non-specific. Parse JSON-backed outputs and inspect OTLP/ATIF attributes by key, or add per-surface key/value assertions, so this fan-out regression verifies the actual association.

As per path instructions, tests should prefer lifecycle and scope-semantic assertions over shallow smoke checks.

🤖 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/pii-redaction/tests/unit/component_tests.rs` around lines 1887 - 1899,
Replace the substring checks in the trusted_scope_metadata assertion within the
fan-out test with structural validation of each key/value association. Parse
JSON-backed outputs and inspect OTLP/ATIF attributes by key, while using
equivalent per-surface assertions where parsing differs; preserve the
session_owner exclusion and verify the value belongs to its expected field
rather than merely appearing elsewhere.

Source: Path instructions

🤖 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/core/src/observability/mod.rs`:
- Around line 302-310: Run the required validation before handoff: just
test-rust, cargo fmt --all, cargo clippy --workspace --all-targets -- -D
warnings, validate-change, the full Rust/Python/Go/Node test matrix, and uv run
pre-commit run --all-files. Confirm all formatting, linting, tests, runtime
checks, and language-matrix validations pass for the Rust changes around
observability metadata handling.

In `@crates/core/tests/unit/observability/openinference_tests.rs`:
- Around line 829-833: Extend the malformed agent_kind coverage in
crates/core/tests/unit/observability/openinference_tests.rs:829-833 by adding a
second-root fixture with agent_kind set to a numeric value and asserting
nemo_relay.agent.kind is absent. Mirror the same fixture and absence assertion
in crates/core/tests/unit/observability/otel_tests.rs:720-724, preserving the
existing valid and omitted-field cases.

---

Outside diff comments:
In `@crates/pii-redaction/tests/unit/component_tests.rs`:
- Around line 1887-1899: Replace the substring checks in the
trusted_scope_metadata assertion within the fan-out test with structural
validation of each key/value association. Parse JSON-backed outputs and inspect
OTLP/ATIF attributes by key, while using equivalent per-surface assertions where
parsing differs; preserve the session_owner exclusion and verify the value
belongs to its expected field rather than merely appearing elsewhere.
🪄 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: 53024ce6-45b0-42ec-8af7-f0e39d613a87

📥 Commits

Reviewing files that changed from the base of the PR and between 139dec1 and dff9d99.

📒 Files selected for processing (6)
  • crates/core/src/observability/mod.rs
  • crates/core/tests/unit/observability/openinference_tests.rs
  • crates/core/tests/unit/observability/otel_tests.rs
  • crates/pii-redaction/README.md
  • crates/pii-redaction/src/trajectory.rs
  • crates/pii-redaction/tests/unit/component_tests.rs
📜 Review details
🧰 Additional context used
📓 Path-based instructions (21)
**/*.{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
**/*

📄 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:

  • crates/pii-redaction/README.md
  • crates/core/src/observability/mod.rs
  • crates/core/tests/unit/observability/otel_tests.rs
  • crates/pii-redaction/src/trajectory.rs
  • crates/core/tests/unit/observability/openinference_tests.rs
  • crates/pii-redaction/tests/unit/component_tests.rs
**/*.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/core/src/observability/mod.rs
  • crates/core/tests/unit/observability/otel_tests.rs
  • crates/pii-redaction/src/trajectory.rs
  • crates/core/tests/unit/observability/openinference_tests.rs
  • crates/pii-redaction/tests/unit/component_tests.rs
{crates/core,crates/adaptive}/**/*

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

Changes to crates/core or crates/adaptive must run the full language matrix

Files:

  • crates/core/src/observability/mod.rs
  • crates/core/tests/unit/observability/otel_tests.rs
  • crates/core/tests/unit/observability/openinference_tests.rs
crates/core/**/*.rs

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

If the change touched crates/core or shared runtime semantics, also use validate-change for broader validation

Files:

  • crates/core/src/observability/mod.rs
  • crates/core/tests/unit/observability/otel_tests.rs
  • crates/core/tests/unit/observability/openinference_tests.rs
**/*.{rs,py}

📄 CodeRabbit inference engine (AGENTS.md)

Follow binding naming conventions in Rust and Python: use snake_case.

Files:

  • crates/core/src/observability/mod.rs
  • crates/core/tests/unit/observability/otel_tests.rs
  • crates/pii-redaction/src/trajectory.rs
  • crates/core/tests/unit/observability/openinference_tests.rs
  • crates/pii-redaction/tests/unit/component_tests.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:

  • crates/core/src/observability/mod.rs
  • crates/core/tests/unit/observability/otel_tests.rs
  • crates/pii-redaction/src/trajectory.rs
  • crates/core/tests/unit/observability/openinference_tests.rs
  • crates/pii-redaction/tests/unit/component_tests.rs
**/*.{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:

  • crates/core/src/observability/mod.rs
  • crates/core/tests/unit/observability/otel_tests.rs
  • crates/pii-redaction/src/trajectory.rs
  • crates/core/tests/unit/observability/openinference_tests.rs
  • crates/pii-redaction/tests/unit/component_tests.rs
**/*.{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:

  • crates/core/src/observability/mod.rs
  • crates/core/tests/unit/observability/otel_tests.rs
  • crates/pii-redaction/src/trajectory.rs
  • crates/core/tests/unit/observability/openinference_tests.rs
  • crates/pii-redaction/tests/unit/component_tests.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:

  • crates/core/src/observability/mod.rs
  • crates/pii-redaction/src/trajectory.rs
crates/{core,adaptive}/**/*

📄 CodeRabbit inference engine (.agents/skills/validate-change/SKILL.md)

If crates/core or crates/adaptive changed, run the full validation matrix across Rust, Python, Go, and Node.js.

Files:

  • crates/core/src/observability/mod.rs
  • crates/core/tests/unit/observability/otel_tests.rs
  • crates/core/tests/unit/observability/openinference_tests.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.

Files:

  • crates/core/src/observability/mod.rs
  • crates/core/tests/unit/observability/otel_tests.rs
  • crates/pii-redaction/src/trajectory.rs
  • crates/core/tests/unit/observability/openinference_tests.rs
  • crates/pii-redaction/tests/unit/component_tests.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:

  • crates/core/src/observability/mod.rs
  • crates/core/tests/unit/observability/otel_tests.rs
  • crates/pii-redaction/src/trajectory.rs
  • crates/core/tests/unit/observability/openinference_tests.rs
  • crates/pii-redaction/tests/unit/component_tests.rs
crates/{core,adaptive}/**/*.rs

⚙️ CodeRabbit configuration file

crates/{core,adaptive}/**/*.rs: Review the Rust runtime for async correctness, scope isolation, middleware ordering, and event lifecycle regressions.
Pay close attention to task-local/thread-local scope propagation, callback lifetimes, stream finalization, and root_uuid isolation.
Public API changes should preserve existing behavior unless tests and docs show the intended migration path.

Files:

  • crates/core/src/observability/mod.rs
  • crates/core/tests/unit/observability/otel_tests.rs
  • crates/core/tests/unit/observability/openinference_tests.rs
{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:

  • crates/core/tests/unit/observability/otel_tests.rs
  • crates/core/tests/unit/observability/openinference_tests.rs
  • crates/pii-redaction/tests/unit/component_tests.rs
🔇 Additional comments (8)
crates/pii-redaction/src/trajectory.rs (3)

14-34: LGTM!


158-164: LGTM!


180-196: 🔒 Security & Privacy

Trusted scope metadata is intentionally preserved. agent_kind and harness are documented low-cardinality fields, and nemo_relay.agent.kind is projected from metadata.agent_kind by design; this is not a redaction bypass.

			> Likely an incorrect or invalid review comment.
crates/pii-redaction/README.md (1)

157-165: LGTM!

crates/core/tests/unit/observability/openinference_tests.rs (1)

899-902: LGTM!

Also applies to: 914-918, 936-947

crates/core/tests/unit/observability/otel_tests.rs (1)

793-809: LGTM!

Also applies to: 833-841

crates/pii-redaction/tests/unit/component_tests.rs (2)

615-622: LGTM!

Also applies to: 636-643, 689-700


1825-1832: LGTM!

Also applies to: 1861-1861, 1872-1877, 1911-1920

Comment thread crates/core/src/observability/mod.rs
Comment thread crates/core/tests/unit/observability/openinference_tests.rs
Comment thread crates/core/src/observability/mod.rs
@willkill07

Copy link
Copy Markdown
Member Author

/merge

@rapids-bot
rapids-bot Bot merged commit 059af4b into NVIDIA:release/0.6 Jul 22, 2026
60 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bug issue describes bug; PR fixes bug lang:rust PR changes/introduces Rust code size:M PR is medium

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants