reuse-surface/tests/test_plan_check.py
tegwick 0c6b1e2538 Harden federated compose against malformed member indexes (REUSE-WP-0020)
Repointing the production hub's 50 Gitea-hosted federation sources to Forgejo
ahead of the 2026-08-31 CoulombCore retirement took /v1/federated to HTTP 500.
One member index (evidence-binder) has capability rows with no `id`, and
compose_federated_index dereferenced item["id"] unguarded. Its Gitea copy was a
stale snapshot returning a non-mapping, so those rows had never been parsed.

A single malformed member index must not take down the whole endpoint. Extract
_read_index_entries(): unparseable YAML, a non-mapping body, an empty file, and
a non-list `capabilities` each degrade to a warning and an empty row list, and
rows without an `id` are skipped individually. A failed source stays listed with
count 0 so it remains visible to operators rather than silently disappearing.

Also fix wall-clock rot in tests/test_plan_check.py, which was already failing
at clean HEAD: three tests pinned the compose date to a literal that has now
aged past STALE_DAYS.

Add workplan REUSE-WP-0020 covering the full cutover.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 00:04:39 +02:00

499 lines
18 KiB
Python

from __future__ import annotations
import json
from datetime import datetime, timedelta, timezone
from reuse_surface.plan_check import STALE_DAYS
def _recent_date() -> str:
"""A compose date that is always inside the staleness window.
A hardcoded literal here made the test rot: it passed when written and
began failing once wall-clock time drifted past STALE_DAYS.
"""
fresh = datetime.now(timezone.utc) - timedelta(days=max(STALE_DAYS - 1, 0))
return fresh.strftime("%Y-%m-%d")
from reuse_surface.plan_check import (
Match,
MatchQuery,
apply_rerank,
load_query_from_intent,
load_query_from_workplan,
maybe_file_capability_request,
match_query,
record_manual_reuse_event,
record_outcome,
request_rerank,
run_plan_check,
verdict_for_score,
)
SAMPLE_CAPABILITIES = [
{
"id": "capability.infotech.issue-tracking",
"name": "Universal Issue Tracking Coordination",
"summary": "Unified interface for issue tracking coordination across Gitea, GitHub, GitLab.",
"vector": "D4 / A2 / C2 / R1",
"owner": "issue-core",
"tags": ["issue-tracking", "coordination"],
},
{
"id": "capability.audit.event-retain",
"name": "Audit Event Retention",
"summary": "Collect, normalize, retain, and search audit events with integrity evidence across tenants.",
"vector": "D4 / A2 / C2 / R1",
"owner": "audit-core",
"tags": ["audit"],
},
]
def test_verdict_thresholds():
assert verdict_for_score(0.5) == "reuse"
assert verdict_for_score(0.3) == "extend"
assert verdict_for_score(0.1) == "new"
assert verdict_for_score(0.45) == "reuse"
assert verdict_for_score(0.22) == "extend"
def test_match_query_finds_close_match():
query = load_query_from_intent(
"unified issue tracking coordination across Gitea GitHub GitLab"
)
matches = match_query(query, SAMPLE_CAPABILITIES)
assert matches
assert matches[0].id == "capability.infotech.issue-tracking"
assert matches[0].score > 0.3
def test_match_query_empty_when_no_overlap():
query = load_query_from_intent("something entirely unrelated xyzzy plugh")
matches = match_query(query, SAMPLE_CAPABILITIES)
assert matches == []
def test_match_query_no_capabilities():
query = load_query_from_intent("anything")
assert match_query(query, []) == []
def test_load_query_from_workplan(tmp_path):
workplan = tmp_path / "TEST-WP-0001-thing.md"
workplan.write_text(
"""---
id: TEST-WP-0001
title: "Unified issue tracking coordination"
status: proposed
---
# Unified issue tracking coordination
## Core Idea
Build a single interface for issue tracking across Gitea, GitHub, and GitLab.
"""
)
query = load_query_from_workplan(workplan)
assert query.source == "workplan"
assert query.workplan_id == "TEST-WP-0001"
assert "issue tracking" in query.text.lower()
matches = match_query(query, SAMPLE_CAPABILITIES)
assert matches[0].id == "capability.infotech.issue-tracking"
def test_run_plan_check_reuse_verdict(monkeypatch):
monkeypatch.setattr(
"reuse_surface.plan_check.load_federated_capabilities",
lambda: (SAMPLE_CAPABILITIES, _recent_date()),
)
query = MatchQuery(
source="intent",
text="unified issue tracking coordination gitea github gitlab",
tokens={"unified", "issue", "tracking", "coordination", "gitea", "github", "gitlab"},
)
result = run_plan_check(query)
assert result["verdict"] == "reuse"
assert result["matches"][0]["id"] == "capability.infotech.issue-tracking"
assert result["federated_index_stale_warning"] is None
def test_run_plan_check_stale_warning(monkeypatch):
monkeypatch.setattr(
"reuse_surface.plan_check.load_federated_capabilities",
lambda: (SAMPLE_CAPABILITIES, "2020-01-01"),
)
query = load_query_from_intent("nothing matches this at all zzz")
result = run_plan_check(query)
assert result["verdict"] == "new"
assert "days old" in result["federated_index_stale_warning"]
def test_record_outcome_appends_jsonl(tmp_path, monkeypatch):
telemetry_path = tmp_path / "plan-check-events.jsonl"
monkeypatch.setattr("reuse_surface.plan_check.TELEMETRY_PATH", telemetry_path)
result = {
"verdict": "reuse",
"matches": [{"id": "capability.infotech.issue-tracking"}],
}
record_outcome(result, "reused", consumer_repo="some-repo")
lines = telemetry_path.read_text().splitlines()
assert len(lines) == 1
event = json.loads(lines[0])
assert event["consumer_repo"] == "some-repo"
assert event["capability_id"] == "capability.infotech.issue-tracking"
assert event["outcome"] == "reused"
assert event["source"] == "plan-check"
def test_record_outcome_posts_to_hub_when_reachable(tmp_path, monkeypatch):
telemetry_path = tmp_path / "plan-check-events.jsonl"
monkeypatch.setattr("reuse_surface.plan_check.TELEMETRY_PATH", telemetry_path)
monkeypatch.setattr(
"reuse_surface.hub_client.hub_record_reuse_event",
lambda event, base_url=None: (201, event),
)
result = {"verdict": "reuse", "matches": [{"id": "capability.infotech.issue-tracking"}]}
recorded = record_outcome(result, "reused", consumer_repo="some-repo")
assert recorded["recorded_to"] == "hub"
assert not telemetry_path.exists()
def test_record_outcome_falls_back_when_hub_rejects(tmp_path, monkeypatch):
telemetry_path = tmp_path / "plan-check-events.jsonl"
monkeypatch.setattr("reuse_surface.plan_check.TELEMETRY_PATH", telemetry_path)
monkeypatch.setattr(
"reuse_surface.hub_client.hub_record_reuse_event",
lambda event, base_url=None: (500, {"error": "boom"}),
)
result = {"verdict": "reuse", "matches": [{"id": "capability.infotech.issue-tracking"}]}
recorded = record_outcome(result, "reused", consumer_repo="some-repo")
assert recorded["recorded_to"] == "local"
assert telemetry_path.exists()
def test_record_outcome_falls_back_when_hub_unconfigured(tmp_path, monkeypatch):
monkeypatch.delenv("REUSE_SURFACE_URL", raising=False)
telemetry_path = tmp_path / "plan-check-events.jsonl"
monkeypatch.setattr("reuse_surface.plan_check.TELEMETRY_PATH", telemetry_path)
result = {"verdict": "reuse", "matches": [{"id": "capability.infotech.issue-tracking"}]}
recorded = record_outcome(result, "reused", consumer_repo="some-repo")
assert recorded["recorded_to"] == "local"
def test_record_manual_reuse_event_local_fallback(tmp_path, monkeypatch):
monkeypatch.delenv("REUSE_SURFACE_URL", raising=False)
telemetry_path = tmp_path / "plan-check-events.jsonl"
monkeypatch.setattr("reuse_surface.plan_check.TELEMETRY_PATH", telemetry_path)
recorded = record_manual_reuse_event(
consumer_repo="some-repo",
capability_id="capability.infotech.issue-tracking",
verdict="reuse",
outcome="reused",
)
assert recorded["recorded_to"] == "local"
event = json.loads(telemetry_path.read_text().splitlines()[0])
assert event["source"] == "manual"
assert event["consumer_repo"] == "some-repo"
def test_record_manual_reuse_event_posts_to_hub(tmp_path, monkeypatch):
telemetry_path = tmp_path / "plan-check-events.jsonl"
monkeypatch.setattr("reuse_surface.plan_check.TELEMETRY_PATH", telemetry_path)
monkeypatch.setattr(
"reuse_surface.hub_client.hub_record_reuse_event",
lambda event, base_url=None: (201, event),
)
recorded = record_manual_reuse_event(
consumer_repo="some-repo", capability_id=None, verdict="new", outcome="new",
)
assert recorded["recorded_to"] == "hub"
assert recorded["event"]["source"] == "manual"
assert recorded["event"]["capability_id"] is None
def test_record_manual_reuse_event_rejects_invalid_verdict(monkeypatch):
monkeypatch.delenv("REUSE_SURFACE_URL", raising=False)
try:
record_manual_reuse_event(
consumer_repo="some-repo", capability_id=None, verdict="not-a-verdict",
)
assert False, "expected ValueError"
except ValueError as exc:
assert "schema validation failed" in str(exc)
def test_maybe_file_capability_request_only_on_new_verdict(monkeypatch):
called = []
monkeypatch.setattr(
"reuse_surface.plan_check.file_capability_request",
lambda **kwargs: called.append(kwargs) or {"id": "req-1"},
)
reuse_result = {"verdict": "reuse", "query": {"text": "x", "workplan_id": None}}
assert maybe_file_capability_request(
reuse_result, requesting_domain="infotech", requesting_agent="a"
) is None
assert called == []
new_result = {"verdict": "new", "query": {"text": "some new intent", "workplan_id": None}}
filed = maybe_file_capability_request(
new_result, requesting_domain="infotech", requesting_agent="a"
)
assert filed == {"id": "req-1"}
assert called[0]["requesting_domain"] == "infotech"
def test_cmd_plan_check_file_request_flag(monkeypatch):
from reuse_surface.cli import main
monkeypatch.setattr(
"reuse_surface.plan_check.load_federated_capabilities",
lambda: (SAMPLE_CAPABILITIES, _recent_date()),
)
filed_calls = []
monkeypatch.setattr(
"reuse_surface.cli.maybe_file_capability_request",
lambda result, **kwargs: filed_calls.append(kwargs) or {"id": "req-9"},
)
exit_code = main(
["plan-check", "--intent", "totally unrelated xyzzy plugh", "--file-request"]
)
assert exit_code == 0
assert filed_calls
def test_cmd_plan_check_intent_json(monkeypatch):
from reuse_surface.cli import main
monkeypatch.setattr(
"reuse_surface.plan_check.load_federated_capabilities",
lambda: (SAMPLE_CAPABILITIES, _recent_date()),
)
exit_code = main(
["plan-check", "--intent", "issue tracking gitea github gitlab", "--format", "json"]
)
assert exit_code == 0
def test_cmd_plan_check_requires_input():
from reuse_surface.cli import main
exit_code = main(["plan-check"])
assert exit_code == 1
def test_cmd_plan_check_rejects_both_inputs(tmp_path):
from reuse_surface.cli import main
workplan = tmp_path / "x.md"
workplan.write_text("---\nid: X\n---\nbody")
exit_code = main(["plan-check", str(workplan), "--intent", "also this"])
assert exit_code == 1
# --- T03: LLM rerank ---
SAMPLE_MATCHES = [
Match(
id="capability.infotech.issue-tracking",
score=0.36,
kind="deterministic",
vector="D4 / A2 / C2 / R1",
owner="issue-core",
summary="Unified interface for issue tracking.",
),
Match(
id="capability.audit.event-retain",
score=0.12,
kind="deterministic",
vector="D4 / A2 / C2 / R1",
owner="audit-core",
summary="Collect and retain audit events.",
),
]
def test_request_rerank_valid_response(monkeypatch):
monkeypatch.setattr(
"reuse_surface.plan_check.execute_prompt",
lambda prompt, **kwargs: json.dumps(
{
"candidates": [
{"id": "capability.infotech.issue-tracking", "confidence": 0.9, "rationale": "strong match"},
{"id": "capability.audit.event-retain", "confidence": 0.1, "rationale": "unrelated"},
]
}
),
)
query = load_query_from_intent("issue tracking across platforms")
result = request_rerank(query, SAMPLE_MATCHES)
assert len(result) == 2
assert result[0]["confidence"] == 0.9
def test_request_rerank_rejects_malformed_response(monkeypatch):
monkeypatch.setattr(
"reuse_surface.plan_check.execute_prompt",
lambda prompt, **kwargs: json.dumps({"candidates": [{"id": "capability.infotech.issue-tracking"}]}),
)
query = load_query_from_intent("issue tracking across platforms")
try:
request_rerank(query, SAMPLE_MATCHES)
assert False, "expected ValueError for missing confidence field"
except ValueError as exc:
assert "schema validation failed" in str(exc)
def test_request_rerank_rejects_non_json_response(monkeypatch):
monkeypatch.setattr(
"reuse_surface.plan_check.execute_prompt",
lambda prompt, **kwargs: "not json at all",
)
query = load_query_from_intent("issue tracking across platforms")
try:
request_rerank(query, SAMPLE_MATCHES)
assert False, "expected ValueError for non-JSON response"
except ValueError:
pass
def test_request_rerank_ignores_invented_ids(monkeypatch):
monkeypatch.setattr(
"reuse_surface.plan_check.execute_prompt",
lambda prompt, **kwargs: json.dumps(
{
"candidates": [
{"id": "capability.infotech.issue-tracking", "confidence": 0.8},
{"id": "capability.madeup.not-real", "confidence": 0.99},
]
}
),
)
query = load_query_from_intent("issue tracking across platforms")
result = request_rerank(query, SAMPLE_MATCHES)
assert [c["id"] for c in result] == ["capability.infotech.issue-tracking"]
def test_apply_rerank_appends_after_deterministic_matches():
rerank_result = [
{"id": "capability.audit.event-retain", "confidence": 0.95, "rationale": "actually a great fit"},
]
combined = apply_rerank(SAMPLE_MATCHES, rerank_result)
# Deterministic matches keep their original order and scores untouched.
assert combined[0].id == "capability.infotech.issue-tracking"
assert combined[0].score == 0.36
assert combined[0].kind == "deterministic"
assert combined[1].id == "capability.audit.event-retain"
assert combined[1].score == 0.12
assert combined[1].kind == "deterministic"
# LLM entry is appended after, separately labeled.
assert combined[2].id == "capability.audit.event-retain"
assert combined[2].score == 0.95
assert combined[2].kind == "llm"
def test_run_plan_check_skips_llm_gracefully_when_unset(monkeypatch):
monkeypatch.setattr(
"reuse_surface.plan_check.load_federated_capabilities",
lambda: (SAMPLE_CAPABILITIES, "2026-07-07"),
)
monkeypatch.delenv("LLM_CONNECT_URL", raising=False)
query = load_query_from_intent("issue tracking gitea github gitlab")
result = run_plan_check(query)
assert result["verdict"] in {"reuse", "extend"}
assert any("LLM_CONNECT_URL not set" in n for n in result.get("notes", []))
assert all(m["kind"] == "deterministic" for m in result["matches"])
def test_run_plan_check_no_llm_flag_skips_without_attempting(monkeypatch):
called = []
monkeypatch.setattr(
"reuse_surface.plan_check.load_federated_capabilities",
lambda: (SAMPLE_CAPABILITIES, "2026-07-07"),
)
monkeypatch.setattr(
"reuse_surface.plan_check.request_rerank",
lambda *a, **k: called.append(1) or [],
)
query = load_query_from_intent("issue tracking gitea github gitlab")
run_plan_check(query, use_llm=False)
assert called == []
def test_run_plan_check_integrates_successful_rerank(monkeypatch):
monkeypatch.setattr(
"reuse_surface.plan_check.load_federated_capabilities",
lambda: (SAMPLE_CAPABILITIES, "2026-07-07"),
)
monkeypatch.setattr(
"reuse_surface.plan_check.execute_prompt",
lambda prompt, **kwargs: json.dumps(
{"candidates": [{"id": "capability.infotech.issue-tracking", "confidence": 0.77}]}
),
)
query = load_query_from_intent("issue tracking gitea github gitlab")
result = run_plan_check(query)
assert "notes" not in result or not result["notes"]
llm_entries = [m for m in result["matches"] if m["kind"] == "llm"]
assert len(llm_entries) == 1
assert llm_entries[0]["score"] == 0.77
# deterministic top match is still first and unaffected
assert result["matches"][0]["kind"] == "deterministic"
def test_cmd_record_reuse_cli_local_fallback(tmp_path, monkeypatch, capsys):
from reuse_surface.cli import main
monkeypatch.delenv("REUSE_SURFACE_URL", raising=False)
telemetry_path = tmp_path / "plan-check-events.jsonl"
monkeypatch.setattr("reuse_surface.plan_check.TELEMETRY_PATH", telemetry_path)
exit_code = main([
"record-reuse",
"--consumer-repo", "some-repo",
"--capability-id", "capability.infotech.issue-tracking",
"--verdict", "reuse",
"--outcome", "reused",
])
assert exit_code == 0
out = capsys.readouterr().out
assert "local" in out
event = json.loads(telemetry_path.read_text().splitlines()[0])
assert event["consumer_repo"] == "some-repo"
assert event["source"] == "manual"
def test_cmd_record_reuse_cli_rejects_invalid_verdict():
import pytest
from reuse_surface.cli import main
with pytest.raises(SystemExit) as exc_info:
main([
"record-reuse",
"--consumer-repo", "some-repo",
"--verdict", "not-a-verdict",
])
assert exc_info.value.code == 2 # argparse choices rejection
def test_cmd_record_reuse_cli_json_format(tmp_path, monkeypatch, capsys):
from reuse_surface.cli import main
monkeypatch.delenv("REUSE_SURFACE_URL", raising=False)
telemetry_path = tmp_path / "plan-check-events.jsonl"
monkeypatch.setattr("reuse_surface.plan_check.TELEMETRY_PATH", telemetry_path)
exit_code = main([
"record-reuse",
"--consumer-repo", "some-repo",
"--verdict", "new",
"--format", "json",
])
assert exit_code == 0
out = capsys.readouterr().out
payload = json.loads(out)
assert payload["recorded_to"] == "local"
assert payload["event"]["capability_id"] is None