Files
multi-agent-mux/.agents/reports/reviewer-grok-01/report-42f6a97d.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

71 lines
8.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 42f6a97d — Issue #17 follow-up, inherited WORKSPACE_ROOT
Head `ac48cb78617af88584db529b5766acf02f4af73c` (tree `b043034eda891bd83b547dcb34d7422a6977b89d`) closes the two checkout `run_loop.sh` writers left at `8b47cc7`. The opt-in root is in place, the new nodes are in the isolation test, and both required pytest passes are green.
Snapshot `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261008T133858Z-9e7f5b/3` only. Base `6b00b6e06f55299cb60f156ccef09ede4bae5bdd` (control-plane main, still that commit, porcelain empty). Branch commits: `d198dd5`, `8b47cc7`, `ac48cb7`. Seventeen files, +221/−18, all under `tests/`. `git diff --check 6b00b6e..HEAD` is clean. `.agents/skills` and `VERSIONS.md` are outside the diff. No version bump.
Interpreter: worktree `.venv` Python 3.9.6, bash 3.2.57. `lib.sh:2050` uses `AGENT_PYTHON_BIN` when that path is executable. The suite set `AGENT_PYTHON_BIN` to the worktree interpreter and put its `bin` first on `PATH`.
## What ac48cb7 adds
`tests/test_o1_rebuttal.py:12` opts the module in with `pytestmark = pytest.mark.usefixtures("own_workspace_root")`. `test_v3_rebut_option_parsing_and_budget` (`:69-76`) still runs the checkout `run_loop.sh` twice (`--help`, and `--max-rebut abc`) with no `env` argument. The mark sets `WORKSPACE_ROOT` to `tmp_path/.mam-test-state/workspace` before the body, and a subprocess with no `env` inherits that value. `run_loop.sh:17` sources `lib.sh` before the option parser, so the shim is written under the test directory.
`tests/test_o2_race_free_lock.py:198` puts the same fixture on `test_o2_12_run_loop_exits_on_lock_failure` only. That test copies `os.environ` after the fixture's `setenv` (`:204-206`) and runs the checkout `run_loop.sh`. The other tests in the file source `loop_lock.sh`, which pulls in `lib_int.sh` and does not source `lib.sh`. `test_o2_14` (`:230`) is `bash -n`.
`tests/test_issue17_workspace_root_isolation.py:41-42` adds both node ids to W1:
- `tests/test_o2_race_free_lock.py::test_o2_12_run_loop_exits_on_lock_failure`
- `tests/test_o1_rebuttal.py::test_v3_rebut_option_parsing_and_budget`
The comment on the o2 mark says a module-wide mark would add an entry to `test_o2_7`'s `tmp_path`. `test_o2_7` (`:130`) asserts `list(tmp_path.glob("*")) == []`, and `Path.glob("*")` skips dot names, so `.mam-test-state` would not show up. The function-level mark is still the right scope: only `test_o2_12` executes `run_loop.sh`.
`d198dd5` and `8b47cc7` are unchanged by this commit. `tests/conftest.py:181-192` is the opt-in fixture (a temp workspace, not autouse). `tests/test_issue17_item4_decisions.py:224-233` drops an inherited `WORKSPACE_ROOT` and sets the helper's `tmp_path`. Unset would make `lib.sh:26` derive the checkout that contains the sourced script; `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 directory, so a value that names this checkout survives collection. A test that also requests `mam_sandbox` keeps the sandbox root, because that fixture runs later. The orc-onboard tests request `mam_sandbox` and passed in the suite below.
The module mark is on `test_o1_rebuttal.py`, `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 unfixed command writes the sentinel
Product `run_loop.sh` is unchanged, so the command `test_v3` used to run is the pre-fix case. With `WORKSPACE_ROOT=/tmp/42f6pre/sentinel` (the directory existed) and the inherited `HERDR_*` / `MAM_*` / `MQTT_*` / `SKS_*` bindings removed:
`bash <snapshot>/run_loop.sh --help` exited 1 (usage) and left `.mam`, `.mam/shim`, and `.mam/shim/herdr` under that sentinel. The snapshot's `.mam/shim/herdr` stayed absent. The snapshot copy of `run_loop.sh` is mode `644`; invoking it as the program raises `PermissionError`. The probe and the tests call it through `bash`.
W1 and W2, and `test_c_helpers_write_nothing_to_an_inherited_workspace`, passed inside both suites below. W1 is the check that still names the checkout: it sets `WORKSPACE_ROOT` to a copy of this tree, conftest keeps that value, and the copy must grow no `.mam`.
## Requirement 4 — suite
`AGENT_PYTHON_BIN` and `PATH` pointed at the worktree `.venv`. Inherited `HERDR_*`, `MAM_*`, `MQTT_*`, `SKS_*`, and `WORKSPACE_ROOT` were cleared in the parent. `PYTHONDONTWRITEBYTECODE=1`, `-p no:cacheprovider`. Basetemp directories are `/tmp/42f6A.n4k8Qw` and `/tmp/42f6B.p2m7Lx`. Neither path contains `mam-review`.
(a) `WORKSPACE_ROOT` unset. The 16 modified test modules plus `tests/test_issue33_budget.py`, `tests/test_issue5_phase1_delegation.py`, and `tests/test_tier1_unit.py`: **675 passed** in 836.91s, exit 0.
(b) `WORKSPACE_ROOT=/tmp/42f6sent.t8c3Vr` (the directory existed). The 16 modified modules: **522 passed** in 672.98s, exit 0. The sentinel was empty afterwards.
`pytest_configure` drops a `WORKSPACE_ROOT` whose real path is some other directory, so the outer sentinel staying empty shows that nothing wrote there before collection. The runs that keep a checkout-named root are W1 and the item-4 test, which monkeypatches a sentinel after configure. Both passed inside (a) and (b). The +32 tests against the previous head's 643 / 490 are the two modules this commit brought into the run.
After the pair: snapshot porcelain empty, snapshot `.mam/shim/herdr` absent, control-plane main still `6b00b6e` with empty porcelain, control-plane shim mtime `1791482611` size `45360` (same before and after), `~/.config/herdr/config.toml` mtime `1784456394`, directory mtime `1791382452`.
## 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. No remaining writer runs the checkout `lib.sh` / `run_loop.sh` / wrapper on an inherited checkout root.
| 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:403` | `test_t2_8` sets `WORKSPACE_ROOT` to `mam_sandbox`; `_mutate` sets the temp tree |
| `test_workspace_scope.py:32` | subprocess env sets the test workspace |
| `test_issue18_liveness_contract.py:58` | `_env` sets the helper cwd |
| `test_issue21_phase2_loop_a.py:58` | sources a copy with `WORKSPACE_ROOT` set to that root |
| `test_issue21_loop_b.py:236` | sets `WORKSPACE_ROOT` to `tmp_path` before `run_loop.sh` |
| `test_layout.py:318` | the script exports the test workspace, then sources `lib.sh` |
| `test_issue20_state_isolation.py:201` | sets `WORKSPACE_ROOT` to the temp repo the test is about |
| `test_issue19_subscriber_daemon_lifecycle.py:57` | sources the sandbox copy; callers use `mam_sandbox` |
| `test_issue34_job_tree.py:589` | sources the sandbox copy after `mam_sandbox` has set the root |
| `test_tier3_integration.py:286` | sources the sandbox copy inside a `mam_sandbox` test; `:337` is a debug string that also sets the temp root |
| `test_b7_diff_untracked.py:166` | sources `diff_collect.sh`, which sources `lib_int.sh` (`diff_collect.sh:14`) |
| `test_o2_race_free_lock.py:10` and `:231` | `loop_lock.sh` sources `lib_int.sh`; `bash -n` does not execute `run_loop.sh` |
| `test_issue5_phase2a_loop.py:754` | the `source` line is text inside an assertion |
| `test_deploy_freshness.py:473` | reads `run_loop.sh` as text |
`test_issue6_fail_closed.py:1247` sources the checkout `lib.sh` with the process environment. The module mark supplies the temp root, and that node is in W1. `test_issue21_acceptance.py` runs a `run_loop.sh` inside a temp git repo. `test_issue33_budget.py`, `test_issue36_prompt_transport.py`, `test_issue6_turn_handshake.py`, `test_issue14_delivery_ack.py`, `test_issue26_envfile.py`, `test_issue26_ints.py`, and `test_c1_tui_readiness.py` set a temp root in the helper env. `test_issue10_13_purge.py` and `test_issue9_server_env.py` / `test_issue45_restore.py` run through `mam_sandbox` or the rig, which has already set the root. `test_issue30_stall_watch.py` reaches the wrapper through `mam_sandbox` or `test_issue18._submit`.
[VERDICT: PASS]