diff --git a/tests/test_activity_classify.py b/tests/test_activity_classify.py new file mode 100644 index 0000000..dd6f091 --- /dev/null +++ b/tests/test_activity_classify.py @@ -0,0 +1,152 @@ +"""Tests for diagnostics/activity_endpoint.py classify_pr_operation. + +Covers the Leo gotcha — extract/* branches with commit_type=enrich or +challenge classify by commit_type, not branch prefix. Same class of bug +as the contributor-role wiring fix. +""" + +import sys +from pathlib import Path + +import pytest + +# diagnostics/ isn't on sys.path by default; add it for these tests. +_DIAG = Path(__file__).resolve().parents[1] / "diagnostics" +if str(_DIAG) not in sys.path: + sys.path.insert(0, str(_DIAG)) + +# aiohttp is imported at module load time; skip cleanly if not installed. +pytest.importorskip("aiohttp") + +from activity_endpoint import classify_pr_operation # noqa: E402 + + +# ─── Merged PRs: commit_type wins over branch prefix ─────────────────────── + + +def test_extract_branch_legacy_knowledge_classifies_new(): + assert classify_pr_operation("merged", "knowledge", "extract/foo", None) == "new" + + +def test_extract_branch_with_enrich_commit_type_classifies_enrich(): + """Leo gotcha: extract/* + commit_type=enrich → enrich, not new.""" + assert classify_pr_operation("merged", "enrich", "extract/foo", None) == "enrich" + + +def test_extract_branch_with_challenge_commit_type_classifies_challenge(): + """Leo gotcha: extract/* + commit_type=challenge → challenge, not new.""" + assert classify_pr_operation("merged", "challenge", "extract/foo", None) == "challenge" + + +def test_challenged_by_in_description_classifies_challenge(): + assert ( + classify_pr_operation( + "merged", "knowledge", "extract/foo", "evidence for challenged_by claim" + ) + == "challenge" + ) + + +# ─── Branch prefix fallback (when commit_type is generic) ────────────────── + + +def test_reweave_branch_classifies_enrich(): + assert classify_pr_operation("merged", "knowledge", "reweave/batch-1", None) == "enrich" + + +def test_challenge_branch_classifies_challenge(): + assert ( + classify_pr_operation("merged", "knowledge", "challenge/nuclear-moloch", None) + == "challenge" + ) + + +# ─── Maintenance commit_types → infra ────────────────────────────────────── + + +def test_fix_commit_type_classifies_infra(): + assert classify_pr_operation("merged", "fix", "fix/deploy-bug", None) == "infra" + + +def test_pipeline_commit_type_classifies_infra(): + assert ( + classify_pr_operation("merged", "pipeline", "epimetheus/migration-v14", None) + == "infra" + ) + + +# ─── Knowledge-producing commit_types → new ──────────────────────────────── + + +def test_research_commit_type_classifies_new(): + assert ( + classify_pr_operation("merged", "research", "theseus/cornelius-batch-2", None) + == "new" + ) + + +def test_entity_commit_type_classifies_new(): + assert classify_pr_operation("merged", "entity", "leo/entities-update", None) == "new" + + +# ─── Non-merged statuses route through NON_MERGED_STATUS_TO_OPERATION ────── + + +def test_open_pr_classifies_extract(): + assert classify_pr_operation("open", None, "extract/foo", None) == "extract" + + +def test_approved_pr_classifies_new(): + assert classify_pr_operation("approved", None, "extract/foo", None) == "new" + + +def test_closed_pr_classifies_infra(): + assert classify_pr_operation("closed", None, "extract/foo", None) == "infra" + + +def test_conflict_pr_classifies_challenge(): + assert classify_pr_operation("conflict", None, "extract/foo", None) == "challenge" + + +def test_validating_pr_classifies_extract(): + assert classify_pr_operation("validating", None, "extract/foo", None) == "extract" + + +def test_reviewing_pr_classifies_extract(): + assert classify_pr_operation("reviewing", None, "extract/foo", None) == "extract" + + +def test_merging_pr_classifies_new(): + assert classify_pr_operation("merging", None, "extract/foo", None) == "new" + + +def test_zombie_pr_classifies_infra(): + assert classify_pr_operation("zombie", None, "extract/foo", None) == "infra" + + +# ─── Priority order: reweave commit_type vs reweave/ branch ───────────────── +# Reweave commit_type is in _MAINTENANCE_COMMIT_TYPES (→ infra), but +# branch.startswith('reweave/') is checked first (→ enrich). The bifurcation +# is real spec behavior — nightly reweave PRs must classify as enrich, not +# infra. Locking this in prevents a silent flip on future priority refactors. + + +def test_reweave_commit_type_with_reweave_branch_classifies_enrich(): + """Branch prefix wins over maintenance — reweave PRs are enrich, not infra.""" + assert classify_pr_operation("merged", "reweave", "reweave/batch-1", None) == "enrich" + + +def test_reweave_commit_type_without_reweave_branch_classifies_infra(): + """Without reweave/ prefix, reweave commit_type falls to maintenance → infra.""" + assert classify_pr_operation("merged", "reweave", "epimetheus/foo", None) == "infra" + + +# ─── Defensive cases — null/empty inputs shouldn't crash ─────────────────── + + +def test_null_commit_type_and_branch_classifies_new(): + assert classify_pr_operation("merged", None, None, None) == "new" + + +def test_unknown_status_falls_back_to_infra(): + assert classify_pr_operation("nonsense", None, None, None) == "infra"