import asyncio from pathlib import Path from a2a_pack import LocalRunContext, PlatformUserAuth from a2a_pack.cli.local import load_local_project import agent ROOT = Path(__file__).resolve().parents[1] def test_full_stack_product_contract(): manifest = (ROOT / "a2a.yaml").read_text(encoding="utf-8") source = (ROOT / "agent.py").read_text(encoding="utf-8") frontend = (ROOT / "frontend" / "src" / "App.jsx").read_text(encoding="utf-8") frontend_client = (ROOT / "frontend" / "src" / "a2a.js").read_text(encoding="utf-8") assert "frontend:" in manifest and "mount: /app" in manifest assert "public: false" in manifest assert "resources:" in manifest and "databases:" in manifest assert "runtime:" in manifest and "platform_skill_calls: 3" in manifest assert "PlatformUserAuth" in source assert "AccountAccess(required=True, platform_skill_calls=3, after_trial=\"byok\")" in source assert "AgentPlatformResources" in source and "AgentDatabase(" in source assert "Skill runner" not in frontend, "replace generic scaffold with product workflow" assert "data-testid=\"agent-app\"" in frontend assert "data-testid=\"agent-submit\"" in frontend assert "data-testid=\"agent-result\"" in frontend assert "data-testid=\"agent-download\"" in frontend assert "unwrapInvokeResponse" in frontend_client assert "DATABASE_URL" not in frontend migrations = list((ROOT / "db" / "migrations").glob("*.sql")) assert migrations and all(path.read_text(encoding="utf-8").strip() for path in migrations) card = load_local_project(ROOT).agent_cls().card() skills = {skill.name: skill for skill in card.skills} assert {"build_dashboard", "list_history", "scheduled_rollup"}.issubset(skills) assert "updates_text" in skills["build_dashboard"].input_schema["properties"] assert "run_key" in skills["scheduled_rollup"].input_schema["properties"] databases = card.runtime.platform_resources.databases assert databases, "live Agent Card must declare its managed database" assert databases[0].migrations is not None assert databases[0].migrations.path == "db/migrations" assert card.runtime.account_access.platform_skill_calls == 3 def test_deterministic_analysis_fixture(): rows = agent._analyze_updates(agent.DEFAULT_UPDATES) assert len(rows) == 4 exceptions = agent._build_exceptions(rows) trends = agent._build_trends(rows) assert trends["status_counts"] == {"green": 2, "yellow": 1, "red": 1} assert trends["average_utilization"] == 78.8 assert len(exceptions) == 2 assert {item["client"] for item in exceptions} == {"Beacon CRM", "Cedar Mobile"} csv_text = agent._rows_to_csv(rows) assert "agency-ops-dashboard" not in csv_text assert "Acme Portal" in csv_text def test_missing_database_returns_setup_required(): async def run(): app = agent.ProductionProofV116HighUtili72551() ctx = LocalRunContext( auth=PlatformUserAuth(sub="stable-user", user_id=123, email="dev@example.local"), task_id="test-dashboard", ) result = await app.invoke("build_dashboard", ctx) return result, ctx result, ctx = asyncio.run(run()) assert result.status == "setup_required" assert result.dashboard_data assert result.artifact.name == "agency-ops-dashboard.csv" assert result.artifact.media_type == "text/csv" assert "DATABASE_URL" not in result.summary assert "agency-ops-dashboard.csv" in ctx.artifacts