from __future__ import annotations from django.test import Client from django.urls import reverse from agents.control_room import AgentControlRoomService from control_plane.agents.management.commands.seed_core_agents import Command as SeedAgentsCommand from control_plane.agents.models import AgentRole, AgentVersion, PromotionStatus, ProgenySignal from control_plane.events.bus import EventBus from control_plane.events.models import EventType from control_plane.projects.models import Exploration, ExplorationOpportunity, Project, ProjectPlan, Milestone, RoadmapItem, Scenario, ScenarioFinding, ScenarioRun, ScenarioSuite, StewardFinding, Task, TaskAttempt, TaskStatus from control_plane.resources.models import Resource, ResourceKind from control_plane.verification.models import Review, TestRun, Verification, VerificationLevel, VerificationResult from graph.bootstrap import champion_project_exploration_graph_v1, champion_task_execution_graph_v1 from graph.models import GraphApproval, GraphRun, GraphRunStatus def fixture() -> dict[str, object]: SeedAgentsCommand().handle() AgentControlRoomService().bootstrap_frontend_agents() team = AgentControlRoomService().create_software_feature_team() Resource.objects.create(name="Qwen", kind=ResourceKind.MODEL, provider="local_inference", roles=["CODING"], health_status="AVAILABLE", config={"model": "qwen38"}) project = Project.objects.create(name="UI Dogfood", goal="Operate Artifex through the UI", repository_path="/tmp/ui") plan = ProjectPlan.objects.create(project=project, version=1, goal=project.goal, scope="UI V1") milestone = Milestone.objects.create(project=project, plan=plan, key="UI", title="UI", goal="Build UI") task = Task.objects.create(project=project, milestone=milestone, task_type="implementation", status=TaskStatus.COMPLETE, goal="Render dashboard", acceptance_criteria=["loads"]) coder = AgentVersion.objects.get(agent__role=AgentRole.CODER, promotion_status=PromotionStatus.CHAMPION) reviewer = AgentVersion.objects.get(agent__role=AgentRole.REVIEWER, promotion_status=PromotionStatus.CHAMPION) judge = AgentVersion.objects.get(agent__role=AgentRole.PROJECT_JUDGE, promotion_status=PromotionStatus.CHAMPION) TaskAttempt.objects.create(task=task, attempt_number=1, coder=coder, status="COMPLETE") TestRun.objects.create(project=project, task=task, command="pytest", status="PASS") Review.objects.create(task=task, reviewer=reviewer, status="PASS") Verification.objects.create(project=project, task=task, judge=judge, level=VerificationLevel.TASK, result=VerificationResult.PASS) graph_version = champion_task_execution_graph_v1() graph_run = GraphRun.objects.create(project=project, task=task, execution_graph_version=graph_version, current_node="review", status=GraphRunStatus.PAUSED, metadata={"telemetry": {}}) node_run = graph_run.node_runs.create(node_id="review", node_type="review", status="PAUSED", visit_index=1, agent_version=reviewer, output_metadata={"review_status": "RUNNING"}) approval = GraphApproval.objects.create(graph_run=graph_run, node_run=node_run, reason="AWAITING_UI_APPROVAL") exploration = Exploration.objects.create(project=project, status="COMPLETE") opportunity = ExplorationOpportunity.objects.create(exploration=exploration, project=project, title="Add status filter", description="Filter dashboard cards", opportunity_type="UX", recommended_action="EXTEND", value_score=0.8, effort_score=0.2, risk_score=0.2, confidence=0.8, technical_fit=0.8, strategic_fit=0.8, composite_score=0.75, grouping_key="ui-opp") roadmap_item = RoadmapItem.objects.create(project=project, title="Improve graph viewer", description="Expose node details", horizon="NOW", target_action="EXTEND", grouping_key="ui-roadmap") suite = ScenarioSuite.objects.create(project=project, name="UI Suite") scenario = Scenario.objects.create(project=project, suite=suite, name="Permission denial", title="Permission denial", scenario_type="PERMISSION", target_type="PROJECT", target_id=str(project.id), injected_condition={"mechanism": "permission_denial"}, expected_invariants=["safe"], success_criteria=["pass"], resource_budget={"max_seconds": 5}) run = ScenarioRun.objects.create(project=project, scenario=scenario, result="FAIL", status="COMPLETE", failure_evidence={"summary": "denied"}) finding = ScenarioFinding.objects.create(project=project, scenario=scenario, scenario_run=run, title="Scenario failed", summary="permission denied", failure_category="PERMISSION", recommended_action="EXTEND", recommended_route="RoadmapItem", grouping_key="ui-scenario") StewardFinding.objects.create(project=project, finding_type="RELIABILITY", title="Open issue", summary="Needs attention", severity="HIGH", confidence=0.8, recommended_action="REPAIR", grouping_key="ui-steward") ProgenySignal.objects.create(project=project, agent_version=coder, source="ui", severity="MEDIUM", failure_category="MALFORMED", summary="Signal", grouping_key="ui-signal") EventBus().publish(EventType.TASK_COMPLETED, project=project, task=task, actor="test") return {"project": project, "task": task, "graph_run": graph_run, "approval": approval, "opportunity": opportunity, "roadmap_item": roadmap_item, "finding": finding, "coder": coder, "team": team} def assert_ok(client: Client, url: str, text: str) -> None: response = client.get(url) assert response.status_code == 200 assert text.encode() in response.content def test_control_plane_core_pages_render_and_link() -> None: data = fixture() client = Client() project = data["project"] task = data["task"] graph_run = data["graph_run"] coder = data["coder"] assert_ok(client, reverse("dashboard"), "Dashboard") assert_ok(client, reverse("projects"), "UI Dogfood") assert_ok(client, reverse("project_workspace", args=[project.id]), "Project DAG") assert_ok(client, reverse("project_brain", args=[project.id]), "Project Brain") assert_ok(client, reverse("project_archaeologist", args=[project.id]), "Archaeologist") assert_ok(client, reverse("graph_run_detail", args=[graph_run.id]), "Live execution graph viewer") assert_ok(client, reverse("task_detail", args=[task.id]), "Acceptance") assert_ok(client, reverse("steward"), "Open issue") assert_ok(client, reverse("explore"), "Add status filter") assert_ok(client, reverse("roadmap"), "Improve graph viewer") assert_ok(client, reverse("scenarios"), "Permission denial") assert_ok(client, reverse("progeny"), "Signal") assert_ok(client, reverse("agent_control_room"), "Agent Control Room") assert_ok(client, reverse("agent_detail", args=[coder.id]), "Competencies") assert_ok(client, reverse("resources"), "Qwen") assert_ok(client, reverse("approvals"), "AWAITING_UI_APPROVAL") assert_ok(client, reverse("activity"), "TASK_COMPLETED") def test_json_endpoints_and_ui_actions_work() -> None: data = fixture() client = Client() project = data["project"] graph_run = data["graph_run"] approval = data["approval"] opportunity = data["opportunity"] roadmap_item = data["roadmap_item"] finding = data["finding"] assert client.get(reverse("graph_run_json", args=[graph_run.id])).json()["status"] == "PAUSED" assert client.get(reverse("project_dag_json", args=[project.id])).json()["tasks"] assert client.get(reverse("agent_performance_json", args=[data["coder"].id])).json()["quality"] response = client.post(reverse("opportunity_action", args=[opportunity.id]), {"action": "roadmap"}) assert response.status_code == 302 assert project.roadmap_items.filter(title="Add status filter").exists() response = client.post(reverse("roadmap_action", args=[roadmap_item.id]), {"action": "NEXT"}) assert response.status_code == 302 roadmap_item.refresh_from_db() assert roadmap_item.horizon == "NEXT" response = client.post(reverse("scenario_finding_action", args=[finding.id]), {"action": "roadmap"}) assert response.status_code == 302 response = client.post(reverse("approval_action", args=[approval.id]), {"action": "approve"}) assert response.status_code == 302 approval.refresh_from_db() graph_run.refresh_from_db() assert approval.status == "APPROVED" assert graph_run.status == "RUNNING" def test_ui_can_start_safe_explore_graph() -> None: data = fixture() client = Client() response = client.post(reverse("run_explore", args=[data["project"].id])) assert response.status_code == 302 assert GraphRun.objects.filter(execution_graph_version__graph__name="project_exploration", project=data["project"]).exists()