"""Demand-weighted suggestion backlog tests (STATE-WP-0061).""" from __future__ import annotations import pytest from tests.conftest import create_test_repo, create_test_workplan from tests.test_capability_requests import _create_domain, _create_topic async def _create_suggestion(client, **kwargs): payload = { "domain": "custodian", "title": "Issue-core ingestion API key path", "description": "OpenBao KV path for issue-core ingestion", "origin_ref": "issue-core-ingestion-api-key", "base_value": 4.0, "job_size": 2.0, } payload.update(kwargs) r = await client.post("/suggestions/", json=payload) assert r.status_code == 201, r.text return r.json() @pytest.mark.asyncio async def test_create_list_and_wsjf_ranking(client): await _create_domain(client, "custodian", "Custodian") low = await _create_suggestion( client, title="Low priority path", origin_ref="low-priority", base_value=1.0, job_size=5.0, ) high = await _create_suggestion( client, title="High priority path", origin_ref="high-priority", base_value=5.0, job_size=1.0, ) r = await client.get("/suggestions/?rank=wsjf") assert r.status_code == 200 ranked = r.json() assert ranked[0]["id"] == high["id"] assert ranked[0]["wsjf"] > ranked[1]["wsjf"] await client.post( f"/suggestions/{low['id']}/bump-relevance", json={"reason": "hit again", "author": "agent-a"}, ) await client.post( f"/suggestions/{low['id']}/bump-relevance", json={"reason": "hit again", "author": "agent-b"}, ) r2 = await client.get(f"/suggestions/{low['id']}") assert r2.json()["relevance"] == 2 @pytest.mark.asyncio async def test_bump_relevance_debounces_duplicate_explicit_bumps(client): await _create_domain(client, "custodian", "Custodian") suggestion = await _create_suggestion(client) first = await client.post( f"/suggestions/{suggestion['id']}/bump-relevance", json={"reason": "routing gap", "author": "codex"}, ) second = await client.post( f"/suggestions/{suggestion['id']}/bump-relevance", json={"reason": "routing gap", "author": "codex"}, ) assert first.status_code == 200 assert second.status_code == 200 refreshed = await client.get(f"/suggestions/{suggestion['id']}") assert refreshed.json()["relevance"] == 1 @pytest.mark.asyncio async def test_vet_decline_and_promote_flow(client): await _create_domain(client, "custodian", "Custodian") topic = await _create_topic(client, "custodian") repo = await create_test_repo(client, domain_slug="custodian", slug="state-hub") workplan = await create_test_workplan( client, repo_id=repo["id"], topic_id=topic["id"], slug="state-wp-0061", title="WP-0061", ) suggestion = await _create_suggestion( client, workplan_id=workplan["id"], title="Promotable gated need", origin_ref="promote-me", ) vet = await client.post( f"/suggestions/{suggestion['id']}/vet", json={"note": "Vetted as requirement", "author": "codex"}, ) assert vet.status_code == 200 assert vet.json()["stage"] == "requirement" bad_promote = await client.post( f"/suggestions/{suggestion['id']}/promote", json={"note": "too early"}, ) assert bad_promote.status_code == 200 promoted = bad_promote.json() assert promoted["stage"] == "promoted" assert promoted["promoted_task_id"] is not None task = await client.get(f"/tasks/{promoted['promoted_task_id']}") assert task.status_code == 200 assert task.json()["title"] == "Promotable gated need" fresh = await _create_suggestion(client, title="Decline me", origin_ref="decline-me") declined = await client.post( f"/suggestions/{fresh['id']}/decline", json={"note": "Not needed", "author": "codex"}, ) assert declined.status_code == 200 assert declined.json()["stage"] == "declined" illegal = await client.post( f"/suggestions/{fresh['id']}/vet", json={"note": "too late"}, ) assert illegal.status_code == 409 @pytest.mark.asyncio async def test_next_steps_surfaces_and_bumps_suggestions(client): await _create_domain(client, "custodian", "Custodian") await _create_suggestion(client, title="Surfaced need", origin_ref="surfaced-need") before = await client.get("/suggestions/?origin_ref=surfaced-need") # no filter by origin_ref on list - get all and find all_items = await client.get("/suggestions/") item = next(i for i in all_items.json() if i["origin_ref"] == "surfaced-need") assert item["relevance"] == 0 steps = await client.get("/state/next_steps") assert steps.status_code == 200 payload = steps.json() assert any(s["type"] == "open_suggestion" for s in payload) after = await client.get(f"/suggestions/{item['id']}") assert after.json()["relevance"] >= 1 @pytest.mark.asyncio async def test_summary_includes_ranked_suggestions(client): await _create_domain(client, "custodian", "Custodian") await _create_suggestion(client, title="Summary ranked", origin_ref="summary-ranked") summary = await client.get("/state/summary") assert summary.status_code == 200 data = summary.json() assert "ranked_suggestions" in data assert any(s["origin_ref"] == "summary-ranked" for s in data["ranked_suggestions"])