aboutsummaryrefslogtreecommitdiff
path: root/.ai/scripts/tests/test_cross_agent_discover.py
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-05-06 21:59:52 -0500
committerCraig Jennings <c@cjennings.net>2026-05-06 21:59:52 -0500
commitd81b23ad6b6e437dfe3c338a00a4be39bc555146 (patch)
tree2d4b0d7890fd1fc70d81282b81fed2808c28a106 /.ai/scripts/tests/test_cross_agent_discover.py
parent201377f57430ef28d02e703a2191434bbee55c75 (diff)
downloadrulesets-d81b23ad6b6e437dfe3c338a00a4be39bc555146.tar.gz
rulesets-d81b23ad6b6e437dfe3c338a00a4be39bc555146.zip
chore(ai): initialize project notes and Claude tooling surfaces
Replace the seed notes.org with project-specific context (layout, install modes, task tracker location, recent inflection point). Bring in the synced template surfaces (protocols, workflows, scripts, references, retrospectives, someday-maybe) as tracked content for this content/documentation project.
Diffstat (limited to '.ai/scripts/tests/test_cross_agent_discover.py')
-rw-r--r--.ai/scripts/tests/test_cross_agent_discover.py204
1 files changed, 204 insertions, 0 deletions
diff --git a/.ai/scripts/tests/test_cross_agent_discover.py b/.ai/scripts/tests/test_cross_agent_discover.py
new file mode 100644
index 0000000..f0d2bb7
--- /dev/null
+++ b/.ai/scripts/tests/test_cross_agent_discover.py
@@ -0,0 +1,204 @@
+"""Tests for cross-agent-discover (TDD: tests written before implementation)."""
+
+from __future__ import annotations
+
+import json
+import os
+import subprocess
+import textwrap
+from pathlib import Path
+
+import pytest
+
+SCRIPT = Path(__file__).resolve().parent.parent / "cross-agent-comms" / "cross-agent-discover"
+
+
+def _run(args: list[str], env: dict | None = None) -> subprocess.CompletedProcess:
+ return subprocess.run([str(SCRIPT), *args], capture_output=True, text=True, env=env)
+
+
+@pytest.fixture
+def fake_home(tmp_path, monkeypatch):
+ home = tmp_path / "home"
+ home.mkdir()
+ monkeypatch.setenv("HOME", str(home))
+ return home
+
+
+def _make_project(home: Path, name: str) -> Path:
+ proj = home / "projects" / name
+ (proj / ".ai").mkdir(parents=True)
+ return proj
+
+
+def _write_peers_toml(home: Path, content: str) -> Path:
+ cfg = home / ".config" / "cross-agent-comms"
+ cfg.mkdir(parents=True, exist_ok=True)
+ peers = cfg / "peers.toml"
+ peers.write_text(content)
+ return peers
+
+
+def test_discover_help(fake_home):
+ result = _run(["--help"], env={**os.environ, "HOME": str(fake_home)})
+ assert result.returncode == 0
+ assert "discover" in result.stdout.lower() or "enumerate" in result.stdout.lower()
+
+
+def test_discover_local_only_no_projects(fake_home):
+ """Empty home → reports zero local projects, zero peers."""
+ result = _run(["--no-cache"], env={**os.environ, "HOME": str(fake_home)})
+ assert result.returncode == 0
+ # No crash; mentions local somehow.
+ assert "local" in result.stdout.lower() or "0 project" in result.stdout.lower()
+
+
+def test_discover_lists_local_projects(fake_home):
+ _make_project(fake_home, "homelab")
+ _make_project(fake_home, "career")
+ _make_project(fake_home, "claude-templates")
+ result = _run(["--no-cache"], env={**os.environ, "HOME": str(fake_home)})
+ assert result.returncode == 0
+ assert "homelab" in result.stdout
+ assert "career" in result.stdout
+ assert "claude-templates" in result.stdout
+
+
+def test_discover_excludes_dirs_without_ai_subdir(fake_home):
+ """Directories under ~/projects/ that lack .ai/ are NOT projects."""
+ _make_project(fake_home, "real-project")
+ (fake_home / "projects" / "not-a-project").mkdir(parents=True)
+ result = _run(["--no-cache"], env={**os.environ, "HOME": str(fake_home)})
+ assert result.returncode == 0
+ assert "real-project" in result.stdout
+ assert "not-a-project" not in result.stdout
+
+
+def test_discover_no_peers_toml_just_local(fake_home):
+ _make_project(fake_home, "homelab")
+ result = _run(["--no-cache"], env={**os.environ, "HOME": str(fake_home)})
+ assert result.returncode == 0
+ # No peers section since no toml.
+ assert "homelab" in result.stdout
+
+
+def test_discover_lists_peers_from_toml(fake_home):
+ _write_peers_toml(fake_home, textwrap.dedent("""\
+ [peers.velox]
+ host = "velox"
+ ssh_user = "cjennings"
+
+ [peers.bastion]
+ host = "bastion.local"
+ ssh_user = "cjennings"
+ """))
+ _make_project(fake_home, "homelab")
+ result = _run(["--no-cache"], env={**os.environ, "HOME": str(fake_home)})
+ assert result.returncode == 0
+ assert "velox" in result.stdout
+ assert "bastion" in result.stdout
+
+
+def test_discover_malformed_peers_toml_errors_clearly(fake_home):
+ _write_peers_toml(fake_home, "not valid toml at all = = =")
+ result = _run(["--no-cache"], env={**os.environ, "HOME": str(fake_home)})
+ assert result.returncode != 0
+ assert "peers.toml" in result.stderr or "TOML" in result.stderr or "parse" in result.stderr.lower()
+
+
+def test_discover_json_output_schema(fake_home):
+ _make_project(fake_home, "homelab")
+ _make_project(fake_home, "career")
+ _write_peers_toml(fake_home, textwrap.dedent("""\
+ [peers.velox]
+ host = "velox"
+ """))
+ result = _run(["--json", "--no-cache"], env={**os.environ, "HOME": str(fake_home)})
+ assert result.returncode == 0
+ payload = json.loads(result.stdout)
+ assert "local" in payload
+ assert "peers" in payload
+ assert isinstance(payload["local"], list)
+ assert isinstance(payload["peers"], list)
+ assert "homelab" in payload["local"]
+ assert "career" in payload["local"]
+ velox = next((p for p in payload["peers"] if p["name"] == "velox"), None)
+ assert velox is not None
+ # Reachability is a key — value depends on actual SSH state.
+ assert "reachable" in velox
+
+
+def test_discover_peer_scope(fake_home):
+ _write_peers_toml(fake_home, textwrap.dedent("""\
+ [peers.velox]
+ host = "velox"
+
+ [peers.bastion]
+ host = "bastion.local"
+ """))
+ result = _run(["--peer", "velox", "--no-cache", "--json"], env={**os.environ, "HOME": str(fake_home)})
+ assert result.returncode == 0
+ payload = json.loads(result.stdout)
+ peer_names = [p["name"] for p in payload["peers"]]
+ assert "velox" in peer_names
+ assert "bastion" not in peer_names
+
+
+def test_discover_unreachable_peer_marked(fake_home):
+ """A peer with a definitely-unreachable host gets reachable=False."""
+ _write_peers_toml(fake_home, textwrap.dedent("""\
+ [peers.bogus]
+ host = "definitely-not-a-real-host.invalid"
+ ssh_user = "nobody"
+ """))
+ result = _run(["--no-cache", "--json"], env={**os.environ, "HOME": str(fake_home)}, )
+ assert result.returncode == 0
+ payload = json.loads(result.stdout)
+ bogus = next((p for p in payload["peers"] if p["name"] == "bogus"), None)
+ assert bogus is not None
+ assert bogus["reachable"] is False
+
+
+def test_discover_cache_hit_within_window(fake_home):
+ """Second invocation within 5 min reads cache (skip the SSH probe)."""
+ _make_project(fake_home, "homelab")
+ # First call populates cache.
+ result1 = _run(["--json"], env={**os.environ, "HOME": str(fake_home)})
+ assert result1.returncode == 0
+ cache = fake_home / ".cache" / "cross-agent-comms" / "discovery.json"
+ assert cache.exists()
+ # Tamper with the cache to a marker only the cache path can produce.
+ payload = json.loads(cache.read_text())
+ payload["_test_marker"] = True
+ cache.write_text(json.dumps(payload))
+ # Second call (no --no-cache) should return the tampered payload.
+ result2 = _run(["--json"], env={**os.environ, "HOME": str(fake_home)})
+ assert result2.returncode == 0
+ payload2 = json.loads(result2.stdout)
+ assert payload2.get("_test_marker") is True
+
+
+def test_discover_no_cache_flag_bypasses(fake_home):
+ """--no-cache ignores even a fresh cache."""
+ _make_project(fake_home, "homelab")
+ cache_dir = fake_home / ".cache" / "cross-agent-comms"
+ cache_dir.mkdir(parents=True)
+ cache_dir.joinpath("discovery.json").write_text(json.dumps({
+ "_test_marker": True, "local": [], "peers": []
+ }))
+ result = _run(["--no-cache", "--json"], env={**os.environ, "HOME": str(fake_home)})
+ assert result.returncode == 0
+ payload = json.loads(result.stdout)
+ # Cache marker should NOT appear in fresh result.
+ assert payload.get("_test_marker") is None or payload.get("_test_marker") is False
+ assert "homelab" in payload["local"]
+
+
+def test_discover_halt_shows_banner(fake_home):
+ halt = fake_home / ".config" / "cross-agent-comms" / "HALT"
+ halt.parent.mkdir(parents=True)
+ halt.write_text("halted")
+ _make_project(fake_home, "homelab")
+ result = _run(["--no-cache"], env={**os.environ, "HOME": str(fake_home)})
+ assert result.returncode == 0 # discover continues to print under HALT
+ assert "HALT" in result.stdout