Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 20 additions & 10 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ jobs:
with:
python-version: "3.12"
cache: "pip"
- run: pip install -e ".[dev,binary]"
- run: mypy --config-file pyproject.toml features/ shared/ mcp_server/ rag/ hooks/ wiki/ lifecycle/ graph/ core/
- uses: astral-sh/setup-uv@v5
- run: uv sync --locked --extra dev --extra binary --python 3.12
- run: uv run mypy --config-file pyproject.toml features/ shared/ mcp_server/ rag/ hooks/ wiki/ lifecycle/ graph/ core/

quality:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -81,9 +82,15 @@ jobs:
with:
python-version: ${{ matrix.python-version }}
cache: "pip"
- run: pip install -e ".[dev,binary]" "aiosqlite>=0.21.0,!=0.22.0"
- run: python scripts/install_ner_models.py
- run: pytest tests/ -v --tb=long --timeout=30
- uses: astral-sh/setup-uv@v5
# Seed pip into the venv: scripts/install_ner_models.py shells out to
# `sys.executable -m pip install <wheel URLs>`, and a uv-created venv
# has no pip otherwise. `uv sync` keeps the seeded pip, and the pip
# cache (setup-python `cache: pip`) keeps the model wheels warm.
- run: uv venv --seed --python ${{ matrix.python-version }}
- run: uv sync --locked --extra dev --extra binary --python ${{ matrix.python-version }}
- run: uv run python scripts/install_ner_models.py
- run: uv run pytest tests/ -v --tb=long --timeout=30 -n auto

coverage:
runs-on: ubuntu-latest
Expand All @@ -93,9 +100,11 @@ jobs:
with:
python-version: "3.12"
cache: "pip"
- run: pip install -e ".[dev,binary]" "aiosqlite>=0.21.0,!=0.22.0"
- run: python scripts/install_ner_models.py
- run: pytest tests/ --cov=features --cov=shared --cov=core --cov=rag --cov=wiki --cov=graph --cov=lifecycle --cov=hooks --cov=mcp_server --cov-report=xml --cov-report=term-missing --cov-fail-under=60 --timeout=60
- uses: astral-sh/setup-uv@v5
- run: uv venv --seed --python 3.12 # NER installer needs pip in the venv
- run: uv sync --locked --extra dev --extra binary --python 3.12
- run: uv run python scripts/install_ner_models.py
- run: uv run pytest tests/ -n auto --cov=features --cov=shared --cov=core --cov=rag --cov=wiki --cov=graph --cov=lifecycle --cov=hooks --cov=mcp_server --cov-report=xml --cov-report=term-missing --cov-fail-under=60 --timeout=60
- uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
Expand Down Expand Up @@ -136,6 +145,7 @@ jobs:
with:
python-version: "3.12"
cache: "pip"
- run: pip install -e ".[docs]"
- uses: astral-sh/setup-uv@v5
- run: uv sync --locked --extra docs --python 3.12
- name: Build docs (strict — fails on broken refs)
run: mkdocs build --strict
run: uv run mkdocs build --strict
2 changes: 1 addition & 1 deletion tests/test_features/test_source_time.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ async def get_layer(self, *a: Any, **k: Any) -> Any:
@pytest.mark.asyncio
@pytest.mark.parametrize(
("payload_ts", "expected"),
[(time.time() - 5 * 86400, "forwarded"), ("2026-09-18T07:03:00", "refused"), (None, "refused")],
[(1700000000.0, "forwarded"), ("2026-09-18T07:03:00", "refused"), (None, "refused")],
)
async def test_new_message_forwards_a_numeric_ts_and_refuses_anything_else(cm: Any, payload_ts: Any, expected: str, monkeypatch) -> None:
"""Hop 4: the daemon's `ts` reaches capture — if, and only if, it is a number.
Expand Down
13 changes: 9 additions & 4 deletions tests/test_s17_stage1_tail.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,13 +174,16 @@ async def test_distiller_similar_to_on_conflict() -> None:


@pytest.fixture
async def migrated_cm():
async def migrated_cm(tmp_path, monkeypatch):
"""Hermetic global DB + полная схема (l0_journal и co-таблицы живут миграциями)."""
from shared.connection import connection_manager
from shared.migrations import MigrationManager

monkeypatch.setattr(connection_manager, "base_dir", tmp_path) # патчим base_dir, не подменяем объект
connection_manager._conns.clear() # cached conns pin the old tmp dir
await MigrationManager(cm=connection_manager).migrate()
return connection_manager
yield connection_manager
connection_manager._conns.clear()


@pytest.mark.asyncio
Expand Down Expand Up @@ -231,11 +234,12 @@ async def test_zero_result_journal_and_miner(migrated_cm) -> None:

@pytest.mark.asyncio
async def test_zero_result_single_hit_not_surfaced(migrated_cm) -> None:
from lifecycle.graph_miners import log_zero_result, miner_zero_results
from lifecycle.graph_miners import ensure_zero_result, log_zero_result, miner_zero_results
from shared.constants import DB_NAME

cm = migrated_cm
conn = await cm.get(DB_NAME)
await ensure_zero_result(cm) # lazy-ensure таблица: без неё DELETE падает в герметичной БД
await conn.execute("DELETE FROM recall_zero_results") # сессионная БД: изолируем журнал
await conn.commit()
await log_zero_result(cm, "user", "s17zr2", "единичный провал запроса XYZ")
Expand All @@ -253,11 +257,12 @@ async def test_zero_result_miner_lets_a_failure_escape(migrated_cm, monkeypatch)
ноль — это работа, которая не нашлась, а сбой пусть ловит `graph_enrich`.
"""
from graph.epistemic import EpistemicGraph
from lifecycle.graph_miners import log_zero_result, miner_zero_results
from lifecycle.graph_miners import ensure_zero_result, log_zero_result, miner_zero_results
from shared.constants import DB_NAME

cm = migrated_cm
conn = await cm.get(DB_NAME)
await ensure_zero_result(cm) # lazy-ensure таблица: без неё DELETE падает в герметичной БД
await conn.execute("DELETE FROM recall_zero_results")
await conn.commit()
for _ in range(2):
Expand Down
Loading