Skip to content

FIX: Fingerprint target judgment adaptation in replay contract (#3753) - #3845

Open
Hrushikesh Ramilla (Hrushikesh-ramilla) wants to merge 1 commit into
microsoft:mainfrom
Hrushikesh-ramilla:fix/judgment-replay-normalizer-adaptation-3753
Open

Hrushikesh Ramilla (Hrushikesh-ramilla) wants to merge 1 commit into
microsoft:mainfrom
Hrushikesh-ramilla:fix/judgment-replay-normalizer-adaptation-3753

Conversation

@Hrushikesh-ramilla

@Hrushikesh-ramilla Hrushikesh Ramilla (Hrushikesh-ramilla) commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Description

Fixes #3753.

When replaying a target-backed judgment observation, previously only the response handler, category, and judgment identity were fingerprinted in the stored replay contract. If an otherwise identical target had a modified JsonSchemaNormalizer schema-instructions template (or differing normalizer adaptation), the replay check accepted the observation without calling the target, even though the changed instructions alter the judge's effective behavior.

This change:

  • Projects effective normalizer configurations via TargetConfiguration.project_pipeline() and includes target adaptation in _contract_fingerprint / _replay_contract_fingerprint.
  • Replays with matching normalizer templates without calling the target, while rejecting targets with changed schema instruction templates or differing adaptation.
  • Preserves explicit backwards compatibility for legacy observations acquired before target adaptation was included in the replay contract.

Tests and Documentation

Added comprehensive unit tests in tests/unit/score/test_judgment_observation.py:

  • test_judgment_replay_rejects_changed_schema_normalizer_template_async
  • test_judgment_replay_rejects_native_vs_adapted_json_schema_async
  • test_judgment_replay_schema_template_variant_verified_after_sqlite_reopen_async
  • test_judgment_replay_legacy_observation_compatibility_async

All 86 tests in test_judgment_observation.py and existing tests across prompt_target and message_normalizer pass cleanly.

Copilot AI balanced review requested due to automatic review settings November 2, 2026 23:34
@Hrushikesh-ramilla
Hrushikesh Ramilla (Hrushikesh-ramilla) force-pushed the fix/judgment-replay-normalizer-adaptation-3753 branch from 64ea1ad to bb53c11 Compare November 2, 2026 23:38

Copilot AI 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.

🟡 Changes recommended

Replay fingerprints omit the wrapped normalizer’s prompt-affecting settings, allowing replay to accept judgments acquired with different prompts.

1 open issue
What changed in this PR

This PR addresses #3753 by including target-side normalizer configuration in PyRIT’s judgment replay contract, preventing reuse when schema instructions or adaptation differ.

Changes:

  • Adds parameter-aware normalizer projections to replay fingerprints.
  • Passes targets into scorer replay validation while preserving legacy observation compatibility.
  • Adds regression tests for template changes, native versus adapted schemas, and SQLite reopen behavior.
File Description
tests/​unit/​score/​test_judgment_observation.py Adds adaptation and legacy replay regression tests.
pyrit/​score/​true_false/​shieldgemma_scorer.py Passes target into replay validation.
pyrit/​score/​true_false/​self_ask_true_false_scorer.py Passes target into replay validation.
pyrit/​score/​true_false/​self_ask_refusal_scorer.py Passes target into replay validation.
pyrit/​score/​true_false/​self_ask_general_true_false_scorer.py Passes target into replay validation.
pyrit/​score/​true_false/​self_ask_category_scorer.py Passes target into replay validation.
pyrit/​score/​true_false/​llamaguard_scorer.py Passes target into replay validation.
pyrit/​score/​llm_scoring.py Fingerprints target adaptation and handles legacy contracts.
pyrit/​score/​float_scale/​self_ask_scale_scorer.py Passes target into replay validation.
pyrit/​score/​float_scale/​self_ask_likert_scorer.py Passes target into replay validation.
pyrit/​score/​float_scale/​self_ask_general_float_scale_scorer.py Passes target into replay validation.
pyrit/​score/​float_scale/​insecure_code_scorer.py Passes target into replay validation.
pyrit/​score/​float_scale/​decision_scorer.py Passes target into replay validation.
pyrit/​prompt_target/​common/​target_configuration.py Projects normalizer types and parameters.
pyrit/​message_normalizer/​json_schema_normalizer.py Exposes schema instruction template parameters.
pyrit/​message_normalizer/​history_squash_normalizer.py Exposes history count and child formatter identity.
pyrit/​message_normalizer/​generic_system_squash.py Exposes an empty parameter projection.
pyrit/​message_normalizer/​chat_message_normalizer.py Exposes role and system-message settings.

Review effort: Balanced

Comment on lines +71 to +73
params["message_normalizer"] = self._message_normalizer.get_identifier().model_dump(
mode="json", exclude={"pyrit_version", "hash", "eval_hash"}
)
@Hrushikesh-ramilla
Hrushikesh Ramilla (Hrushikesh-ramilla) force-pushed the fix/judgment-replay-normalizer-adaptation-3753 branch 2 times, most recently from a7798f3 to 15a2349 Compare November 3, 2026 00:25
…soft#3753)

Fingerprint effective target-side judgment adaptation in the stored replay contract to prevent replaying observations across targets with changed schema instruction templates. Maintain explicit compatibility for legacy observations stored before target adaptation fingerprinting.

Signed-off-by: Hrushikesh Ramilla <ramillahrushikesh@gmail.com>
@Hrushikesh-ramilla
Hrushikesh Ramilla (Hrushikesh-ramilla) force-pushed the fix/judgment-replay-normalizer-adaptation-3753 branch from 15a2349 to 299468d Compare November 6, 2026 16:00

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Judgment replay accepts a changed target schema-normalization template despite its exact-configuration contract

2 participants