Skip to content

feat(sanitizers)!: add mark and scope event sanitizer registries [1/6]#371

Merged
rapids-bot[bot] merged 7 commits into
NVIDIA:mainfrom
willkill07:feat/relay-409-event-sanitizer-core
Jul 8, 2026
Merged

feat(sanitizers)!: add mark and scope event sanitizer registries [1/6]#371
rapids-bot[bot] merged 7 commits into
NVIDIA:mainfrom
willkill07:feat/relay-409-event-sanitizer-core

Conversation

@willkill07

@willkill07 willkill07 commented Jul 7, 2026

Copy link
Copy Markdown
Member

Overview

Adds the shared Rust runtime, plugin, native ABI, and worker protocol infrastructure for sanitizing mark and scope event observability fields without changing existing APIs or ABI v1 offsets.

Warning

BREAKING CHANGE: [Behavioral] Sanitizer Failures are now fail-closed.

If a sanitizer is invoked within the path of any event and fails, the event
being sanitized will be dropped by the Relay runtime. This may result in
missing observability/event data.

If fail-open behavior is desired, then failure logic must be wrapped inside
of a sanitizer itself.

  • 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

  • Adds EventSanitizeFields for data, category_profile, and metadata.
  • Adds global and scope-local mark, scope-start, and scope-end registries.
  • Extends Rust plugin contexts, the appended native host table, and worker registration surfaces 30–32.
  • Applies scope event sanitizers to every category after specialized tool/LLM sanitizers.
  • Covers explicit, pending, plugin-runtime, and streaming marks.
  • Adds exhaustive ordering, inheritance, cleanup, rollback, ABI, worker, and exporter tests.
  • Contains no documentation changes; documentation is isolated in a final independent PR.
  • Breaking changes: none.

Validation: just test-rust, CI-style Rust coverage (2515 tests), Python/Node/Go binding matrices, formatting, Clippy, and pre-commit.

Where should the reviewer start?

Start with crates/types/src/api/event.rs, crates/core/src/api/registry.rs, and the event sanitizer integration tests in crates/core/tests/integration/api_surface_tests.rs.

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

  • Relates to: RELAY-409

Summary by CodeRabbit

  • New Features

    • Added event field sanitization via EventSanitizeFields, with new sanitizer guardrail registration APIs for mark events and scope (start/end) events (global and scope-local).
    • Extended native plugin and worker SDK support with new event-sanitizer surfaces and callback wiring.
  • Bug Fixes

    • Event sanitization is now consistently applied across scope/mark lifecycle, pending marks, tool/LLM lifecycle, and streaming chunk/end emissions.
    • Events are only dispatched when sanitization succeeds.
  • Tests

    • Expanded integration/unit coverage for ordering, rewrites, deregistration, and plugin/worker sanitizer metadata.

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

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

@willkill07 willkill07 added this to the 0.6 milestone Jul 7, 2026
@willkill07 willkill07 self-assigned this Jul 7, 2026
@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

License Diff

Compared against origin/main.

Lockfile license changes

Lockfile License Changes

Rust

Added

  • None

Removed

  • None

Updated/Changed

  • None

Node

Added

  • None

Removed

  • None

Updated/Changed

  • None

Python

Added

  • None

Removed

  • None

Updated/Changed

  • None
Status output
[license-diff] selected languages: rust, node, python
[license-diff] generating current inventory
[license-diff] current: generating Rust inventory
[license-diff] current: Rust inventory complete (378 packages)
[license-diff] current: generating Node inventory
[license-diff] current: Node inventory complete (363 packages)
[license-diff] current: generating Python inventory
[license-diff] current: Python inventory complete (105 packages)
[license-diff] current inventory complete
[license-diff] checking out base ref origin/main into a temporary worktree
[license-diff] base: generating Rust inventory
[license-diff] base: Rust inventory complete (378 packages)
[license-diff] base: generating Node inventory
[license-diff] base: Node inventory complete (363 packages)
[license-diff] base: generating Python inventory
[license-diff] base: Python inventory complete (105 packages)
[license-diff] base inventory complete
[license-diff] removing temporary base worktree
[license-diff] comparing inventories
[license-diff] rendering Markdown output
[license-diff] done

@willkill07 willkill07 marked this pull request as ready for review July 7, 2026 15:25
@willkill07 willkill07 requested a review from a team as a code owner July 7, 2026 15:25
@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Adds event field sanitization types and callbacks, applies sanitization before emitting lifecycle events, wires new guardrail registries and plugin APIs, extends native and worker plugin support, and updates proto values plus test coverage.

Changes

Event Sanitization Feature

Layer / File(s) Summary
EventSanitizeFields contract and Event methods
crates/types/src/api/event.rs, crates/core/src/api/runtime/callbacks.rs, crates/core/src/api/runtime.rs, crates/core/tests/unit/types_tests.rs
Adds EventSanitizeFields, Event::sanitize_fields/apply_sanitize_fields/base_mut, and EventSanitizeFn with runtime export coverage.
Sanitize helpers and emitted event application
crates/core/src/api/shared.rs, crates/core/src/api/scope.rs, crates/core/src/api/tool.rs, crates/core/src/api/llm.rs, crates/core/src/stream.rs, crates/core/src/api/runtime/state.rs
Adds sanitization helpers and applies them before emitting scope, tool, LLM, guardrail-scope, and stream events.
Sanitizer registries and registry APIs
crates/core/src/context/registries.rs, crates/core/src/api/registry.rs, crates/core/src/plugin.rs
Adds global and scope-local sanitizer registries, generates mark/scope guardrail APIs, and wires PluginRegistrationContext registration methods.
Native plugin sanitize ABI
crates/plugin/src/lib.rs, crates/core/src/plugin/dynamic/native.rs, crates/core/tests/fixtures/native_plugin/src/lib.rs, crates/plugin/tests/typed_callbacks.rs, crates/core/tests/integration/native_plugin_tests.rs
Adds native sanitizer callback types, host API entries, registration adapters, and fixture/test coverage for native plugins.
Worker plugin sanitize surfaces
crates/worker-proto/proto/nemo/relay/worker/v1/plugin_worker.proto, crates/worker-proto/tests/proto_tests.rs, crates/worker/src/lib.rs, crates/core/src/plugin/dynamic/worker.rs, crates/core/tests/fixtures/worker_plugin/src/main.rs, crates/worker/tests/worker_sdk_tests.rs, crates/core/tests/unit/dynamic_worker_tests.rs
Adds worker RegistrationSurface values, worker-side sanitize dispatch, dynamic adapter support, and fixture/SDK coverage.
Core registry and sanitizer tests
crates/core/tests/integration/api_surface_tests.rs, crates/core/tests/integration/middleware_tests.rs, crates/core/tests/unit/plugin_tests.rs
Extends integration and unit tests for registration, duplicate and missing handling, and end-to-end sanitization behavior.

