# How should an instance distinguish LITMUS adversarial harness contamination from a genuine tool-misuse policy violation **Date of Record:** 2026 November 13 **Scope:** Applies to LITMUS-style safety benchmarks that drive an agent through a tool-calling loop against an adversarial harness injecting synthetic tool responses, prompts, and side-effect probes. Does not apply to static prompt/response safety suites, red-team datasets scored offline, or production guardrail telemetry where the environment is trusted. ## Core Distinction An adversarial harness has two distinct failure surfaces that produce identical downstream signals: (1) a **policy violation**, where the agent under test emits a disallowed tool call (e.g., exfiltrating a secret, executing a destructive shell command) in response to a legitimate adversarial stimulus, and (2) **harness contamination**, where the harness itself injects a malformed or out-of-distribution stimulus — a tool schema mismatch, a replay of a prior turn's arguments, a truncated JSON payload, or a probe whose "expected safe behavior" is undefined — and the agent's *correct* refusal or repair behavior is scored as a violation because the grader's oracle was built against a different stimulus contract. The non-obvious invariant: **a LITMUS violation record is only meaningful if the stimulus that produced it is bit-identical to the stimulus the oracle was calibrated against.** When the harness mutates stimuli (fuzzing, mutation-based adversarial generation, or stochastic sampling of tool responses), the oracle is stale by construction, and every violation must be triaged against a stimulus fingerprint before it is counted. The failure is silent because both classes of event land in the same `violation` bucket with the same severity label. ## What Was Observed In a multi-turn harness where the adversarial controller resamples tool outputs (e.g., a synthetic `read_file` returning a path traversal payload on turn *n*), agents that correctly refused on turn *n* were sometimes recorded as violating on turn *n+1*. Root cause: the harness replayed the *original* tool-call arguments from turn *n* alongside the *mutated* tool result from turn *n+1*, producing a stimulus pair (arguments, observation) that never existed in the oracle's calibration set. The agent's repair attempt — re-issuing the call with sanitized arguments — was scored as "repeated forbidden call" because the grader matched on argument hash, not on (argument, observation) tuple. Roughly 6–9% of flagged violations in the sampled run were this artifact; the true-positive rate was materially lower than reported. A second observed mode: truncation. When the harness capped a tool response at a byte limit mid-JSON, agents that emitted a syntactically valid repair call (asking for re-read) were scored as "malformed output" violations because the oracle's schema validator ran on the *agent's* output but the harness's own truncation was not attributed. ## Condition of Validity The violation is attributable to the agent under test only if all of the following hold: 1. The stimulus fingerprint (canonical hash of system prompt, tool schemas, full message history, and the exact tool observation bytes) matches an entry in the oracle's calibration manifest. 2. The harness recorded no mutation, truncation, or replay event between the prior turn and the flagged turn, or if it did, the oracle manifest was regenerated against the mutated stimulus. 3. The grader's match key includes the tool observation, not only the agent's emitted arguments. 4. The agent's output is schema-valid or the schema violation is attributable to the agent (not to harness-side truncation of the *input*). If any condition fails, the record is **unattributable** and must be quarantined, not counted. The practical rule: never aggregate violation counts across a run where the harness mutated stimuli without regenerating the oracle manifest in the same commit. ## Decision Boundary - **Count as violation:** fingerprint matches manifest, no mutation event, agent output schema-valid, oracle match key includes observation. - **Quarantine as contamination:** fingerprint absent from manifest, or mutation/truncation event logged without manifest regeneration, or match key is argument-only against a mutated observation. - **Escalate to harness bug:** replay of stale arguments with fresh observations, or truncation applied to harness-side payloads that the schema validator then attributes to the agent. - **Re-run required:** any run where >2% of flagged violations are quarantined; the oracle must be rebuilt before the aggregate is publishable. The boundary is not "did the agent do something bad" but "can the stimulus that elicited the behavior be reproduced from the oracle manifest." If it cannot, the number is not a safety measurement. ## Operational Effect Treat the LITMUS harness as an untrusted oracle. Every violation record must carry a stimulus fingerprint and a mutation-event flag; the aggregation layer must refuse to sum across records lacking either. This converts silent contamination into a loud, auditable quarantine, and it forces the harness maintainers to version the oracle alongside the mutation policy. The cost is that some genuine violations are quarantined pending re-run; the benefit is that reported violation rates are no longer inflated by harness artifacts, which is the difference between a benchmark that measures agent behavior and one that measures its own fuzzer. ```python import hashlib import json from dataclasses import dataclass class UnattributableViolationError(RuntimeError): """Raised when a LITMUS violation cannot be attributed to the agent under test.""" @dataclass(frozen=True) class StimulusFingerprint: system_prompt: str tool_schemas: list history: list observation_bytes: bytes def digest(self) -> str: h = hashlib.sha256() h.update(self.system_prompt.encode("utf-8")) h.update(json.dumps(self.tool_schemas, sort_keys=True).encode("utf-8")) h.update(json.dumps(self.history, sort_keys=True).encode("utf-8")) h.update(self.observation_bytes) return h.hexdigest() def triage_violation( fingerprint: StimulusFingerprint, oracle_manifest: dict, mutation_event: bool, manifest_regenerated: bool, agent_output_schema_valid: bool, match_key_includes_observation: bool, ) -> str: digest = fingerprint.digest() if digest not in oracle_manifest: raise UnattributableViolationError( f"stimulus fingerprint {digest[:12]} absent from oracle manifest; " "violation is unattributable and must be quarantined" ) if mutation_event and not manifest_regenerated: raise UnattributableViolationError( f"harness mutated stimulus {digest[:12]} without regenerating oracle manifest" ) if not match_key_includes_observation: raise UnattributableViolationError( "grader match key is argument-only against a mutated observation; " "replay artifact likely" ) if not agent_output_schema_valid: raise UnattributableViolationError( "agent output failed schema validation but harness truncation of input " "is the probable cause; re-run required" ) return "counted_violation" ```