test(opencode): the 2.x schema and CLI, a fake opencode, and an opt-in real-binary contract (Issue #60)

tests/_fake_opencode.py implements the two commands MAM calls (debug paths,
session delete) as measured on 2.0.32; unit tests never run a real opencode
(it would migrate the test database). test_real_opencode_2x_contract runs a
real 2.x opencode, when installed, in a home and tmp dir of its own with
--standalone.

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-18 14:58:29 +09:00
1 parent a311c23303
commit f0d1c000f9
5 files changed
+353 -147

No files matched your search

+15 -5
View File
@@ -34,6 +34,7 @@ sys.path.insert(0, str(SKILLS))
from lib_py.agents.registry import get_adapter # noqa: E402
from lib_py.agents.base import DiscoveryContext # noqa: E402
from lib_py.verify_session import workspace_key # noqa: E402
import _fake_opencode # noqa: E402 (tests/ is on sys.path via conftest)
SESSION_ENV = ("CLAUDE_CODE_SESSION_ID", "ANTIGRAVITY_CONVERSATION_ID",
"HERMES_SESSION_ID", "GROK_SESSION_ID", "OPENCODE_SESSION_ID")
@@ -896,9 +897,14 @@ def _db(path: Path, ddl: list, rows: list):
def test_opencode_residual_reports_event_rows(home, tmp_path, monkeypatch):
# A database migrated from 1.x (Issue #60): `opencode session delete`
# (the fake, as measured on 2.0.32) removes the 2.x rows, the purge
# deletes the 1.x session/message/part rows, and todo is reported.
u, o = f"ses_{uuidlib.uuid4().hex}", f"ses_{uuidlib.uuid4().hex}"
db = home / ".local" / "share" / "opencode" / "opencode.db"
ddl = ["CREATE TABLE session (id TEXT PRIMARY KEY)",
"CREATE TABLE session_v2 (id TEXT PRIMARY KEY, parent_id TEXT)",
"CREATE TABLE session_message (id TEXT, session_id TEXT)",
"CREATE TABLE message (id TEXT, session_id TEXT)",
"CREATE TABLE part (id TEXT, session_id TEXT)",
"CREATE TABLE event (id TEXT, aggregate_id TEXT)",
@@ -907,6 +913,8 @@ def test_opencode_residual_reports_event_rows(home, tmp_path, monkeypatch):
rows = []
for s in (u, o):
rows += [("INSERT INTO session VALUES (?)", (s,)),
("INSERT INTO session_v2 VALUES (?, NULL)", (s,)),
("INSERT INTO session_message VALUES ('sm', ?)", (s,)),
("INSERT INTO message VALUES ('m', ?)", (s,)),
("INSERT INTO part VALUES ('p', ?)", (s,)),
("INSERT INTO event VALUES ('e1', ?)", (s,)),
@@ -915,14 +923,16 @@ def test_opencode_residual_reports_event_rows(home, tmp_path, monkeypatch):
("INSERT INTO todo VALUES ('t', ?)", (s,))]
_db(db, ddl, rows)
adapter = get_adapter("opencode")
monkeypatch.setattr(adapter, "_resolve_db", lambda ctx: str(db)) # never run a real opencode
fake = _fake_opencode.write(tmp_path / "fakebin" / "opencode")
monkeypatch.setattr(adapter, "_bin", lambda ctx: fake) # never run a real opencode
ctx = DiscoveryContext(workspace=str(tmp_path), agent_name="opencode", home_dir=str(home))
assert f"{db} (session_v2.id: 1 rows)" in adapter.residual_artifacts(u, ctx)
adapter.purge_artifacts(u, ctx)
assert adapter.purge_artifacts(u, ctx) == [f"opencode session (with its child sessions): {u}",
f"sqlite rows for session: {u}"]
assert adapter.residual_artifacts(u, ctx) == [f"{db} (event.aggregate_id: 2 rows)",
f"{db} (event_sequence.aggregate_id: 1 rows)",
f"{db} (todo.session_id: 1 rows)"]
assert adapter.residual_artifacts(u, ctx) == [f"{db} (todo.session_id: 1 rows)"]
assert len(adapter.residual_artifacts(o, ctx)) == 8 # the other session is untouched: one entry per table
def test_codex_residual_reports_name_and_thread_rows(home, tmp_path, monkeypatch, conv, other):