Refs #17 (follow-up to the v4.8.7 review; #17 stays open)
v4.8.8 (PATCH, tests only — no change under .agents/skills except the version lines). lib.sh rewrites $WORKSPACE_ROOT/.mam/shim/herdr every time it is sourced. Tests that inherit the shell environment therefore rewrote the shim of whatever workspace that variable named: the agent pane's own workspace, or, during the PR #51 review, another workspace.
Changes
tests/test_issue17_item4_decisions.py: _env sets WORKSPACE_ROOT to the test's tmp dir. Only dropping it would make lib.sh fall back to the checkout itself.
tests/conftest.py: an opt-in fixture own_workspace_root (<tmp_path>/.mam-test-state/workspace). It is not autouse, because some code reads the variable in-process and some tests unset it on purpose.
The same defect, fixed in 12 more modules: version_consistency, b19, b8, issue6_fail_closed, loop_cli, issue5_phase3, issue5_phase4, o3_scoped_guard, issue25_plan_reuse, orc_onboard (import-time env), o1_rebuttal, o2_race_free_lock. test_workspace_scope and test_issue21_worktree_prereqs._mutate now pin the root they already create.
Verification
New tests/test_issue17_workspace_root_isolation.py, plus a sentinel test in the item-4 file. All of them fail on the pre-fix commits, which create .mam/shim/herdr in the sentinel or the checkout copy.
Review loop in the merge workspace, all four reviewers: round 1 grok/codex NOT PASS (11 more modules). Round 2 claude/grok NOT PASS (2 modules missed). Round 3 (@ac48cb7) 4/4 PASS.
Full suite at ac48cb7 (macOS, Python 3.9, herdr 0.9.3), run with WORKSPACE_ROOT pointing at an empty sentinel: 1751 passed / 0 failed / 38 skipped. The sentinel stayed empty, and the main checkout's shim was not modified.
Follow-ups
The codex adapter's resume command lacks --no-daemon. Through the shared daemon, the resume fails, and a daemon restart silently drops the sandbox bypass. That restart is what blocked codex's MQTT publishes during this loop.
An empty, ignored .mam/ directory appeared in the review worktree after the sentinel run. It holds no shim, and the test that creates it was not identified.
Refs #17 (follow-up to the v4.8.7 review; #17 stays open)
v4.8.8 (PATCH, tests only — no change under `.agents/skills` except the version lines). `lib.sh` rewrites `$WORKSPACE_ROOT/.mam/shim/herdr` every time it is sourced. Tests that inherit the shell environment therefore rewrote the shim of whatever workspace that variable named: the agent pane's own workspace, or, during the PR #51 review, another workspace.
## Changes
- `tests/test_issue17_item4_decisions.py`: `_env` sets `WORKSPACE_ROOT` to the test's tmp dir. Only dropping it would make lib.sh fall back to the checkout itself.
- `tests/conftest.py`: an opt-in fixture `own_workspace_root` (`<tmp_path>/.mam-test-state/workspace`). It is not autouse, because some code reads the variable in-process and some tests unset it on purpose.
- The same defect, fixed in 12 more modules: version_consistency, b19, b8, issue6_fail_closed, loop_cli, issue5_phase3, issue5_phase4, o3_scoped_guard, issue25_plan_reuse, orc_onboard (import-time env), o1_rebuttal, o2_race_free_lock. `test_workspace_scope` and `test_issue21_worktree_prereqs._mutate` now pin the root they already create.
## Verification
- New `tests/test_issue17_workspace_root_isolation.py`, plus a sentinel test in the item-4 file. All of them fail on the pre-fix commits, which create `.mam/shim/herdr` in the sentinel or the checkout copy.
- Review loop in the merge workspace, all four reviewers: round 1 grok/codex NOT PASS (11 more modules). Round 2 claude/grok NOT PASS (2 modules missed). Round 3 (@ac48cb7) **4/4 PASS**.
- Full suite at ac48cb7 (macOS, Python 3.9, herdr 0.9.3), run with `WORKSPACE_ROOT` pointing at an empty sentinel: **1751 passed / 0 failed / 38 skipped**. The sentinel stayed empty, and the main checkout's shim was not modified.
## Follow-ups
- The codex adapter's resume command lacks `--no-daemon`. Through the shared daemon, the resume fails, and a daemon restart silently drops the sandbox bypass. That restart is what blocked codex's MQTT publishes during this loop.
- An empty, ignored `.mam/` directory appeared in the review worktree after the sentinel run. It holds no shim, and the test that creates it was not identified.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01VCgu9Fa9iT7TbJUSzdq4Ff
_env kept an inherited WORKSPACE_ROOT, so every helper that sources the
wrapper (lib.sh's _init_herdr_isolation) rewrote <that workspace>/.mam/shim/
herdr - another workspace's during the PR #51 review (v4.8.7 review, claude).
Only dropping it is not enough: lib.sh then derives the checkout itself, and
conftest keeps a WORKSPACE_ROOT that names this checkout, so the run would
rewrite the checkout's own shim (the real one when this is the main
checkout). _env now sets WORKSPACE_ROOT to the test's tmp dir.
Test: with a sentinel WORKSPACE_ROOT in the environment, _run_both and a
direct _env run leave the sentinel empty and the checkout's shim untouched,
and the shell sees the tmp dir. With the old _env the sentinel gets
.mam/shim/herdr.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HCGpJXhSZasJLU38ksDghe
d198dd5 fixed one helper; the same defect was in eleven more modules
(reviews grok and codex R1/R2): their shells inherited the process
environment, so each `source lib.sh` rewrote <WORKSPACE_ROOT>/.mam/shim/herdr
- the checkout's own when the variable is unset or names this checkout (which
pytest_configure keeps), another workspace's under --noconftest.
- conftest: own_workspace_root, an opt-in fixture setting WORKSPACE_ROOT to
<tmp_path>/.mam-test-state/workspace. Not autouse: runner.py and
mqtt_common read WORKSPACE_ROOT in-process, and some tests unset it on
purpose. mam_sandbox and explicit envs run later and still win.
- pytestmark usefixtures("own_workspace_root") in test_version_consistency,
test_b19_headless_reconcile_fixes, test_b8_send_keys_verification,
test_issue6_fail_closed, test_loop_cli, test_issue5_phase3_loop,
test_issue5_phase4_runtime, test_o3_scoped_guard, test_issue25_plan_reuse,
test_orc_onboard (their shells inherit os.environ, many with no env at all).
- test_orc_onboard (R2): SCRUBBED_ENV is taken at import and no longer
carries WORKSPACE_ROOT; every call builds _scrubbed_env(root) with the root
of the call (ws / cwd / mam_sandbox, else this test's).
- test_workspace_scope (unittest) and test_issue21_worktree_prereqs._mutate
pin the root they already create.
Tests (test_issue17_workspace_root_isolation.py): W1 copies the checkout and
runs one test of each of those modules there with WORKSPACE_ROOT naming the
copy - the copy gets no .mam; W2 imports test_orc_onboard under a sentinel
root, then calls it under another - the sentinel stays empty. At d198dd5 both
fail (the copy gets .mam/shim/herdr; the sentinel gets it).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HCGpJXhSZasJLU38ksDghe
Two modules still ran the checkout's run_loop.sh - which sources lib.sh
before it parses an option - with the process environment and no root of
their own: test_o2_race_free_lock's test_o2_12 (review claude; it was in the
sweep's list and missed in 8b47cc7) and test_o1_rebuttal's
test_v3_rebut_option_parsing_and_budget, whose calls pass no env (review
grok; outside the env-copy grep). Both now use own_workspace_root, and W1
runs one node of each: at 8b47cc7 W1 fails with the copy's .mam/shim/herdr.
A last pass over the test files that run lib.sh, run_loop.sh, the wrapper or a
skill script: every one is marked, uses mam_sandbox or pins WORKSPACE_ROOT,
or does not source lib.sh (b7 diff_collect, deploy, issue42, issue45 config,
issue5_phase0, local_mqtt).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HCGpJXhSZasJLU38ksDghe
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
Godopu
merged commit 97c2946ee0 into main2026-10-08 20:01:25 +00:00
리뷰 3회차에서 4/4 PASS. 1회차에 grok·codex 가 같은 결함을 다른 모듈 11 곳에서, 2회차에 claude·grok 이 빠진 2 곳(test_o2_race_free_lock, test_o1_rebuttal)을 찾았습니다.
다른 문제가 없는지: 전체 스위트를 WORKSPACE_ROOT = 빈 센티널 디렉터리로 돌려 1751 passed / 0 failed / 38 skipped. 센티널은 비었고 본 체크아웃의 shim 은 수정되지 않았습니다. 병합 후 본 체크아웃에서 워크트리에서는 skip 되는 가드 테스트도 통과(41 passed).
리뷰 중 codex 는 공유 app-server 데몬 재시작으로 샌드박스 우회가 풀려 MQTT 발행·로컬 브로커 테스트를 못 했습니다. 루프 뒤 --no-daemon 으로 재기동해 복구했습니다. codex 어댑터 resume 명령에 --no-daemon 을 넣는 것은 후속입니다.
병합했습니다 (97c2946, v4.8.8).
- 리뷰 3회차에서 4/4 PASS. 1회차에 grok·codex 가 같은 결함을 다른 모듈 11 곳에서, 2회차에 claude·grok 이 빠진 2 곳(test_o2_race_free_lock, test_o1_rebuttal)을 찾았습니다.
- 다른 문제가 없는지: 전체 스위트를 `WORKSPACE_ROOT` = 빈 센티널 디렉터리로 돌려 1751 passed / 0 failed / 38 skipped. 센티널은 비었고 본 체크아웃의 shim 은 수정되지 않았습니다. 병합 후 본 체크아웃에서 워크트리에서는 skip 되는 가드 테스트도 통과(41 passed).
- 리뷰 중 codex 는 공유 app-server 데몬 재시작으로 샌드박스 우회가 풀려 MQTT 발행·로컬 브로커 테스트를 못 했습니다. 루프 뒤 `--no-daemon` 으로 재기동해 복구했습니다. codex 어댑터 resume 명령에 `--no-daemon` 을 넣는 것은 후속입니다.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Refs #17 (follow-up to the v4.8.7 review; #17 stays open)
v4.8.8 (PATCH, tests only — no change under
.agents/skillsexcept the version lines).lib.shrewrites$WORKSPACE_ROOT/.mam/shim/herdrevery time it is sourced. Tests that inherit the shell environment therefore rewrote the shim of whatever workspace that variable named: the agent pane's own workspace, or, during the PR #51 review, another workspace.Changes
tests/test_issue17_item4_decisions.py:_envsetsWORKSPACE_ROOTto the test's tmp dir. Only dropping it would make lib.sh fall back to the checkout itself.tests/conftest.py: an opt-in fixtureown_workspace_root(<tmp_path>/.mam-test-state/workspace). It is not autouse, because some code reads the variable in-process and some tests unset it on purpose.test_workspace_scopeandtest_issue21_worktree_prereqs._mutatenow pin the root they already create.Verification
tests/test_issue17_workspace_root_isolation.py, plus a sentinel test in the item-4 file. All of them fail on the pre-fix commits, which create.mam/shim/herdrin the sentinel or the checkout copy.ac48cb7(macOS, Python 3.9, herdr 0.9.3), run withWORKSPACE_ROOTpointing at an empty sentinel: 1751 passed / 0 failed / 38 skipped. The sentinel stayed empty, and the main checkout's shim was not modified.Follow-ups
--no-daemon. Through the shared daemon, the resume fails, and a daemon restart silently drops the sandbox bypass. That restart is what blocked codex's MQTT publishes during this loop..mam/directory appeared in the review worktree after the sentinel run. It holds no shim, and the test that creates it was not identified.🤖 Generated with Claude Code
https://claude.ai/code/session_01VCgu9Fa9iT7TbJUSzdq4Ff
병합했습니다 (
97c2946, v4.8.8).WORKSPACE_ROOT= 빈 센티널 디렉터리로 돌려 1751 passed / 0 failed / 38 skipped. 센티널은 비었고 본 체크아웃의 shim 은 수정되지 않았습니다. 병합 후 본 체크아웃에서 워크트리에서는 skip 되는 가드 테스트도 통과(41 passed).--no-daemon으로 재기동해 복구했습니다. codex 어댑터 resume 명령에--no-daemon을 넣는 것은 후속입니다.