release(v4.9.8): agy, codex and hermes read their databases read-only (Issue #64) - archive the review reports, bump the lockstep version
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
b0eccc5301
commit
38ea4f3b8e
24 files changed
+408
-26
No files matched your search
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"loop_id": "loop-20261019T134017Z-d90c23",
|
||||
"base_sha": "3ce5d5fdc108b0435e933a251fe1c1256b5d7973",
|
||||
"head_sha": "b0eccc530149bc6e9211727e19921665c7b80492",
|
||||
"tree_sha": "f5a412a3ee96465db7c4b3223d2d76e95716ddfa",
|
||||
"review_commit": "b0eccc530149bc6e9211727e19921665c7b80492",
|
||||
"reviewer": "reviewer-agy-01",
|
||||
"job_id": "e95527ef",
|
||||
"verdict": "PASS",
|
||||
"transport": "herdr",
|
||||
"evidence": "review-tree",
|
||||
"isolation": "worktree",
|
||||
"verified_at": "2026-10-19T14:59:46Z"
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
# Issue #64 Code Review Report (`3ce5d5f..b0eccc5`)
|
||||
|
||||
- **Job ID**: `e95527ef`
|
||||
- **Reviewer**: `agy` (`herdr:reviewer-agy-01`)
|
||||
- **Branch**: `fix/issue-64-ro-connect`
|
||||
- **Base .. Head**: `3ce5d5fdc108b0435e933a251fe1c1256b5d7973` (`v4.9.7`) .. `b0eccc530149bc6e9211727e19921665c7b80492` (1 commit)
|
||||
- **Verification Worktree**: `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261019T134017Z-d90c23/1`
|
||||
|
||||
---
|
||||
|
||||
## 1. Root Cause Analysis (Task 1)
|
||||
|
||||
**Why did the Issue #55 agent home guard detect newly created `.db-wal` and `.db-shm` sidecars beside another workspace's `agy` conversation DB during a macOS test run?**
|
||||
|
||||
1. **Global `agy` conversation directory scan in `reconcile.sh` drift C (`.agents/skills/multi-agent-mux-monitor/scripts/reconcile.sh:797-817`)**:
|
||||
- When an `agy` session is `running` and unpinned (`agy_conversation_id_own` is `None`), `reconcile.sh` globs every `*.db` in `${HOME_DIR}/.gemini/antigravity-cli/conversations/` (a global directory shared across all workspaces under that `HOME`) and invokes `verify_session_uuid(cwd, 'agy', uuid, s_eval, mode="discover")`.
|
||||
2. **`AgyAgentAdapter.verify_artifact` opened every candidate `.db` with read-write `sqlite3.connect(path)` (`.agents/skills/lib_py/agents/adapters/agy.py:60-80`)**:
|
||||
- In `discover` mode, `verify_artifact` reads `cache/last_conversations.json`. When `lc_data.get(ctx.cwd) == uuid` is `False` (for example, `uuid` belongs to another workspace), `verify_artifact` only filters out `uuid` if it is in `ctx.row.get("_sibling_claimed_uuids")` (which tracks siblings in the **same** workspace `cwd`) or if `os.path.getmtime(path) < ctx.epoch`.
|
||||
- For any conversation `.db` from another workspace whose `mtime >= ctx.epoch` (or when `ctx.epoch` is not set), `verify_artifact` proceeded to `conn = sqlite3.connect(path)` to run `SELECT count(*) FROM steps`.
|
||||
3. **macOS persistent WAL sidecar creation**:
|
||||
- On macOS, Apple's system `libsqlite3.dylib` sets `SQLITE_FCNTL_PERSIST_WAL = 1` by default. Opening a WAL-mode `.db` that currently has no `-wal`/`-shm` sidecars with read-write `sqlite3.connect(path)` and closing it creates `<uuid>.db-wal` and `<uuid>.db-shm` and leaves them on disk.
|
||||
- Similarly, if any `reconcile.sh` or `verify_artifact` call ran against the real `HOME` (or if another workspace's `reconcile.sh` / `agy` process scanned `conversations/*.db` while the test suite was running), opening a clean WAL `.db` with `sqlite3.connect(path)` created `<uuid>.db-wal` and `<uuid>.db-shm` in `~/.gemini/antigravity-cli/conversations/`, which `_agent_home_guard` flagged at session teardown.
|
||||
- Replacing `sqlite3.connect(path)` with `_ro_connect(path)` (`mode=ro&immutable=1` when no `-wal` exists) prevents MAM from ever creating or removing `-wal`/`-shm` sidecars when inspecting `agy` conversation databases (verified by `test_unpinned_agy_reconcile_leaves_other_workspace_clean_db_without_sidecars`, which fails on `base` `3ce5d5f` and passes on `head` `b0eccc5`).
|
||||
|
||||
---
|
||||
|
||||
## 2. Summary of Changes (`3ce5d5f..b0eccc5`)
|
||||
|
||||
### Changed Files & Lines (Read-Only Agent DB Queries)
|
||||
1. **`.agents/skills/lib_py/agents/base.py:111-145`**:
|
||||
- Moved `_ro_connect(db: str)` to `lib_py.agents.base` as a shared helper (with `tempfile.TemporaryDirectory(prefix="mam-ro-")` and `os.path.basename(path) or "state.db"` for the `walonly` branch).
|
||||
- Updated `db_rows_naming` default `connect` to `_ro_connect` (`conn = (connect or _ro_connect)(db)`), so `codex.residual_artifacts` (`state_*.sqlite`, `thread_history_*.sqlite`) and any other `db_rows_naming` callers also use `_ro_connect` instead of plain `mode=ro`.
|
||||
2. **`.agents/skills/lib_py/agents/adapters/opencode.py:3, 161-185`**:
|
||||
- Imports and reuses `_ro_connect` from `lib_py.agents.base`.
|
||||
3. **`.agents/skills/lib_py/agents/adapters/agy.py:3, 74`**:
|
||||
- `verify_artifact` (and `discover`, which delegates to `verify_artifact`) opens `conversations/<uuid>.db` via `_ro_connect(path)`.
|
||||
4. **`.agents/skills/lib_py/agents/adapters/codex.py:3, 80, 195`**:
|
||||
- `_find_rollout_via_db` (used by `_find_rollout`, `artifact_path`, `verify_artifact`) and `discover` open `state_*.sqlite` via `_ro_connect(db)`.
|
||||
5. **`.agents/skills/lib_py/agents/adapters/hermes.py:3, 51, 100`**:
|
||||
- `verify_artifact` and `discover` open `~/.hermes/state.db` via `_ro_connect(hdb)`.
|
||||
6. **`.agents/skills/multi-agent-mux-status/scripts/status.sh:90-91, 103, 120-121, 290-291, 303, 320-321`**:
|
||||
- Both `--json` and text modes use `_ro_connect` from `lib_py.agents.base` for `hermes` (`hdb`), `opencode` (`odb`), and `codex` (`db`). Zero raw `sqlite3.connect` calls remain in `status.sh`.
|
||||
7. **`.agents/skills/multi-agent-mux-monitor/scripts/reconcile.sh:423, 865, 954, 1047`**:
|
||||
- Imports `_ro_connect` from `lib_py.agents.base` at top level and uses it for `hermes` drift C (`_ro_connect(hdb)`), `opencode` drift C (`_ro_connect(odb)`), and `codex` drift C (`_ro_connect(state_db)`). Zero raw `sqlite3.connect` calls remain in `reconcile.sh`.
|
||||
8. **`tests/test_issue64_ro_connect.py` (lines 1-408)**:
|
||||
- 43 new regression tests covering shared helper identity, all 4 WAL states (`clean`, `leftover`, `walonly`, `writer`) across `agy`, `codex`, `hermes`, and `db_rows_naming`, static and runtime checks of `status.sh` and `reconcile.sh`, and cross-workspace unpinned `agy` drift-C discovery.
|
||||
|
||||
### Intentionally Excluded `sqlite3.connect` Call Sites
|
||||
- **Agent DB write paths (`purge_artifacts`)**:
|
||||
- `lib_py/agents/adapters/codex.py:152` (`DELETE FROM threads WHERE id=?`)
|
||||
- `lib_py/agents/adapters/hermes.py:74` (`DELETE FROM sessions` / `DELETE FROM messages`)
|
||||
- `lib_py/agents/adapters/opencode.py:193` (`DELETE` from 1.x legacy tables)
|
||||
- **MAM's own state database (`agent-sessions.db`)**:
|
||||
- `lib_py/atomic_yaml.py:61`, `lib_py/state.py:17`, `lib_py/verify_session.py:41`, `lib_py/loop/runner.py:416`, `lib.sh:1599, 2068`.
|
||||
|
||||
---
|
||||
|
||||
## 3. Test Results (Base vs. Head) & Remaining Risks
|
||||
|
||||
1. **Negative verification on `base` (`3ce5d5f`)**:
|
||||
- Running `tests/test_issue64_ro_connect.py` against an archive copy of `base` (`3ce5d5f`) on macOS: **`23 failed, 20 passed in 10.97s`** (every `clean` and `walonly` state across `agy`, `codex`, `hermes`, `db_rows_naming`, `status.sh`, `reconcile.sh`, plus `test_ro_connect_lives_in_base_and_opencode_reuses_it`, `test_status_and_reconcile_static_ro_connect_usage`, and `test_unpinned_agy_reconcile_leaves_other_workspace_clean_db_without_sidecars` failed as expected).
|
||||
2. **Verification on `head` (`b0eccc5`)**:
|
||||
- `tests/test_issue64_ro_connect.py`: **43 passed**
|
||||
- `tests/test_issue60_linux_fixes.py`: **52 passed**
|
||||
- `tests/test_issue60_opencode_v2.py`: **15 passed**
|
||||
- `tests/test_a4_adapter_contract.py`: **33 passed**
|
||||
- `tests/test_issue55_agent_homes.py`: **11 passed**
|
||||
- `tests/test_issue31_purge_residual.py`: **67 passed**
|
||||
- **Total**: **`221 passed in 119.66s`**
|
||||
- `git status -s` and `git diff --check` in the verification worktree are completely clean.
|
||||
3. **Remaining risks**:
|
||||
- External processes outside MAM (such as an active `agy` IDE/CLI session running in another workspace on the same host) can still create or remove their own conversation `.db-wal`/`.db-shm` sidecars in `~/.gemini/antigravity-cli/conversations/` while a pytest session is running, which `_agent_home_guard` (which only exempts live non-temp workspace directories for `claude`) can observe as a new directory entry. Within MAM itself, all read-only queries against `agy`, `codex`, `hermes`, and `opencode` databases are now sidecar-safe.
|
||||
|
||||
[VERDICT: PASS]
|
||||
Reference in new issue
Block a user