Skip to content

[FEAT]: Deprecate omitted observability_level across public APIs #167

Description

Summary

Deprecate omitting observability_level on every public API that defaults it, so a caller that misses the argument gets a signal instead of silently keeping the old behavior.

Follow-up to a review comment on #141, filed at Nina Chikanov (@nina-msft)'s request and rescoped to the feedback below.

Motivation

#141 added observability_level to evaluate_turn_async with a compatibility default:

observability_level: ObservabilityLevel = ObservabilityLevel.TOOL_AND_SIDE_EFFECTS,

That default keeps every existing caller working, which is the right call for that PR. The cost is that it fails open. A caller that omits the argument treats every adapter as fully observable, which is the bug #140 describes: an evaluator that needs an evidence channel the adapter does not report returns NOT_DETECTED, and resolve_as_attack turns that into SAFE.

The same default is on EvalContext and on EvalContext.from_response. Result defaults the same field the other way, to RESPONSE_ONLY, where it is reporting metadata that every built-in path overwrites with the adapter's actual profile. evaluate_turn_async is exported from rampart.core and docs/contributing/extending-rampart.md presents it as the seam for a custom execution strategy, so out-of-repo callers are the ones most likely to miss it.

No shipped code relies on any of these defaults: every Result and EvalContext built in rampart/ passes observability_level explicitly. The repo's own tests are another matter. Counting the construction sites by AST, 83 calls under tests/ omit the argument: 64 Result, 13 EvalContext, 3 EvalContext.from_response and 3 evaluate_turn_async, including test_observability_level_defaults_to_no_declared_limit, which asserts the very default the warning would be about. Those would need the argument or an explicit filter before the warning lands.

Proposed solution

Making observability_level required is out of scope. The deprecation is:

  1. After [BREAKING] [FIX]: Return UNDETERMINED when an evaluator cannot observe the evidence it needs #141 merges, inventory every public API that defaults observability_level: evaluate_turn_async, direct EvalContext construction, EvalContext.from_response, and direct Result construction.
  2. When the argument is omitted, emit an actionable DeprecationWarning that names the affected API, explains the compatibility fallback being applied, directs the caller to pass the adapter's declared level, normally adapter.observability_profile, and names the removal release.
  3. Warn on omission only. Passing any ObservabilityLevel explicitly, including the value that is the current default, must not warn.
  4. Emit exactly one warning per omitted public call, including wrapper paths such as EvalContext.from_response.
  5. Preserve the current fallback behavior for the whole deprecation window.
  6. Name the removal release under the existing two-minor-version policy in docs/contributing/release-process.md: a warning shipped in 0.x.0 targets 0.(x+2).0.
  7. Update the docs and the generated reference: docs/contributing/extending-rampart.md, the direct Result(...) example in docs/usage/pytest-integration.md, the Result(...) helper in docs/contributing/testing.md, the EvalContext, Result and evaluate_turn_async docstrings, and add evaluate_turn_async to the rampart.core.execution members on docs/api/core-protocols.md, where it is public but absent.
  8. Add tests proving an omitted argument warns once and an explicit value does not warn at all.

Alternatives considered

  • Leave the defaults. Cheapest, but the failure is silent and points the wrong way for a safety framework.
  • Make the argument required now. A breaking API change with no migration window, and out of scope per the review discussion.
  • Default EvalContext to RESPONSE_ONLY to match Result. Fails safe, but it changes behavior for every caller that omits the argument, with no migration window, and makes a fully observable adapter look unobservable, which is its own false signal.
  • Infer the level inside evaluate_turn_async. It receives the evaluator and the turn data, not the adapter, so there is nothing to infer from.

Additional context

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions