From 77d2c4569afb7fe6f5cfcd18c7bda9887c1c2b9b Mon Sep 17 00:00:00 2001 From: sora <2075279110@qq.com> Date: Mon, 14 Sep 2026 07:15:50 +0000 Subject: [PATCH] JSON-tolerant report/checkpoint saves (default=str) A finished 12-minute humaneval bench died at the save line: some scorer detail carried a non-JSON object (Ellipsis) and report.save's json.dumps had no default. Every dumps on the save path now stringifies exotic objects instead of killing the run; verified by replaying the exact crashed checkpoint end-to-end (pass 82.3%, 15s, no crash). Co-Authored-By: Claude --- evalharness/eval/checkpoint.py | 2 +- evalharness/eval/record.py | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/evalharness/eval/checkpoint.py b/evalharness/eval/checkpoint.py index aa44d03..692762c 100644 --- a/evalharness/eval/checkpoint.py +++ b/evalharness/eval/checkpoint.py @@ -70,7 +70,7 @@ class CheckpointStore: worst case loses the last in-flight sample on crash).""" rec = {'key': key, 'ts': time.time(), 'pred': pred} with open(self.path, 'a', encoding='utf-8') as f: - f.write(json.dumps(rec, ensure_ascii=False) + '\n') + f.write(json.dumps(rec, ensure_ascii=False, default=str) + '\n') self._entries[key] = pred def scores(self) -> Dict[str, Dict[str, Any]]: diff --git a/evalharness/eval/record.py b/evalharness/eval/record.py index 72edf98..b32d85d 100644 --- a/evalharness/eval/record.py +++ b/evalharness/eval/record.py @@ -68,20 +68,25 @@ class EvalReport(BaseModel): def save(self, path) -> None: import json + # default=str everywhere: score_details/samples carry arbitrary + # scorer output, and ONE exotic object (an Ellipsis sneaked in via + # a scorer's detail dict) must not kill a finished benchmark at + # the save line if str(path).endswith('.jsonl'): # streaming format: first line = report header, then one # sample per line (grep/split/tail friendly) head = self.model_dump(exclude={'samples'}) head['type'] = 'report' with open(path, 'w', encoding='utf-8') as f: - f.write(json.dumps(head, ensure_ascii=False) + '\n') + f.write(json.dumps(head, ensure_ascii=False, default=str) + '\n') for smp in self.samples: row = smp if isinstance(smp, dict) else smp.model_dump() row['type'] = 'sample' - f.write(json.dumps(row, ensure_ascii=False) + '\n') + f.write(json.dumps(row, ensure_ascii=False, default=str) + '\n') return with open(path, 'w', encoding='utf-8') as f: - json.dump(self.model_dump(), f, ensure_ascii=False, indent=2) + json.dump(self.model_dump(), f, ensure_ascii=False, indent=2, + default=str) @classmethod def load(cls, path) -> 'EvalReport':