Files
multi-agent-mux/.agents/reports/reviewer-grok-01/report-35f0c94f.md
T
GodopuandClaude Opus 5.5 e0181ea9be release(v4.8.8): Issue #17 follow-up - archive the review reports and bump the lockstep version
Merge-workspace review loop (--all-reviewer): round 1 (@d198dd5) claude
agy PASS, grok codex NOT PASS (the same inherited WORKSPACE_ROOT in eleven
more modules; test_orc_onboard's import-time env); fixed in 8b47cc7.
Round 2 claude grok NOT PASS (test_o2_race_free_lock, test_o1_rebuttal
missed), agy codex PASS; fixed in ac48cb7. Round 3 (@ac48cb7) 4/4 PASS.
Full suite at ac48cb7 on macOS / Python 3.9 / herdr 0.9.3 with
WORKSPACE_ROOT set to an empty sentinel: 1751 passed / 0 failed / 38
skipped; the sentinel stayed empty and the main checkout's shim was not
touched.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VCgu9Fa9iT7TbJUSzdq4Ff
2026-10-09 05:01:05 +09:00

87 lines
9.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Review 35f0c94f — Issue #17 follow-up, inherited WORKSPACE_ROOT
Head `8b47cc76eed4582b1848b2eec529523a61497320` (tree `bfe5fcbbefbde9562334515b4a9803bee96f84fd`) closes the writers named in the previous review and the new isolation tests pass. `tests/test_o1_rebuttal.py:68` still runs the checkout `run_loop.sh` with the process environment, and that script sources `lib.sh` before it parses `--help`, so an agent pane whose `WORKSPACE_ROOT` names this checkout still gets `.mam/shim/herdr` rewritten.
Snapshot `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261008T133858Z-9e7f5b/2` only. Base `6b00b6e06f55299cb60f156ccef09ede4bae5bdd` (control-plane main, unchanged). Branch commits: `d198dd5` then `8b47cc7`. Fifteen files, +212/−18, `git diff --check` clean. Product code under `.agents/skills` is unchanged. No version bump.
Interpreter: worktree `.venv` Python 3.9.6, bash 3.2.57. `lib.sh` picks that interpreter when `AGENT_PYTHON_BIN` is set (`lib.sh:2050`); otherwise it falls through to `/usr/bin/python3`, which has neither `paho` nor `yaml`.
## What the branch does
`tests/conftest.py:181-192` adds an opt-in fixture `own_workspace_root`. It creates `tmp_path/.mam-test-state/workspace` and sets `WORKSPACE_ROOT` there. It is not autouse, because in-process code also reads `WORKSPACE_ROOT`. Modules whose shells inherit the process environment opt in with `pytestmark = pytest.mark.usefixtures("own_workspace_root")`.
On this pytest, a test that requests both the mark and `mam_sandbox` finishes with `mam_sandbox`'s value. A one-test probe (usefixtures plus a `mam_sandbox` parameter) left `os.environ["WORKSPACE_ROOT"]` as the sandbox path. The orc-onboard tests, which use `mam_sandbox` and pass that directory into `_scrubbed_env`, passed in the suite below, so a test that names its own root still keeps it.
`tests/test_issue17_item4_decisions.py:224-233` drops an inherited `WORKSPACE_ROOT` and sets the helper's `tmp_path`. Unset is the wrong fix: `lib.sh:26` derives the checkout that contains the script, and `lib.sh:3088` calls `_init_herdr_isolation` (`lib.sh:143`), which rewrites `$WORKSPACE_ROOT/.mam/shim/herdr`. `pytest_configure` (`tests/conftest.py:144-146`) drops `WORKSPACE_ROOT` only when its real path is a different checkout, so a value that names this checkout survives collection. That is why the item-4 helpers missed the autouse state fixture: they never request `mam_sandbox`.
`tests/test_orc_onboard.py:19-30` still copies `os.environ` at import, and that copy now drops `WORKSPACE_ROOT`. Every source path rebuilds the env at call time from the current root (`_scrubbed_env`). `tests/test_issue21_worktree_prereqs.py:547` sets `WORKSPACE_ROOT` to the temp tree inside `_mutate`. `tests/test_workspace_scope.py:32` sets it to that test's workspace.
The same mark is on `test_b19_headless_reconcile_fixes.py`, `test_b8_send_keys_verification.py`, `test_issue6_fail_closed.py`, `test_version_consistency.py`, `test_loop_cli.py`, `test_issue5_phase3_loop.py`, `test_issue5_phase4_runtime.py`, `test_o3_scoped_guard.py`, `test_issue25_plan_reuse.py`, and `test_orc_onboard.py`.
## Requirement 3 — the new tests fail on the pre-fix code
`tests/test_issue17_workspace_root_isolation.py` adds W1 and W2. W1 copies the checkout, runs one node from each previously inheriting module with `WORKSPACE_ROOT` naming that copy (conftest keeps a root that names the checkout), and requires the copy to have no `.mam`. W2 imports `test_orc_onboard` while `WORKSPACE_ROOT` is a sentinel, then points the process env at a later directory and calls `run_find_uuid`.
Pre-fix probe, snapshot `lib.sh`, outside the tree:
- Base `tests/test_orc_onboard.py` from `6b00b6e`, loaded from a temp tree whose `.agents` is the snapshot's, imported with `WORKSPACE_ROOT` set to a sentinel, then `os.environ` pointed at another directory and `run_find_uuid` called: the sentinel received `.mam`, `.mam/shim`, `.mam/shim/herdr`. The later directory received nothing. Return code 0.
- The same probe against the head module: the sentinel stayed empty, and the later directory received `.mam/shim/herdr`. Return code 0.
`bash run_loop.sh --help` with `WORKSPACE_ROOT` set to `/tmp/35f0o1sent.q8w2` also wrote `.mam/shim/herdr` there (usage exits 1). Source is `run_loop.sh:17`, before the option parser. The snapshot shim was absent before and after that probe.
W1 and W2 are in the passing suite below. The item-4 sentinel test `test_c_helpers_write_nothing_to_an_inherited_workspace` is in the same file as the `_env` fix and passed with it.
## Requirement 4 — suite
`AGENT_PYTHON_BIN` and `PATH` pointed at the worktree `.venv`. Inherited `HERDR_*`, `MAM_*`, `MQTT_*`, `SKS_*`, and `WORKSPACE_ROOT` were unset in the parent. `PYTHONDONTWRITEBYTECODE=1`, `-p no:cacheprovider`. Basetemp directories are under `/tmp` and do not contain `mam-review`.
(a) `WORKSPACE_ROOT` unset, basetemp `/tmp/35f0C.m2k8Qn`, the 14 modified test modules plus `tests/test_issue33_budget.py`, `tests/test_issue5_phase1_delegation.py`, and `tests/test_tier1_unit.py`: **643 passed** in 837.78s, exit 0.
(b) `WORKSPACE_ROOT=/tmp/35f0sent2.w9c3Tb` (the directory existed), basetemp `/tmp/35f0D.h6p4Js`, the 14 modified modules: **490 passed** in 672.56s, exit 0. The sentinel was empty afterwards.
`pytest_configure` removes a foreign `WORKSPACE_ROOT` before collection, so an outer sentinel stays empty even if a helper is wrong. The runs that keep a checkout-named root are W1 (it sets `WORKSPACE_ROOT` to the copied checkout) and the item-4 test (it monkeypatches a sentinel after configure). Both passed inside (a) and (b).
A first pair of runs without `AGENT_PYTHON_BIN` reported 22 failed / 621 passed and 22 failed / 468 passed. Those failures are `/usr/bin/python3` missing `paho` and `yaml` (`mqtt_common.py` and `atomic_yaml.py` via `_delegate_py_bin`). The same nodes pass once `AGENT_PYTHON_BIN` is the worktree interpreter, which is the command the brief specifies. They are not a defect of `8b47cc7`.
After both pairs: snapshot porcelain empty, snapshot `.mam/shim/herdr` absent, control-plane main still `6b00b6e` with empty porcelain, control-plane shim mtime `1791475620`, `~/.config/herdr/config.toml` mtime `1784456394`, directory mtime `1791382452`.
## The writer this head leaves in place
`tests/test_o1_rebuttal.py:68` and `:72` (`test_v3_rebut_option_parsing_and_budget`) run `bash` on the checkout `run_loop.sh` (`--help`, and `--max-rebut abc`) with no `env`. The module has no `own_workspace_root` mark. `run_loop.sh:17` sources `lib.sh` before option parsing, and `lib.sh:3088` rewrites `$WORKSPACE_ROOT/.mam/shim/herdr`. With the variable unset, `lib.sh:26` derives this checkout. W1's node list does not name this test, so the new regression does not catch it.
Add `pytestmark = pytest.mark.usefixtures("own_workspace_root")` to `tests/test_o1_rebuttal.py`, the same opt-in `test_loop_cli.py` uses, and add `tests/test_o1_rebuttal.py::test_v3_rebut_option_parsing_and_budget` to `NODES` in `tests/test_issue17_workspace_root_isolation.py`. Passing `WORKSPACE_ROOT` set to a temp directory on those two `subprocess.run` calls is the same fix at the call site.
## Survey — same pattern, already pinned
These execute `lib.sh`, `run_loop.sh`, or a skill script that sources `lib.sh`, and they already give that shell a temp root or they do not execute the source. They stay as they are.
| Location | Why the checkout shim is not the target |
| --- | --- |
| `test_issue17_item4_decisions.py:224` | `_env` sets `WORKSPACE_ROOT` to the helper tmp |
| `test_issue21_worktree_prereqs.py:547` | `_mutate` sets the temp tree; `test_t2_8` sets `mam_sandbox` |
| `test_workspace_scope.py:32` | subprocess env sets the test workspace |
| `test_issue33_budget.py:47` | helper home |
| `test_issue18_liveness_contract.py:58` | helper cwd; `_submit` uses that env |
| `test_issue36_prompt_transport.py:61` and `:537` | helper home, and the shell loop sets `ctl` |
| `test_issue21_phase2_loop_a.py:49` | temp root |
| `test_issue21_loop_b.py:236` | `tmp_path` |
| `test_issue6_turn_handshake.py:29` | cwd |
| `test_issue14_delivery_ack.py:36` | cwd |
| `test_issue26_envfile.py:76`, `test_issue26_ints.py:124` | helper home |
| `test_c1_tui_readiness.py:19` | temp directory |
| `test_layout.py:318` | the script exports the test workspace |
| `test_issue19_subscriber_daemon_lifecycle.py:138` | the only `_run_helper` caller uses `mam_sandbox` |
| `test_issue34_job_tree.py:590` | copies the process env after `mam_sandbox` has set the root |
| `test_issue10_13_purge.py:149` | `_run_onboard` callers request `mam_sandbox`, so the copied env already names the sandbox |
| `test_issue20_state_isolation.py:201` | sets `WORKSPACE_ROOT` to the temp repo the test is about |
| `test_issue9_server_env.py`, `test_issue45_restore.py` | callers use `mam_sandbox` / `rig`, which has already set the root |
| `test_issue30_stall_watch.py:124` | `_env` itself does not assign the root; wrapper calls go through `mam_sandbox` or `test_issue18._submit` |
| `test_o2_race_free_lock.py:229` | `bash -n` does not execute `run_loop.sh` |
| `test_issue5_phase2a_loop.py:754` | the `source` line is text inside an assertion |
| `test_tier3_integration.py:337` | the `source` is a debug string, and that env sets the temp root |
| `test_deploy_freshness.py:473` | reads `run_loop.sh` as text |
Marked modules listed above are covered by `own_workspace_root`. `test_issue21_acceptance.py` runs a `run_loop.sh` inside a temp git repo from its `ctl` fixture.
[VERDICT: NOT PASS]