# Review 5e7e2324 — PR #58, Issue #57 follow-up Reviewed only the snapshot `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261014T152849Z-f1a415/1` (`loop-20261014T152849Z-f1a415`). Head `63d816468e6d48d01bd96f31d8a25eeadfbaab60`, tree `e8f162f74b7ce8ee8cc6ba7954b7d28dfa3f89f6`, base `e32c9574644a9185813a4dc881812694d62b6204` is an ancestor. Eleven commits, 21 files, +659/−95. `git diff --check` is clean. Snapshot porcelain is empty and the snapshot has no `.mam`. Control-plane main is still `e32c9574644a9185813a4dc881812694d62b6204`, porcelain empty. No product file was edited. The source worktree was not used. Host tools: `/usr/bin/python3` 3.9.6, the control-plane venv is also 3.9.6, and `/bin/bash` is 3.2.57. The changed Python modules parse with `ast` on 3.9.6. `bash -n` accepts `lib.sh`, the delegate-job wrapper, `worktree_prepare.sh`, `status.sh`, `reconcile.sh`, and `stop_session.sh`. Added lines do not use `match`, `tomllib`, or `X | Y` unions. ## The previous holes are closed The rule is `mqtt_common.get_logs_dir(registry_dir)` (`mqtt_common.py:192-208`). A non-blank `DELEGATE_JOB_LOGS_DIR` is returned unchanged. Otherwise the audit root is `sibling_logs_dir` (`mqtt_common.py:186-189`): `delegate_job_logs` next to `os.path.abspath` of the registry, or of `default_registry_dir()` when the caller does not pass one. Writers and readers that know a registry pass it: `engine._flush`, `registry.py` register/pick/logs, `publish_event.record_outcome`, `remote.publish_dispatch`, the legacy status mirror (`mqtt_common.py:528`), `reconcile.sh`, and every `job_subscriber` append including the reconnect line. `runner._fingerprint` (`runner.py:1087`) excludes that same root. `Path` treats the absolute result as absolute, so `workspace_root / logs` stays the logs directory. `control_plane.from_env` (`control_plane.py:54-57`) records `_abs(sibling_logs_dir(mam_jobs_dir))` when `DELEGATE_JOB_LOGS_DIR` is blank. `forwarded_keys` (`control_plane.py:77-84`) drops `delegate_job_logs_dir` when that stored path equals the same expression, and `prefix` emits only those keys. An explicit non-sibling root stays in the prefix. With no overrides, `from_env` still equals `defaults`, so the usual binding is not forwarded. `worktree_prepare.sh:239-240` appends `DELEGATE_JOB_LOGS_DIR` only when the caller already set it. `stop_session.sh:154-158` still exports the row's `delegate_job_logs_dir` when the environment variable is unset. A row written by the new `from_env` stores the sibling, so that export points at the sibling. Both `get_job_status` copies in `status.sh` (`:168-173` and `:380-385`) search the explicit logs dir and the row's logs dir, then `sibling_logs_dir` of `MAM_JOBS_DIR` and of the row's `mam_jobs_dir`. The script was not executed against a real checkout. The sandbox test below runs it. `job_subscriber._check_disk_fallback` (`job_subscriber.py:96-121`) reads `status` from the audit dict. A versioned registry record adopts that status only when `transition_seq` is present and `int(aud_seq) >= int(rec_seq)`. A missing or non-numeric audit sequence is treated as stale for a versioned record. An unversioned record, and a missing record, keep the old rule. A registry status that is already terminal is left as it is. Token and attempt checks still run after that. The wrapper removes the sixteen `$WORKDIR/delegate_job_logs` defaults. `LOGS_DIR_ABS` is set to `""` before `cmd_submit` (`multi-agent-mux-delegate-job:203`). After `cd` and `cd -P` of the registry, `cmd_submit` assigns `LOGS_DIR_ABS="$(_logs_dir_abs)"` and exits 1 if that command fails (`:281`), then exports it (`:284`). Later prints in that command use `$LOGS_DIR_ABS`. `cmd_logs` (`:1090-1109`) parses `--registry-dir` itself and passes it to `registry.py`. It does not read `LOGS_DIR_ABS`. `delegate_logs_dir` in `lib.sh:2375` is the same one-liner. On failure, `delegate_started_recorded` skips only the audit file and still reads the registry `events.log` (`lib.sh:2386-2389`). `delegate_wait_started` resolves the root once (`lib.sh:2446`). ## This Mac `/tmp` is a symlink to `/private/tmp`. A probe under `/tmp` (deleted afterward; no herdr, no real `.mam`) called `from_env` and `forwarded_keys` with the jobs directory given as the `/tmp` path and again with the `/var` form of a `/private/var` path: - The stored logs path equals `_abs(sibling_logs_dir(mam_jobs_dir))`, and `delegate_job_logs_dir` is absent from `forwarded_keys`. - `get_logs_dir` of the realpathed jobs directory equals that stored path as a string. - `from_env` of a workspace under `/tmp`, with cwd `/` and no `MAM_JOBS_DIR`, equals `defaults`. `get_logs_dir()` is the same directory as that binding. - A relative `MAM_JOBS_DIR` is stored absolute. After `chdir("/")` the derivable root is still not forwarded. - An explicit custom logs directory is forwarded. - A jobs directory that is itself a symlink to another parent is recorded next to the target, and that binding is not forwarded. `sibling_logs_dir` of the symlink path is a different directory, because it uses `abspath` and does not resolve the link. The wrapper physicalizes the registry with `cd -P` before it resolves logs, and the pane receives the realpathed `MAM_JOBS_DIR`, so those two writers agree. A direct `get_logs_dir` of the symlink path follows the path as given. `logs --registry-dir` with no value, under `set -euo pipefail`, exits 1 with an unbound `$2`. The same shift pattern is how `parse_opts` reads every flag. The process exits before it writes. A failing command substitution assigned with `||` is caught on this bash. ## Tests Pytest used the control-plane venv (Python 3.9.6), `PYTHONDONTWRITEBYTECODE=1`, `-p no:cacheprovider`, and `--basetemp` `/tmp/mam57-5e7e2324-pytest`. Inherited `HERDR_*`, `MAM_*`, `MQTT_*`, `SKS_*`, `WORKSPACE_ROOT`, `DELEGATE_JOB_LOGS_DIR`, `PYTHONPATH`, `HOME_DIR`, `CLAUDE_PROJECT_DIR`, and `CODEX_HOME` were dropped. `AGENT_PYTHON_BIN` and `DELEGATE_JOB_PYTHON` pointed at that venv. On the snapshot, 23 tests passed in 122.75s: `tests/test_issue57_logs_follow_registry.py` (resolver, registry CLI, wrapper dry-run and unreachable broker, publish, binding, explicit override, worktree prepare, status json and text, conflict and legacy claim, redispatched-attempt audit, prefix, create, and the pane that moves logs with `--registry-dir`), plus `test_logs_dir_follows_the_same_order`, `test_t3_0_control_plane_module`, `test_t3_1_create_persists_and_forwards_a_foreign_binding`, `test_t3_2_default_binding_is_recorded_not_forwarded`, `test_t3_3_4_stop_keeps_the_binding_and_resume_reforwards_it`, `test_a2_pane_env_carries_the_binding_not_the_agent_args`, and `test_b9_logs_dir_follows_cwd_changes`. The same four new tests copied onto an archive of base `e32c957` failed in 0.16s: `get_logs_dir()` rejected the registry argument, `from_env` kept the workspace logs directory, the disk fallback did not adopt an audit-only terminal status, and the prefix test did not see the sibling on the row. The archive and both basetemps were removed. Snapshot porcelain stayed empty. The full suite was left to the orchestrator. `tests/test_issue10_13_purge.py` was not run. ## Documentation left as written `SKILL.md:139-141` and `registry.md:152-154` state the sibling rule. `SKILL.md:175` (Audit Logs) still names only `.mam/delegate_job_logs//`, which is the directory the rule produces when the registry is `.mam/jobs`. `docs/design/worktree-creator-model.md:126` lists the status candidates and does not mention the sibling lookup that `status.sh` now performs. `README.md` is outside this diff and still names the workspace directory. Those sentences do not change where the code writes. The pane herdr config file is newer than the mtime recorded at the end of the previous review. This review did not start herdr and did not write that file. `~/.config/herdr/config.toml` is unchanged. That mtime is not part of the verdict. [VERDICT: PASS]