Merge pull request #104 from zixuanguo786-ctrl/codex/preserve-fractional-hard-score

[codex] Preserve fractional rollout hard scores
This commit is contained in:
Yifan Yang
2026-07-14 17:41:42 +09:00
committed by GitHub
2 changed files with 20 additions and 7 deletions
+5 -5
View File
@@ -11,12 +11,12 @@ BatchSpec — from skillopt.datasets.base
""" """
from __future__ import annotations from __future__ import annotations
from dataclasses import dataclass, field, fields as dc_fields from dataclasses import dataclass, field
from dataclasses import fields as dc_fields
from typing import Any, Literal from typing import Any, Literal
from skillopt.evaluation.gate import GateAction, GateResult # noqa: F401
from skillopt.datasets.base import BatchSpec # noqa: F401 from skillopt.datasets.base import BatchSpec # noqa: F401
from skillopt.evaluation.gate import GateAction, GateResult # noqa: F401
# ── Atomic types ───────────────────────────────────────────────────────── # ── Atomic types ─────────────────────────────────────────────────────────
@@ -109,7 +109,7 @@ class RolloutResult:
""" """
id: str id: str
hard: int hard: float
soft: float soft: float
n_turns: int = 0 n_turns: int = 0
fail_reason: str = "" fail_reason: str = ""
@@ -142,7 +142,7 @@ class RolloutResult:
extras = {k: v for k, v in d.items() if k not in known} extras = {k: v for k, v in d.items() if k not in known}
return cls( return cls(
id=str(d.get("id", "")), id=str(d.get("id", "")),
hard=int(d.get("hard", 0)), hard=float(d.get("hard", 0)),
soft=float(d.get("soft", 0.0)), soft=float(d.get("soft", 0.0)),
n_turns=int(d.get("n_turns", 0)), n_turns=int(d.get("n_turns", 0)),
fail_reason=str(d.get("fail_reason", "")), fail_reason=str(d.get("fail_reason", "")),
+15 -2
View File
@@ -3,8 +3,7 @@ from __future__ import annotations
import pytest import pytest
from skillopt.types import Edit, Patch from skillopt.types import Edit, Patch, RolloutResult
# ── Edit ──────────────────────────────────────────────────────────────────── # ── Edit ────────────────────────────────────────────────────────────────────
@@ -247,3 +246,17 @@ class TestPatchEdgeCases:
assert isinstance(p.edits[0], Edit) assert isinstance(p.edits[0], Edit)
assert p.edits[0].op == "append" assert p.edits[0].op == "append"
assert p.edits[0].content == "hello" assert p.edits[0].content == "hello"
# ── RolloutResult ────────────────────────────────────────────────────────────
class TestRolloutResultRoundTrip:
"""RolloutResult.to_dict() / RolloutResult.from_dict() round-trip."""
def test_preserves_fractional_hard_score(self) -> None:
"""Hard can be a continuous reward and must not be truncated."""
result = RolloutResult.from_dict({"id": "episode-1", "hard": 0.75, "soft": 0.5})
assert result.hard == pytest.approx(0.75)
assert result.to_dict()["hard"] == pytest.approx(0.75)