Added Discovery UI

This commit is contained in:
2026-04-26 16:13:53 +02:00
parent 924efe67dc
commit e1139a89f1
3 changed files with 475 additions and 4 deletions

View File

@@ -1129,6 +1129,162 @@ def test_ui_manual_registry_entry_loop(tmp_path):
app.dependency_overrides.clear()
def test_ui_discovery_compare_gap_and_export(tmp_path):
def override_settings():
return Settings(
database_path=str(tmp_path / "ui-discovery.sqlite3"),
checkout_root=str(tmp_path / "ui-discovery-checkouts"),
)
app.dependency_overrides[get_settings] = override_settings
client = TestClient(app)
try:
first = client.post(
"/repos",
json={
"name": "MailRouter",
"url": "https://example.com/mail-router-ui.git",
"description": "Routes customer email.",
},
).json()
second = client.post(
"/repos",
json={
"name": "SupportRouter",
"url": "https://example.com/support-router-ui.git",
"description": "Routes support requests.",
},
).json()
empty = client.post(
"/repos",
json={
"name": "EmptyProfile",
"url": "https://example.com/empty-profile-ui.git",
"description": "No approved entries yet.",
},
).json()
first_ability = client.post(
f"/repos/{first['id']}/abilities",
json={
"name": "Business Email Routing",
"description": "Route inbound messages.",
"confidence": 0.9,
},
).json()["id"]
first_capability = client.post(
f"/repos/{first['id']}/capabilities",
json={
"ability_id": first_ability,
"name": "Classify Incoming Email",
"description": "Classify messages by intent.",
"confidence": 0.8,
},
).json()["id"]
client.post(
f"/repos/{first['id']}/evidence",
json={
"capability_id": first_capability,
"type": "unit_test",
"reference": "tests/test_classify.py",
"strength": "strong",
},
)
client.post(
f"/repos/{first['id']}/capabilities",
json={
"ability_id": first_ability,
"name": "Route Email to Team",
"description": "Route messages to owning teams.",
},
)
second_ability = client.post(
f"/repos/{second['id']}/abilities",
json={
"name": "Business Email Routing",
"description": "Support routing workflows.",
"confidence": 0.7,
},
).json()["id"]
second_capability = client.post(
f"/repos/{second['id']}/capabilities",
json={
"ability_id": second_ability,
"name": "Classify Incoming Email",
"description": "Classify support requests.",
"confidence": 0.6,
},
).json()["id"]
client.post(
f"/repos/{second['id']}/evidence",
json={
"capability_id": second_capability,
"type": "documentation",
"reference": "README.md",
"strength": "medium",
},
)
client.post(
f"/repos/{second['id']}/capabilities",
json={
"ability_id": second_ability,
"name": "Archive Email",
"description": "Archive resolved messages.",
},
)
discovery = client.get("/ui/discovery")
assert discovery.status_code == 200
assert "Compare Repositories" in discovery.text
assert "Capability Gap Report" in discovery.text
assert "EmptyProfile" in discovery.text
assert "No approved profile" in discovery.text
comparison = client.get(
"/ui/discovery/compare",
params=[
("repository_ids", first["id"]),
("repository_ids", second["id"]),
],
)
assert comparison.status_code == 200
assert "Repository Comparison" in comparison.text
assert "Business Email Routing" in comparison.text
assert "Route Email to Team" in comparison.text
assert "Archive Email" in comparison.text
gaps = client.post(
"/ui/discovery/gaps",
data={
"desired_ability": "Business Email Routing",
"desired_capabilities": (
"Classify Incoming Email\n"
"Route Email to Team\n"
"German Benchmark Evaluation"
),
"repository_ids": [str(first["id"]), str(second["id"])],
},
)
assert gaps.status_code == 200
assert "Capability Gap Report" in gaps.text
assert "German Benchmark Evaluation" in gaps.text
assert "Weak Evidence" in gaps.text
assert "Duplicates" in gaps.text
detail = client.get(f"/ui/repos/{first['id']}")
assert detail.status_code == 200
assert f'/ui/repos/{first["id"]}/export' in detail.text
export = client.get(f"/ui/repos/{first['id']}/export")
assert export.status_code == 200
assert export.headers["content-type"].startswith("application/x-yaml")
assert 'name: "MailRouter"' in export.text
assert 'name: "Classify Incoming Email"' in export.text
finally:
app.dependency_overrides.clear()
def test_api_rejects_candidate_capability_feature_and_evidence(tmp_path):
source = tmp_path / "repo"
source.mkdir()