Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/NEXT_STATUS.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ language — this table is the current status source of truth.
| A | partial | Brief + runnable lumen task v1 + strict verifier (#33-35), reference-policy A3 comparison (#44) | A3 trained-checkpoint comparison; A5 external reproduction (blocked: partner) |
| B | partial | Threat model + env scrubbing (#36), container backend (#38), bounded transfer (#39), remainder + attestation + CI image (#40), probes (#41) | B5 cloud mint/storage (blocked: cloud owner); registry image publication (commercial decision) |
| C | partial | Dossier + cited gate (#37), orphan-label refusal + provenance + fault robustness (#42) | C4 world-native distributions (need SOFA/GPU world revisions); C5 phantom (blocked: partner) |
| D | partial | Paired comparison + CIs (#43), compare CLI (#45), split manifests with patient/site grouping (#60, #61, #62), scorecard uncertainty views | D5 benchmark-level reporting with external study data |
| D | partial | Paired comparison + CIs (#43), compare CLI (#45), split manifests with patient/site grouping (#60-62), D5 explicit cohort subgroup validation, head-covered trial bindings, clustered continuous bootstrap, and cloud parity (#64, cloud #5) | D5 benchmark-level reporting with external study data |
| E | partial | Obs/action contract + A3 (#44), interactive streams (#46), LeRobot reader + MONAI (#51), honest video adapter (#54) | E4 media alignment (no test media; mp4 banned from VC); semantic output schemas (needs E contract design) |
| F | partial | Prefix-replay branching proof + seed caveat (#47), trajectory-backed forecast task + null baseline (#56), planning utility measurement and recipe (#58) | F1 trajectory benchmark imports; F4 closed-loop simulator branching |
| G | partial | SB3 PPO recipe + measurement (#48), runnable fixes (#50, #52), kernel-observed episode divergence (#57, #59) | Verifier-derived training rewards (projection withdrawn); Prime interop |
| G | partial | SB3 PPO recipe + measurement (#48), runnable fixes (#50, #52), kernel-observed episode divergence (#57, #59), verifier-derived training rewards with divergence penalty (#65) | Prime interop |
| H | partial | Episode resume (#49), crash-safe writes + partial recovery (#53), strict trial provenance + pre-write drift rejection (#59) | Fleet queue/autoscaling (blocked: hosted capacity decision); vectorized stepping (not justified by measured need) |

### Status and evidence rules
Expand Down
2 changes: 2 additions & 0 deletions docs/examples/tasks/lumen-nav-safe/verifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ def score(self, context: dict[str, Any]) -> dict[str, Any]:
safety_max_pen = float(context["safety_max_pen"])
max_pen = _finite_number(info.get("max_pen"))
diverged = _exact_bool(info.get("diverged"))
if diverged is None and context.get("diverged_observed") is True:
diverged = True
raw_unsafe = info.get("unsafe")
if raw_unsafe is None:
unsafe = None if max_pen is None else max_pen > safety_max_pen
Expand Down
2 changes: 2 additions & 0 deletions src/or_audit/eval/export_verifiers.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
GymEnv,
GymFactory,
assert_perturbations_applied,
episode_diverged,
make_gym,
run_gym_episode,
sample_action,
Expand Down Expand Up @@ -995,6 +996,7 @@ def action_fn(env: GymEnv, observation: Any, step: int) -> Any:
"info": info,
"trajectory": [dict(step) for step in steps],
"safety_max_pen": safety,
"diverged_observed": episode_diverged(steps),
},
runtime=verifier,
)
Expand Down
2 changes: 2 additions & 0 deletions src/or_audit/eval/wrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -1062,6 +1062,8 @@ def _render_verifier(spec: WrapRequest) -> str:
" info: dict[str, Any] = raw_info if isinstance(raw_info, dict) else {}",
' raw_success = _boolean(info, "raw_success", "success", "is_success")',
' diverged = _boolean(info, "diverged")',
' if diverged is None and context.get("diverged_observed") is True:',
" diverged = True",
" breached: list[str] = []",
" unreported: list[str] = []",
" for gate_id, signal, predicate in GATES:",
Expand Down
35 changes: 35 additions & 0 deletions tests/test_eval_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -635,3 +635,38 @@ def test_nonfinite_kind_numpy_scalars() -> None:
assert nonfinite_kind(np.float64("inf")) == "+inf"
assert nonfinite_kind(np.float32("-inf")) == "-inf"
assert nonfinite_kind(np.float32(1.5)) == ""


def test_lumen_verifier_consumes_diverged_observed_and_fails_gate() -> None:
import importlib.util

path = ROOT / "docs/examples/tasks/lumen-nav-safe/verifier.py"
spec = importlib.util.spec_from_file_location("lumen_verifier", path)
assert spec is not None
assert spec.loader is not None
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
verifier = mod.LumenVerifier()
res = verifier.score(
{
"info": {"success": True, "max_pen": 0.05},
"safety_max_pen": 0.3,
"diverged_observed": True,
}
)
assert res["metrics"]["diverged"] is True
assert res["metrics"]["safe_success"] is False
assert res["gates"]["wall_penetration"]["status"] == "fail"
assert "episode diverged" in res["gates"]["wall_penetration"]["reason"]

# When diverged_observed is None -> diverged is None (unassessed)
res_none = verifier.score(
{
"info": {"success": True, "max_pen": 0.05},
"safety_max_pen": 0.3,
"diverged_observed": None,
}
)
assert res_none["metrics"]["diverged"] is None
assert res_none["metrics"]["safe_success"] is None
assert res_none["gates"]["wall_penetration"]["status"] == "pass"
Loading