# Review d384cdc0 — Issue #60, third pass Reviewed only the snapshot `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261018T073639Z-b5cb7f/1` (`loop-20261018T073639Z-b5cb7f`). Head `0e05b1b6777ceb837066454ac688e04a0f5d14a0`, tree `c5cb1b16af283b3fdb447bafb865ba1abbfbb5a8`, base `74333f87d0c02888c2b5b281e912d97e74348c01` is an ancestor. Five commits, 15 files, +705/−330. `git diff --check` is clean. Snapshot porcelain is empty and the snapshot has no `.mam`. Control-plane main is `74333f87d0c02888c2b5b281e912d97e74348c01`, porcelain empty. No product file was edited. The new commit on top of `cb5f439` is `0e05b1b`. It changes three files: `tests/_agent_home_guard.py`, `.agents/skills/multi-agent-mux-status/scripts/status.sh` (both copies of `resume_on_disk`), and the `--version` probe in `tests/test_issue60_opencode_v2.py`. Host tools: the control-plane venv is Python 3.9.6, `/bin/bash` is 3.2.57. `bash -n` accepts `status.sh` and `create_session.sh`. `opencode --version` in a temporary home, with an environment of only `PATH`, `HOME`, and `TMPDIR`, printed `opencode v2.0.32`. The user's background service stayed up. Its pid is 86524, the command is `opencode serve --service`, and both service-file mtimes stayed 1792246838. The real database mtime stayed 1792247140, with 4 `session` rows and 4 `session_v2` rows. The real `opencode.log` mtime stayed 1792308195 and its size stayed the same. The herdr config mtime stayed 1784456394. ## What 0e05b1b fixes `_agent_home_guard.DROPPED_VARS` now includes `XDG_DATA_HOME` (`_agent_home_guard.py:21`). `conftest._isolate_agent_homes` drops that tuple for every test, and `pytest_configure` records the value first so the session guard can watch it. `watch_dirs` uses `/opencode` when the recorded environment has the variable, and `/.local/share/opencode` otherwise (`_agent_home_guard.py:48-49`). That matches the second-pass failure. The adapter follows the caller's `XDG_DATA_HOME` when `ctx.home_dir` is the caller's own home. A sandbox that only changed `HOME` still inherited the runner's `XDG_DATA_HOME`, so discovery and purge resolved the runner's data directory. Dropping the variable makes `HOME` govern, which is what `_data_home` does when the variable is unset. `test_l1_every_path_variable_the_code_reads_is_accounted_for` scans adapters for `*_HOME` reads. `XDG_DATA_HOME` is one of them (`opencode.py` `os.environ.get("XDG_DATA_HOME")`). A clone whose `DROPPED_VARS` omitted it failed that test in 0.04 s with `['XDG_DATA_HOME']`. The suite below was started with `XDG_DATA_HOME` pointed at an empty directory `/tmp/mamd384-d384cdc0-xdg`. After 65 passed tests that directory was still empty. `status.sh` `resume_on_disk`, in the `--json` block and in the text block, asks `get_adapter('opencode')._resolve_db(DiscoveryContext(..., home_dir=home))` (`status.sh:108-111` and `:305-308` in the second copy). `home` is `HOME_DIR`. `env_python` passes the parent environment through, so a set `XDG_DATA_HOME` reaches `_data_home` when `HOME_DIR` is the caller's home. A copy of the tree, with the fake opencode on `PATH` and the only database under a separate `XDG_DATA_HOME`, returned exit 0. `--json` `resume_state` was `yes` for `ses_probe` and `MISSING` for an id the database does not hold. Text mode exited 0 and the session's line contained `yes`. `~/.local/share/opencode/opencode.db` under that sandbox home was not created. The existing status checks in the same suite (`test_status_json_schema_fields`, `test_status_text_headers_presence`, and the claude and agy `resume_on_disk` helpers) also exited 0. `_real_opencode` runs `--version` inside `tempfile.TemporaryDirectory` with `HOME` and `TMPDIR` set to that directory and no `XDG_*` variables (`test_issue60_opencode_v2.py:298-300`). The same shape, run on its own, wrote a log only under that temporary home. The real log was unchanged. The opt-in contract ran as part of the 65 (no skip). ## Suite Pytest used the control-plane venv, `PYTHONDONTWRITEBYTECODE=1`, `-p no:cacheprovider`, and `--basetemp` `/tmp/mamd384-d384cdc0-pybase`. Inherited `HERDR_*`, `MAM_*`, `MQTT_*`, `SKS_*`, `WORKSPACE_ROOT`, `DELEGATE_JOB_LOGS_DIR`, `HOME_DIR`, `CLAUDE_*`, `CODEX_HOME`, and `PYTHONPATH` were dropped. `XDG_DATA_HOME` was the empty sentinel above. `XDG_STATE_HOME`, `XDG_CONFIG_HOME`, and `XDG_CACHE_HOME` were unset. 65 passed in 68.75 s: `tests/test_issue55_agent_homes.py`, `tests/test_issue60_opencode_v2.py` (including the real-binary contract), `tests/test_a4_adapter_contract.py`, `tests/test_issue31_purge_residual.py::test_opencode_purge_leaves_no_rows`, `tests/test_tier2_component.py::test_comp_opencode_create_and_reconcile_and_stop`, and the four status cases named above. No skip and no error. Snapshot porcelain stayed empty. `opencode debug paths` in a temporary home prints the `db` line under that home's `.local/share/opencode` and creates `log/opencode.log` there. It does not create `opencode.db`. So an opencode row in `status.sh` now runs that command, and a real status check appends the log under the data directory `_resolve_db` is about to open. The RESUME value and the exit code measured above stay 0 / `yes` / `MISSING`. The database file is untouched by the path lookup. The earlier commits are unchanged in this pass: purge still collects descendants before `session delete` and deletes the 1.x rows of parent and children, `conversation_in_use` still ignores only a `serve --service` holder, drift C still requires `parent_id IS NULL`, and spawn/resume stay `--auto --standalone`. The tier-2 test in this suite pins the parent when a newer child shares the directory, against the mock herdr. This review did not drive a live herdr pane through create, a first TUI message, stop, and resume. The new code uses the environment, sqlite, and `subprocess`. Nothing added in `0e05b1b` is macOS-only. This host is macOS, so Linux was not executed here. After the report, snapshot porcelain is still empty, the snapshot still has no `.mam`, and control-plane porcelain is still empty at `74333f87`. The herdr config mtime is still 1784456394. The opencode database mtime is still 1792247140, the opencode log mtime is still 1792308195, and service pid 86524 is still `opencode serve --service`. [VERDICT: PASS]