opencode-config/docs/handoff/pr-102-e2e-memory-tests.md
Sergey 9d1373a51b
test(memory): E2E coverage for 4 scenarios (#102)
* test(memory): E2E coverage for 4 scenarios

* docs(handoff): set PR number

* style(memory): ruff format e2e test

* docs(project-map): add test_memory_tools_e2e.py after PR#102

---------

Co-authored-by: opencode-agent <agent@opencode.local>
2026-07-27 01:32:53 +03:00

3.3 KiB
Raw Blame History

pr title
102 E2E coverage for 4 hybrid-memory scenarios

Что сделано

Создан tests/test_memory_tools_e2e.py с 4 E2E сценариями, покрывающими гибридную память (keyword + semantic):

  1. zero-config keyword-only — поиск работает без OPENAI_BASE_URL (semantic возвращает []), keyword через ripgrep находит файл.
  2. full hybrid — semantic находит по точному термину и синониму (через embedding), keyword находит по точному слову.
  3. fallback при падении OpenRouter — при невалидном OPENAI_API_KEY semantic возвращает [] (401 не retryable → embedder returns None), keyword работает.
  4. удаление файла — после удаления .md + reindex, ни semantic, ни keyword не находят удалённый файл.

Все тесты маркированы @pytest.mark.skipif(not RUN_LIVE) — запускаются только с RUN_LIVE=1. Без env — 4 skipped.

Вспомогательные функции:

  • _rg_search(pattern, dir) — keyword через ripgrep (subprocess), fallback на /root/.cache/opencode/bin/rg если нет в PATH.
  • _semantic_search(query, index_dir, env) — semantic через python3 -m src.memory search --json (subprocess), с передачей кастомного env.
  • _reindex(memory_dir, index_dir) — reindex + poll reindex.log до done:.
  • _make_memory_file(dir, term, synonym) — tmp .md с frontmatter + уникальным термином zzuniqtestterm42 + опциональным синонимом.

Почему

Фаза 1 (PR #100) сделала Python backend safe (lazy-init, return None). Фаза 2 (PR #101) создала 5 TS tools. Нужна E2E гарантия что keyword fallback работает когда semantic недоступен — без E2E регрессии: lazy-init поломался → все tools падают; fallback сломался → semantic-up → memory-down.

Подробное обоснование в technical/memory-keyword-vs-semantic-decision.md — гибрид выбран вместо semantic-only именно из-за стабильности keyword path.

Pending

Watch out

  • Тесты требуют OPENAI_BASE_URL, OPENAI_API_KEY, OPENAI_EMBEDDING_MODEL в env (реальный OpenRouter, не mock). Запуск: RUN_LIVE=1 uv run pytest tests/test_memory_tools_e2e.py -v --no-cov.
  • Сценарий 4 (deletion) требует dummy-файл в memory_dir — иначе run_index возвращает по if not md_files без обновления index.json, и удалённая запись остаётся в индексе. Добавлен _make_dummy_file.
  • rg может быть не в PATH — _rg_bin() пробует shutil.which затем /root/.cache/opencode/bin/rg, pytest.skip если нет.
  • Timeout: сценарий 3 — 300с (хотя 401 не retryable и embedder returns None быстро, на всякий случай), сценарии 2/4 — 180с.
  • Ruff: subprocess.run требует check=False (PLW1510) — добавлено явно.