diff --git a/src/e2e_pipeline.py b/src/e2e_pipeline.py index 6322aee..096388f 100644 --- a/src/e2e_pipeline.py +++ b/src/e2e_pipeline.py @@ -412,7 +412,13 @@ def _test_script_verify_fn(node_artifact_types, script_artifact_type="test_scrip def verify_fn(node, output): if node_artifact_types.get(node["node_id"]) != script_artifact_type: return True, None - return check_script_compiles(output["content"]) + ok, detail = check_script_compiles(output["content"]) + # work_graph_orchestrate._verify_and_maybe_regenerate does + # "; ".join(feedback or []), i.e. it expects a list of messages (the + # PRD-consistency verify_fn's `issues` shape) -- check_script_compiles + # returns a single string, which `join` would otherwise iterate + # character-by-character into a garbled reflect-prompt. + return ok, ([detail] if detail else None) return verify_fn diff --git a/src/test_e2e_pipeline.py b/src/test_e2e_pipeline.py index bcee763..edd6177 100644 --- a/src/test_e2e_pipeline.py +++ b/src/test_e2e_pipeline.py @@ -272,6 +272,12 @@ class TestScriptVerifyFnTest(unittest.TestCase): verify_fn = e2e_pipeline._test_script_verify_fn(node_artifact_types) ok, detail = verify_fn({"node_id": "script"}, {"content": "this is narrative, not code, no way"}) self.assertFalse(ok) + # regression: work_graph_orchestrate does "; ".join(feedback or []) on + # this return value -- a bare string would get joined character-by- + # character into a garbled reflect prompt (2026-08-06 self-hosting + # incident). Must be a list containing the message, not the message. + self.assertIsInstance(detail, list) + self.assertIn("py_compile", detail[0]) def test_test_script_node_with_real_code_passes(self): node_artifact_types = {"script": "test_script"}