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
This commit is contained in:
GodopuandClaude Opus 5.5 committed 2026-10-09 05:01:05 +09:00
1 parent ac48cb7861
commit e0181ea9be
32 files changed
+1192 -26

No files matched your search

@@ -0,0 +1,59 @@
# Review: Issue #17 workspace root @ d198dd5
- Role: Reviewer (grok)
- Identity: loop `loop-20261008T133858Z-9e7f5b`, snapshot `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261008T133858Z-9e7f5b/1`, base `6b00b6e06f55299cb60f156ccef09ede4bae5bdd` (main still `6b00b6e`), head `d198dd50aaf6119dc21f36d88704e64850e67413`, tree `114ec21d3fc7de8932f5e1d34f895edd24ad7c01`. One commit, `tests/test_issue17_item4_decisions.py` only, +36/−2. `git diff --check` clean. Snapshot porcelain empty after the runs. No version bump.
- Verified read-only at the snapshot. Python 3.9.6 from the `issue17-wsroot` worktree `.venv`, bash 3.2.57. Inherited `HERDR_*`, `MAM_*`, and `MQTT_*` were unset. `.mam.env` was not exported. `started` for this dispatch is `dispatch_verified` with attempt-id 1.
- Product code under `.agents/skills` is unchanged. `lib.sh` still installs the herdr shim when it is sourced (`lib.sh:143`, called at `:3088`). Aiming that write at a temp directory belongs in the test environment.
## What this commit does
`_env` (`tests/test_issue17_item4_decisions.py:224-233`) drops an inherited `WORKSPACE_ROOT` and sets it to the helper's `tmp_path`. The comment matches `lib.sh:26`: with the variable unset, the library sets `WORKSPACE_ROOT` to the checkout that contains `lib.sh` and the source still rewrites that checkout's `.mam/shim/herdr`.
At `6b00b6e` the same helper kept every inherited `WORKSPACE_ROOT` (`git show 6b00b6e:tests/test_issue17_item4_decisions.py`, the old `:224-229`). Sourcing the wrapper with that filter and `WORKSPACE_ROOT` pointed at `/tmp/0a8aprobe.DcRQYA/sentinel` created `.mam/shim/herdr` under the sentinel. The head filter, pointed at the test directory, left a second sentinel empty and wrote `.mam/shim/herdr` under that test directory. `test_c_helpers_write_nothing_to_an_inherited_workspace` (`:477-498`) is that check: a monkeypatched sentinel stays empty, the checkout shim's mtime stays put, `_run_both` still sees `ws=<W>`, and the direct source sees the test directory. The checkout shim was absent before these runs and is still absent.
`_human_submit` (`:692-696`) already set `WORKSPACE_ROOT` to its `tmp_path`. Callers that pass `WORKSPACE_ROOT` through `extra` still override the default (`:232`).
## Why this file was outside the common fixture
`pytest_configure` (`tests/conftest.py:144-146`) drops `WORKSPACE_ROOT` only when its real path is some other checkout. A value that names this checkout stays. The autouse fixture (`:161-177`) sets `MAM_JOBS_DIR`, `DELEGATE_JOB_LOGS_DIR`, and `MAM_ENV_FILE`, and leaves `WORKSPACE_ROOT` alone. `mam_sandbox` (`:215`) does set it to the sandbox, and these helpers do not use that fixture. `_env` copies `os.environ` into the bash that sources the wrapper, so a root conftest kept is the directory `lib.sh` rewrites.
## Same defect left in place
Each of these copies `os.environ` (or passes no `env`, so the child inherits it) and sources `lib.sh` or the wrapper without setting `WORKSPACE_ROOT` to a temp directory. A probe of the `test_version_consistency.py:134` shape, with `WORKSPACE_ROOT` on a sentinel, created `.mam/shim/herdr` there.
| Location | What it does |
|---|---|
| `tests/test_version_consistency.py:29-31` and `:134-136` | Sources `lib.sh` to print `MAM_VERSION`. The second call copies `os.environ` and only replaces `MAM_VERSION`. |
| `tests/test_b19_headless_reconcile_fixes.py:125-134` | Copies `os.environ` and sources `lib.sh`. The later `_init_herdr_isolation() { :; }` runs after `lib.sh:3088` has already written the shim. |
| `tests/test_b8_send_keys_verification.py:11` and `:32` | The script sources `lib.sh`. `subprocess.run` passes no `env`. |
| `tests/test_issue6_fail_closed.py:1241-1244` | Sources `.agents/skills/lib.sh` with the process environment and `cwd` set to the repo. |
| `tests/test_orc_onboard.py:15-18`, `:33-42`, `:46-56`, `:60-65` | `SCRUBBED_ENV` copies `os.environ` at import. The find, verify, and dump helpers source `lib.sh` without assigning `WORKSPACE_ROOT`. |
| `tests/test_issue21_worktree_prereqs.py:544-546` | `_mutate` sources that temp tree's `lib.sh` with the process environment. An inherited `WORKSPACE_ROOT` is where the shim is written. |
Apply the same two assignments `_env` now makes: drop `WORKSPACE_ROOT` from the copied environment and set it to that test's temporary directory before the `source`.
## Surveyed, and already aimed at a temp directory
These copy `os.environ` and source `lib.sh` or the wrapper, and they assign `WORKSPACE_ROOT` to the test directory (or to a sandbox the fixture already set):
- `tests/test_issue33_budget.py:47`
- `tests/test_issue18_liveness_contract.py:58`
- `tests/test_issue14_delivery_ack.py:36`
- `tests/test_issue26_envfile.py:76`
- `tests/test_issue26_ints.py:124`
- `tests/test_issue6_turn_handshake.py:28-29` (every call passes `cwd`, and the helper then sets `WORKSPACE_ROOT` to that `cwd`)
- `tests/test_c1_tui_readiness.py:19`
- `tests/test_layout.py:318`
- `tests/test_issue21_phase2_loop_a.py:49` and `:59`
- `tests/test_issue19_subscriber_daemon_lifecycle.py:53` — its only caller (`:138`) uses `mam_sandbox`, which has already set `WORKSPACE_ROOT` to that sandbox
- `tests/test_issue34_job_tree.py:590` — same, the callers pass `mam_sandbox`
`tests/test_issue20_state_isolation.py:150` and `:201` set `WORKSPACE_ROOT` on purpose and assert what that root receives. `tests/test_issue17_item4_decisions.py:172` runs `python -m lib_py.delegation.wrapper`, which does not install the shim. `:465` sources `lib_int.sh` only.
## Tests
`--basetemp=/tmp/0a8aA.2zJF3l`. The process started with `WORKSPACE_ROOT` equal to that basetemp; `conftest.py:144-146` drops it because it is not this checkout, so the tests ran with the variable unset. `tests/test_issue17_item4_decisions.py`, `tests/test_issue33_budget.py`, `tests/test_issue5_phase1_delegation.py`, `tests/test_tier1_unit.py`: **443 passed** in 466.90 s.
`--basetemp=/tmp/0a8aB.XgggUw`, outer `WORKSPACE_ROOT=/tmp/0a8asent.7l9EpB`. `tests/test_issue17_item4_decisions.py`: **290 passed** in 319.77 s. The outer sentinel was empty afterwards. `conftest.py:144-146` also drops that foreign root before collection, so the outer variable is not what `_env` sees. The check that reaches `_env` is `test_c_helpers_write_nothing_to_an_inherited_workspace`, which passed in both runs, together with the direct probe above.
[VERDICT: NOT PASS]
@@ -0,0 +1,86 @@
# 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]
@@ -0,0 +1,14 @@
{
"loop_id": "loop-20261008T133858Z-9e7f5b",
"base_sha": "6b00b6e06f55299cb60f156ccef09ede4bae5bdd",
"head_sha": "ac48cb78617af88584db529b5766acf02f4af73c",
"tree_sha": "b043034eda891bd83b547dcb34d7422a6977b89d",
"review_commit": "ac48cb78617af88584db529b5766acf02f4af73c",
"reviewer": "reviewer-grok-01",
"job_id": "42f6a97d",
"verdict": "PASS",
"transport": "herdr",
"evidence": "review-tree",
"isolation": "worktree",
"verified_at": "2026-10-08T18:40:20Z"
}
@@ -0,0 +1,70 @@
# 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]