replace_evaluation_results() deletes registry lines it could not read
まだ誰も着手していません。
評価
- 難易度
- 3/5
- 見積もり時間
- 1〜2日
- 初心者へのやさしさ
- 65/100
- issue の種類
- バグ
- 明瞭さ
- 明確に書かれている
- 活発さ
- 活発
- 技術スタック
- python
調査の方向性
The bug is in pyrit/score/scorer_evaluation/scorer_metrics_io.py, specifically the replace_evaluation_results() function and its helper _load_jsonl(). Start by reading the file and understanding how it currently loads and writes JSONL. The fix must ensure that unparseable lines are preserved and that a read error prevents a rewrite. Look at the existing tests for scorer_metrics_io to see how to add a test for this behavior. 'Done' means the repro script passes and no data is lost on partial reads or invalid JSON lines.
索引モデルが issue の本文から書いたものです。
説明
Describe the bug
replace_evaluation_results() rebuilds a scorer-metrics registry from _load_jsonl() (pyrit/score/scorer_evaluation/scorer_metrics_io.py:366-378), but that helper is a lookup: it skips lines it cannot parse, and if the read itself fails it logs Failed to load registry ... and returns whatever it managed to read (:304-311). Used as the source of truth for a truncating rewrite, both behaviours destroy data:
- an entry whose line is not valid JSON — a write killed mid-line, a hand edit — is deleted from the rewritten file for good;
- one undecodable byte anywhere in the file stops the read early, and the rewrite then contains only the new entry: every other pre-computed metric in that file is gone, and the call returns without an error.
These files ship with the package (pyrit/datasets/scorer_evals/, e.g. refusal_metrics.jsonl at 191 KB) and hold scores produced by hours of model calls, so this is not a rebuildable cache. The docstring states that only the entry with the matching eval_hash is removed and that the write is atomic; open(file_path, "w") over a short list does neither.
Steps/Code to Reproduce
import json
from pathlib import Path
from pyrit.models import ComponentIdentifier
from pyrit.score.scorer_evaluation.scorer_metrics import ObjectiveScorerMetrics
from pyrit.score.scorer_evaluation.scorer_metrics_io import (
_load_jsonl,
add_evaluation_results,
replace_evaluation_results,
)
path = Path("/tmp/pyrit-issue-repro/registry.jsonl")
path.parent.mkdir(parents=True, exist_ok=True)
path.unlink(missing_ok=True)
ident = ComponentIdentifier(class_name="A", class_module="pyrit.score.test", params={"model_name": "m"})
metrics = ObjectiveScorerMetrics(
num_responses=100, num_human_raters=3, accuracy=0.9,
accuracy_standard_error=0.02, f1_score=0.91, precision=0.93, recall=0.90,
)
add_evaluation_results(file_path=path, scorer_identifier=ident, eval_hash="hash_a", metrics=metrics)
path.write_text(path.read_text() + '{"hash_b": "b", "metrics": {"acc\n', encoding="utf-8") # torn line
replace_evaluation_results(file_path=path, scorer_identifier=ident, eval_hash="hash_new", metrics=metrics)
print("torn line survived the rewrite:", '{"hash_b"' in path.read_text(encoding="utf-8"))
path.write_bytes(path.read_bytes() + b'{"eval_hash": "bad", "metrics": \xff\xfe}\n') # undecodable byte
replace_evaluation_results(file_path=path, scorer_identifier=ident, eval_hash="hash_new2", metrics=metrics)
print("entries left:", [e["eval_hash"] for e in _load_jsonl(path)])
No network, no API key, no GPU.
Expected Results
The rewrite removes only the entry with the matching eval_hash. An unparseable line is left as it was, and a file that cannot be read is not rewritten at all.
Actual Results
On fc692226 (current main):
Invalid JSON at line 2 in /tmp/pyrit-issue-repro/registry.jsonl: Unterminated string starting at: line 1 column 29 (char 28)
Failed to load registry from /tmp/pyrit-issue-repro/registry.jsonl: 'utf-8' codec can't decode byte 0xff in position 882: invalid start byte
torn line survived the rewrite: False
entries left: ['hash_new2']
The torn line was deleted, and after the failed read hash_a was deleted too — with no exception reaching the caller.
Screenshots
Not applicable.
Versions
- OS: macOS 27.2 (arm64)
- Python version: 3.11.15
- PyRIT version: 1.2.0.dev0, run from source at
fc692226 pyrit.show_version()was not run; the repro above only touchespyrit.scoreandpyrit.models.
- 主要言語
- Python
- スター
- 4.5k
- フォーク
- 896
- 平均マージ
- 3日 8時間
- マージ済み PR(30日)
- 191
コントリビューションガイド
このリポジトリのコントリビューションガイドは索引されていません
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
microsoft/PyRIT のほかの issue
-
BUG HarmBench loader drops ContextString, so contextual behaviors are sent without their context オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 74/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
-
難易度 5/5 1週間以上 初心者へのやさしさ 35/100
microsoft/PyRIT の issue をすべて見る
似ている issue
-
agent-ready documentation needs-triage
難易度 1/5 1〜3時間 初心者へのやさしさ 88/100
-
documentation
難易度 1/5 1時間未満 初心者へのやさしさ 91/100
-
workflow-status page template still says reusable workflows are "triggered only by workflow_call:" オープン
難易度 1/5 1時間未満 初心者へのやさしさ 92/100
-
instance instance add
難易度 1/5 1時間未満 初心者へのやさしさ 72/100
searxng/searx-instances#939 · コメント 1 件 ·
-
area-deployment area-integrations triage:bot-seen
難易度 2/5 半日 初心者へのやさしさ 86/100