fix(delegation): the path rules live in a stdlib-only module; the package imports without paho (Issue #57, Mac F1)
control_plane and status.sh imported sibling_logs_dir from mqtt_common, which imports paho at module level, so create/resume's binding and status died on an interpreter without paho-mqtt (_delegate_py_bin's last fallback is the PATH's python3). The registry/audit-log path rules move to lib_py/delegation/logroot.py (standard library only) and mqtt_common re-exports them. The package's own import chain also reached paho through service -> publish_event -> publisher, so mqtt_common and publisher import paho tolerantly and make_client() refuses with a clear error when a broker is actually needed. control_plane, status.sh, lib.sh's delegate_publish_cmd and delegate_logs_dir, and the wrapper's _logs_dir_abs import from logroot. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
63d816468e
commit
75c004222c
8 files changed
+145
-60
No files matched your search
@@ -472,3 +472,64 @@ def test_a_forwarded_pane_moves_its_logs_with_the_registry(tmp_path, monkeypatch
|
||||
assert res.stdout.strip().splitlines()[-1] == str(Path(os.path.realpath(main)) / ".mam" / "delegate_job_logs" / jid2)
|
||||
assert os.listdir(real_logs) == [jid2]
|
||||
assert not (wt / ".mam" / "delegate_job_logs").exists()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Mac review F1: the path helpers must not need paho
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@pytest.fixture
|
||||
def nopaho(tmp_path):
|
||||
"""A `paho` package that fails to import, first on PYTHONPATH: the real
|
||||
import path then behaves like an interpreter without paho-mqtt."""
|
||||
d = tmp_path / "nopaho"
|
||||
(d / "paho").mkdir(parents=True)
|
||||
(d / "paho" / "__init__.py").write_text("raise ModuleNotFoundError(\"No module named 'paho'\")\n")
|
||||
probe = subprocess.run([sys.executable, "-c", "import paho.mqtt.client"], capture_output=True, text=True,
|
||||
env={**os.environ, "PYTHONPATH": f"{d}:{SKILLS}"}, timeout=60)
|
||||
assert probe.returncode != 0 and "No module named 'paho'" in probe.stderr, probe.stderr
|
||||
return d
|
||||
|
||||
|
||||
def test_control_plane_binding_works_without_paho(moved, nopaho):
|
||||
"""_delegate_py_bin's last fallback is the PATH's python3, which may lack
|
||||
paho: create/resume's binding and lib.sh's publish-command prefix must still
|
||||
resolve the audit-log root."""
|
||||
ws, reg, logs = moved
|
||||
env = _env(ws, MAM_JOBS_DIR=str(reg), PYTHONPATH=f"{nopaho}:{SKILLS}", AGENT_PYTHON_BIN=sys.executable)
|
||||
res = subprocess.run([sys.executable, "-m", "lib_py.control_plane", "json", str(ws / "wt")],
|
||||
capture_output=True, text=True, env=env, cwd=str(ws), timeout=60)
|
||||
assert res.returncode == 0, res.stderr
|
||||
desc = json.loads(res.stdout)
|
||||
assert desc["delegate_job_logs_dir"] == os.path.realpath(logs)
|
||||
res = subprocess.run([sys.executable, "-m", "lib_py.control_plane", "prefix", json.dumps(desc)],
|
||||
capture_output=True, text=True, env=env, cwd=str(ws), timeout=60)
|
||||
assert res.returncode == 0 and "MAM_JOBS_DIR=" in res.stdout and "DELEGATE_JOB_LOGS_DIR=" not in res.stdout, res.stdout
|
||||
# lib.sh's injected publish command still pins the root (it resolved it with the same interpreter)
|
||||
res = subprocess.run(["bash", "-c", f"source '{SKILLS}/lib.sh' && delegate_publish_cmd j57"],
|
||||
capture_output=True, text=True, env=env, cwd=str(ws), timeout=60)
|
||||
assert res.returncode == 0, res.stderr
|
||||
assert res.stdout.startswith(f"DELEGATE_JOB_LOGS_DIR={os.path.realpath(logs)} "), res.stdout + res.stderr
|
||||
|
||||
|
||||
@pytest.mark.parametrize("mode", ["json", "text"])
|
||||
def test_status_works_without_paho(mam_sandbox, nopaho, monkeypatch, mode):
|
||||
tmp = mam_sandbox
|
||||
reg = tmp / ".mam" / "jobs"
|
||||
jid = registry.register_job("s57 nopaho", registry_dir=str(reg), agent_session="herdr:s57-nopaho")
|
||||
registry.update_status(jid, str(reg), "completed")
|
||||
_mutate(tmp, f"""
|
||||
d['herdr_sessions'] = [{{'name': 's57-creator-claude', 'status': 'running', 'delegate_job_id': {jid!r},
|
||||
'pane': {{'cwd': {str(tmp)!r}}}}}]
|
||||
""")
|
||||
monkeypatch.setenv("PYTHONPATH", str(nopaho))
|
||||
monkeypatch.setenv("AGENT_PYTHON_BIN", sys.executable)
|
||||
args = ["--json"] if mode == "json" else []
|
||||
res = subprocess.run(["bash", _skill(tmp, "multi-agent-mux-status", "scripts", "status.sh"), *args],
|
||||
capture_output=True, text=True, timeout=120)
|
||||
assert res.returncode == 0, res.stdout[-500:] + res.stderr[-800:]
|
||||
if mode == "json":
|
||||
assert json.loads(res.stdout)["sessions_detail"][0]["job_status"] == "completed"
|
||||
else:
|
||||
(line,) = [l for l in res.stdout.splitlines() if l.startswith("s57-creator-claude")]
|
||||
assert "completed" in line, line
|
||||
Reference in new issue
Block a user