Compare commits
2
Commits
c982616188
...
63d816468e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
63d816468e | ||
|
|
c57e7667aa |
No files matched your search
@@ -5,6 +5,10 @@ WORKSPACE_ROOT, AGENT_SESSIONS_YAML, MAM_JOBS_DIR, DELEGATE_JOB_LOGS_DIR.
|
||||
create/resume persist it on the row (`control_plane`) and forward it to the
|
||||
pane only when it differs from what `--workspace` alone would imply, through
|
||||
the leading `K=V` tokens lib.sh's new-session already turns into `--env`.
|
||||
The audit-log root is recorded but not forwarded when it is derivable from
|
||||
the registry (its sibling delegate_job_logs, Issue #57): in the pane the
|
||||
registry alone then decides where the audit log goes, so `--registry-dir`
|
||||
moves both.
|
||||
|
||||
CLI (used by lib.sh):
|
||||
python -m lib_py.control_plane json <workspace> [<row control_plane JSON>]
|
||||
@@ -70,10 +74,20 @@ def describe(workspace: str, row: Optional[dict] = None) -> dict:
|
||||
"whitespace": any(any(c.isspace() for c in v) for v in b.values()), "source": source}
|
||||
|
||||
|
||||
def forwarded_keys(desc: dict) -> list:
|
||||
"""The binding keys the pane receives: all four, minus the audit-log root
|
||||
when it is the sibling of the registry and so derivable there (Issue #57).
|
||||
An explicit, non-sibling root is forwarded as before."""
|
||||
keys = list(KEYS)
|
||||
if desc.get("delegate_job_logs_dir") == _abs(mqtt_common.sibling_logs_dir(desc["mam_jobs_dir"])):
|
||||
keys.remove("delegate_job_logs_dir")
|
||||
return keys
|
||||
|
||||
|
||||
def prefix(desc: dict) -> str:
|
||||
if not desc.get("forward"):
|
||||
return ""
|
||||
return "".join(f"{ENV[k]}={shlex.quote(desc[k])} " for k in KEYS)
|
||||
return "".join(f"{ENV[k]}={shlex.quote(desc[k])} " for k in forwarded_keys(desc))
|
||||
|
||||
|
||||
def main(argv=None) -> int:
|
||||
|
||||
@@ -35,7 +35,7 @@ MAM 은 **워크스페이스 = `.agents/skills` 가 들어 있는 체크아웃
|
||||
- **creator = 워크트리 전용 인스턴스.** 제품 코드를 편집·커밋하는 유일한 에이전트이므로 cwd 가 곧 이슈 브랜치여야 한다. 오케스트레이터 커밋과 루프의 리포트 승격(`runner.py` 의 Promotion 블록 → 제어 루트 `.agents/reports/`)은 별도 소유다. 이슈마다 `creator-<agent>-<issue>` 로 만들고 끝나면 정지(대화 보존, 필요 시 재개). 재개하려면 같은 워크트리 경로가 있어야 한다(대화 키가 cwd).
|
||||
- **리뷰어 풀 = 본 체크아웃 공유.** 리뷰어는 소스를 편집하지 않는다. 그러나 테스트 실행은 쓰기를 동반하므로 '읽기 전용'이 아니다. `--worktree`/`--base` 에서는 러너가 매 라운드를 스냅샷 `(loop_id, base, head, tree)` 에 묶고(항목 5), 리뷰어는 그 스냅샷의 detached 리뷰 워크트리(기본) 또는 env 격리 지침으로 소스 루트에서 검증한다. 리뷰 중 소스가 바뀐 라운드의 승인은 버리고 다시 리뷰하며, 승격 직전에도 다시 확인한다. 원격 리뷰어는 리뷰 트리에 닿을 수 없어 기본 거부, `--remote-review diff-only` 로만 받는다. 리뷰가 병목이면 리뷰어 인스턴스를 추가한다.
|
||||
- **오케스트레이터 커밋 = 워크트리.** 본 체크아웃은 리뷰어의 작업 공간이므로 오케스트레이터는 그곳에서 브랜치를 바꾸지 않는다.
|
||||
- **제어 평면 = 본 체크아웃의 `.mam` 하나.** create/resume 이 바인딩(`WORKSPACE_ROOT`·`AGENT_SESSIONS_YAML`·`MAM_JOBS_DIR`·`DELEGATE_JOB_LOGS_DIR`)을 행(`control_plane`)에 영속하고, `--workspace` 기본값과 다르면 pane 에 명시 전파한다(항목 3). 호출자 env 만으로는 pane 상속이 보장되지 않는다(lib.sh:667-680 — new-session 은 선행 `K=V` 토큰만 `--env` 로 바꾼다). 행의 `pane.cwd` 는 워크트리다.
|
||||
- **제어 평면 = 본 체크아웃의 `.mam` 하나.** create/resume 이 바인딩(`WORKSPACE_ROOT`·`AGENT_SESSIONS_YAML`·`MAM_JOBS_DIR`·`DELEGATE_JOB_LOGS_DIR`)을 행(`control_plane`)에 영속하고, `--workspace` 기본값과 다르면 pane 에 명시 전파한다(항목 3; 유도 가능한 감사 로그 루트 = `MAM_JOBS_DIR` 의 형제는 행에만 기록하고 전파하지 않는다, #57). 호출자 env 만으로는 pane 상속이 보장되지 않는다(lib.sh:667-680 — new-session 은 선행 `K=V` 토큰만 `--env` 로 바꾼다). 행의 `pane.cwd` 는 워크트리다.
|
||||
|
||||
## 3. C 안의 동작 방식 (1단계 + 2단계 루프 A 반영)
|
||||
|
||||
@@ -123,7 +123,7 @@ bash "$MAIN/.agents/skills/multi-agent-mux-stop/scripts/worktree_remove.sh" --pa
|
||||
|
||||
| 스킬 | 제어 평면 바인딩 | 워크트리 cwd 행 | 1단계 이후 남은 제한 (항목) |
|
||||
|---|---|---|---|
|
||||
| create | env 에서 결정 → 행 `control_plane` 에 항상 영속. `--workspace` 기본값과 다르면 새 pane 의 생성 호출(`pane split`/`workspace create`)에 `--env` 로 전파한다. 전파가 필요하면 idle pane 을 재사용하지 않는다(`agent start -- <args>` 는 `--` 뒤를 에이전트 인자로 넘기므로 `env K=V` 를 쓸 수 없다). 전파가 필요한데 경로에 공백이 있으면 exit 2. `~/.local/bin` wrapper 경로는 기록만 하고 경고 | pane.cwd = `--workspace`. 바인딩 계산 실패 시 워크트리면 exit 2, 제어 루트면 경고 | — (루프 A: 즉시 reconcile·watchdog 은 제어 루트 코드와 `WORKSPACE_ROOT` 로 기동, prepare 가 `MAM_NO_SUBSCRIBER_DAEMON=1`) |
|
||||
| create | env 에서 결정 → 행 `control_plane` 에 항상 영속. `--workspace` 기본값과 다르면 새 pane 의 생성 호출(`pane split`/`workspace create`)에 바인딩(유도 가능한 감사 로그 루트 제외)을 `--env` 로 전파한다. 전파가 필요하면 idle pane 을 재사용하지 않는다(`agent start -- <args>` 는 `--` 뒤를 에이전트 인자로 넘기므로 `env K=V` 를 쓸 수 없다). 전파가 필요한데 경로에 공백이 있으면 exit 2. `~/.local/bin` wrapper 경로는 기록만 하고 경고 | pane.cwd = `--workspace`. 바인딩 계산 실패 시 워크트리면 exit 2, 제어 루트면 경고 | — (루프 A: 즉시 reconcile·watchdog 은 제어 루트 코드와 `WORKSPACE_ROOT` 로 기동, prepare 가 `MAM_NO_SUBSCRIBER_DAEMON=1`) |
|
||||
| resume | 행 바인딩 우선(호출자 env 와 다르면 stderr 경고) 재전파. 바인딩 없는 기존 행은 호출자 바인딩으로 채움. 이미 살아 있는 세션에도 바인딩을 영속한다. 계산 실패 시 워크트리면 exit 2 | 원래 cwd 로만: 경로 불일치·부재 시 exit 2 | 워크트리 삭제 시 재개 불가(대화 보존, 같은 경로에 다시 만들면 재개) |
|
||||
| stop | `MAM_JOBS_DIR` > 행의 `mam_jobs_dir` > `$WORKSPACE_ROOT/.mam/jobs` 순으로 잡 조회·발행. 감사 로그도 `DELEGATE_JOB_LOGS_DIR` > 행의 `delegate_job_logs_dir` 순 | 행 cwd 로 uuid 캡처·purge. 워크트리 해체는 `worktree_remove.sh` 가 판정(잠금·세션·잡·청결·서브모듈) 뒤에만 정지·제거, 서브모듈 워크트리는 검증 후 `--force` 1회 | — |
|
||||
| status | `MAM_JOBS_DIR`·행 `mam_jobs_dir`·감사 로그(`DELEGATE_JOB_LOGS_DIR`·행 `delegate_job_logs_dir`)·기존 후보 순 조회 | 행 cwd 로 대화 키 | — |
|
||||
@@ -131,6 +131,6 @@ bash "$MAIN/.agents/skills/multi-agent-mux-stop/scripts/worktree_remove.sh" --pa
|
||||
| delegate-job | `--registry-dir` > `MAM_JOBS_DIR` > `.mam/jobs`(`--workdir` 기준), 모두 절대화. 발행 명령이 감사 로그 루트(`DELEGATE_JOB_LOGS_DIR`)를 고정 | 문구·명령·리포트 경로 절대 | 작은따옴표가 든 경로는 지원 범위 밖 |
|
||||
| loop | `MAM_JOBS_DIR` 존중, 래퍼에 `--registry-dir` 명시. `--worktree` 로 소스 루트 분리 | diff·base·head 만 소스 루트. **구현이 루프 밖이면 `--base <구현 전 sha> --review-only` 필수**. `--worktree`/`--base` 가 있으면 빈 변경분 거부 | 루프 하나(8). 원격 리뷰어는 identity 모드에서 거부(기본) 또는 diff-only(`--remote-review diff-only`); 원격 리뷰어가 트리를 검증하게 하는 스냅샷 공유(공유 원격의 `refs/mam/review/<loop_id>/<n>`)는 범위 밖. 레거시 셸 루프(`MAM_LOOP_PY=0`)는 새 옵션 거부 |
|
||||
|
||||
실제 herdr 가 `pane split --env` / `workspace create --env` 로 pane 환경을 넘기는지는 mock 수준으로만 검증했다. 수용 사례 A2 는 러너가 바인딩 4개를 `--env` 로 싣고 `agent start --` 뒤에는 싣지 않음을 고정한다. 실제 herdr pane 안에서 값이 보이는지는 단계 C 시험 운영에서 확인한다.
|
||||
실제 herdr 가 `pane split --env` / `workspace create --env` 로 pane 환경을 넘기는지는 mock 수준으로만 검증했다. 수용 사례 A2 는 러너가 바인딩(유도 가능한 감사 로그 루트 제외)을 `--env` 로 싣고 `agent start --` 뒤에는 싣지 않음을 고정한다. 실제 herdr pane 안에서 값이 보이는지는 단계 C 시험 운영에서 확인한다.
|
||||
|
||||
**호환성 메모 (루프 B)**: 1단계부터 있던 `--worktree`/`--base` + 원격 리뷰어 조합은 이전에는 원격 리뷰어가 도달할 수 없는 로컬 경로를 프롬프트에 담아 진행했다. 이제는 어떤 잡도 위임하기 전에 기본으로 거부하며, `--remote-review diff-only` 로 opt-in 할 수 있다. 옵션 없는 루프는 그대로다. 스냅샷 커밋은 ref 가 없어 gc 가 정리하고(기본 2주), 리뷰 워크트리는 라운드마다 지운다.
|
||||
@@ -21,7 +21,8 @@ import pytest
|
||||
from test_issue21_loop_b import LOCAL_ROWS, _drive, _reviews, _sidecars, _state
|
||||
from test_issue21_phase2_loop_a import (REM, _calls, _prepare, _resume, _rows, _run, _skill, _wt, # noqa: F401
|
||||
ctl)
|
||||
from test_issue21_worktree_prereqs import (CP_ENV, WRAPPER, _assert_no_env_in_agent_args, _binding, _dry_submit,
|
||||
from test_issue21_worktree_prereqs import (CP_ENV, FORWARDED_ENV, WRAPPER, _assert_no_env_in_agent_args, _binding, # noqa: F401
|
||||
_dry_submit,
|
||||
_env, _env_flags, _injected, _kill_timer, _only_job_id)
|
||||
from test_issue21_worktree_prereqs import _git as _g
|
||||
from test_issue21_worktree_prereqs import wt_repo # noqa: F401
|
||||
@@ -70,7 +71,7 @@ def test_a2_pane_env_carries_the_binding_not_the_agent_args(ctl, mock_herdr, moc
|
||||
main = ctl
|
||||
wt, since, _ = _sibling(main, mock_herdr)
|
||||
flags = _env_flags(mock_herdr, since)
|
||||
for k, v in zip(CP_ENV, _binding(main).values()):
|
||||
for k, v in zip(FORWARDED_ENV, list(_binding(main).values())[:3]):
|
||||
assert f"{k}={v}" in flags, flags
|
||||
spawns = [c for c in _calls(mock_herdr) if c[:2] in (["pane", "split"], ["workspace", "create"])]
|
||||
assert spawns and any("--env" in c for c in spawns), "the binding rides on the pane-creating call"
|
||||
|
||||
@@ -493,6 +493,8 @@ def test_t2_14_undeterminable_change_set_is_refused(wt_repo, monkeypatch, tmp_pa
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
CP_ENV = ("WORKSPACE_ROOT", "AGENT_SESSIONS_YAML", "MAM_JOBS_DIR", "DELEGATE_JOB_LOGS_DIR")
|
||||
# Issue #57: the derivable audit-log root is recorded on the row, not forwarded
|
||||
FORWARDED_ENV = CP_ENV[:3]
|
||||
|
||||
|
||||
def _binding(root: Path) -> dict:
|
||||
@@ -576,7 +578,7 @@ def test_t3_1_create_persists_and_forwards_a_foreign_binding(mam_sandbox, mock_h
|
||||
(row,) = _rows(tmp)
|
||||
assert row["control_plane"] == _binding(tmp)
|
||||
flags = _env_flags(mock_herdr)
|
||||
for k, v in zip(CP_ENV, _binding(tmp).values()):
|
||||
for k, v in zip(FORWARDED_ENV, list(_binding(tmp).values())[:3]):
|
||||
assert f"{k}={v}" in flags, flags
|
||||
assert "WORKSPACE_ROOT=" not in row["pane"]["cmd_full"]
|
||||
assert "WORKSPACE_ROOT=" not in row["start_command"]
|
||||
@@ -625,7 +627,7 @@ def test_t3_3_4_stop_keeps_the_binding_and_resume_reforwards_it(mam_sandbox, moc
|
||||
# tokens to the agent as arguments, review R1): resume takes a new pane,
|
||||
# whose creation call carries the binding as --env.
|
||||
flags = _env_flags(mock_herdr, since)
|
||||
for k, v in zip(CP_ENV, _binding(tmp).values()):
|
||||
for k, v in zip(FORWARDED_ENV, list(_binding(tmp).values())[:3]):
|
||||
assert f"{k}={v}" in flags, (res.stderr[-1500:], flags)
|
||||
_assert_no_env_in_agent_args(mock_herdr, since)
|
||||
(row,) = _rows(tmp)
|
||||
|
||||
@@ -38,6 +38,7 @@ from lib_py import control_plane # noqa: E402
|
||||
from lib_py.delegation import engine, job_subscriber, mqtt_common, registry # noqa: E402
|
||||
from test_issue21_phase2_loop_a import _mutate, _prepare, _rows, _skill, _wt # noqa: E402
|
||||
from test_issue21_phase2_loop_a import ctl # noqa: E402,F401
|
||||
from test_issue21_worktree_prereqs import _env_flags, _sent_texts # noqa: E402
|
||||
|
||||
UNREACHABLE = {"MQTT_BROKER": "127.0.0.1", "MQTT_PORT": "9", "MQTT_TLS": "0"}
|
||||
DROP = ("MAM_JOBS_DIR", "DELEGATE_JOB_LOGS_DIR")
|
||||
@@ -153,9 +154,9 @@ def test_registry_cli_writes_and_reads_next_to_the_registry(moved):
|
||||
# L3 — the wrapper's last line names the directory it wrote
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _wrapper(ws: Path, *args, **extra) -> subprocess.CompletedProcess:
|
||||
def _wrapper(ws: Path, *args, cwd: Path = None, **extra) -> subprocess.CompletedProcess:
|
||||
return subprocess.run(["bash", str(WRAPPER), *args], capture_output=True, text=True,
|
||||
env=_env(ws, **extra), cwd=str(ws), timeout=120)
|
||||
env=_env(ws, **extra), cwd=str(cwd or ws), timeout=120)
|
||||
|
||||
|
||||
def _only_job_id(reg: Path) -> str:
|
||||
@@ -280,6 +281,10 @@ def test_worktree_prepare_keeps_the_logs_next_to_the_control_root_registry(ctl,
|
||||
jid = row["delegate_job_id"]
|
||||
assert (main / "elsewhere" / "delegate_job_logs" / jid / "status.json").is_file()
|
||||
assert not (main / ".mam" / "delegate_job_logs").exists()
|
||||
# the pane carries the registry, not the audit-log root derived from it
|
||||
flags = _env_flags(mock_herdr)
|
||||
assert any(f == f"MAM_JOBS_DIR={os.path.realpath(reg)}" for f in flags), flags
|
||||
assert not [f for f in flags if f.startswith("DELEGATE_JOB_LOGS_DIR=")], flags
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -380,3 +385,90 @@ def test_old_audit_terminal_does_not_complete_the_redispatched_attempt(moved, mo
|
||||
pending, terminal = {jid}, {}
|
||||
job_subscriber._check_disk_fallback(pending, str(reg), terminal, {jid: rec["dispatch_token"]}, {jid: 2})
|
||||
assert pending == set() and terminal == {jid: "completed"}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# plan §2-B (user decision): the derivable audit-log root is recorded, not forwarded
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _cp_cli(ws: Path, *args, **extra) -> subprocess.CompletedProcess:
|
||||
return subprocess.run([sys.executable, "-m", "lib_py.control_plane", *args], capture_output=True, text=True,
|
||||
env=_env(ws, **extra), cwd=str(ws), timeout=60)
|
||||
|
||||
|
||||
def test_prefix_forwards_only_what_cannot_be_derived(moved, monkeypatch, tmp_path):
|
||||
ws, reg, logs = moved
|
||||
monkeypatch.setenv("MAM_JOBS_DIR", str(reg))
|
||||
d = control_plane.describe(str(ws / "wt"))
|
||||
assert d["forward"] is True
|
||||
assert d["delegate_job_logs_dir"] == os.path.realpath(logs), "the row still records the sibling"
|
||||
p = control_plane.prefix(d)
|
||||
assert "WORKSPACE_ROOT=" in p and "AGENT_SESSIONS_YAML=" in p and f"MAM_JOBS_DIR={os.path.realpath(reg)} " in p, p
|
||||
assert "DELEGATE_JOB_LOGS_DIR=" not in p, p
|
||||
# an audit-log root that cannot be derived is still forwarded
|
||||
custom = tmp_path / "custom-logs"
|
||||
monkeypatch.setenv("DELEGATE_JOB_LOGS_DIR", str(custom))
|
||||
d2 = control_plane.describe(str(ws / "wt"))
|
||||
assert d2["delegate_job_logs_dir"] == os.path.realpath(custom)
|
||||
assert f"DELEGATE_JOB_LOGS_DIR={os.path.realpath(custom)} " in control_plane.prefix(d2)
|
||||
# the CLI lib.sh calls agrees on both
|
||||
monkeypatch.delenv("DELEGATE_JOB_LOGS_DIR")
|
||||
res = _cp_cli(ws, "json", str(ws / "wt"), MAM_JOBS_DIR=str(reg))
|
||||
assert res.returncode == 0, res.stderr
|
||||
cli = _cp_cli(ws, "prefix", res.stdout.strip(), MAM_JOBS_DIR=str(reg))
|
||||
assert cli.returncode == 0 and "MAM_JOBS_DIR=" in cli.stdout and "DELEGATE_JOB_LOGS_DIR=" not in cli.stdout, cli.stdout
|
||||
res = _cp_cli(ws, "json", str(ws / "wt"), MAM_JOBS_DIR=str(reg), DELEGATE_JOB_LOGS_DIR=str(custom))
|
||||
cli = _cp_cli(ws, "prefix", res.stdout.strip(), MAM_JOBS_DIR=str(reg), DELEGATE_JOB_LOGS_DIR=str(custom))
|
||||
assert f"DELEGATE_JOB_LOGS_DIR={os.path.realpath(custom)} " in cli.stdout, cli.stdout
|
||||
|
||||
|
||||
def test_create_binds_the_sibling_and_does_not_forward_it(mam_sandbox, mock_herdr, mock_agents, monkeypatch):
|
||||
tmp = mam_sandbox
|
||||
reg, sibling = tmp / "elsewhere" / "jobs", tmp / "elsewhere" / "delegate_job_logs"
|
||||
monkeypatch.setenv("MAM_JOBS_DIR", str(reg))
|
||||
monkeypatch.delenv("DELEGATE_JOB_LOGS_DIR", raising=False)
|
||||
wt = tmp / "wt"
|
||||
wt.mkdir()
|
||||
res = subprocess.run(["bash", _skill(tmp, "multi-agent-mux-create", "scripts", "create_session.sh"),
|
||||
"--workspace", str(wt), "--agent", "claude", "--role", "creator", "--onboard"],
|
||||
capture_output=True, text=True, cwd=str(tmp), timeout=180)
|
||||
assert res.returncode == 0, res.stdout + res.stderr
|
||||
(row,) = _rows(tmp)
|
||||
assert row["control_plane"]["mam_jobs_dir"] == os.path.realpath(reg)
|
||||
assert row["control_plane"]["delegate_job_logs_dir"] == os.path.realpath(sibling)
|
||||
flags = _env_flags(mock_herdr)
|
||||
assert any(f == f"MAM_JOBS_DIR={os.path.realpath(reg)}" for f in flags), flags
|
||||
assert not [f for f in flags if f.startswith("DELEGATE_JOB_LOGS_DIR=")], flags
|
||||
# the injected publish commands still pin the root per command
|
||||
texts = [t for t in _sent_texts(json.loads(Path(mock_herdr).read_text())) if "publish_event.py" in t]
|
||||
assert texts and f"DELEGATE_JOB_LOGS_DIR={os.path.realpath(sibling)} " in "".join(texts), texts
|
||||
jid = row["delegate_job_id"]
|
||||
assert (sibling / jid / "status.json").is_file()
|
||||
assert not (tmp / ".mam" / "delegate_job_logs").exists()
|
||||
|
||||
|
||||
def test_a_forwarded_pane_moves_its_logs_with_the_registry(tmp_path, monkeypatch):
|
||||
"""The issue's scene: a worktree creator pane after §2-B carries the control
|
||||
root's WORKSPACE_ROOT and MAM_JOBS_DIR but no DELEGATE_JOB_LOGS_DIR."""
|
||||
for k in DROP:
|
||||
monkeypatch.delenv(k, raising=False)
|
||||
main, wt, exp = tmp_path / "main", tmp_path / "wt", tmp_path / "exp" / "jobs"
|
||||
real_logs = main / ".mam" / "delegate_job_logs"
|
||||
real_logs.mkdir(parents=True)
|
||||
wt.mkdir()
|
||||
pane = dict(WORKSPACE_ROOT=str(main), MAM_JOBS_DIR=str(main / ".mam" / "jobs"))
|
||||
res = _wrapper(main, "submit", "--dry-run", "--agent", "human", "--registry-dir", str(exp),
|
||||
"--workdir", str(wt), "--prompt", "t", cwd=wt, **pane)
|
||||
assert res.returncode == 0, res.stdout[-800:] + res.stderr[-800:]
|
||||
jid = _only_job_id(exp)
|
||||
assert res.stdout.strip().splitlines()[-1] == str(Path(os.path.realpath(tmp_path / "exp")) / "delegate_job_logs" / jid)
|
||||
assert (tmp_path / "exp" / "delegate_job_logs" / jid / "meta.json").is_file()
|
||||
assert os.listdir(real_logs) == [], "the experiment leaked into the control root"
|
||||
# the usual run in that pane is unchanged: the default registry's sibling
|
||||
res = _wrapper(main, "submit", "--dry-run", "--agent", "human", "--workdir", str(wt), "--prompt", "t",
|
||||
cwd=wt, **pane)
|
||||
assert res.returncode == 0, res.stdout[-800:] + res.stderr[-800:]
|
||||
jid2 = _only_job_id(main / ".mam" / "jobs")
|
||||
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()
|
||||
Reference in new issue
Block a user