Estimated code review effort: 4 (Complex) | ~75 minutes

Suggested labels: DO NOT MERGE

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Title check ✅ Passed The title uses Conventional Commits and accurately summarizes the sanitizer registry changes.
Description check ✅ Passed The template sections are present and filled with relevant overview, details, reviewer start, and related issue info.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@zhongxuanwang-nv zhongxuanwang-nv left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Used powerful AIs to help; everything looks great!

Comment thread crates/worker/src/lib.rs Outdated
Comment thread crates/core/src/plugin/dynamic/native.rs
@willkill07 willkill07 changed the title feat: add mark and scope event sanitizer registries feat: add mark and scope event sanitizer registries [1/6] Jul 7, 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: 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/core/src/api/shared.rs`:
- Around line 44-93: The sanitizer path in sanitize_event_with_scope_stack
currently fails open by returning the original Event when
global_context().read() errors, which can leak unsanitized data. Update
sanitize_event_with_scope_stack (and its sanitize_event caller if needed) to
fail closed by dropping the event or surfacing an error instead of returning the
raw event on lock/read failure, matching the existing stream wrapper behavior.
Keep the existing event type handling for Event::Mark, Event::Scope Start, and
other Scope events, but ensure any context read failure prevents emission of the
unsanitized payload.

In `@crates/plugin/tests/typed_callbacks.rs`:
- Around line 2627-2657: The new ABI callback coverage in the typed_callbacks
test only checks null user_data and out_fields_json, so add direct null-pointer
assertions for the required input strings as well. Update the test around the
event sanitize registration callback to invoke the registered cb with a null
event_json and separately with a null fields_json, and assert
NemoRelayStatus::NullPointer in each case to cover the contract of the new
callback surface.
- Around line 3038-3050: The invalid-fields assertion in the typed callback test
is not verifying that the trampoline clears a previously set output pointer
because `out` is already null after the invalid-event case. In
`typed_callbacks.rs`, reset `out` to `stale_out` before calling
`registration.cb` with `invalid_fields`, then keep asserting
`NemoRelayStatus::InvalidJson` and that `out` becomes null so the test covers
clearing stale output on error.

In `@crates/types/src/api/event.rs`:
- Around line 367-384: The sanitization flow is replacing the entire
CategoryProfile instead of preserving existing fields, so update
apply_sanitize_fields() and its use of EventSanitizeFields::category_profile to
merge only the sanitizer-provided fields into the current profile. Keep
tool_call_id and extra intact when a sanitizer changes only subtype or
model_name, and only fall back to full replacement if that is the intended
contract for EventSanitizeFields and its docs.
🪄 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: b57882e6-204b-47d9-b83e-5d6da43f7ecb

📥 Commits

Reviewing files that changed from the base of the PR and between 942ca3c and c8bac1a.

📒 Files selected for processing (29)
  • crates/core/src/api/llm.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/api/runtime.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/scope.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/api/tool.rs
  • crates/core/src/context/registries.rs
  • crates/core/src/plugin.rs
  • crates/core/src/plugin/dynamic/native.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/core/src/stream.rs
  • crates/core/tests/fixtures/native_plugin/src/lib.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/tests/integration/api_surface_tests.rs
  • crates/core/tests/integration/middleware_tests.rs
  • crates/core/tests/integration/native_plugin_tests.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/types_tests.rs
  • crates/plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/types/src/api/event.rs
  • crates/worker-proto/proto/nemo/relay/worker/v1/plugin_worker.proto
  • crates/worker-proto/tests/proto_tests.rs
  • crates/worker/src/lib.rs
  • crates/worker/tests/worker_sdk_tests.rs
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
  • GitHub Check: Check / Run
  • GitHub Check: Preview docs
🧰 Additional context used
📓 Path-based instructions (19)
**/*.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

Follow Rust naming conventions, including snake_case identifiers and Rust-facing runtime API shapes.

**/*.rs: When changing the core runtime or Rust-facing API surface, format Rust code with cargo fmt (rustfmt defaults), keep cargo clippy -- -D warnings clean, and pass cargo deny check.
When touching the core Rust crate, run the Rust tests and the other affected binding test suites because the bindings depend on the core runtime.

Files:

  • crates/core/src/api/runtime.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/core/src/stream.rs
  • crates/worker-proto/tests/proto_tests.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/tests/unit/types_tests.rs
  • crates/core/tests/integration/native_plugin_tests.rs
  • crates/core/src/context/registries.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/tests/fixtures/native_plugin/src/lib.rs
  • crates/core/src/api/scope.rs
  • crates/core/src/api/tool.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/llm.rs
  • crates/types/src/api/event.rs
  • crates/core/src/plugin/dynamic/native.rs
  • crates/core/tests/integration/middleware_tests.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/plugin.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/worker/src/lib.rs
  • crates/core/tests/integration/api_surface_tests.rs
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.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/api/runtime.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/core/src/stream.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/tests/unit/types_tests.rs
  • crates/core/tests/integration/native_plugin_tests.rs
  • crates/core/src/context/registries.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/tests/fixtures/native_plugin/src/lib.rs
  • crates/core/src/api/scope.rs
  • crates/core/src/api/tool.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/llm.rs
  • crates/core/src/plugin/dynamic/native.rs
  • crates/core/tests/integration/middleware_tests.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/plugin.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/core/tests/integration/api_surface_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

If the change touched shared runtime semantics in crates/core, also use validate-change.

Files:

  • crates/core/src/api/runtime.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/core/src/stream.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/tests/unit/types_tests.rs
  • crates/core/tests/integration/native_plugin_tests.rs
  • crates/core/src/context/registries.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/tests/fixtures/native_plugin/src/lib.rs
  • crates/core/src/api/scope.rs
  • crates/core/src/api/tool.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/llm.rs
  • crates/core/src/plugin/dynamic/native.rs
  • crates/core/tests/integration/middleware_tests.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/plugin.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/core/tests/integration/api_surface_tests.rs
**/*.{rs,py,js,ts,mjs,c,h,md,toml,yml,yaml,sh,json,go}

📄 CodeRabbit inference engine (AGENTS.md)

Keep SPDX headers on source files, documentation, scripts, and configuration files.

Files:

  • crates/core/src/api/runtime.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/core/src/stream.rs
  • crates/worker-proto/tests/proto_tests.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/tests/unit/types_tests.rs
  • crates/core/tests/integration/native_plugin_tests.rs
  • crates/core/src/context/registries.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/tests/fixtures/native_plugin/src/lib.rs
  • crates/core/src/api/scope.rs
  • crates/core/src/api/tool.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/llm.rs
  • crates/types/src/api/event.rs
  • crates/core/src/plugin/dynamic/native.rs
  • crates/core/tests/integration/middleware_tests.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/plugin.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/worker/src/lib.rs
  • crates/core/tests/integration/api_surface_tests.rs
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
crates/{core,adaptive,ffi,python,node,wasm}/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

Use Json = serde_json::Value in Rust-facing runtime APIs where existing code expects JSON payloads.

Files:

  • crates/core/src/api/runtime.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/core/src/stream.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/tests/unit/types_tests.rs
  • crates/core/tests/integration/native_plugin_tests.rs
  • crates/core/src/context/registries.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/tests/fixtures/native_plugin/src/lib.rs
  • crates/core/src/api/scope.rs
  • crates/core/src/api/tool.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/llm.rs
  • crates/core/src/plugin/dynamic/native.rs
  • crates/core/tests/integration/middleware_tests.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/plugin.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/core/tests/integration/api_surface_tests.rs
crates/{core,adaptive}/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

Use Result<T> with FlowError in core runtime paths, and keep errors explicit and binding-appropriate at the wrapper layer.

Files:

  • crates/core/src/api/runtime.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/core/src/stream.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/tests/unit/types_tests.rs
  • crates/core/tests/integration/native_plugin_tests.rs
  • crates/core/src/context/registries.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/tests/fixtures/native_plugin/src/lib.rs
  • crates/core/src/api/scope.rs
  • crates/core/src/api/tool.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/llm.rs
  • crates/core/src/plugin/dynamic/native.rs
  • crates/core/tests/integration/middleware_tests.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/plugin.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/core/tests/integration/api_surface_tests.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/api/runtime.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/core/src/stream.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/tests/unit/types_tests.rs
  • crates/core/tests/integration/native_plugin_tests.rs
  • crates/core/src/context/registries.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/tests/fixtures/native_plugin/src/lib.rs
  • crates/core/src/api/scope.rs
  • crates/core/src/api/tool.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/llm.rs
  • crates/core/src/plugin/dynamic/native.rs
  • crates/core/tests/integration/middleware_tests.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/plugin.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/core/tests/integration/api_surface_tests.rs
**/*.{rs,py,go,js,ts,jsx,tsx,md,mdx,toml,yaml,yml,html}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

All source files must include an SPDX license header using the comment syntax appropriate for the file type, with SPDX-FileCopyrightText for 2026 NVIDIA CORPORATION & AFFILIATES and SPDX-License-Identifier: Apache-2.0.

Files:

  • crates/core/src/api/runtime.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/core/src/stream.rs
  • crates/worker-proto/tests/proto_tests.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/tests/unit/types_tests.rs
  • crates/core/tests/integration/native_plugin_tests.rs
  • crates/core/src/context/registries.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/tests/fixtures/native_plugin/src/lib.rs
  • crates/core/src/api/scope.rs
  • crates/core/src/api/tool.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/llm.rs
  • crates/types/src/api/event.rs
  • crates/core/src/plugin/dynamic/native.rs
  • crates/core/tests/integration/middleware_tests.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/plugin.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/worker/src/lib.rs
  • crates/core/tests/integration/api_surface_tests.rs
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
**/*.{rs,py,go,js,ts}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use the naming conventions appropriate to each language: Rust snake_case, C FFI exports prefixed nemo_relay_, Go PascalCase, Node.js camelCase, and Python snake_case.

Files:

  • crates/core/src/api/runtime.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/core/src/stream.rs
  • crates/worker-proto/tests/proto_tests.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/tests/unit/types_tests.rs
  • crates/core/tests/integration/native_plugin_tests.rs
  • crates/core/src/context/registries.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/tests/fixtures/native_plugin/src/lib.rs
  • crates/core/src/api/scope.rs
  • crates/core/src/api/tool.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/llm.rs
  • crates/types/src/api/event.rs
  • crates/core/src/plugin/dynamic/native.rs
  • crates/core/tests/integration/middleware_tests.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/plugin.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/worker/src/lib.rs
  • crates/core/tests/integration/api_surface_tests.rs
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
**/*.{rs,py,go,js,ts,md,mdx,toml,yaml,yml,json}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Avoid using SONAR_IGNORE_START / SONAR_IGNORE_END except for documented false positives; keep the ignored block small, add a brief explanatory comment, and call it out in the PR description.

Files:

  • crates/core/src/api/runtime.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/core/src/stream.rs
  • crates/worker-proto/tests/proto_tests.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/tests/unit/types_tests.rs
  • crates/core/tests/integration/native_plugin_tests.rs
  • crates/core/src/context/registries.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/tests/fixtures/native_plugin/src/lib.rs
  • crates/core/src/api/scope.rs
  • crates/core/src/api/tool.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/llm.rs
  • crates/types/src/api/event.rs
  • crates/core/src/plugin/dynamic/native.rs
  • crates/core/tests/integration/middleware_tests.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/plugin.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/worker/src/lib.rs
  • crates/core/tests/integration/api_surface_tests.rs
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
crates/core/src/api/**/*.rs

📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)

Implement public runtime behavior first in crates/core/src/api/ and related core modules such as crates/core/src/api/runtime/, crates/core/src/codec/, or crates/core/src/json.rs.

Files:

  • crates/core/src/api/runtime.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/core/src/api/scope.rs
  • crates/core/src/api/tool.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/llm.rs
  • crates/core/src/api/registry.rs
**/*.{rs,py,go,js,ts,wasm}

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

Ensure binding-native wrappers expose the same observability configuration knobs and lifecycle behavior across Rust, Python, Go, Node.js, and WebAssembly.

Files:

  • crates/core/src/api/runtime.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/core/src/stream.rs
  • crates/worker-proto/tests/proto_tests.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/tests/unit/types_tests.rs
  • crates/core/tests/integration/native_plugin_tests.rs
  • crates/core/src/context/registries.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/tests/fixtures/native_plugin/src/lib.rs
  • crates/core/src/api/scope.rs
  • crates/core/src/api/tool.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/llm.rs
  • crates/types/src/api/event.rs
  • crates/core/src/plugin/dynamic/native.rs
  • crates/core/tests/integration/middleware_tests.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/plugin.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/worker/src/lib.rs
  • crates/core/tests/integration/api_surface_tests.rs
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
**/*.{rs,rlib}

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

**/*.{rs,rlib}: 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.

Files:

  • crates/core/src/api/runtime.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/core/src/stream.rs
  • crates/worker-proto/tests/proto_tests.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/tests/unit/types_tests.rs
  • crates/core/tests/integration/native_plugin_tests.rs
  • crates/core/src/context/registries.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/tests/fixtures/native_plugin/src/lib.rs
  • crates/core/src/api/scope.rs
  • crates/core/src/api/tool.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/llm.rs
  • crates/types/src/api/event.rs
  • crates/core/src/plugin/dynamic/native.rs
  • crates/core/tests/integration/middleware_tests.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/plugin.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/worker/src/lib.rs
  • crates/core/tests/integration/api_surface_tests.rs
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
crates/core/**

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

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

Files:

  • crates/core/src/api/runtime.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/core/src/stream.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/tests/unit/types_tests.rs
  • crates/core/tests/integration/native_plugin_tests.rs
  • crates/core/src/context/registries.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/tests/fixtures/native_plugin/src/lib.rs
  • crates/core/src/api/scope.rs
  • crates/core/src/api/tool.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/llm.rs
  • crates/core/src/plugin/dynamic/native.rs
  • crates/core/tests/integration/middleware_tests.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/plugin.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/core/tests/integration/api_surface_tests.rs
**

⚙️ CodeRabbit configuration file

**:

AGENTS.md

This file provides guidance to agents, including Claude Code and OpenAI Codex, when working in this repository.

Project Overview

NeMo Relay is a multi-language agent runtime framework for execution scopes, lifecycle events, middleware, plugins, and observability around tool and LLM calls. The core runtime is Rust. Primary supported bindings are Rust, Python, and Node.js. Go and the raw C FFI are experimental and source-first.

The shared runtime model is:

  1. Scope stacks decide where work belongs and which scope-local behavior is visible.
  2. Middleware registries decide what guardrails and intercepts run around managed calls.
  3. Plugins install reusable runtime behavior from configuration.
  4. Events record runtime behavior in ATOF form.
  5. Subscribers and exporters consume events in-process or export them to ATIF, OpenTelemetry, OpenInference, or other backends.

Repository Structure

The repository layout separates the Rust runtime, language bindings,
documentation, integrations, and agent-facing skills.

crates/
  core/       # Rust core runtime crate, published as nemo-relay
  adaptive/   # Adaptive runtime primitives and plugin components
  python/     # PyO3 native extension for the Python package
  ffi/        # Raw C ABI layer used by downstream bindings such as Go
  node/       # NAPI Node.js binding and JavaScript/TypeScript entry points
python/
  nemo_relay/  # Python wrapper package: scopes, tools, LLM, middleware, typed helpers, plugins, adaptive helpers
  tests/      # Python tests
go/
  nemo_relay/  # Experimental Go CGo binding and tests
fern/         # Fern documentation site
scripts/      # Stable wrappers and helper scripts; build/test/docs entry points live in justfile
skills/       # Published Codex/agent skills for NeMo Relay usage patterns

Prerequisites

Insta...

Files:

  • crates/core/src/api/runtime.rs
  • crates/core/src/api/runtime/callbacks.rs
  • crates/core/src/stream.rs
  • crates/worker-proto/tests/proto_tests.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/tests/unit/types_tests.rs
  • crates/worker-proto/proto/nemo/relay/worker/v1/plugin_worker.proto
  • crates/core/tests/integration/native_plugin_tests.rs
  • crates/core/src/context/registries.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/src/plugin/dynamic/worker.rs
  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/tests/fixtures/native_plugin/src/lib.rs
  • crates/core/src/api/scope.rs
  • crates/core/src/api/tool.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/llm.rs
  • crates/types/src/api/event.rs
  • crates/core/src/plugin/dynamic/native.rs
  • crates/core/tests/integration/middleware_tests.rs
  • crates/core/src/api/registry.rs
  • crates/core/src/plugin.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/worker/src/lib.rs
  • crates/core/tests/integration/api_surface_tests.rs
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/plugin/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
crates/core/src/api/runtime/callbacks.rs

📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)

Define or reuse callback type aliases in crates/core/src/api/runtime/callbacks.rs using Box<dyn Fn(...)> pattern for new middleware types

Files:

  • crates/core/src/api/runtime/callbacks.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/worker-proto/tests/proto_tests.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/tests/unit/types_tests.rs
  • crates/core/tests/integration/native_plugin_tests.rs
  • crates/core/tests/unit/dynamic_worker_tests.rs
  • crates/core/tests/unit/plugin_tests.rs
  • crates/core/tests/fixtures/native_plugin/src/lib.rs
  • crates/core/tests/integration/middleware_tests.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/core/tests/integration/api_surface_tests.rs
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/plugin/tests/typed_callbacks.rs
crates/core/src/api/{tool,llm}.rs

📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)

Wire the new middleware chain into the execute path in crates/core/src/api/tool.rs or crates/core/src/api/llm.rs at the appropriate pipeline stage

Files:

  • crates/core/src/api/tool.rs
  • crates/core/src/api/llm.rs
crates/core/src/api/runtime/state.rs

📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)

crates/core/src/api/runtime/state.rs: Add registry fields as SortedRegistry<GuardrailEntry<T>> or SortedRegistry<Intercept<T>> to NemoRelayContextState in crates/core/src/api/runtime/state.rs
Add chain execution helpers to NemoRelayContextState following the pattern of existing methods like tool_sanitize_request_chain or tool_request_intercepts_chain

Files:

  • crates/core/src/api/runtime/state.rs
crates/core/src/api/registry.rs

📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)

Use existing global_*_registry_api! and scope_*_registry_api! macro patterns in crates/core/src/api/registry.rs for both global and scope-local registration APIs unless design explicitly rules one out

Files:

  • crates/core/src/api/registry.rs
🪛 Buf (1.71.0)
crates/worker-proto/proto/nemo/relay/worker/v1/plugin_worker.proto

[error] 49-49: Enum value name "MARK_SANITIZE_GUARDRAIL" should be prefixed with "REGISTRATION_SURFACE_".

(ENUM_VALUE_PREFIX)


[error] 50-50: Enum value name "SCOPE_SANITIZE_START_GUARDRAIL" should be prefixed with "REGISTRATION_SURFACE_".

(ENUM_VALUE_PREFIX)


[error] 51-51: Enum value name "SCOPE_SANITIZE_END_GUARDRAIL" should be prefixed with "REGISTRATION_SURFACE_".

(ENUM_VALUE_PREFIX)

🔇 Additional comments (30)
crates/types/src/api/event.rs (1)

706-712: LGTM!

crates/core/src/api/runtime/callbacks.rs (1)

17-30: LGTM!

crates/core/src/api/shared.rs (1)

8-11: LGTM!

crates/core/src/api/scope.rs (1)

10-12: LGTM!

Also applies to: 234-238, 262-298, 324-352

crates/core/src/api/tool.rs (1)

14-14: LGTM!

Also applies to: 255-258, 339-365, 367-383

crates/core/src/api/runtime/state.rs (1)

24-31: LGTM!

Also applies to: 53-58, 96-98, 557-587, 589-634

crates/core/src/api/runtime.rs (1)

13-14: LGTM!

crates/core/tests/unit/types_tests.rs (1)

13-15: LGTM!

Also applies to: 951-992

crates/core/src/api/llm.rs (1)

24-25: LGTM!

Also applies to: 324-324, 351-351, 525-525, 557-557

crates/core/src/stream.rs (1)

40-40: LGTM!

Also applies to: 231-231, 259-259

crates/core/src/context/registries.rs (1)

14-14: LGTM!

Also applies to: 27-32, 68-70

crates/core/src/api/registry.rs (1)

8-8: LGTM! Macro invocations correctly wire the three new guardrail surfaces to the fields added in registries.rs, consistent with the established global_guardrail_registry_api!/scope_guardrail_registry_api! pattern.

Also applies to: 470-494, 607-631

crates/core/tests/integration/api_surface_tests.rs (1)

13-13: LGTM! Priority ordering, scope-local inheritance to nested scopes, duplicate/missing-scope error paths, and cleanup are all exercised correctly and consistently with the sanitizer contract.

Also applies to: 23-47, 80-141, 143-281, 565-587, 745-794, 949-978, 1048-1071, 1103-1103, 1112-1116, 1380-1389, 1447-1447, 1463-1463

crates/core/src/plugin.rs (1)

26-39: LGTM! New sanitizer registration methods mirror the established PluginRegistrationContext pattern (qualify → register → push rollback closure), and error message prefixes match the corresponding test expectations in plugin_tests.rs.

Also applies to: 326-408

crates/core/tests/integration/middleware_tests.rs (1)

29-35: LGTM! Sanitizer mutation logic (merge vs. full replace) is consistent with the pre-existing metadata state in each test, and assertions/cleanup correctly reflect that.

Also applies to: 674-684, 774-775, 803-803, 3122-3130, 3218-3228

crates/core/tests/unit/plugin_tests.rs (1)

986-999: LGTM! New sanitizer coverage is correctly ordered against the expected_messages zip and matches the error-prefix strings defined in plugin.rs.

Also applies to: 1074-1091, 1281-1294, 1368-1370

crates/plugin/src/lib.rs (1)

20-20: LGTM!

Also applies to: 203-210, 506-535, 1284-1374, 1701-1763, 2097-2124

crates/core/src/plugin/dynamic/native.rs (1)

18-40: LGTM!

Also applies to: 600-605, 1410-1455, 1475-1530

crates/core/tests/integration/native_plugin_tests.rs (1)

165-196: LGTM!

Also applies to: 218-221, 231-234, 250-250

crates/plugin/tests/typed_callbacks.rs (1)

17-21: LGTM!

Also applies to: 41-56, 229-229, 286-286, 316-436, 589-597, 1082-1110, 1155-1182, 1373-1380, 2127-2201, 2232-2309, 3008-3037, 3051-3059, 4856-4919

crates/worker/tests/worker_sdk_tests.rs (1)

201-201: LGTM!

Also applies to: 457-481, 1003-1023, 1136-1146, 1563-1574, 2176-2192

crates/core/tests/integration/worker_plugin_tests.rs (1)

105-136: LGTM!

Also applies to: 164-167, 177-184, 231-231

crates/core/tests/unit/dynamic_worker_tests.rs (1)

379-379: LGTM!

Also applies to: 439-451

crates/worker/src/lib.rs (2)

142-156: 🎯 Functional Correctness | ⚡ Quick win

Shared event_sanitizers map can misroute callbacks across surfaces.

event_sanitizers: HashMap<String, EventSanitizeFn> is shared by MarkSanitizeGuardrail, ScopeSanitizeStartGuardrail, and ScopeSanitizeEndGuardrail, keyed only by name. Every other guardrail family here (tool/llm sanitize request vs. response, etc.) uses a dedicated map per surface, so a name is only ever ambiguous within one surface. If a plugin registers the same name on two of these three sanitize surfaces, the second registration silently overwrites the first in this map, and event_sanitizer() (lines 1523-1533) has no way to disambiguate by surface — the wrong sanitizer runs for mark vs. scope-start/end events.

This was raised in a prior review round and dismissed as "consistent with other middleware," but the other middleware maps are actually per-surface, not shared — worth revisiting.

🛠️ Proposed fix using per-surface maps (or a compound key)
 struct WorkerHandlers {
     registrations: Vec<Registration>,
     subscribers: HashMap<String, SubscriberFn>,
-    event_sanitizers: HashMap<String, EventSanitizeFn>,
+    mark_sanitizers: HashMap<String, EventSanitizeFn>,
+    scope_start_sanitizers: HashMap<String, EventSanitizeFn>,
+    scope_end_sanitizers: HashMap<String, EventSanitizeFn>,
     ...
 }

Then route inserts/lookups in register_event_sanitizer and event_sanitizer by surface into the matching map instead of a single shared one.

Also applies to: 198-211, 1523-1533


37-37: LGTM!

Also applies to: 121-122, 1402-1413, 1997-2014

crates/core/tests/fixtures/native_plugin/src/lib.rs (1)

8-9: LGTM!

Also applies to: 50-62, 194-200

crates/worker-proto/proto/nemo/relay/worker/v1/plugin_worker.proto (1)

49-51: 📐 Maintainability & Code Quality

Buf flags missing enum-value prefix; matches existing convention.

Static analysis flags MARK_SANITIZE_GUARDRAIL, SCOPE_SANITIZE_START_GUARDRAIL, and SCOPE_SANITIZE_END_GUARDRAIL for lacking the REGISTRATION_SURFACE_ prefix, but all 12 pre-existing values in this enum (e.g., SUBSCRIBER, TOOL_SANITIZE_REQUEST_GUARDRAIL) have the same "violation," so this isn't a new regression. Worth confirming whether ENUM_VALUE_PREFIX is intentionally disabled/excepted in the project's buf lint config, since otherwise CI would already be failing on the pre-existing entries.

Source: Linters/SAST tools

crates/worker-proto/tests/proto_tests.rs (1)

41-43: LGTM!

crates/core/tests/fixtures/worker_plugin/src/main.rs (1)

9-9: LGTM!

Also applies to: 64-76, 97-103

crates/core/src/plugin/dynamic/worker.rs (1)

54-54: LGTM!

Also applies to: 815-837, 1169-1188

Comment thread crates/core/src/api/shared.rs
Comment thread crates/plugin/tests/typed_callbacks.rs
Comment thread crates/plugin/tests/typed_callbacks.rs
Comment thread crates/types/src/api/event.rs
Signed-off-by: Will Killian <wkillian@nvidia.com>
@bbednarski9 bbednarski9 self-requested a review July 8, 2026 16:04
Comment thread crates/core/src/plugin/dynamic/worker.rs
Comment thread crates/worker/src/lib.rs
Signed-off-by: Will Killian <wkillian@nvidia.com>
@willkill07 willkill07 changed the title feat: add mark and scope event sanitizer registries [1/6] feat!: add mark and scope event sanitizer registries [1/6] Jul 8, 2026
@github-actions github-actions Bot added the breaking PR introduces a breaking change label Jul 8, 2026
@willkill07 willkill07 changed the title feat!: add mark and scope event sanitizer registries [1/6] feat(sanitizers)!: add mark and scope event sanitizer registries [1/6] Jul 8, 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: 1

Caution

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

⚠️ Outside diff range comments (1)
crates/core/src/api/shared.rs (1)

45-94: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Fail-closed fix confirmed; consider logging the drop path.

The Err(_) => return None fix for the previously-flagged fail-open issue is in place and correct. One gap: once this path triggers (context lock poisoned), every subsequent mark/scope event is silently dropped with no diagnostic signal — in an observability runtime, losing events silently is worth a tracing::warn! (or equivalent) so operators can detect degraded sanitization rather than just missing data downstream.

♻️ Suggested addition
         let state = match context.read() {
             Ok(state) => state,
-            Err(_) => return None,
+            Err(_) => {
+                tracing::warn!("dropping event: sanitizer context lock poisoned");
+                return None;
+            }
         };
🤖 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/core/src/api/shared.rs` around lines 45 - 94, In
sanitize_event_with_scope_stack, the fail-closed return on a poisoned
global_context read is correct, but the drop path is silent. Add a diagnostic
log (for example via tracing::warn!) immediately before returning None in the
Err(_) branch so operators can detect when mark/scope events are being discarded
due to sanitization state failure. Keep the change localized to
sanitize_event_with_scope_stack and preserve the existing None behavior.
🤖 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/worker/src/lib.rs`:
- Around line 1314-1325: The duplicate-registration error in
validate_unique_registrations currently formats registration.surface as a raw
integer, which makes the WorkerSdkError hard to read. Update the error निर्माण
in validate_unique_registrations to render a human-friendly surface name instead
of the protobuf i32, using the appropriate surface enum/display helper already
available in this module or nearby types. Keep the duplicate local_name wording,
but ensure the surface value in the formatted message is descriptive for logs
and gRPC errors.

---

Outside diff comments:
In `@crates/core/src/api/shared.rs`:
- Around line 45-94: In sanitize_event_with_scope_stack, the fail-closed return
on a poisoned global_context read is correct, but the drop path is silent. Add a
diagnostic log (for example via tracing::warn!) immediately before returning
None in the Err(_) branch so operators can detect when mark/scope events are
being discarded due to sanitization state failure. Keep the change localized to
sanitize_event_with_scope_stack and preserve the existing None behavior.
🪄 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: b116f01b-b5ce-4bec-86ba-0a654baffc6e

📥 Commits

Reviewing files that changed from the base of the PR and between c8bac1a and cb89482.

📒 Files selected for processing (11)
  • crates/core/src/api/llm.rs
  • crates/core/src/api/runtime/state.rs
  • crates/core/src/api/scope.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/api/tool.rs
  • crates/core/src/stream.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/plugin/tests/typed_callbacks.rs
  • crates/worker/src/lib.rs
  • crates/worker/tests/worker_sdk_tests.rs
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
  • GitHub Check: Check / Run
  • GitHub Check: Preview docs
🧰 Additional context used
📓 Path-based instructions (17)
**/*.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

Follow Rust naming conventions, including snake_case identifiers and Rust-facing runtime API shapes.

**/*.rs: When changing the core runtime or Rust-facing API surface, format Rust code with cargo fmt (rustfmt defaults), keep cargo clippy -- -D warnings clean, and pass cargo deny check.
When touching the core Rust crate, run the Rust tests and the other affected binding test suites because the bindings depend on the core runtime.

Files:

  • crates/core/src/stream.rs
  • crates/core/src/api/llm.rs
  • crates/core/src/api/tool.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/src/api/scope.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/api/runtime/state.rs
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/worker/src/lib.rs
  • crates/plugin/tests/typed_callbacks.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/stream.rs
  • crates/core/src/api/llm.rs
  • crates/core/src/api/tool.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/src/api/scope.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/api/runtime/state.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

If the change touched shared runtime semantics in crates/core, also use validate-change.

Files:

  • crates/core/src/stream.rs
  • crates/core/src/api/llm.rs
  • crates/core/src/api/tool.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/src/api/scope.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/api/runtime/state.rs
**/*.{rs,py,js,ts,mjs,c,h,md,toml,yml,yaml,sh,json,go}

📄 CodeRabbit inference engine (AGENTS.md)

Keep SPDX headers on source files, documentation, scripts, and configuration files.

Files:

  • crates/core/src/stream.rs
  • crates/core/src/api/llm.rs
  • crates/core/src/api/tool.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/src/api/scope.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/api/runtime/state.rs
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/worker/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
crates/{core,adaptive,ffi,python,node,wasm}/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

Use Json = serde_json::Value in Rust-facing runtime APIs where existing code expects JSON payloads.

Files:

  • crates/core/src/stream.rs
  • crates/core/src/api/llm.rs
  • crates/core/src/api/tool.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/src/api/scope.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/api/runtime/state.rs
crates/{core,adaptive}/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

Use Result<T> with FlowError in core runtime paths, and keep errors explicit and binding-appropriate at the wrapper layer.

Files:

  • crates/core/src/stream.rs
  • crates/core/src/api/llm.rs
  • crates/core/src/api/tool.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/src/api/scope.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/api/runtime/state.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/stream.rs
  • crates/core/src/api/llm.rs
  • crates/core/src/api/tool.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/src/api/scope.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/api/runtime/state.rs
**/*.{rs,py,go,js,ts,jsx,tsx,md,mdx,toml,yaml,yml,html}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

All source files must include an SPDX license header using the comment syntax appropriate for the file type, with SPDX-FileCopyrightText for 2026 NVIDIA CORPORATION & AFFILIATES and SPDX-License-Identifier: Apache-2.0.

Files:

  • crates/core/src/stream.rs
  • crates/core/src/api/llm.rs
  • crates/core/src/api/tool.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/src/api/scope.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/api/runtime/state.rs
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/worker/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
**/*.{rs,py,go,js,ts}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Use the naming conventions appropriate to each language: Rust snake_case, C FFI exports prefixed nemo_relay_, Go PascalCase, Node.js camelCase, and Python snake_case.

Files:

  • crates/core/src/stream.rs
  • crates/core/src/api/llm.rs
  • crates/core/src/api/tool.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/src/api/scope.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/api/runtime/state.rs
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/worker/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
**/*.{rs,py,go,js,ts,md,mdx,toml,yaml,yml,json}

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Avoid using SONAR_IGNORE_START / SONAR_IGNORE_END except for documented false positives; keep the ignored block small, add a brief explanatory comment, and call it out in the PR description.

Files:

  • crates/core/src/stream.rs
  • crates/core/src/api/llm.rs
  • crates/core/src/api/tool.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/src/api/scope.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/api/runtime/state.rs
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/worker/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
**/*.{rs,py,go,js,ts,wasm}

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

Ensure binding-native wrappers expose the same observability configuration knobs and lifecycle behavior across Rust, Python, Go, Node.js, and WebAssembly.

Files:

  • crates/core/src/stream.rs
  • crates/core/src/api/llm.rs
  • crates/core/src/api/tool.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/src/api/scope.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/api/runtime/state.rs
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/worker/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
**/*.{rs,rlib}

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

**/*.{rs,rlib}: 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.

Files:

  • crates/core/src/stream.rs
  • crates/core/src/api/llm.rs
  • crates/core/src/api/tool.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/src/api/scope.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/api/runtime/state.rs
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/worker/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
crates/core/**

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

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

Files:

  • crates/core/src/stream.rs
  • crates/core/src/api/llm.rs
  • crates/core/src/api/tool.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/src/api/scope.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/api/runtime/state.rs
**

⚙️ CodeRabbit configuration file

**:

AGENTS.md

This file provides guidance to agents, including Claude Code and OpenAI Codex, when working in this repository.

Project Overview

NeMo Relay is a multi-language agent runtime framework for execution scopes, lifecycle events, middleware, plugins, and observability around tool and LLM calls. The core runtime is Rust. Primary supported bindings are Rust, Python, and Node.js. Go and the raw C FFI are experimental and source-first.

The shared runtime model is:

  1. Scope stacks decide where work belongs and which scope-local behavior is visible.
  2. Middleware registries decide what guardrails and intercepts run around managed calls.
  3. Plugins install reusable runtime behavior from configuration.
  4. Events record runtime behavior in ATOF form.
  5. Subscribers and exporters consume events in-process or export them to ATIF, OpenTelemetry, OpenInference, or other backends.

Repository Structure

The repository layout separates the Rust runtime, language bindings,
documentation, integrations, and agent-facing skills.

crates/
  core/       # Rust core runtime crate, published as nemo-relay
  adaptive/   # Adaptive runtime primitives and plugin components
  python/     # PyO3 native extension for the Python package
  ffi/        # Raw C ABI layer used by downstream bindings such as Go
  node/       # NAPI Node.js binding and JavaScript/TypeScript entry points
python/
  nemo_relay/  # Python wrapper package: scopes, tools, LLM, middleware, typed helpers, plugins, adaptive helpers
  tests/      # Python tests
go/
  nemo_relay/  # Experimental Go CGo binding and tests
fern/         # Fern documentation site
scripts/      # Stable wrappers and helper scripts; build/test/docs entry points live in justfile
skills/       # Published Codex/agent skills for NeMo Relay usage patterns

Prerequisites

Insta...

Files:

  • crates/core/src/stream.rs
  • crates/core/src/api/llm.rs
  • crates/core/src/api/tool.rs
  • crates/core/tests/fixtures/worker_plugin/src/main.rs
  • crates/core/src/api/scope.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/api/runtime/state.rs
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/worker/src/lib.rs
  • crates/plugin/tests/typed_callbacks.rs
crates/core/src/api/{tool,llm}.rs

📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)

Wire the new middleware chain into the execute path in crates/core/src/api/tool.rs or crates/core/src/api/llm.rs at the appropriate pipeline stage

Files:

  • crates/core/src/api/llm.rs
  • crates/core/src/api/tool.rs
crates/core/src/api/**/*.rs

📄 CodeRabbit inference engine (.agents/skills/add-binding-feature/SKILL.md)

Implement public runtime behavior first in crates/core/src/api/ and related core modules such as crates/core/src/api/runtime/, crates/core/src/codec/, or crates/core/src/json.rs.

Files:

  • crates/core/src/api/llm.rs
  • crates/core/src/api/tool.rs
  • crates/core/src/api/scope.rs
  • crates/core/src/api/shared.rs
  • crates/core/src/api/runtime/state.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/fixtures/worker_plugin/src/main.rs
  • crates/core/tests/integration/worker_plugin_tests.rs
  • crates/worker/tests/worker_sdk_tests.rs
  • crates/plugin/tests/typed_callbacks.rs
crates/core/src/api/runtime/state.rs

📄 CodeRabbit inference engine (.agents/skills/add-middleware/SKILL.md)

crates/core/src/api/runtime/state.rs: Add registry fields as SortedRegistry<GuardrailEntry<T>> or SortedRegistry<Intercept<T>> to NemoRelayContextState in crates/core/src/api/runtime/state.rs
Add chain execution helpers to NemoRelayContextState following the pattern of existing methods like tool_sanitize_request_chain or tool_request_intercepts_chain

Files:

  • crates/core/src/api/runtime/state.rs
🔇 Additional comments (14)
crates/plugin/tests/typed_callbacks.rs (1)

2647-2668: LGTM! Both previously-requested fixes — null-pointer coverage for event/fields, and the out = stale_out reset before the invalid-fields case — are present and correct.

Also applies to: 3060-3073

crates/core/src/stream.rs (1)

40-40: LGTM!

Also applies to: 230-234, 259-263

crates/core/src/api/llm.rs (1)

24-25: LGTM!

Also applies to: 324-328, 330-357, 452-537, 539-564

crates/core/src/api/tool.rs (1)

14-14: LGTM!

Also applies to: 255-259, 291-367, 369-386

crates/core/src/api/scope.rs (1)

10-12: LGTM!

Also applies to: 209-240, 264-302, 328-357

crates/core/src/api/runtime/state.rs (1)

53-58: LGTM! New registries and chain helpers follow the existing _entries/_snapshot_chain pattern used elsewhere in this file, and the guardrail-scope emit paths correctly release locks before invoking sanitizer closures.

As per coding guidelines, "Add chain execution helpers to NemoRelayContextState following the pattern of existing methods like tool_sanitize_request_chain or tool_request_intercepts_chain."

Also applies to: 96-98, 557-635

crates/core/tests/fixtures/worker_plugin/src/main.rs (1)

64-94: LGTM!

crates/core/tests/integration/worker_plugin_tests.rs (2)

17-19: LGTM!

Also applies to: 107-138, 166-169, 179-186, 233-233


282-321: Solid coverage for sanitizer field-preservation semantics.

The test correctly demonstrates that mark_event_fields merges into existing metadata (both original_metadata and worker_plugin_mark survive) while a later-priority sanitizer that assigns fields.data directly fully replaces prior data — matching the two fixture guardrails' distinct merge vs. overwrite behaviors.

crates/worker/tests/worker_sdk_tests.rs (2)

201-215: Good regression coverage for the (surface, name) duplicate-registration fix.

worker_service_rejects_duplicate_registration_names_on_one_surface plus DuplicateEventSanitizerPlugin directly exercise the fix for the previously-flagged collision risk (same name registered twice on MarkSanitizeGuardrail), and the updated event-sanitize name-reuse-across-surfaces assertions confirm cross-surface reuse remains allowed.

Also applies to: 258-285, 1466-1479


492-516: LGTM!

Also applies to: 1612-1623

crates/worker/src/lib.rs (3)

142-159: Past collision concern resolved via per-surface sanitizer maps.

Splitting mark_sanitizers / scope_start_sanitizers / scope_end_sanitizers into separate maps, combined with validate_unique_registrations enforcing (surface, name) uniqueness, directly addresses the previously raised concern that mark and scope sanitizers sharing one name-keyed map could silently overwrite each other. Same-name reuse across different event surfaces (as exercised by SurfacePlugin/fixture tests) remains intentionally supported.

Also applies to: 200-269, 1552-1567


1046-1051: Duplicate check runs before committing handler state — correct ordering.

validate_unique_registrations is invoked on ctx.handlers.registrations before self.handlers.lock() is updated, so a rejected duplicate never leaks a partially-overwritten sanitizer map into the live handler state.

Also applies to: 1314-1326


1431-1442: LGTM!

Comment thread crates/worker/src/lib.rs
@bbednarski9

Copy link
Copy Markdown
Contributor

Nice, as expected the new unit test failed. I think we'll need to patch that

@bbednarski9 bbednarski9 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.

Just that unit test failing

Signed-off-by: Will Killian <wkillian@nvidia.com>
@coderabbitai coderabbitai Bot added the DO NOT MERGE PR should not be merged; see PR for details label Jul 8, 2026
@willkill07 willkill07 removed the DO NOT MERGE PR should not be merged; see PR for details label Jul 8, 2026
Signed-off-by: Will Killian <wkillian@nvidia.com>
@willkill07

Copy link
Copy Markdown
Member Author

/merge

@rapids-bot rapids-bot Bot merged commit 0e61dcd into NVIDIA:main Jul 8, 2026
70 of 72 checks passed
rapids-bot Bot pushed a commit that referenced this pull request Jul 9, 2026
#### Overview

Extends the built-in PII redaction policy onto the event sanitizer infrastructure from PR #371 so raw PII does not escape through marks or generic scope events.

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

#### Details

- Broadens `input` to LLM requests and non-tool/LLM scope starts.
- Broadens `output` to LLM responses and non-tool/LLM scope ends.
- Adds `mark`, defaulting to `true`, with `mark = false` as the opt-out.
- Sanitizes `data`, `category_profile`, and `metadata` independently.
- Leaves generic tool/LLM scope fields unchanged so specialized sanitizers do not hash or mask twice.
- Updates config validation, schema/editor surfaces, and default behavior tests.
- Adds a Hermes-style regression across subscribers, ATOF, ATIF, OpenTelemetry, and OpenInference.
- Contains no documentation changes; documentation is isolated in a final independent PR.
- Breaking changes: none. The intentional default behavior change protects marks when `mark` is omitted.

Validation: `nemo-relay-pii-redaction` tests and coverage, relevant CLI/config tests, full Rust and binding matrices, and pre-commit.

#### Where should the reviewer start?

Start with `crates/pii-redaction/src/component.rs`, `crates/pii-redaction/src/builtin.rs`, and the cross-exporter PII regression in the component tests.

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

- Fixes: RELAY-409



## Summary by CodeRabbit

* **New Features**
  * Added a new PII redaction surface toggle to mark events (`mark`), defaulting to enabled and configurable via the editor.
  * Extended built-in sanitization to cover additional scope-level guardrails (start/end) alongside existing LLM/tool sanitization.

* **Bug Fixes**
  * Ensured event/category-profile sanitization is handled correctly, including dropping the category profile when sanitization fails.

* **Tests**
  * Added/expanded unit and security regression tests for mark redaction behavior, metadata correctness, and verification that raw PII never appears in subscribers or telemetry exports.

Authors:
  - Will Killian (https://github.com/willkill07)

Approvers:
  - Bryan Bednarski (https://github.com/bbednarski9)

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

Labels

breaking PR introduces a breaking change Feature a new feature lang:rust PR changes/introduces Rust code size:XL PR is extra large

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants