release(v4.9.5): a claude purge removes every path the session owns (Issue #31, PR #59) - archive the review reports, bump the lockstep version, load logroot eagerly
Review loop (--review-only, --all-reviewer, focused on this Mac: macOS, /usr/bin/python3 3.9.6, bash 3.2): round 1 (@6f4f40a) agy and grok PASS, claude and codex NOT PASS (a non-uuid id `memory` purged the auto-memory dir, a linked dir below a root was followed, a NaN startedAt counted as dead), sent as a PR comment and fixed by the author in eleven commits; round 2 (@2a8d738) confirmed all three fixed but 4/4 NOT PASS on one test holder (`sh -c "sleep 120" <uuid>` loses the uuid on macOS /bin/sh), fixed in de6f3fc; round 3 (@de6f3fc) 4/4 PASS. Full suite on macOS / Python 3.9.6 @de6f3fc: 1934 passed, 56 skipped, 1 error (the known #55 false positive: agy conversations of another workspace). The real ~/.claude, /private/tmp/claude-<uid> and herdr panes unchanged. Also names lib_py.delegation.logroot in eager.CORE_MODULES (the v4.9.4 review's non-blocking note). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VCgu9Fa9iT7TbJUSzdq4Ff
This commit is contained in:
1 parent
de6f3fc81f
commit
6fd417a7b7
32 files changed
+916
-26
No files matched your search
@@ -0,0 +1,64 @@
|
||||
# Review Report — PR #59 (Issue #31: Complete Claude purge, residual reporting, and live-process stop gate)
|
||||
|
||||
- **Reviewer**: `agy` (`herdr:reviewer-agy-01`)
|
||||
- **Job ID**: `2fff60bd`
|
||||
- **Branch / Range**: `fix/issue-31` (`26e2c43753169671b600d03274901dbe203988dd..6f4f40a4adb2115d5997dffd31fb6473f05cab68`, 13 commits, 12 files)
|
||||
- **Verification Worktree**: `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261016T003524Z-a51548/1`
|
||||
- **Platform**: macOS Darwin (`arm64-apple-darwin25`, `/usr/bin/python3` 3.9.6, `.venv/bin/python` 3.9.6, `/bin/bash` 3.2.57)
|
||||
|
||||
---
|
||||
|
||||
## 1. Executive Summary
|
||||
|
||||
PR #59 resolves Issue #31 by unifying the Claude adapter's owned-path resolution (`_owned_paths`) across `purge_artifacts`, `has_artifacts`, and `residual_artifacts`, covering:
|
||||
- `projects/<key>/<uuid>.jsonl` and `projects/<key>/<uuid>/` (across both `ctx.claude_dir` and `<config_dir>/projects`),
|
||||
- `file-history/<uuid>/` and `session-env/<uuid>/`,
|
||||
- `jobs/<uuid[:8]>/` (only when `state.json` has `sessionId == uuid`, removing `state.json` last so partial failure preserves ownership evidence),
|
||||
- `sessions/<pid>.<64hex>.key` (masked in output as `<pid>.*.key`) and `sessions/<pid>.json` for dead or PID-reused processes (removing keys before the `.json` file so ownership evidence survives partial failure),
|
||||
- `<tmp>/claude-<uid>/<key>/<uuid>/` across `CLAUDE_CODE_TMPDIR`, `TMPDIR`/`TMP`/`TEMP`, and `/tmp`.
|
||||
|
||||
It also adds `residual_artifacts` for `claude`, `codex`, `grok`, and `opencode`; wires `stop_session.sh` to report residuals after `--purge-conversation` and to check `python -m lib_py.agents in-use <agent> <uuid> <cwd> --wait 5` before purging (exiting 4 without mutating state if a live agent process still holds the conversation); supports `CLAUDE_CONFIG_DIR` across `lib.sh`, `DiscoveryContext`, `claude.py`, and `_agent_home_guard.py`; and updates `multi-agent-mux-stop/SKILL.md` + `tests/data/skill_code_blocks.json` to reflect that `--purge-conversation` removes the session row rather than leaving `status: terminated`.
|
||||
|
||||
All 12 modified files pass Python 3.9.6 AST compilation and Bash 3.2 (`set -u`) syntax checks, all 11 regression test cases fail against base `26e2c43` and pass on head `6f4f40a`, and 217 tests across 6 test suites pass on macOS.
|
||||
|
||||
---
|
||||
|
||||
## 2. macOS Environment & Deletion-Scope Safety Verification
|
||||
|
||||
1. **BSD `ps -o lstart=` Format, Locale (`LC_ALL=C`), and `startedAt + 2` Comparison on macOS**:
|
||||
- Verified BSD `ps -p <pid> -o lstart=` on this Mac under `LC_ALL=C`: outputs `'Fri Oct 16 09:48:41 2026 \n'`.
|
||||
- `" ".join(out.split())` normalizes multi-space padding (including single-digit days like `'Oct 2'`) and trailing whitespace before `time.strptime(..., "%a %b %d %H:%M:%S %Y")`.
|
||||
- Inspected 4 live `~/.claude/sessions/<pid>.json` files on this Mac (read-only): `startedAt / 1000.0 - lstart` ranged from `+0.694 s` to `+2.430 s`, so `lstart <= started + 2` holds for all live processes and rejects reused PIDs started after the session file was written.
|
||||
- Fail-safe behavior: invalid/non-positive PIDs, `started <= 0`, missing `startedAt`, or `ps`/parse errors all return `True` (treated as live, refusing purge).
|
||||
|
||||
2. **macOS Temp Root Resolution (`TMPDIR` vs `/tmp` -> `/private/tmp`) & Real Layout Agreement**:
|
||||
- On this Mac, `TMPDIR` is `/var/folders/q_/.../T/` (which has no `claude-501`), while Claude Code's actual scratchpad directory is `/private/tmp/claude-501/<workspace_key>/<uuid>/` (accessed via `/tmp/claude-501` symlink).
|
||||
- `_tmp_roots()` checks `CLAUDE_CODE_TMPDIR` (both `<override>/claude-<uid>` and `<override>` when already named `claude-<uid>`), `TMPDIR`/`TMP`/`TEMP`, and `/tmp/claude-<uid>`, deduplicating via `os.path.realpath(c)`. This ensures `/private/tmp/claude-<uid>` is always discovered on macOS even when `TMPDIR` points to `/var/folders/.../T/`.
|
||||
- Read-only inspection of `~/.claude` on this Mac confirmed exact structural agreement for `projects/<key>/`, `file-history/<uuid>/`, `session-env/<uuid>/`, `sessions/<pid>.json` + `<pid>.<64hex>.key`, and `jobs/<uuid[:8]>/state.json` (while shared files like `jobs/pins.json` and `history.jsonl` are untouched).
|
||||
|
||||
3. **Deletion Scope Isolation, Malformed UUID Rejection, and Symlink Safety**:
|
||||
- `_plausible_id(uuid)` rejects `""`, `"."`, `".."`, `"*"`, and any string containing `"/"`, `".."`, or `"*"` before constructing any path or scanning any directory.
|
||||
- `_owned_job` checks `json.load(open(job/state.json)).get("sessionId") == uuid`, leaving another session's `jobs/<uuid[:8]>/` (and `jobs/pins.json`) untouched.
|
||||
- `_key_files` matches `rf"{stem}\.[0-9a-f]{{64}}\.key"` only for a `sessions/<pid>.json` whose `sessionId == uuid`, never reading key contents and never touching lone keys or other sessions' PIDs.
|
||||
- `_remove` checks `if os.path.islink(path) or not os.path.isdir(path): os.remove(path)` before `shutil.rmtree(path, ignore_errors=True)`, and `scan_names` uses `os.walk(root)` (`followlinks=False`), ensuring symlinks are never traversed outside the target scope.
|
||||
|
||||
4. **Stop Exit 4 Contract, Residual Reporting, and Documentation Lockstep**:
|
||||
- `stop_session.sh` runs `"$(_delegate_py_bin)" -m lib_py.agents in-use "$AGENT" "$PURGE_UUID" "$TARGET_CWD" --wait 5` before `atomic_dump_yaml`; if non-zero, it publishes a `cancelled` job event and exits `4` with all records and files preserved.
|
||||
- `tests/data/skill_code_blocks.json` hashes (`301c347ff881`, `a973676cb2d1`) and line number (`stop_session.sh:327`) match `multi-agent-mux-stop/SKILL.md` and `stop_session.sh` (`test_issue42_skill_blocks.py` passes).
|
||||
|
||||
---
|
||||
|
||||
## 3. Test Suite Execution Summary
|
||||
|
||||
Executed in `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261016T003524Z-a51548/1` with `HERDR_*`, `WORKSPACE_ROOT`, `MAM_ENV_FILE`, `MAM_JOBS_DIR`, `DELEGATE_JOB_LOGS_DIR`, and `CLAUDE_CONFIG_DIR` scrubbed, `PYTHONDONTWRITEBYTECODE=1`, `-p no:cacheprovider`, and `--basetemp=/tmp/mam_verify_pr59_bt`:
|
||||
|
||||
- `tests/test_issue31_purge_residual.py`: **32 passed** (11 core regression cases verified to fail on base `26e2c43`)
|
||||
- `tests/test_issue55_agent_homes.py`: **11 passed**
|
||||
- `tests/test_issue42_skill_blocks.py`: **15 passed**
|
||||
- `tests/test_a4_adapter_contract.py`: **55 passed**
|
||||
- `tests/test_orc_onboard.py`: **37 passed, 1 skipped**
|
||||
- `tests/test_tier1_unit.py`: **67 passed**
|
||||
|
||||
Total: **217 passed, 1 skipped, 0 failed**. Verification worktree `git status -s` is empty and no `.mam` directory was created.
|
||||
|
||||
[VERDICT: PASS]
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"loop_id": "loop-20261017T145452Z-6c5aa6",
|
||||
"base_sha": "26e2c43753169671b600d03274901dbe203988dd",
|
||||
"head_sha": "de6f3fc81f8c33a9d2335320742dc5a47f566cda",
|
||||
"tree_sha": "ffc291e6fc93822070f2b9f1d17009e83f176fcf",
|
||||
"review_commit": "de6f3fc81f8c33a9d2335320742dc5a47f566cda",
|
||||
"reviewer": "reviewer-agy-01",
|
||||
"job_id": "7c325532",
|
||||
"verdict": "PASS",
|
||||
"transport": "herdr",
|
||||
"evidence": "review-tree",
|
||||
"isolation": "worktree",
|
||||
"verified_at": "2026-10-17T15:16:54Z"
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
# Pre-Merge Review Report (Round 3): PR #59 (`fix/issue-31`)
|
||||
|
||||
- **Job ID**: `7c325532`
|
||||
- **Reviewer**: `herdr:reviewer-agy-01` (`agy`)
|
||||
- **Commit Range**: `26e2c43753169671b600d03274901dbe203988dd` .. `de6f3fc81f8c33a9d2335320742dc5a47f566cda` (25 commits; Round 3 delta: `2a8d73825b3832376aeaf96b09548359dc3cb887..de6f3fc81f8c33a9d2335320742dc5a47f566cda`, 1 commit)
|
||||
- **Verification Worktree**: `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261017T145452Z-6c5aa6/1`
|
||||
- **Host / Runtime**: macOS `arm64-apple-darwin25` (Darwin 25.3.0), `/usr/bin/python3` 3.9.6 & `.venv/bin/python` 3.9.6, `/bin/bash` 3.2.57
|
||||
|
||||
---
|
||||
|
||||
## 1. Round 3 Delta Verification (`2a8d738..de6f3fc`)
|
||||
|
||||
- **Commit `de6f3fc81f8c33a9d2335320742dc5a47f566cda`**:
|
||||
- Replaces `subprocess.Popen(["sh", "-c", "sleep 120", conv])` at `tests/test_issue31_purge_residual.py:315` with:
|
||||
```python
|
||||
# Not `sh -c "sleep 120" <uuid>`: a shell execs its last simple command
|
||||
# and the uuid would vanish from the process list (macOS /bin/sh).
|
||||
named = subprocess.Popen([sys.executable, "-c", "import time; time.sleep(120)", conv])
|
||||
```
|
||||
- **Verification Checklist**:
|
||||
1. **Lowercase UUID retained in `argv` on macOS**: The Python holder process does not `exec` a separate binary, so `conv` stays visible in `ps -axo pid=,command=` for the lifetime of `named`.
|
||||
2. **Passes `[upper]` and `[mixed]` on macOS**: Both `test_any_spelling_of_the_uuid_is_the_lowercase_session[upper]` and `[mixed]` pass on Darwin (`67/67` tests in `tests/test_issue31_purge_residual.py` pass).
|
||||
3. **Regression sensitivity preserved**: Reverting `for u in {canon, uuid}` to `for u in (uuid,)` in `ClaudeAgentAdapter.conversation_in_use` (in an isolated `/tmp` copy) causes both `[upper]` and `[mixed]` to fail immediately at `tests/test_issue31_purge_residual.py:320` (`AssertionError: a command line naming the lowercase id`).
|
||||
4. **Process cleanup (`finally: named.kill(); named.wait()`)**: Because `named` is a single Python process with no forked child `sleep`, `named.kill()` and `named.wait()` terminate it cleanly without leaving orphaned processes.
|
||||
|
||||
---
|
||||
|
||||
## 2. Cumulative Review Summary (`26e2c43..de6f3fc`)
|
||||
|
||||
- **Canonical UUID & deletion scope safety**: `_canonical(uuid)` in `.agents/skills/lib_py/agents/adapters/claude.py` gates `_candidates`, `has_artifacts`, `conversation_in_use`, `purge_artifacts`, and `residual_artifacts`, preventing non-UUID names (`memory`, `notes`, `uuid-c`, etc.) from matching or deleting `projects/<key>/memory/` or any other directory.
|
||||
- **Symlink boundary protection**: `_inside(root, path)` verifies via `os.lstat` that no intermediate directory component between `root` and `os.path.dirname(path)` is a symlink and that `realpath(dirname(path))` stays strictly inside `realpath(root)`, while `has_artifacts` counts `_candidates` so symlinked orphans still select `claude` and appear in `residual_artifacts`.
|
||||
- **macOS `ps -o lstart=` & `startedAt` fail-safe liveness**: `_session_file_live` runs `ps -p <pid> -o lstart=` with `LC_ALL="C", TZ="UTC0"`, parses via `calendar.timegm`, and treats `bool`, non-`(int, float)`, `OverflowError`, `NaN`, `±inf`, and `<= 0` `startedAt` values as live when the PID exists.
|
||||
- **`stop_session.sh` & CLI `in-use` gate**: `in_use_hints` and exit-4 error messages accurately report where live holders may be found and that registry records and conversation files are preserved.
|
||||
- **Test suite execution**:
|
||||
- `tests/test_issue31_purge_residual.py`: **67 passed**
|
||||
- `tests/test_issue55_agent_homes.py`: **PASSED**
|
||||
- `tests/test_issue42_skill_blocks.py`: **PASSED**
|
||||
- `tests/test_a4_adapter_contract.py`: **PASSED**
|
||||
- `tests/test_orc_onboard.py`: **PASSED**
|
||||
- Total run in Round 3 verification worktree: **185 passed, 1 skipped** in 48.05s (`test_tier1_unit.py` also verified passing in Round 2 with no production changes since `2a8d738`).
|
||||
- **Worktree hygiene**: Verification worktree `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261017T145452Z-6c5aa6/1` is clean (`git status -s` empty, no `.mam` directory created, basetemp removed).
|
||||
|
||||
[VERDICT: PASS]
|
||||
@@ -0,0 +1,81 @@
|
||||
# Pre-Merge Review Report (Round 2): PR #59 (`fix/issue-31`)
|
||||
|
||||
- **Job ID**: `b4aa3aff`
|
||||
- **Reviewer**: `herdr:reviewer-agy-01` (`agy`)
|
||||
- **Commit Range**: `26e2c43753169671b600d03274901dbe2039887` .. `2a8d73825b3832376aeaf96b09548359dc3cb887` (Round 2 delta: `6f4f40a4adb2115d5997dffd31fb6473f05cab68..2a8d73825b3832376aeaf96b09548359dc3cb887`, 11 commits)
|
||||
- **Verification Worktree**: `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261017T135731Z-e93f0a/1`
|
||||
- **Host / Runtime**: macOS `arm64-apple-darwin25` (Darwin 25.3.0), `/usr/bin/python3` 3.9.6 & `.venv/bin/python` 3.9.6, `/bin/bash` 3.2.57
|
||||
|
||||
---
|
||||
|
||||
## 1. Round 1 Findings Verification
|
||||
|
||||
All three required production fixes and all four non-blocking improvements from Round 1 are cleanly resolved in `6f4f40a..2a8d738`:
|
||||
|
||||
1. **[Blocker — Resolved] Canonical UUID enforcement across Claude adapter (`bd09c6a`, `c0248b8`, `81b6c2e`, `2a8d738`)**:
|
||||
- `_canonical(uuid)` in `.agents/skills/lib_py/agents/adapters/claude.py:10-18` validates `isinstance(uuid, str) and _UUID.fullmatch(uuid)` (`[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}`, case-insensitive) and normalizes to lowercase.
|
||||
- `_candidates`, `has_artifacts`, `conversation_in_use`, `purge_artifacts`, and `residual_artifacts` all gate on `_canonical(uuid)`, ensuring non-UUID names (such as `memory`, `notes`, or `uuid-c`) never touch `projects/<key>/memory/` or any other directory/file.
|
||||
- `conversation_in_use` checks `any(conversation_in_use(u, [self.artifact_path(canon, ctx)]) for u in {canon, uuid})` plus `self._session_files(canon, ctx)`, properly handling uppercase/mixed-case UUIDs on case-insensitive APFS.
|
||||
- `tests/test_a4_adapter_contract.py:225-232` was updated with user approval to use a canonical UUID (`0c1a5f3e-6b2d-4c8e-9a7f-1d2e3f4a5b6c`).
|
||||
|
||||
2. **[P1 — Resolved] Symlink boundary check below Claude roots (`6e0361c`, `dd292c1`)**:
|
||||
- `_inside(root, path)` in `.agents/skills/lib_py/agents/adapters/claude.py:108-122` walks every path component of `os.path.relpath(os.path.dirname(path), root)` and verifies `stat.S_ISDIR(os.lstat(cur).st_mode)` (rejecting any intermediate symlink) and `os.path.realpath(os.path.dirname(path)).startswith(real_root.rstrip(os.sep) + os.sep)`.
|
||||
- Roots that are themselves symlinks (such as `/tmp -> /private/tmp` on macOS or a symlinked `~/.claude`) and leaf symlinks (`_remove` unlinks the leaf symlink without traversing) work as intended.
|
||||
- `has_artifacts` checks `bool(self._candidates(uuid, ctx))` so a candidate behind a symlink still selects `claude` in `purge auto` / `purge claude` and is reported in `residual_artifacts` without being deleted.
|
||||
|
||||
3. **[P2 — Resolved] Fail-safe `startedAt` validation in `_session_file_live` (`f943b0d`, `60779ba`)**:
|
||||
- `.agents/skills/lib_py/agents/adapters/claude.py:87-95` rejects `bool`, non-`(int, float)`, `OverflowError` on `float(started) / 1000.0` (e.g. `10**400`), `NaN`, `±inf`, and `<= 0`, returning `True` (fail-safe live) whenever the PID is alive.
|
||||
|
||||
4. **[Non-Blocking Notes — Resolved]**:
|
||||
- **UTC `lstart` parsing (`af8ed39`)**: `ps -p <pid> -o lstart=` runs with `LC_ALL="C", TZ="UTC0"` and parses via `calendar.timegm`. Verified directly on macOS Darwin with both `.venv/bin/python` and `/usr/bin/python3` (`abs(time.time() - lstart) < 0.7s`).
|
||||
- **Actionable `in_use_hints` & exit-4 wording (`e156179`)**: `BaseAgentAdapter.in_use_hints` and `ClaudeAgentAdapter.in_use_hints` print the active `<cfg>/sessions/` path and `ps -axww | grep <uuid>` hint on stderr when `in-use` or `stop_session.sh --purge-conversation` exits 4; `SKILL.md` and `stop_session.sh` accurately state that registry records and conversation files are preserved even though the herdr session itself may already be down.
|
||||
- **Host `/tmp/claude-<uid>` test isolation (`26fb1c4`)**: `_SYSTEM_TMP = "/tmp"` in `claude.py` is redirected by the `own_tmp_roots` autouse fixture (and `sitecustomize.py` for child Python processes) in `tests/test_issue31_purge_residual.py`.
|
||||
|
||||
5. **Pre-fix failure verification**:
|
||||
- Running the new Round 2 regression tests from `tests/test_issue31_purge_residual.py` against pre-fix code (`26fb1c4`, before `bd09c6a..2a8d738`) in an isolated `/tmp` copy produced **25 test failures** across all targeted bug classes (`test_claude_rejects_malformed_uuid`, `test_any_spelling_of_the_uuid_is_the_lowercase_session`, `test_claude_purge_never_follows_a_linked_dir_below_a_root`, `test_purge_cli_reports_a_linked_orphan_it_will_not_remove`, `test_a_non_uuid_id_reaches_nothing`, `test_liveness_reads_lstart_as_utc`, `test_an_unusable_started_at_means_live`, `test_a_live_holder_with_an_unusable_started_at_blocks_the_purge`).
|
||||
|
||||
---
|
||||
|
||||
## 2. Remaining Issue Blocking Merge
|
||||
|
||||
### [P1] `test_any_spelling_of_the_uuid_is_the_lowercase_session` fails on macOS due to `/bin/sh -c` single-command `exec` optimization
|
||||
|
||||
- **Location**: `tests/test_issue31_purge_residual.py:315` (introduced in commit `c0248b8`)
|
||||
- **Symptom**:
|
||||
Running pytest on macOS fails both parametrizations (`[upper]` and `[mixed]`):
|
||||
```text
|
||||
FAILED tests/test_issue31_purge_residual.py::test_any_spelling_of_the_uuid_is_the_lowercase_session[upper]
|
||||
FAILED tests/test_issue31_purge_residual.py::test_any_spelling_of_the_uuid_is_the_lowercase_session[mixed]
|
||||
AssertionError: a command line naming the lowercase id
|
||||
assert False is True
|
||||
```
|
||||
- **Root Cause**:
|
||||
Line 315 spawns the dummy holder process as:
|
||||
```python
|
||||
named = subprocess.Popen(["sh", "-c", "sleep 120", conv])
|
||||
```
|
||||
On macOS (`/bin/sh` is GNU bash 3.2.57 in POSIX mode), `sh -c "sleep 120" <conv>` sees a single simple command with no subsequent commands or traps and optimizes by calling `execve("/bin/sleep", ["sleep", "120"])` directly in-place (`CMD_NO_FORK`). Within ~10ms (before `time.sleep(0.05)` finishes), the process image and argv in `ps -axo pid=,command=` become `sleep 120`, and `$0` (`conv`) vanishes from the process list.
|
||||
Note that `tests/test_issue10_13_purge.py:111-118` (`_holder`) already documents this exact pitfall:
|
||||
> `(Not sh -c 'sleep …': a shell execs its last simple command and the uuid would vanish from the process list.)`
|
||||
- **Required Fix**:
|
||||
In `tests/test_issue31_purge_residual.py:315`, use `sys.executable` instead of `sh -c`:
|
||||
```python
|
||||
named = subprocess.Popen([sys.executable, "-c", "import time; time.sleep(120)", conv])
|
||||
```
|
||||
*(Verified in an isolated `/tmp` copy on macOS: replacing line 315 with `sys.executable` makes both `[upper]` and `[mixed]` pass in 2.24s, with no orphaned child `sleep` process after `named.kill()`).*
|
||||
|
||||
---
|
||||
|
||||
## 3. Verification Summary
|
||||
|
||||
- Targeted pytest suite run against `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261017T135731Z-e93f0a/1` with scrubbed herdr/MAM/Claude environment variables:
|
||||
- `tests/test_issue55_agent_homes.py`: **PASSED**
|
||||
- `tests/test_issue42_skill_blocks.py`: **PASSED**
|
||||
- `tests/test_a4_adapter_contract.py`: **PASSED**
|
||||
- `tests/test_orc_onboard.py`: **PASSED**
|
||||
- `tests/test_tier1_unit.py`: **PASSED**
|
||||
- `tests/test_issue31_purge_residual.py`: **65 passed, 2 failed** (`test_any_spelling_of_the_uuid_is_the_lowercase_session[upper]` and `[mixed]`)
|
||||
- Total: **250 passed, 2 failed, 1 skipped** (all 252 pass once `tests/test_issue31_purge_residual.py:315` uses `sys.executable`).
|
||||
- Verification worktree `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261017T135731Z-e93f0a/1` verified clean (`git status -s` empty, no `.mam` directory created).
|
||||
|
||||
[VERDICT: NOT PASS]
|
||||
Reference in new issue
Block a user