Files
multi-agent-mux/.agents/reports/reviewer-agy-01/report-1abe0a90.md
T

7.4 KiB

Review Report: Issue #60 (fix/issue-60-opencode-v2)

  • Job ID: 1abe0a90
  • Reviewer: herdr:reviewer-agy-01 (agy)
  • Commit Range: 74333f87d0c02888c2b5b281e912d97e74348c01 .. 6b4b96fa1875862ef3bed830fe7b04166b1fad58 (3 commits across 13 files)
  • Verification Worktree: /var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261018T055915Z-abe16e/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, opencode v2.0.32 (/Users/godopu16/.opencode/bin/opencode)

1. Review Findings by Focus Area

1.1 OpenCode 2.x Schema, CLI Contract, and Purge Safety

  • _resolve_db (opencode debug paths):
    • .agents/skills/lib_py/agents/adapters/opencode.py:88-107 invokes self._run(ctx, ["debug", "paths"], timeout=5) with HOME, HOME_DIR, and XDG_DATA_HOME=<ctx.home_dir>/.local/share, parses the db line, and falls back to f"{ctx.home_dir}/.local/share/opencode/opencode.db".
    • Verified against real opencode v2.0.32 in an isolated temporary HOME: debug paths returns <home>/.local/share/opencode/opencode.db without creating the database file.
  • verify_artifact and discover (session_v2 & parent_id IS NULL):
    • verify_artifact (.agents/skills/lib_py/agents/adapters/opencode.py:113-147) queries SELECT directory, time_created FROM session_v2 WHERE id=?, converts millisecond time_created (float(started_at) / 1000.0) against ctx.epoch, and checks workspace_key(found_cwd) == workspace_key(ctx.cwd).
    • discover (.agents/skills/lib_py/agents/adapters/opencode.py:198-235) queries SELECT id FROM session_v2 WHERE parent_id IS NULL, filtering out subagent child sessions (which share directory and have newer time_created than the top-level TUI session).
    • Verified against read-only inspection (mode=ro) of the host's migrated opencode.db and a fresh 2.0.32 DB in a temporary HOME: fresh 2.x databases contain session_v2 (with id, parent_id, directory, time_created) and no session/message/part/todo/session_share tables.
  • purge_artifacts and residual_artifacts:
    • purge_artifacts (.agents/skills/lib_py/agents/adapters/opencode.py:149-181) checks self._has_session(db, uuid) (SELECT 1 FROM session_v2 WHERE id=?) before calling self._run(ctx, ["session", "delete", "--standalone", "--", uuid], timeout=60).
    • Using -- before uuid prevents option-flag injection if an ID ever starts with -, and --standalone avoids starting or attaching to a per-user background service.
    • In a fresh 2.0.32 DB, session_inbox, session_message, session_pending, instruction_entry, and instruction_state all have ON DELETE CASCADE foreign keys to session_v2(id), and opencode session delete also removes event and event_sequence rows (aggregate_id) for the session and its child sessions while leaving other sessions untouched.
    • For databases migrated from 1.x, purge_artifacts subsequently deletes matching uuid rows from part/parts/message/messages/session/sessions (if those tables exist) and residual_artifacts reports any surviving todo.session_id or session_v2.id (e.g., if session delete failed or the binary was missing, in which case purge_artifacts emits a WARN: on stderr).

1.2 End-to-End Lifecycle (create → reconcile drift C → status → stop → resume)

  • create_session.sh, resume_session.sh, update_yaml_resumed.sh:
    • All three scripts and OpenCodeAgentAdapter.spawn_spec / resume_spec consistently use opencode --auto --standalone (and opencode --session <uuid> --auto --standalone on materialized resume), removing the defunct --agent build flag rejected by OpenCode 2.x TUI.
  • reconcile.sh (drift C) and status.sh:
    • .agents/skills/multi-agent-mux-monitor/scripts/reconcile.sh:955-990 inspects PRAGMA table_info(session_v2), filters by parent_id IS NULL, directory = ?, and time_created >= ? (ms), and validates candidates via verify_session_uuid(cwd, 'opencode', uuid, s_eval, mode="discover").
    • .agents/skills/multi-agent-mux-status/scripts/status.sh:127,337 checks SELECT 1 FROM session_v2 WHERE id=? in both human and JSON status paths.
  • --standalone process lifecycle & stop_session.sh:
    • Verified in an isolated PTY with real opencode v2.0.32: opencode --auto --standalone spawns opencode serve --stdio --port 0 as a direct child of the TUI process; closing the PTY master terminates both the TUI and its opencode serve --stdio --port 0 child cleanly within ~0.1s with zero lingering background processes.
    • stop_session.sh's graceful /exit (send_keys_safe with echo wait before Enter) -> herdr kill-session (closes PTY) -> SIGKILL fallback and in-use gate (ps argv check for --session <uuid>) work cleanly with --standalone.

1.3 Linux Portability, Shell/Python Compatibility, and Completeness

  • Linux & XDG portability:
    • OpenCodeAgentAdapter._run explicitly sets HOME, HOME_DIR, and XDG_DATA_HOME = os.path.join(ctx.home_dir, ".local/share"), ensuring that even on Linux hosts where XDG_DATA_HOME is set in the ambient desktop environment, adapter CLI invocations remain isolated to ctx.home_dir.
    • test_real_opencode_2x_contract explicitly unsets XDG_DATA_HOME, XDG_STATE_HOME, XDG_CONFIG_HOME, XDG_CACHE_HOME, and HOME_DIR via monkeypatch.delenv.
  • Python 3.9 & Bash 3.2 compatibility:
    • Verified on macOS /usr/bin/python3 / .venv/bin/python (3.9.6) and /bin/bash (3.2.57 with set -u).
  • Repository-wide search for stale 1.x assumptions:
    • Grepping .agents/skills/, tests/, and docs/ for db path, --agent build, FROM session\b, INTO session\b, and table_info(session) confirms no remaining 1.x code or documentation assumptions exist outside explanatory comments.
  • Test coverage & negative regression verification:
    • tests/test_issue60_opencode_v2.py (10/10 passed, including test_real_opencode_2x_contract against real opencode v2.0.32), tests/test_a4_adapter_contract.py, tests/test_issue31_purge_residual.py, tests/test_issue42_skill_blocks.py, tests/test_issue55_agent_homes.py, and tests/test_tier1_unit.py all pass.
    • Reverting SELECT id FROM session_v2 WHERE parent_id IS NULL to SELECT id FROM session in an isolated /tmp copy immediately fails test_discover_and_verify_read_session_v2_and_skip_child_sessions and test_a_fresh_2x_database_has_no_session_table_and_still_works.

2. Non-Blocking Observation (Out of Scope for Issue #60)

  • [Note — stall_watch.py background_children with --standalone]:
    • Because opencode --auto --standalone keeps opencode serve --stdio --port 0 alive as a child process of the TUI while idle, and OpenCodeAgentAdapter.resident_children is (), lib_py.stall_watch.background_children(agent_pid, adapter.resident_children) sees the opencode serve --stdio --port 0 child process and conservatively withholds the optional idle nudge (NOTIFY_IDLE_AND_NUDGE). If idle nudging is desired for --standalone OpenCode in the future, stall_watch.background_children can exempt children whose argv matches opencode serve --stdio (while still walking any tool subprocesses spawned beneath that server). This does not affect any session lifecycle, discovery, or purge behavior in Issue #60.

[VERDICT: PASS]