Spaces:
Running
Running
Download tests/test_loop.py from RDS777/TARGET_SPACE: direct link, hf CLI and curl.
- Browser
- Download file 7.07 kB
-
https://huggingface.co/spaces/RDS777/TARGET_SPACE/resolve/main/tests/test_loop.py
- Command line
-
hf download hf://spaces/RDS777/TARGET_SPACE/tests/test_loop.py
-
curl -L -o test_loop.py https://huggingface.co/spaces/RDS777/TARGET_SPACE/resolve/main/tests/test_loop.py
7.07 kB
| import pytest | |
| from mouh.jev.audit import AuditLog | |
| from mouh.jev.types import ( | |
| JevMessageType as T, JevProofObligation, TaskPayload, VERIFICATION_THRESHOLD, | |
| ) | |
| from mouh.verification import ( | |
| CallableGenerator, CorrectionStore, NullGenerator, TestTimeVerificationLoop, parse_files, | |
| ) | |
| BUGGY = "def add(a, b):\n return a - b\n" | |
| FIXED = "def add(a, b):\n return a + b\n" | |
| TESTS = "from calc import add\n\ndef test_add():\n assert add(2, 3) == 5\n\ndef test_zero():\n assert add(0, 0) == 0\n" | |
| def make_task(code=None, tests=TESTS, proofs=()): | |
| return TaskPayload(instruction="écrire add(a, b)", candidate_files={"calc.py": code} if code else {}, | |
| test_files={"test_calc.py": tests} if tests else {}, proofs=tuple(proofs)) | |
| def types_of(outcome): | |
| return [m.type for m in outcome.messages] | |
| def test_threshold_constant(): | |
| assert VERIFICATION_THRESHOLD == 0.85 | |
| def test_certified_on_first_attempt_emits_certificate(tmp_path): | |
| audit = AuditLog(tmp_path / "audit.jsonl") | |
| loop = TestTimeVerificationLoop(audit=audit) | |
| out = loop.run(make_task(FIXED)) | |
| assert out.status == "certified" and out.attempts == 1 | |
| assert out.final.certificate.score >= 0.85 and "tests" in out.final.certificate.evidence | |
| assert T.FINAL_ANSWER in types_of(out) and out.abort is None | |
| assert audit.verify() == (True, None) | |
| # chaque saut a été journalisé | |
| kinds = [r["event"]["kind"] for r in audit.records()] | |
| assert kinds.count("accepted") == len(out.messages) | |
| def test_correction_loop_repairs_bug_and_remembers_fix(tmp_path): | |
| calls = [] | |
| def gen(req): | |
| calls.append(req) | |
| assert req.message_type is T.CORRECTION_REQUEST and req.attempt == 2 | |
| assert req.experts[0] == 5 # expert n°5 (refactoring) prioritaire | |
| assert any(d.error_type.value == "test_failure" for d in req.diagnostics) | |
| return {"calc.py": FIXED} | |
| store = CorrectionStore(tmp_path / "fixes.jsonl") | |
| loop = TestTimeVerificationLoop(CallableGenerator(gen), corrections=store) | |
| out = loop.run(make_task(BUGGY)) | |
| assert out.status == "certified" and out.attempts == 2 and len(calls) == 1 | |
| assert [a["certified"] for a in out.attempts_log] == [False, True] | |
| assert out.attempts_log[0]["score"] < 1.0 | |
| assert T.CORRECTION_REQUEST in types_of(out) | |
| assert len(store) == 1 | |
| # la correction mémorisée devient un indice et une donnée d'affinage | |
| again = TestTimeVerificationLoop(CallableGenerator(lambda r: {"calc.py": FIXED} if r.hints else pytest.fail("pas d'indice")), | |
| corrections=CorrectionStore(tmp_path / "fixes.jsonl")) | |
| assert again.run(make_task(BUGGY)).status == "certified" | |
| n = store.export_sft(tmp_path / "sft.jsonl") | |
| assert n == 1 and "<diagnostics>" in (tmp_path / "sft.jsonl").read_text() | |
| def test_exhausted_budget_emits_no_final_text(): | |
| loop = TestTimeVerificationLoop(CallableGenerator(lambda r: {"calc.py": BUGGY + f"# v{r.attempt}\n"}), max_attempts=3) | |
| out = loop.run(make_task(BUGGY)) | |
| assert out.status == "exhausted" and out.final is None and out.attempts == 3 | |
| assert T.FINAL_ANSWER not in types_of(out) and out.abort.reason.startswith("budget de tentatives épuisé") | |
| def test_no_progress_detected(): | |
| loop = TestTimeVerificationLoop(CallableGenerator(lambda r: {"calc.py": BUGGY}), max_attempts=5) | |
| out = loop.run(make_task(BUGGY)) | |
| assert out.status == "aborted" and "aucun progrès" in out.abort.reason and out.attempts == 1 | |
| def test_null_generator_only_verifies_given_code(): | |
| out = TestTimeVerificationLoop(NullGenerator()).run(make_task(BUGGY)) | |
| assert out.status == "aborted" and out.final is None | |
| def test_no_oracle_means_nothing_is_certified(): | |
| out = TestTimeVerificationLoop().run(make_task(FIXED, tests="")) | |
| assert out.status == "aborted" and "aucun oracle" in out.abort.reason and out.final is None | |
| def test_syntax_error_then_repaired(): | |
| seq = iter([{"calc.py": FIXED}]) | |
| out = TestTimeVerificationLoop(CallableGenerator(lambda r: next(seq))).run(make_task("def add(a, b:\n return\n")) | |
| assert out.status == "certified" and out.attempts == 2 | |
| assert out.attempts_log[0]["components"]["static_analysis"] == 0.0 | |
| def test_policy_violation_blocks_certification(): | |
| evil = "import subprocess\ndef add(a, b):\n return a + b\n" | |
| out = TestTimeVerificationLoop(NullGenerator()).run(make_task(evil)) | |
| assert out.status == "aborted" and out.final is None | |
| assert out.attempts_log[0]["components"]["static_analysis"] == 0.0 | |
| def test_formal_proof_obligations_participate(): | |
| good = JevProofObligation(name="monotone", declarations={"x": "Int"}, assumptions=([">", "x", 0],), | |
| goal=[">", ["+", "x", 1], 1]) | |
| bad = JevProofObligation(name="faux", declarations={"x": "Int"}, assumptions=([">", "x", 0],), goal=[">", "x", 5]) | |
| ok = TestTimeVerificationLoop().run(make_task(FIXED, proofs=[good])) | |
| assert ok.status == "certified" and "proofs" in ok.final.certificate.evidence | |
| ko = TestTimeVerificationLoop().run(make_task(FIXED, proofs=[good, bad])) | |
| assert ko.final is None and ko.attempts_log[0]["components"]["proofs"] == 0.5 | |
| def test_proofs_alone_can_certify_without_tests(): | |
| p = JevProofObligation(name="p", declarations={"a": "Int"}, goal=["=", ["+", "a", 0], "a"]) | |
| out = TestTimeVerificationLoop().run(TaskPayload(instruction="x", candidate_files={"m.py": "x = 1\n"}, proofs=(p,))) | |
| assert out.status == "certified" | |
| def test_generator_crash_is_contained_and_reported(): | |
| def boom(req): | |
| raise RuntimeError("générateur en panne") | |
| out = TestTimeVerificationLoop(CallableGenerator(boom)).run(make_task(BUGGY)) | |
| assert out.final is None and out.status == "aborted" | |
| assert out.abort.diagnostics and out.abort.diagnostics[0].error_type.value == "handler_failure" | |
| def test_generator_proposes_first_attempt_when_no_candidate(): | |
| out = TestTimeVerificationLoop(CallableGenerator(lambda r: {"calc.py": FIXED})).run(make_task(None)) | |
| assert out.status == "certified" and out.attempts == 1 | |
| code_msgs = [m for m in out.messages if m.type is T.CODE_PROPOSAL] | |
| assert code_msgs[0].payload.origin == "model" | |
| def test_all_hops_are_schema_validated_and_routed_through_bus(): | |
| out = TestTimeVerificationLoop().run(make_task(FIXED)) | |
| seq = types_of(out) | |
| for needed in (T.TASK_SUBMISSION, T.ROUTE_REQUEST, T.ROUTE_DECISION, T.CODE_PROPOSAL, T.TOOL_CALL, | |
| T.TOOL_RESULT, T.VERIFICATION_RESULT, T.FINAL_ANSWER): | |
| assert needed in seq, needed | |
| assert seq.index(T.TOOL_CALL) < seq.index(T.TOOL_RESULT) < seq.index(T.VERIFICATION_RESULT) < seq.index(T.FINAL_ANSWER) | |
| def test_parse_files_formats(): | |
| txt = "### FILE: a.py\n```python\nx = 1\n```\n### END\n### FILE: b/c.py\ny = 2\n### END\n" | |
| assert parse_files(txt) == {"a.py": "x = 1\n", "b/c.py": "y = 2\n"} | |
| assert parse_files("```python\nz = 3\n```") == {"solution.py": "z = 3\n"} | |
| assert parse_files(" ") == {} | |