"""ORCH-026 Level B — blocked-task visibility (TC-B06). A dep-blocked task surfaces a waiting-line ("⏳ ждёт ORCH-NNN") in its single Telegram tracker card; the "one card per task" invariant is preserved (the line is added to the SAME render, not a new message). Render is never broken by the dependency lookup (never-raise). """ import os import tempfile import pytest os.environ["ORCH_DB_PATH"] = os.path.join(tempfile.gettempdir(), "test_orch026_visibility.db") os.environ.setdefault("ORCH_GITEA_TOKEN", "test-token") os.environ.setdefault("ORCH_PLANE_API_TOKEN", "test-token") import src.db as db # noqa: E402 from src.db import init_db, get_db # noqa: E402 from src import notifications # noqa: E402 @pytest.fixture(autouse=True) def fresh_db(tmp_path, monkeypatch): dbfile = tmp_path / "vis.db" monkeypatch.setattr(db.settings, "db_path", str(dbfile)) monkeypatch.setattr(db.settings, "task_deps_enabled", True, raising=False) init_db() yield def _make_task(work_item_id, stage="development"): conn = get_db() cur = conn.execute( "INSERT INTO tasks (plane_id, work_item_id, repo, branch, stage, title) " "VALUES (?, ?, ?, ?, ?, ?)", (work_item_id, work_item_id, "orchestrator", f"feature/{work_item_id}", stage, f"title {work_item_id}"), ) tid = cur.lastrowid conn.commit() conn.close() return tid def test_blocked_task_shows_waiting_line(): a = _make_task("ORCH-90", stage="development") b = _make_task("ORCH-91", stage="development") db.add_dependency(b, a) text = notifications.render_task_tracker(b) assert "ждёт" in text assert "ORCH-90" in text def test_ready_task_has_no_waiting_line(): a = _make_task("ORCH-92", stage="done") b = _make_task("ORCH-93", stage="development") db.add_dependency(b, a) text = notifications.render_task_tracker(b) assert "ждёт" not in text def test_done_task_has_no_waiting_line(): a = _make_task("ORCH-94", stage="development") b = _make_task("ORCH-95", stage="done") db.add_dependency(b, a) text = notifications.render_task_tracker(b) # A done task is terminal -> the waiting-line branch is skipped entirely. assert "ждёт" not in text def test_render_never_raises_on_dep_error(monkeypatch): b = _make_task("ORCH-96", stage="development") from src import task_deps monkeypatch.setattr(task_deps, "is_task_ready", lambda tid: (_ for _ in ()).throw(RuntimeError("boom")), raising=False) # Must still produce a card (no crash). text = notifications.render_task_tracker(b) assert "ORCH-96" in text