From b9686a76272c3079c6477284951f64f81a6b0f22 Mon Sep 17 00:00:00 2001 From: Albert Zhao Date: Mon, 9 Nov 2026 02:53:54 -0500 Subject: [PATCH] mwm and RRSI: refuse a learner backend other than Codex or Claude Code at setup mwm ran a Pi learner without its bound model (its session settings carry no provider), and RRSI's roles, kept read-only through Codex's own sandbox mode or Claude Code's tool settings, ran with all of Pi's tools. Both now refuse an evolver.params.backend other than codex or claude before the first step. Each test fails without its check. Co-Authored-By: Claude Opus 5.5 --- hermit/agent/evolver/methods/mwm/evolver.py | 3 +++ hermit/agent/evolver/methods/rrsi_adapter/evolver.py | 3 +++ tests/methods/mwm/test_mwm_evolver.py | 10 ++++++++++ tests/methods/rrsi_adapter/test_rrsi_adapter.py | 2 ++ 4 files changed, 18 insertions(+) diff --git a/hermit/agent/evolver/methods/mwm/evolver.py b/hermit/agent/evolver/methods/mwm/evolver.py index 4ae8ac0d..9b3f473b 100644 --- a/hermit/agent/evolver/methods/mwm/evolver.py +++ b/hermit/agent/evolver/methods/mwm/evolver.py @@ -456,6 +456,9 @@ def _notes(admission: dict | None) -> str: # ------------------------------------------------------------------ steps def setup(self, ctx: Context) -> None: + if ctx.params.get("backend", "codex") not in ("codex", "claude"): # its session texts, homes and sign-ins + raise ValueError("the mwm Evolver's learner is a Codex or Claude Code session: evolver.params.backend is " + f"codex or claude, not {ctx.params.get('backend')!r}") if "network_isolation" in ctx.params: raise ValueError("evolver.params.network_isolation was removed: the learner runs in the run's evolver " "sandbox, whose network reaches only its models, the tool endpoint and " diff --git a/hermit/agent/evolver/methods/rrsi_adapter/evolver.py b/hermit/agent/evolver/methods/rrsi_adapter/evolver.py index 0ac28a4e..31add202 100644 --- a/hermit/agent/evolver/methods/rrsi_adapter/evolver.py +++ b/hermit/agent/evolver/methods/rrsi_adapter/evolver.py @@ -417,6 +417,9 @@ def setup(self, ctx) -> None: """What every step needs, checked once: a broken hyperparameter file or domain, or an unset web_search, stops the run here rather than failing each step.""" _require_rrsi() + if ctx.params.get("backend", "codex") not in ("codex", "claude"): # its roles' settings are those CLIs' + raise ValueError("the RRSI Adapter's proposer and roles are Codex or Claude Code sessions: " + f"evolver.params.backend is codex or claude, not {ctx.params.get('backend')!r}") if not isinstance(ctx.params.get("web_search"), bool): raise ValueError("evolver.params.web_search must be set, true or false") role = ctx.params.get("roles") or {} diff --git a/tests/methods/mwm/test_mwm_evolver.py b/tests/methods/mwm/test_mwm_evolver.py index 687f028b..edcaacf1 100644 --- a/tests/methods/mwm/test_mwm_evolver.py +++ b/tests/methods/mwm/test_mwm_evolver.py @@ -148,6 +148,16 @@ def make(tmp: Path, monkeypatch, steps: int = 2, deployment_param: bool = False) return path +def test_a_learner_that_is_not_codex_or_claude_code_is_refused_at_setup(): + """mwm's session is Codex's or Claude Code's (its texts, homes and sign-ins): another CLI Base Agent, which the + config takes as evolver.base (pi), is refused before any step rather than run without its model (mwm's session + settings carry no `provider`).""" + from types import SimpleNamespace + from hermit.agent.evolver.methods.mwm.evolver import MwmEvolver + with pytest.raises(ValueError, match="backend is codex or claude, not 'pi'"): + MwmEvolver().setup(SimpleNamespace(params={"backend": "pi"})) + + def test_bootstrap_review_mounts_and_records(tmp_path, monkeypatch): cfg = Config.load(make(tmp_path, monkeypatch), []) stale = tmp_path / "taskdir" / "evidence" / "block000" # a record already in the store: hidden from the bootstrap diff --git a/tests/methods/rrsi_adapter/test_rrsi_adapter.py b/tests/methods/rrsi_adapter/test_rrsi_adapter.py index 787b6782..1be09dca 100644 --- a/tests/methods/rrsi_adapter/test_rrsi_adapter.py +++ b/tests/methods/rrsi_adapter/test_rrsi_adapter.py @@ -818,6 +818,8 @@ def test_setup_checks_what_every_step_needs(tmp_path): ev.setup(ctx) with pytest.raises(ValueError, match="web_search"): ev.setup(context(ws, 1, dom, tmp_path, web_search=None)) + with pytest.raises(ValueError, match="backend is codex or claude, not 'pi'"): # its roles' settings are not Pi's + ev.setup(context(ws, 1, dom, tmp_path, backend="pi")) with pytest.raises(Exception): ev.setup(context(ws, 1, str(tmp_path / "dom" / "missing.py") + ":ToyDomain", tmp_path)) with pytest.raises(ValueError, match="roles.model"):