fix(issue-57): the audit log follows the registry; the disk fallback reads the audit status #58
No files matched your search
@@ -79,7 +79,8 @@ def forwarded_keys(desc: dict) -> list:
|
||||
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(sibling_logs_dir(desc["mam_jobs_dir"])):
|
||||
logs = desc.get("delegate_job_logs_dir")
|
||||
if logs and _abs(logs) == _abs(sibling_logs_dir(desc["mam_jobs_dir"])):
|
||||
keys.remove("delegate_job_logs_dir")
|
||||
return keys
|
||||
|
||||
|
||||
@@ -39,9 +39,16 @@ def default_registry_dir() -> str:
|
||||
|
||||
|
||||
def sibling_logs_dir(registry_dir: str) -> str:
|
||||
"""The audit-log root that pairs with ``registry_dir``: its sibling
|
||||
``delegate_job_logs``. Pure; reads no environment. Issue #57."""
|
||||
return os.path.join(os.path.dirname(os.path.abspath(registry_dir)), "delegate_job_logs")
|
||||
"""The audit-log root that pairs with ``registry_dir``: the
|
||||
``delegate_job_logs`` next to it. Pure; reads no environment. Issue #57.
|
||||
|
||||
The registry is taken by its real path: a registry directory that is itself
|
||||
a symlink pairs with the audit log next to its target, which is what the
|
||||
wrapper (``pwd -P``) and the control-plane binding (``realpath``) already
|
||||
see, so submit and logs agree (Mac review R2). A relative registry resolves
|
||||
against the cwd, as registry.py opens it.
|
||||
"""
|
||||
return os.path.join(os.path.dirname(os.path.realpath(registry_dir)), "delegate_job_logs")
|
||||
|
||||
|
||||
def get_logs_dir(registry_dir: Optional[str] = None) -> str:
|
||||
|
||||
@@ -126,7 +126,7 @@ bash "$MAIN/.agents/skills/multi-agent-mux-stop/scripts/worktree_remove.sh" --pa
|
||||
| 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 로 대화 키 | — |
|
||||
| status | `MAM_JOBS_DIR`·행 `mam_jobs_dir`·감사 로그(`DELEGATE_JOB_LOGS_DIR`·행 `delegate_job_logs_dir`)·레지스트리 옆 감사 로그(`MAM_JOBS_DIR`·행 `mam_jobs_dir` 의 형제 `delegate_job_logs`, #57)·기존 후보 순 조회 | 행 cwd 로 대화 키 | — |
|
||||
| monitor/reconcile | `MAM_JOBS_DIR` 우선(정적 가드로만 검증) | 기존 행은 행 cwd 로 검증 | 루트 밖 cwd 의 미등록 세션은 자동 등록 안 됨 → create/prepare 로만 등록 (남은 제한) |
|
||||
| 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`)는 새 옵션 거부 |
|
||||
|
||||
@@ -599,3 +599,35 @@ def test_disk_fallback_rejects_a_terminal_that_belongs_to_a_later_dispatch(moved
|
||||
pending, terminal = {jid}, {}
|
||||
job_subscriber._check_disk_fallback(pending, str(reg), terminal, {jid: tok_a}, {jid: 1})
|
||||
assert pending == {jid} and terminal == {}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Mac review R2: a registry directory that is itself a symlink has one audit log
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_a_symlinked_registry_dir_resolves_to_one_audit_log(tmp_path, monkeypatch):
|
||||
"""submit resolves --registry-dir with pwd -P, so its audit log lands next
|
||||
to the link's target; the resolver must pair the same place for logs."""
|
||||
from lib_py.delegation import logroot
|
||||
for k in DROP:
|
||||
monkeypatch.delenv(k, raising=False)
|
||||
ws = tmp_path / "ws"
|
||||
(ws / ".mam").mkdir(parents=True)
|
||||
monkeypatch.setenv("WORKSPACE_ROOT", str(ws))
|
||||
actual = tmp_path / "actual" / "jobs"
|
||||
actual.mkdir(parents=True)
|
||||
alias = tmp_path / "alias"
|
||||
alias.mkdir()
|
||||
(alias / "jobs").symlink_to(actual)
|
||||
real_actual = Path(os.path.realpath(tmp_path / "actual"))
|
||||
assert logroot.sibling_logs_dir(str(alias / "jobs")) == str(real_actual / "delegate_job_logs")
|
||||
res = _wrapper(ws, "submit", "--dry-run", "--agent", "human", "--registry-dir", str(alias / "jobs"),
|
||||
"--workdir", str(ws), "--prompt", "t")
|
||||
assert res.returncode == 0, res.stdout[-800:] + res.stderr[-800:]
|
||||
jid = _only_job_id(actual)
|
||||
assert res.stdout.strip().splitlines()[-1] == str(real_actual / "delegate_job_logs" / jid)
|
||||
assert (real_actual / "delegate_job_logs" / jid / "meta.json").is_file()
|
||||
assert not (tmp_path / "alias" / "delegate_job_logs").exists()
|
||||
res = _wrapper(ws, "logs", "--registry-dir", str(alias / "jobs"), jid)
|
||||
assert res.returncode == 0 and "registered" in res.stdout, res.stdout + res.stderr
|
||||
assert not (ws / ".mam" / "delegate_job_logs").exists()
|
||||
Reference in new issue
Block a user