generated from coulomb/repo-seed
Some checks failed
ci / validate-registry (push) Has been cancelled
llm-connect came up locally (mock provider, 127.0.0.1:8080), unblocking this task. reuse_surface/plan_check.py: build_rerank_prompt/request_rerank/apply_rerank, reusing llm_bridge.execute_prompt/extract_json_object (same pattern as maintain_llm.py's request_maintain_patches). New schema schemas/plan-check-rerank.schema.json rejects malformed responses (missing fields, non-JSON, invented candidate ids outside the input set) rather than guessing. Per design principle 3 (deterministic matches always rank first), apply_rerank appends LLM-scored entries after the deterministic list (kind: 'llm') instead of reordering it -- the trusted base result is identical with or without the rerank pass. Graceful skip via a 'notes' field when LLM_CONNECT_URL is unset or the response is malformed, mirroring maintain.py's no_llm/skip pattern. New --llm-url/--no-llm CLI flags. Also extended plan-check-result.schema.json for 'notes' and the (pre-existing, previously unschema'd) 'filed_capability_request' field. 9 new pytest cases; 89 total pass. Live-verified against the running llm-connect instance: it correctly rejected the mock provider's non-JSON response and surfaced the skip note, with the deterministic verdict and match order completely unaffected. REUSE-WP-0018 is now fully done (T01-T06). Updated docs/IntentScopeGapAnalysis.md priority 29 to Closed and the workplan's own frontmatter status to finished. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
352 lines
12 KiB
Python
352 lines
12 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
|
|
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_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, "2026-07-06"),
|
|
)
|
|
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_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, "2026-07-06"),
|
|
)
|
|
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, "2026-07-06"),
|
|
)
|
|
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"
|