From e84b09c6efb9a25cda6ff68bf8d5616ed046ccdc Mon Sep 17 00:00:00 2001 From: Anthony Volk <14987227+anth-volk@users.noreply.github.com> Date: Tue, 10 Nov 2026 22:00:22 +0400 Subject: [PATCH 01/16] Test the skill for reaching the Public API from dashboards Adds tests/test_api_access_skill.py for a new policyengine-api-access skill. They fail until the skill exists: they check its frontmatter, its place in the five bundles that build dashboards or call the Public API and in the catalog, that the wrapper build ships it, and that it names the dashboard API's four operations, @policyengine/api-client's exports, the server credential headers, tenants and variables, the refusal bodies, and a row for 401, 403, 429 and 503. Browser-language examples may not name a Public API host, and no credential may sit in a NEXT_PUBLIC_ or VITE_ variable. The token template's tests check that one token serves many requests and is shared between instances through the shared store, is replaced five minutes before it expires, that a refused request is retried once with a new token, and that redirects are never followed. Co-Authored-By: Claude Opus 5.5 --- tests/test_api_access_skill.py | 412 +++++++++++++++++++++++++++++++++ 1 file changed, 412 insertions(+) create mode 100644 tests/test_api_access_skill.py diff --git a/tests/test_api_access_skill.py b/tests/test_api_access_skill.py new file mode 100644 index 0000000..cbda20a --- /dev/null +++ b/tests/test_api_access_skill.py @@ -0,0 +1,412 @@ +"""The policyengine-api-access skill: where it is listed, what it teaches, and its token template. + +The skill tells dashboard developers and agents how to reach the Public API +(api.policyengine.org) once it serves only PolicyEngine's servers: pages use +www.policyengine.org's dashboard API through ``@policyengine/api-client``, and +servers send their own Auth0 client-credentials token. The operation paths, +header names, tenants and refusal bodies below are copied from merged code in +PolicyEngine/policyengine-app-v2 (``website/src/app/api/``, +``website/src/lib/dashboardApi/``, ``packages/public-api-forwarding/`` and +``packages/api-client/``) and PolicyEngine/policyengine-api +(``policyengine_api/request_caller.py``, +``policyengine_api/libs/server_credentials.py``), so an edit to the skill +cannot drift from them unnoticed. + +``templates/public_api_token.py`` is the token cache servers copy. Its tests +use a fake opener and a dict as the shared store, so they never call Auth0 or +the Public API. +""" + +from __future__ import annotations + +import http.server +import importlib.util +import json +import re +import subprocess +import sys +import threading +import urllib.error +from pathlib import Path +from types import ModuleType + +import pytest +import yaml + +REPO_ROOT = Path(__file__).resolve().parent.parent +SKILL_NAME = "policyengine-api-access" +SKILL_DIR = REPO_ROOT / "skills" / SKILL_NAME +SKILL_FILE = SKILL_DIR / "SKILL.md" +TOKEN_TEMPLATE = SKILL_DIR / "templates" / "public_api_token.py" + +# Bundles whose users build dashboards or tools, or call the Public API. +# analysis-tools is the bundle the create-dashboard workflow installs. +BUNDLES_WITH_SKILL = ( + "analysis-tools", + "api-development", + "app-development", + "complete", + "dashboard-builder", +) + +DASHBOARD_API_OPERATIONS = ( + "POST /api/household/calculate", + "POST /api/policies", + "GET /api/economy/compare", + "GET /api/metadata/{country}", +) +API_CLIENT_METHODS = ( + "createPolicyEngineApiClient", + "calculateHousehold", + "createPolicy", + "getEconomyComparison", + "compareEconomy", + "getMetadata", + "PolicyEngineApiError", + "EconomyComparisonTimeoutError", +) +SERVER_CONTRACT_FACTS = ( + "Authorization: Bearer", + "PolicyEngine-User-Authorization", + "PolicyEngine-Unauthenticated-User", + "policyengine-api.uk.auth0.com", + "policyengine-api-staging.uk.auth0.com", + "https://api.policyengine.org/", + "https://staging-api.policyengine.org/", + "PUBLIC_API_SERVER_CLIENT_IDS", + "POLICYENGINE_API_URL", + "POLICYENGINE_API_AUTH0_DOMAIN", + "POLICYENGINE_API_AUTH0_AUDIENCE", + "POLICYENGINE_API_AUTH0_CLIENT_ID", + "POLICYENGINE_API_AUTH0_CLIENT_SECRET", + "vercel env pull", + '{"status":"error","message":"Authentication is required"}', + '{"status":"error","message":"Authentication is unavailable"}', + "Pages on this origin may not call the dashboard API.", + "appZoneRoutes.ts", + "*-policy-engine.vercel.app", +) +HANDLED_STATUSES = ("401", "403", "429", "503") + +BROWSER_LANGUAGES = {"ts", "tsx", "js", "jsx", "javascript", "typescript"} +PUBLIC_API_HOST = re.compile(r"api\.policyengine\.org|policyengine-api[a-z0-9-]*\.[a-z0-9.-]*run\.app") +# A credential-looking name with a prefix that bundlers put into browser code. +PUBLIC_PREFIX_CREDENTIAL = re.compile( + r"\b(?:NEXT_PUBLIC|VITE)_[A-Z0-9_]*(?:AUTH0|SECRET|TOKEN|CLIENT|CREDENTIAL|POLICYENGINE_API)[A-Z0-9_]*" +) +FENCE = re.compile(r"^```([A-Za-z0-9_+-]*)\n(.*?)^```", re.DOTALL | re.MULTILINE) + + +def skill_text() -> str: + assert SKILL_FILE.is_file(), f"{SKILL_FILE.relative_to(REPO_ROOT)} is missing" + return SKILL_FILE.read_text() + + +def skill_frontmatter() -> dict: + text = skill_text() + match = re.match(r"\A---\n(.*?)\n---\n", text, re.DOTALL) + assert match, "SKILL.md has no YAML frontmatter" + return yaml.safe_load(match.group(1)) + + +def fenced_blocks(text: str) -> list[tuple[str, str]]: + return [(language.lower(), body) for language, body in FENCE.findall(text)] + + +def test_frontmatter_names_the_skill_and_its_category() -> None: + frontmatter = skill_frontmatter() + assert frontmatter["name"] == SKILL_NAME + assert frontmatter["metadata"]["category"] == "apps" + description = frontmatter["description"] + assert len(description) <= 1024 + for trigger in ("api.policyengine.org", "dashboard", "@policyengine/api-client"): + assert trigger in description, f"description lacks the trigger {trigger!r}" + + +@pytest.mark.parametrize("bundle_name", BUNDLES_WITH_SKILL) +def test_bundle_ships_the_skill(bundle_name: str) -> None: + bundle = json.loads((REPO_ROOT / "bundles" / f"{bundle_name}.json").read_text()) + assert f"./skills/{SKILL_NAME}" in bundle["skills"] + + +def test_catalog_lists_the_skill() -> None: + catalog = (REPO_ROOT / "skills" / "README.md").read_text() + assert f"| **{SKILL_NAME}** |" in catalog + + +def test_wrapper_build_ships_the_skill_and_template(tmp_path: Path) -> None: + output_dir = tmp_path / "policyengine-claude" + subprocess.run( + [ + sys.executable, + str(REPO_ROOT / "scripts" / "build_claude_wrapper.py"), + "--source-root", + str(REPO_ROOT), + "--output-root", + str(output_dir), + ], + check=True, + ) + assert (output_dir / "skills" / SKILL_NAME / "SKILL.md").is_file() + assert (output_dir / "skills" / SKILL_NAME / "templates" / "public_api_token.py").is_file() + manifest = json.loads((output_dir / ".claude-plugin" / "marketplace.json").read_text()) + plugins_with_skill = { + plugin["name"] + for plugin in manifest["plugins"] + if f"./skills/{SKILL_NAME}" in plugin.get("skills", []) + } + assert plugins_with_skill == set(BUNDLES_WITH_SKILL) + + +@pytest.mark.parametrize("operation", DASHBOARD_API_OPERATIONS) +def test_skill_names_each_dashboard_api_operation(operation: str) -> None: + assert operation in skill_text() + + +@pytest.mark.parametrize("name", API_CLIENT_METHODS) +def test_skill_names_the_browser_client_exports(name: str) -> None: + assert name in skill_text() + + +@pytest.mark.parametrize("fact", SERVER_CONTRACT_FACTS) +def test_skill_states_the_server_contract(fact: str) -> None: + assert fact in skill_text() + + +@pytest.mark.parametrize("status_code", HANDLED_STATUSES) +def test_skill_says_how_to_handle_each_refusal(status_code: str) -> None: + error_section = skill_text().split("## Errors", 1) + assert len(error_section) == 2, "SKILL.md has no '## Errors' section" + assert re.search(rf"^\| {status_code} ", error_section[1], re.MULTILINE), ( + f"the errors table has no row for {status_code}" + ) + + +def test_no_browser_language_example_names_a_public_api_host() -> None: + offenders = [ + body + for language, body in fenced_blocks(skill_text()) + if language in BROWSER_LANGUAGES and PUBLIC_API_HOST.search(body) + ] + assert offenders == [] + + +def test_skill_never_puts_a_credential_in_a_public_prefix_variable() -> None: + assert PUBLIC_PREFIX_CREDENTIAL.findall(skill_text()) == [] + + +def test_public_prefix_credential_pattern_catches_bundled_names() -> None: + for unsafe in ( + "NEXT_PUBLIC_POLICYENGINE_API_AUTH0_CLIENT_SECRET", + "VITE_AUTH0_CLIENT_ID", + "NEXT_PUBLIC_API_TOKEN", + "VITE_POLICYENGINE_API_URL", + ): + assert PUBLIC_PREFIX_CREDENTIAL.search(unsafe), unsafe + for safe in ("NEXT_PUBLIC_*", "VITE_*", "NEXT_PUBLIC_MODAL_URL", "POLICYENGINE_API_AUTH0_CLIENT_SECRET"): + assert not PUBLIC_PREFIX_CREDENTIAL.search(safe), safe + + +def test_skill_points_servers_at_the_token_template() -> None: + assert "templates/public_api_token.py" in skill_text() + + +# --- templates/public_api_token.py ----------------------------------------- + + +def load_token_module() -> ModuleType: + assert TOKEN_TEMPLATE.is_file(), f"{TOKEN_TEMPLATE.relative_to(REPO_ROOT)} is missing" + spec = importlib.util.spec_from_file_location("public_api_token", TOKEN_TEMPLATE) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + return module + + +class FakeResponse: + def __init__(self, status_code: int, body: dict) -> None: + self.status = status_code + self._body = json.dumps(body).encode() + + def read(self) -> bytes: + return self._body + + def __enter__(self) -> FakeResponse: + return self + + def __exit__(self, *exc_info: object) -> None: + return None + + +class RecordingOpener: + """Answers token requests with fresh tokens and Public API requests with 200.""" + + def __init__(self, token_lifetime_seconds: int = 86_400) -> None: + self.token_lifetime_seconds = token_lifetime_seconds + self.token_requests: list[dict] = [] + self.api_requests: list[tuple[str, str, str | None]] = [] + self.refuse_next_api_requests = 0 + + def open(self, request, timeout=None): # noqa: ANN001 - urllib's opener signature + if request.full_url.endswith("/oauth/token"): + self.token_requests.append(json.loads(request.data)) + return FakeResponse( + 200, + { + "access_token": f"token-{len(self.token_requests)}", + "expires_in": self.token_lifetime_seconds, + "token_type": "Bearer", + }, + ) + self.api_requests.append( + (request.get_method(), request.full_url, request.get_header("Authorization")) + ) + if self.refuse_next_api_requests > 0: + self.refuse_next_api_requests -= 1 + raise urllib.error.HTTPError( + request.full_url, + 401, + "Unauthorized", + {"WWW-Authenticate": "Bearer"}, + None, + ) + return FakeResponse(200, {"status": "ok", "message": None, "result": {}}) + + +class Clock: + def __init__(self, start: float = 1_000_000.0) -> None: + self.now = start + + def __call__(self) -> float: + return self.now + + +def make_settings(token_module: ModuleType, api_url: str = "https://api.example.test"): + return token_module.PublicApiSettings.from_environment( + { + "POLICYENGINE_API_URL": api_url, + "POLICYENGINE_API_AUTH0_DOMAIN": "tenant.example.test", + "POLICYENGINE_API_AUTH0_AUDIENCE": "https://audience.example.test/", + "POLICYENGINE_API_AUTH0_CLIENT_ID": "placeholder-client-id", + "POLICYENGINE_API_AUTH0_CLIENT_SECRET": "placeholder-client-secret", + } + ) + + +def test_template_requests_one_token_for_many_requests() -> None: + token_module = load_token_module() + opener = RecordingOpener() + tokens = token_module.PublicApiTokenProvider( + make_settings(token_module), shared_store={}, clock=Clock(), opener=opener + ) + assert [tokens.access_token() for _ in range(5)] == ["token-1"] * 5 + assert len(opener.token_requests) == 1 + assert opener.token_requests[0] == { + "grant_type": "client_credentials", + "client_id": "placeholder-client-id", + "client_secret": "placeholder-client-secret", + "audience": "https://audience.example.test/", + } + + +def test_template_shares_one_token_between_instances() -> None: + token_module = load_token_module() + shared_store: dict = {} + opener = RecordingOpener() + first_instance = token_module.PublicApiTokenProvider( + make_settings(token_module), shared_store=shared_store, clock=Clock(), opener=opener + ) + second_instance = token_module.PublicApiTokenProvider( + make_settings(token_module), shared_store=shared_store, clock=Clock(), opener=opener + ) + assert first_instance.access_token() == second_instance.access_token() == "token-1" + assert len(opener.token_requests) == 1 + assert "placeholder-client-secret" not in json.dumps(shared_store) + + +def test_template_replaces_the_token_five_minutes_before_it_expires() -> None: + token_module = load_token_module() + clock = Clock() + opener = RecordingOpener(token_lifetime_seconds=86_400) + tokens = token_module.PublicApiTokenProvider( + make_settings(token_module), shared_store={}, clock=clock, opener=opener + ) + assert tokens.access_token() == "token-1" + clock.now += 86_400 - 301 + assert tokens.access_token() == "token-1" + clock.now += 2 + assert tokens.access_token() == "token-2" + + +def test_template_retries_a_refused_request_once_with_a_new_token() -> None: + token_module = load_token_module() + opener = RecordingOpener() + opener.refuse_next_api_requests = 1 + tokens = token_module.PublicApiTokenProvider( + make_settings(token_module), shared_store={}, clock=Clock(), opener=opener + ) + answer = token_module.call_public_api(tokens, "POST", "/us/calculate", {"household": {}}) + assert answer == {"status": "ok", "message": None, "result": {}} + assert [header for _, _, header in opener.api_requests] == [ + "Bearer token-1", + "Bearer token-2", + ] + + +def test_template_stops_after_a_second_refusal() -> None: + token_module = load_token_module() + opener = RecordingOpener() + opener.refuse_next_api_requests = 2 + tokens = token_module.PublicApiTokenProvider( + make_settings(token_module), shared_store={}, clock=Clock(), opener=opener + ) + with pytest.raises(urllib.error.HTTPError) as refusal: + token_module.call_public_api(tokens, "GET", "/us/metadata") + assert refusal.value.code == 401 + assert len(opener.api_requests) == 2 + + +def test_template_refuses_partial_settings() -> None: + token_module = load_token_module() + with pytest.raises(token_module.PublicApiSettingsError): + token_module.PublicApiSettings.from_environment( + {"POLICYENGINE_API_URL": "https://api.example.test"} + ) + + +class RedirectingHandler(http.server.BaseHTTPRequestHandler): + requested_paths: list[str] = [] + + def do_GET(self) -> None: # noqa: N802 - http.server's method name + RedirectingHandler.requested_paths.append(self.path) + self.send_response(307) + self.send_header("Location", "/elsewhere") + self.end_headers() + + def log_message(self, *args: object) -> None: + return None + + +def test_template_never_follows_a_redirect() -> None: + token_module = load_token_module() + RedirectingHandler.requested_paths = [] + server = http.server.HTTPServer(("127.0.0.1", 0), RedirectingHandler) + thread = threading.Thread(target=server.serve_forever, daemon=True) + thread.start() + try: + api_url = f"http://127.0.0.1:{server.server_address[1]}" + tokens = token_module.PublicApiTokenProvider( + make_settings(token_module, api_url=api_url), + shared_store={}, + clock=Clock(), + opener=RecordingOpener(), + ) + tokens.access_token() + with pytest.raises(urllib.error.HTTPError) as refusal: + token_module.call_public_api( + tokens, "GET", "/us/metadata", opener=token_module.NO_REDIRECT_OPENER + ) + assert refusal.value.code == 307 + assert RedirectingHandler.requested_paths == ["/us/metadata"] + finally: + server.shutdown() + server.server_close() From 9e63be7d911eb83ac4c629ab55f19d28d3f91880 Mon Sep 17 00:00:00 2001 From: Anthony Volk <14987227+anth-volk@users.noreply.github.com> Date: Tue, 10 Nov 2026 22:04:44 +0400 Subject: [PATCH 02/16] Add policyengine-api-access: reaching the Public API from dashboards and servers The Public API is becoming callable only by PolicyEngine's own servers. The new skill tells dashboard developers and agents how to reach it: - the rules: browser code never calls api.policyengine.org or the Public API's Cloud Run addresses, and no Public API credential or address goes in a NEXT_PUBLIC_ or VITE_ variable; - from pages: www.policyengine.org's four dashboard operations through @policyengine/api-client, with their request and answer shapes, polling, the origins the dashboard API accepts and its rate limits, all taken from policyengine-app-v2's merged website routes, forwarding package and client; - from servers: an Auth0 client-credentials token from the Public API's own tenant in Authorization, one client per caller, cached across instances, and how a client gets on the Public API's allow list before it sends a token; - local development and previews, asking for a new dashboard operation, and a table of the dashboard API's and the Public API's errors. templates/public_api_token.py is a copyable Python token cache for Modal backends, Cloud Run services and scripts: it shares one token between instances, replaces it five minutes before it expires, retries a 401 once with a new token, and never follows redirects. The skill is in the analysis-tools, api-development, app-development, complete and dashboard-builder bundles and the catalog; the plugin version moves to 4.2.0. Co-Authored-By: Claude Opus 5.5 --- bundles/analysis-tools.json | 3 +- bundles/api-development.json | 3 +- bundles/app-development.json | 3 +- bundles/complete.json | 3 +- bundles/country-models.json | 2 +- bundles/dashboard-builder.json | 3 +- bundles/data-science.json | 2 +- bundles/essential.json | 2 +- skills/README.md | 1 + skills/policyengine-api-access/SKILL.md | 264 ++++++++++++++++++ .../templates/public_api_token.py | 261 +++++++++++++++++ targets/claude/marketplace.template.json | 2 +- tests/test_api_access_skill.py | 2 + 13 files changed, 542 insertions(+), 9 deletions(-) create mode 100644 skills/policyengine-api-access/SKILL.md create mode 100644 skills/policyengine-api-access/templates/public_api_token.py diff --git a/bundles/analysis-tools.json b/bundles/analysis-tools.json index 7192011..12f25cf 100644 --- a/bundles/analysis-tools.json +++ b/bundles/analysis-tools.json @@ -2,7 +2,7 @@ "name": "analysis-tools", "description": "Policy analysis and research - impact studies, dashboards, notebooks, and visualizations", "category": "analysis", - "version": "4.1.0", + "version": "4.2.0", "keywords": [ "analysis", "research", @@ -25,6 +25,7 @@ "./skills/policyengine-canada", "./skills/policyengine-healthcare", "./skills/policyengine-user-guide", + "./skills/policyengine-api-access", "./skills/policyengine-design", "./skills/policyengine-writing", "./skills/policyengine-research-lookup", diff --git a/bundles/api-development.json b/bundles/api-development.json index cdee630..5b5d98f 100644 --- a/bundles/api-development.json +++ b/bundles/api-development.json @@ -2,7 +2,7 @@ "name": "api-development", "description": "API development - Flask endpoints, caching, services, and integration patterns", "category": "development", - "version": "4.1.0", + "version": "4.2.0", "keywords": [ "api", "flask", @@ -18,6 +18,7 @@ "hooks": null, "skills": [ "./skills/policyengine-api", + "./skills/policyengine-api-access", "./skills/policyengine-model-development", "./skills/policyengine-us", "./skills/policyengine-uk", diff --git a/bundles/app-development.json b/bundles/app-development.json index 4645926..4c2bc3d 100644 --- a/bundles/app-development.json +++ b/bundles/app-development.json @@ -2,7 +2,7 @@ "name": "app-development", "description": "React app development - app-v2, standalone tools, Vercel deployment, and PolicyEngine-specific patterns", "category": "development", - "version": "4.1.0", + "version": "4.2.0", "keywords": [ "react", "frontend", @@ -21,6 +21,7 @@ "skills": [ "./skills/policyengine-app", "./skills/policyengine-tools", + "./skills/policyengine-api-access", "./skills/policyengine-model-development", "./skills/policyengine-us", "./skills/policyengine-uk", diff --git a/bundles/complete.json b/bundles/complete.json index 3d73563..16a0619 100644 --- a/bundles/complete.json +++ b/bundles/complete.json @@ -2,7 +2,7 @@ "name": "complete", "description": "Complete PolicyEngine knowledge base - all agents, commands, and skills for users, analysts, and contributors", "category": "complete", - "version": "4.1.0", + "version": "4.2.0", "keywords": [ "complete", "all", @@ -25,6 +25,7 @@ "./skills/policyengine-tools", "./skills/policyengine-app", "./skills/policyengine-api", + "./skills/policyengine-api-access", "./skills/policyengine-design", "./skills/policyengine-standards", "./skills/policyengine-cloud-costs", diff --git a/bundles/country-models.json b/bundles/country-models.json index 9ac521b..fc67d1a 100644 --- a/bundles/country-models.json +++ b/bundles/country-models.json @@ -2,7 +2,7 @@ "name": "country-models", "description": "Complete multi-agent workflow for implementing government benefit programs in PolicyEngine country packages", "category": "development", - "version": "4.1.0", + "version": "4.2.0", "keywords": [ "tax", "benefits", diff --git a/bundles/dashboard-builder.json b/bundles/dashboard-builder.json index cac2260..10cd985 100644 --- a/bundles/dashboard-builder.json +++ b/bundles/dashboard-builder.json @@ -2,7 +2,7 @@ "name": "dashboard-builder", "description": "Orchestrated AI workflow for creating PolicyEngine dashboards from natural-language descriptions", "category": "development", - "version": "4.1.0", + "version": "4.2.0", "keywords": [ "dashboard", "calculator", @@ -21,6 +21,7 @@ "skills": [ "./skills/policyengine-tools", "./skills/policyengine-api", + "./skills/policyengine-api-access", "./skills/policyengine-app", "./skills/policyengine-us", "./skills/policyengine-uk", diff --git a/bundles/data-science.json b/bundles/data-science.json index 8e87e9a..19cbe5d 100644 --- a/bundles/data-science.json +++ b/bundles/data-science.json @@ -2,7 +2,7 @@ "name": "data-science", "description": "Data analysis, survey enhancement, imputation, calibration, and microdata utilities", "category": "data", - "version": "4.1.0", + "version": "4.2.0", "keywords": [ "data", "microdata", diff --git a/bundles/essential.json b/bundles/essential.json index 09dea39..7e196eb 100644 --- a/bundles/essential.json +++ b/bundles/essential.json @@ -2,7 +2,7 @@ "name": "essential", "description": "Essential PolicyEngine knowledge for all users - understanding the platform, using the web app, and basic concepts", "category": "getting-started", - "version": "4.1.0", + "version": "4.2.0", "keywords": [ "beginner", "users", diff --git a/skills/README.md b/skills/README.md index 636b2c0..9d2ba65 100644 --- a/skills/README.md +++ b/skills/README.md @@ -54,6 +54,7 @@ lints the whole tree against the failure modes that rotted the previous catalog | **policyengine-cloud-costs** | Deploying your own tool without idle spend: defaults, declared exceptions, a README cost plan, a pre-merge config checker and a bill check | | **policyengine-design** | Design tokens, `@policyengine/ui-kit` consumption, chart styling, design-system migration | | **policyengine-api** | The REST APIs: v1 production endpoints, api-v2 alpha status | +| **policyengine-api-access** | Reaching the Public API from dashboards and servers: the dashboard API through `@policyengine/api-client`, server Auth0 client credentials and their token cache, errors | ### Process diff --git a/skills/policyengine-api-access/SKILL.md b/skills/policyengine-api-access/SKILL.md new file mode 100644 index 0000000..9eb5583 --- /dev/null +++ b/skills/policyengine-api-access/SKILL.md @@ -0,0 +1,264 @@ +--- +name: policyengine-api-access +description: | + Load before writing or reviewing code that reaches the PolicyEngine Public API + (api.policyengine.org) from a dashboard, tool, backend, Modal app, Vercel function or CI + job. The Public API serves only PolicyEngine's servers: pages call www.policyengine.org's + dashboard API through @policyengine/api-client, and servers send their own Auth0 + client-credentials token. Covers the rules, the four dashboard operations, polling, allowed + origins, cached server tokens, getting a client, local development and previews, asking for a + new operation, and 401/403/429/503. + Triggers: api.policyengine.org, Public API, dashboard API, @policyengine/api-client, household + calculate from the browser, economy comparison polling, NEXT_PUBLIC_API_URL, VITE_API_URL, + Auth0 client credentials, server token, PUBLIC_API_SERVER_CLIENT_IDS, Authentication is + required, CORS error from the API. + NOT for: Python analysis (policyengine skill) or the Public API's own endpoints and code + (policyengine-api). +metadata: + category: apps +--- + +# Reaching the Public API from dashboards and servers + +The Public API (`PolicyEngine/policyengine-api`, https://api.policyengine.org) is becoming +callable only by PolicyEngine's own servers. Once its credential requirement is switched on, it +answers every request without a server credential with 401, except `GET`/`HEAD /health`, +`GET /v2/openapi.json` and CORS preflights. Anything in browser code is public, so a page cannot hold that +credential. Pages go through a server that does. + +## The rules + +1. **Browser code never calls the Public API**: not `api.policyengine.org`, and not its Cloud + Run addresses (`policyengine-api-….a.run.app`, `policyengine-api-staging-….a.run.app`, + or a tagged revision's `…---policyengine-api-….a.run.app`). Browser code is everything that + runs in the page: components, hooks, client modules, static exports and anything a bundler + puts in the page. +2. **No Public API credential or address goes in a `NEXT_PUBLIC_*` or `VITE_*` variable.** + Next.js and Vite copy those values into the page's JavaScript. That covers the Auth0 + client ID and secret, tokens, and the Public API's URL. +3. **One Auth0 client per calling server**, never shared between callers or copied into + another repository. The client ID is how the Public API's records identify the caller. + +## Which route to use + +| Where the code runs | How it reaches the Public API | +|---|---| +| A dashboard page (browser) | www.policyengine.org's dashboard API, through `@policyengine/api-client` | +| A dashboard's own backend (Modal, Cloud Run, a Vercel function) | Its own Auth0 client, token in `Authorization: Bearer` | +| A CI job or script | Its own Auth0 client, one token per job run | +| Python analysis or a notebook | The `policyengine` package (policyengine skill), not REST | + +If a backend exists only to relay one of the four dashboard operations, drop it and call the +dashboard API from the page instead. + +## From pages: the dashboard API + +www.policyengine.org (`website/` in `PolicyEngine/policyengine-app-v2`) serves four operations. +Its server adds PolicyEngine's credential, so a dashboard needs none, and dashboards never see +the Public API's paths. + +```bash +npm install @policyengine/api-client +``` + +```ts +import { + createPolicyEngineApiClient, + EconomyComparisonTimeoutError, + PolicyEngineApiError, +} from "@policyengine/api-client"; + +const policyengine = createPolicyEngineApiClient(); + +const household = await policyengine.calculateHousehold({ + country: "us", + household: { + people: { you: { age: { 2026: 40 }, employment_income: { 2026: 50000 } } }, + households: { your_household: { members: ["you"] } }, + }, + policy: { "gov.irs.credits.ctc.amount.base[0].amount": { "2026-01-01.2100-12-31": 3000 } }, +}); + +const reformId = await policyengine.createPolicy({ + country: "us", + parameters: { "gov.irs.credits.ctc.amount.base[0].amount": { "2026-01-01.2100-12-31": 3000 } }, +}); +const impact = await policyengine.compareEconomy( + { country: "us", policy: reformId, baseline: 2, region: "us", year: 2026 }, + { onProgress: (answer) => console.log(answer.status) }, +); + +const metadata = await policyengine.getMetadata("uk"); +``` + +| Operation | Request | Answer | +|---|---|---| +| `POST /api/household/calculate` | JSON `{country, household, policy?}`; `policy` is parameter changes, current law when omitted | The Public API's `{status, message, result}`; `calculateHousehold` resolves with `result` | +| `POST /api/policies` | JSON `{country, parameters}` | `{id}`: 201 for a new policy, 200 for an identical stored one; `createPolicy` resolves with the ID | +| `GET /api/economy/compare` | Query `country`, `policy`, `baseline`, `region`, `year`, each exactly once | `{status: "computing" \| "ok" \| "error", result, …}`, never cached | +| `GET /api/metadata/{country}` | — | `{status, message, result}`, cached by browsers for an hour (`max-age=3600`) | + +- `country` is `us` or `uk`. Any other field or query parameter is refused with 400, and a + body whose `Content-Type` is not JSON with 415. +- `policy` and `baseline` are policy IDs (whole numbers). `baseline` is current law's ID: + 2 for `us`, 1 for `uk` (`result.current_law_id` in the metadata). `year` is four digits; + `region` is `us`, `uk` or a sub-national region such as `state/ca`, at most 200 characters. +- The household and parameter shapes are the Public API's (`household` nests values by year; + read variable and parameter names from the metadata). See the policyengine-api skill. +- Each method takes `{ signal }` to cancel. The result type is a type argument + (`calculateHousehold(…)`), not checked at run time. + +**Polling.** `compareEconomy` reads the comparison every 5 seconds until `status` is `ok`, and +gives up after 30 minutes with `EconomyComparisonTimeoutError`. It waits for `Retry-After` on a +429 and one interval after a 502, 503 or 504, and stops after a fourth such answer in a row. A +comparison that failed (502 with `status: "error"` and `retry_after_seconds`) is thrown at once: +the Public API keeps that failure for `retry_after_seconds`, so polling sooner returns it again. +Keep `intervalMilliseconds` at a few seconds. Use `getEconomyComparison` for one read. + +**Where pages may call it from.** The client's default `baseUrl` is +`https://www.policyengine.org`. The dashboard API answers browser requests from: +- pages on www.policyengine.org itself, which is how dashboards served through the website's + rewrites (`website/src/data/appZoneRoutes.ts`) reach it: same origin, no CORS; +- `http://localhost` and `http://127.0.0.1` on any port; +- the PolicyEngine team's Vercel previews, `*-policy-engine.vercel.app`; +- each dashboard's own `*.vercel.app` host named in `appZoneRoutes.ts`. + +Every other origin gets 403, "Pages on this origin may not call the dashboard API.", and the +request never reaches the Public API. A new dashboard's own host is allowed once its rewrite is +in `appZoneRoutes.ts` and that change is deployed. A dashboard served from anywhere else, such +as a Modal URL, reaches the dashboard API only through its www.policyengine.org path. Allowed +request headers are `Content-Type`, `Authorization` and `PolicyEngine-Unauthenticated-User`; +the client sends no cookies (`credentials: "omit"`). + +**Rate limits.** The dashboard API limits each IP address per minute: 30 household +calculations, 120 economy-comparison reads and 300 other requests. Calculate on a user's +action or after a debounce, not on every keystroke. + +## From servers: your own Auth0 client + +A server (a Modal backend, a Vercel function, a Cloud Run service, a CI job) calls the Public +API directly with an Auth0 client-credentials token from the Public API's own tenant: + +| | Production | Staging | +|---|---|---| +| Auth0 tenant (`POLICYENGINE_API_AUTH0_DOMAIN`) | `policyengine-api.uk.auth0.com` | `policyengine-api-staging.uk.auth0.com` | +| Audience (`POLICYENGINE_API_AUTH0_AUDIENCE`) | `https://api.policyengine.org/` | `https://staging-api.policyengine.org/` | +| Public API (`POLICYENGINE_API_URL`) | `https://api.policyengine.org` | the staging Cloud Run service, given with the client | + +The token request is `POST https:///oauth/token` with JSON +`{"grant_type": "client_credentials", "client_id": …, "client_secret": …, "audience": …}`. +Send the answer's `access_token` as `Authorization: Bearer ` on every request. +A client token from the sign-in tenants (`auth.policyengine.org`, +`policyengine-dev.uk.auth0.com`) is refused with 401. + +Other headers, when a server acts for a browser: +- a signed-in user's Auth0 token goes in `PolicyEngine-User-Authorization: Bearer `, + never in `Authorization`; +- `PolicyEngine-Unauthenticated-User: ` is passed on unchanged; +- send at most one of each; two `Authorization` headers are refused. + +**Cache the token across instances.** Tokens last 24 hours, and Auth0 counts the +machine-to-machine tokens it issues per tenant per month. Never request a token per request, +per container start or per cold start: +- **Python (Modal, Cloud Run, scripts):** copy `templates/public_api_token.py`. It keeps the + token in memory and in a store the instances share (a `modal.Dict` on Modal), replaces it five + minutes before it expires, retries a 401 once with a new token, and never follows a + redirect. Its docstring has the Modal wiring. +- **Vercel functions:** keep it in Vercel Runtime Cache, as app-v2's + `packages/public-api-forwarding/src/accessToken.ts` does: + + ```ts + import { getCache } from "@vercel/functions"; + + const tokenCache = getCache({ namespace: "policyengine-public-api" }); + const cached = (await tokenCache.get(cacheKey)) as { accessToken: string; refreshAt: number } | undefined; + // On a miss, or within five minutes of expiry: request a token, then + await tokenCache.set(cacheKey, { accessToken, refreshAt }, { ttl: expiresIn - 300 }); + ``` + + The key is the tenant, audience and client ID, never the secret. Requests that arrive while a + token is being fetched should wait for that one request. +- **CI:** request one token at the start of the job and reuse it for every request in the job. + +Also: +- **Store the five variables in a secret store**, under the names app-v2 and the template use: + `POLICYENGINE_API_URL`, `POLICYENGINE_API_AUTH0_DOMAIN`, `POLICYENGINE_API_AUTH0_AUDIENCE`, + `POLICYENGINE_API_AUTH0_CLIENT_ID` and `POLICYENGINE_API_AUTH0_CLIENT_SECRET`. That is a Modal + secret, Vercel environment variables (the secret marked sensitive), or GitHub Actions secrets + and variables. Never the repository, never a `NEXT_PUBLIC_*` or `VITE_*` name. +- **Never follow redirects.** A followed 307 or 308 re-sends the token request's body, client + secret included, to wherever it points, and Python's `urllib` also copies `Authorization` to a + redirect's target. The template turns redirects off for both requests; in `fetch`, pass + `redirect: "error"`. +- **Cache what does not change.** `/{country}/metadata` is about 10 MB compressed; read it once + per deployment or hour, not per request. + +### Getting a client + +1. Ask the Public API's maintainers for a client for your caller. Say which repository and + service it is, and which environments it needs: production, and staging if previews or local + work call the Public API too. +2. They create a machine-to-machine application in each tenant, with only the + `client_credentials` grant and a grant for that tenant's audience, and put the secret straight + into your caller's secret store. A secret never goes in an issue, a chat message, a PR or a + file. +3. They add the client ID to `PUBLIC_API_SERVER_CLIENT_IDS` in policyengine-api's GitHub + `production` (and `staging`) environment and redeploy the Public API. +4. **Only then deploy code that sends the token.** A valid token of a client that is not on the + list gets 401 today, even while requests without any `Authorization` header are still served. +5. Check it: `GET /health` with the token answers 200. The Public API checks a sent token on + every route, including `/health`, so 401 there means the client, tenant or audience is wrong. + +## Local development and previews + +- **Dashboard pages:** a dashboard on `http://localhost:` or on its team preview + (`*-policy-engine.vercel.app`) calls the production dashboard API at www.policyengine.org + through CORS, with nothing to configure and no credential on the developer's machine. To try a + change to the dashboard API before it is deployed, pass that website preview's URL as + `baseUrl`; website previews call the Public API's staging service. +- **Servers:** production deployments use the production tenant, client and Public API; + preview and development deployments use the staging tenant, a staging client and the + staging service. On Vercel, set the five variables per environment (Production; Preview and + Development), then run `vercel env pull .env.local` for local work, which writes the + Development values. Vercel cannot mark Development values sensitive, so only staging values go + there. On Modal, keep production and staging values in separate secrets. +- Never point a preview or a local run at the production Public API with the production client. + +## Asking for a new dashboard operation + +The dashboard API has exactly the four operations above. Adding one is a change to +`PolicyEngine/policyengine-app-v2`: a route under `website/src/app/api/` and its check in +`website/src/lib/dashboardApi/operations.ts`, a method in `packages/api-client`, and a new +release of `@policyengine/api-client`. Ask for it in an issue in +`PolicyEngine/policyengine-app-v2` that names the Public API call it maps to, the request and +answer shapes the dashboard needs, how often a page calls it, and whether its answers can be +cached. Until it ships, do not call the Public API from the page as a stopgap; precompute the +data, or use a backend with its own client. + +## Errors + +`@policyengine/api-client` throws `PolicyEngineApiError` with `status` (`null` when no answer +could be read), `message`, `body` and `retryAfterSeconds`. Error bodies from the dashboard API +and the Public API share one shape: `{"status": "error", "message": …, "result": null}`. + +| Status | From | Meaning | What to do | +|---|---|---|---| +| 400 | Dashboard API | A missing or unknown field, or a malformed value | Fix the request; `message` names the field | +| 401 | Public API | `{"status":"error","message":"Authentication is required"}` with `WWW-Authenticate: Bearer`: an invalid or expired token, a client not on the allow list, a client token from another tenant, two `Authorization` headers, or, once the requirement is on, no server credential | Server: drop the cached token and retry once with a new one (the template does this); a second 401 means the client is not listed in that environment, or the tenant or audience is wrong, so stop and report it. Page: the website's own credential failed; show an error, do not retry in a loop | +| 403 | Dashboard API | "Pages on this origin may not call the dashboard API." The page's origin is not allowed | Serve the page from an allowed origin. A cross-origin page cannot read this answer: the browser reports a CORS error and the client throws with `status` `null` | +| 403 | Public API user routes | A forwarded `PolicyEngine-User-Authorization` token is a machine-to-machine token, not a user's | Forward only a signed-in user's own token there | +| 404 | Dashboard API | An unknown country in `/api/metadata/{country}` | Use `us` or `uk` | +| 415 | Dashboard API | The body's `Content-Type` is not JSON | Send `Content-Type: application/json`; the client does | +| 429 | Dashboard API firewall, or the Public API's load balancer | Too many requests from one IP address | Wait `Retry-After` when present, otherwise back off (5 s, then doubling); `compareEconomy` already does. The load balancer's 429 is not JSON. A server's requests with a bearer token skip its per-address limits on `/{country}/metadata`, `/{country}/calculate` and `/{country}/calculate-full` | +| 502 | Dashboard API | Auth0 or the Public API could not be reached, or the Public API answered with a redirect | Retry later with back-off | +| 502 | Public API, economy comparison | `status: "error"` with `retry_after_seconds`: the comparison failed | Show the failure; do not ask again before `retry_after_seconds` | +| 503 | Public API | `{"status":"error","message":"Authentication is unavailable"}`: it could not check the token (Auth0's signing keys unreachable, or its own settings) | Keep the token; retry with back-off. It is not a refusal of the client | +| 503 | Dashboard API | Its own settings are missing or incomplete, for example on a website preview | Not retryable; report it to the website's maintainers | +| 504 | Dashboard API | The Public API did not answer in time (100 s for a household calculation, 40 s for a policy or a comparison read, 60 s for metadata) | Retry later with back-off | + +## Related skills + +- policyengine-api — the Public API's endpoints, household and policy shapes, and the v2 alpha +- policyengine-tools — building and embedding a standalone tool; its data patterns +- policyengine-app — policyengine.org itself, including `appZoneRoutes.ts` +- policyengine-cloud-costs — Modal and Cloud Run settings and secrets for a backend diff --git a/skills/policyengine-api-access/templates/public_api_token.py b/skills/policyengine-api-access/templates/public_api_token.py new file mode 100644 index 0000000..93f8436 --- /dev/null +++ b/skills/policyengine-api-access/templates/public_api_token.py @@ -0,0 +1,261 @@ +"""Auth0 client-credentials tokens for the PolicyEngine Public API, cached across instances. + +Copy this file into a server that calls the Public API (api.policyengine.org) +itself: a Modal backend, a Cloud Run service or a scheduled job. Browser code +never calls the Public API; pages use www.policyengine.org's dashboard API +(the policyengine-api-access skill). + +It reads the five variables below from the server's secret store, asks the +Auth0 tenant for one token, and keeps it until five minutes before it expires: +first in this process's memory, then in a store the server's instances share, +so a deployment asks Auth0 for about one token a day rather than one per +request or per container. Auth0 counts the machine-to-machine tokens it issues +per tenant per month. + + POLICYENGINE_API_URL https://api.policyengine.org in production + POLICYENGINE_API_AUTH0_DOMAIN policyengine-api.uk.auth0.com in production + POLICYENGINE_API_AUTH0_AUDIENCE https://api.policyengine.org/ in production + POLICYENGINE_API_AUTH0_CLIENT_ID this caller's own client + POLICYENGINE_API_AUTH0_CLIENT_SECRET that client's secret + +On Modal, the shared store is a Dict, and each container builds one provider the +first time it needs one (the secret's variables exist only inside the container): + + import functools + + import modal + from public_api_token import PublicApiSettings, PublicApiTokenProvider, call_public_api + + TOKEN_STORE = modal.Dict.from_name("TOOL_NAME-public-api-token", create_if_missing=True) + + @functools.cache + def public_api_tokens() -> PublicApiTokenProvider: + return PublicApiTokenProvider(PublicApiSettings.from_environment(), shared_store=TOKEN_STORE) + + @app.function(secrets=[modal.Secret.from_name("TOOL_NAME-policyengine-api")]) + def household(situation: dict) -> dict: + return call_public_api(public_api_tokens(), "POST", "/us/calculate", {"household": situation}) + +Any object with ``get(key)`` and item assignment works as the shared store; a +plain ``dict`` keeps the token for one process only. Only the token and when to +replace it are stored, never the client secret. + +Requests never follow redirects: a followed redirect would send the client +secret, or the token, to wherever it points. +""" + +from __future__ import annotations + +import json +import logging +import os +import threading +import time +import urllib.error +import urllib.request +from collections.abc import Callable, Mapping, MutableMapping +from dataclasses import dataclass +from typing import Any + +LOGGER = logging.getLogger(__name__) + +# Replace a token this long before it expires (half its life, if shorter). +TOKEN_REFRESH_MARGIN_SECONDS = 300 +TOKEN_REQUEST_TIMEOUT_SECONDS = 10 +PUBLIC_API_TIMEOUT_SECONDS = 120 + +SETTING_VARIABLES = { + "api_url": "POLICYENGINE_API_URL", + "token_endpoint_host": "POLICYENGINE_API_AUTH0_DOMAIN", + "audience": "POLICYENGINE_API_AUTH0_AUDIENCE", + "client_id": "POLICYENGINE_API_AUTH0_CLIENT_ID", + "client_secret": "POLICYENGINE_API_AUTH0_CLIENT_SECRET", +} + + +class PublicApiSettingsError(ValueError): + """A setting is missing or malformed.""" + + +class PublicApiTokenError(RuntimeError): + """Auth0 refused the token request or gave no usable token.""" + + +class _RefuseRedirects(urllib.request.HTTPRedirectHandler): + def redirect_request(self, req, fp, code, msg, headers, newurl): # noqa: ANN001, ANN201 + return None # urllib then raises HTTPError with the 3xx status + + +NO_REDIRECT_OPENER = urllib.request.build_opener(_RefuseRedirects) + + +@dataclass(frozen=True) +class PublicApiSettings: + api_url: str + token_endpoint_host: str + audience: str + client_id: str + client_secret: str + + @classmethod + def from_environment(cls, environment: Mapping[str, str] | None = None) -> PublicApiSettings: + environment = os.environ if environment is None else environment + values = {field: environment.get(name, "").strip() for field, name in SETTING_VARIABLES.items()} + missing = [SETTING_VARIABLES[field] for field, value in values.items() if not value] + if missing: + raise PublicApiSettingsError(f"Set {', '.join(missing)}.") + values["api_url"] = values["api_url"].rstrip("/") + # Accept "tenant.uk.auth0.com", with or without https:// and a trailing slash. + values["token_endpoint_host"] = ( + values["token_endpoint_host"].removeprefix("https://").rstrip("/") + ) + return cls(**values) + + +class PublicApiTokenProvider: + """Gives out one cached access token per client; thread-safe within a process.""" + + def __init__( + self, + settings: PublicApiSettings, + shared_store: MutableMapping[str, Any] | None = None, + clock: Callable[[], float] = time.time, + opener: Any = NO_REDIRECT_OPENER, + ) -> None: + self.settings = settings + self.shared_store = shared_store + self.clock = clock + self.opener = opener + # The client secret is not part of the key, so it never reaches the store. + self.cache_key = " ".join( + ("public-api-token", settings.token_endpoint_host, settings.audience, settings.client_id) + ) + self._remembered: dict[str, Any] | None = None + self._lock = threading.Lock() + + def access_token(self) -> str: + with self._lock: + if self._is_usable(self._remembered): + return self._remembered["access_token"] + shared_token = self._read_shared_token() + if self._is_usable(shared_token): + self._remembered = shared_token + return shared_token["access_token"] + self._remembered = self._request_token() + self._write_shared_token(self._remembered) + return self._remembered["access_token"] + + def forget(self, access_token: str) -> None: + """Drops a token the Public API refused, so the next call gets a new one.""" + with self._lock: + if self._remembered is not None and self._remembered["access_token"] == access_token: + self._remembered = None + shared_token = self._read_shared_token() + if shared_token is not None and shared_token.get("access_token") == access_token: + self._write_shared_token({"access_token": "", "refresh_at": 0}) + + def _is_usable(self, token: dict[str, Any] | None) -> bool: + return ( + isinstance(token, dict) + and isinstance(token.get("access_token"), str) + and bool(token["access_token"]) + and isinstance(token.get("refresh_at"), (int, float)) + and self.clock() < token["refresh_at"] + ) + + def _read_shared_token(self) -> dict[str, Any] | None: + if self.shared_store is None: + return None + try: + return self.shared_store.get(self.cache_key) + except Exception as error: # a store outage must not stop requests + LOGGER.warning("Could not read the Public API token from the shared store: %s", error) + return None + + def _write_shared_token(self, token: dict[str, Any]) -> None: + if self.shared_store is None: + return + try: + self.shared_store[self.cache_key] = token + except Exception as error: + LOGGER.warning("Could not store the Public API token in the shared store: %s", error) + + def _request_token(self) -> dict[str, Any]: + request = urllib.request.Request( + f"https://{self.settings.token_endpoint_host}/oauth/token", + data=json.dumps( + { + "grant_type": "client_credentials", + "client_id": self.settings.client_id, + "client_secret": self.settings.client_secret, + "audience": self.settings.audience, + } + ).encode(), + headers={"Content-Type": "application/json", "Accept": "application/json"}, + method="POST", + ) + try: + with self.opener.open(request, timeout=TOKEN_REQUEST_TIMEOUT_SECONDS) as response: + answer = json.loads(response.read()) + except urllib.error.HTTPError as error: + # Auth0's "error" field is a fixed code such as "access_denied"; the + # rest of the answer is not logged. + try: + error_code = json.loads(error.read()).get("error", "") + except Exception: + error_code = "" + raise PublicApiTokenError( + f"Auth0 refused the token request with HTTP {error.code} {error_code}".strip() + ) from None + except (urllib.error.URLError, TimeoutError, ValueError) as error: + raise PublicApiTokenError(f"The Auth0 token request failed: {error}") from None + + access_token = answer.get("access_token") + lifetime_seconds = answer.get("expires_in") + if not isinstance(access_token, str) or not access_token or not isinstance( + lifetime_seconds, (int, float) + ) or lifetime_seconds <= 0: + raise PublicApiTokenError("Auth0's answer has no access token or lifetime.") + margin_seconds = min(TOKEN_REFRESH_MARGIN_SECONDS, lifetime_seconds / 2) + return { + "access_token": access_token, + "refresh_at": self.clock() + lifetime_seconds - margin_seconds, + } + + +def call_public_api( + tokens: PublicApiTokenProvider, + method: str, + path: str, + body: Any = None, + *, + opener: Any = None, + timeout_seconds: float = PUBLIC_API_TIMEOUT_SECONDS, +) -> Any: + """Sends one request with the server token and returns the parsed JSON answer. + + A 401 means the token was refused: it is dropped and the request is sent once + more with a new token. A second 401 is raised, because the client is then not + on the Public API's allow list for this environment, or its tenant or + audience is wrong; asking Auth0 again would not help. Every other error is + raised as urllib's HTTPError, with the status and the answer's body. + """ + opener = tokens.opener if opener is None else opener + data = None if body is None else json.dumps(body).encode() + for attempt in (1, 2): + access_token = tokens.access_token() + headers = {"Accept": "application/json", "Authorization": f"Bearer {access_token}"} + if data is not None: + headers["Content-Type"] = "application/json" + request = urllib.request.Request( + f"{tokens.settings.api_url}{path}", data=data, headers=headers, method=method + ) + try: + with opener.open(request, timeout=timeout_seconds) as response: + return json.loads(response.read()) + except urllib.error.HTTPError as error: + if error.code == 401 and attempt == 1: + tokens.forget(access_token) + continue + raise + raise AssertionError("unreachable") diff --git a/targets/claude/marketplace.template.json b/targets/claude/marketplace.template.json index e3dfc08..7d769f4 100644 --- a/targets/claude/marketplace.template.json +++ b/targets/claude/marketplace.template.json @@ -1,7 +1,7 @@ { "$schema": "https://claude.ai/schemas/plugin-marketplace.json", "name": "policyengine-claude", - "version": "4.1.0", + "version": "4.2.0", "description": "Complete PolicyEngine knowledge base - for users, analysts, and contributors across the entire PolicyEngine ecosystem", "owner": { "name": "PolicyEngine", diff --git a/tests/test_api_access_skill.py b/tests/test_api_access_skill.py index cbda20a..515a940 100644 --- a/tests/test_api_access_skill.py +++ b/tests/test_api_access_skill.py @@ -218,6 +218,8 @@ def load_token_module() -> ModuleType: assert TOKEN_TEMPLATE.is_file(), f"{TOKEN_TEMPLATE.relative_to(REPO_ROOT)} is missing" spec = importlib.util.spec_from_file_location("public_api_token", TOKEN_TEMPLATE) module = importlib.util.module_from_spec(spec) + # dataclasses resolves the module's annotations through sys.modules. + sys.modules["public_api_token"] = module spec.loader.exec_module(module) return module From 29b87d26b26a4b50f27dc54aa0cdfe12dfe3b86f Mon Sep 17 00:00:00 2001 From: Anthony Volk <14987227+anth-volk@users.noreply.github.com> Date: Tue, 10 Nov 2026 22:07:49 +0400 Subject: [PATCH 03/16] Test that no skill, agent or command sends browser code to the Public API Adds tests/test_public_api_browser_guidance.py. It fails until the guidance is updated: TypeScript and JavaScript examples in skills/, targets/ and docs/ may not name a Public API host (api.policyengine.org or its Cloud Run addresses; the household API and the v2 alpha hosts are not matched), no NEXT_PUBLIC_ or VITE_ variable may be set to one or named like a credential, the skills, agents and commands that guide dashboard and app work must point to policyengine-api-access, the policyengine-api skill must list /health and /v2/openapi.json instead of the removed /specification and liveness and readiness checks, and the tools skill's Pattern B must use @policyengine/api-client. Co-Authored-By: Claude Opus 5.5 --- tests/test_public_api_browser_guidance.py | 155 ++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 tests/test_public_api_browser_guidance.py diff --git a/tests/test_public_api_browser_guidance.py b/tests/test_public_api_browser_guidance.py new file mode 100644 index 0000000..d3a7724 --- /dev/null +++ b/tests/test_public_api_browser_guidance.py @@ -0,0 +1,155 @@ +"""No skill, agent, command or doc tells browser code to call the Public API. + +The Public API (api.policyengine.org) is becoming callable only by +PolicyEngine's own servers. Pages reach it through www.policyengine.org's +dashboard API with ``@policyengine/api-client``, and servers send their own +Auth0 client-credentials token; the policyengine-api-access skill says how. +These tests keep the rest of the catalog from teaching the old way: + +- a browser-language example (TypeScript or JavaScript) never names a Public + API host; +- no ``NEXT_PUBLIC_*`` or ``VITE_*`` variable is set to a Public API host, or + named like a credential; +- the skills, agents and commands that guide dashboard and app work point to + policyengine-api-access; +- the policyengine-api skill lists the Public API's routes as they are now. + +Server-side, notebook and analysis examples that call the Public API (shell +``curl``, Python) are not checked here: they run outside a browser. +""" + +from __future__ import annotations + +import re +from pathlib import Path + +import pytest + +REPO_ROOT = Path(__file__).resolve().parent.parent +SCAN_DIRS = ("skills", "targets", "docs") +TEXT_SUFFIXES = {".md", ".json", ".yaml", ".yml", ".py", ".sh", ".ts", ".tsx", ".js", ".mjs"} + +BROWSER_LANGUAGES = {"ts", "tsx", "js", "jsx", "javascript", "typescript", "mjs"} +# The Public API only: not household.api.policyengine.org (the household API) or +# v2.api.policyengine.org (the v2 alpha), hence the left boundary. +PUBLIC_API_HOST = re.compile( + r"(? list[Path]: + return sorted( + path + for directory in SCAN_DIRS + for path in (REPO_ROOT / directory).rglob("*") + if path.is_file() and path.suffix in TEXT_SUFFIXES and "__pycache__" not in path.parts + ) + + +def browser_blocks_naming_the_public_api(text: str) -> list[str]: + return [ + body + for language, body in FENCE.findall(text) + if language.lower() in BROWSER_LANGUAGES and PUBLIC_API_HOST.search(body) + ] + + +def test_no_browser_language_example_names_the_public_api() -> None: + offenders = [ + path.relative_to(REPO_ROOT).as_posix() + for path in scanned_files() + if path.suffix == ".md" and browser_blocks_naming_the_public_api(path.read_text()) + ] + assert offenders == [], f"browser-language examples that call the Public API: {offenders}" + + +def test_no_public_prefix_variable_holds_the_public_api_or_a_credential() -> None: + offenders = [] + for path in scanned_files(): + for line_number, line in enumerate(path.read_text().splitlines(), start=1): + if PUBLIC_PREFIX_SET_TO_PUBLIC_API.search(line) or PUBLIC_PREFIX_CREDENTIAL.search(line): + offenders.append(f"{path.relative_to(REPO_ROOT).as_posix()}:{line_number}") + assert offenders == [] + + +def test_guards_catch_the_patterns_they_name() -> None: + browser_example = "```ts\nconst API_BASE = 'https://api.policyengine.org';\n```\n" + indented_example = " ```js\n fetch(`https://api.policyengine.org/us/calculate`)\n ```\n" + cloud_run_example = "```tsx\nfetch('https://policyengine-api-staging-abc123defg-uc.a.run.app/us/metadata')\n```\n" + shell_example = "```bash\ncurl https://api.policyengine.org/us/metadata\n```\n" + household_api_example = "```ts\nfetch('https://household.api.policyengine.org/us/calculate')\n```\n" + assert browser_blocks_naming_the_public_api(browser_example) + assert browser_blocks_naming_the_public_api(indented_example) + assert browser_blocks_naming_the_public_api(cloud_run_example) + assert not browser_blocks_naming_the_public_api(shell_example) + assert not browser_blocks_naming_the_public_api(household_api_example) + for unsafe in ( + "NEXT_PUBLIC_API_URL=https://api.policyengine.org", + "VITE_API_URL: 'https://api.policyengine.org'", + "NEXT_PUBLIC_POLICYENGINE_API_AUTH0_CLIENT_SECRET", + "VITE_API_TOKEN", + ): + assert PUBLIC_PREFIX_SET_TO_PUBLIC_API.search(unsafe) or PUBLIC_PREFIX_CREDENTIAL.search(unsafe), unsafe + for safe in ( + "NEXT_PUBLIC_API_URL=https://policyengine--my-tool-fastapi-app.modal.run", + "never a `NEXT_PUBLIC_*` or `VITE_*` name", + "NEXT_PUBLIC_API_V2_URL || 'https://v2.api.policyengine.org'", + "VITE_HOUSEHOLD_API_URL=https://household.api.policyengine.org", + ): + assert not PUBLIC_PREFIX_SET_TO_PUBLIC_API.search(safe), safe + assert not PUBLIC_PREFIX_CREDENTIAL.search(safe), safe + + +@pytest.mark.parametrize("relative_path", DASHBOARD_GUIDANCE) +def test_dashboard_guidance_points_to_the_access_skill(relative_path: str) -> None: + assert ACCESS_SKILL in (REPO_ROOT / relative_path).read_text() + + +def test_api_skill_lists_the_public_routes_as_they_are_now() -> None: + text = API_SKILL.read_text() + # The Public API removed these (policyengine_api/migration_flags.py). + for removed_path in ("/specification", "/liveness-check", "/readiness-check"): + assert removed_path not in text, removed_path + for public_path in ("/health", "/v2/openapi.json"): + assert public_path in text, public_path + + +def test_api_skill_does_not_send_frontends_to_the_public_api() -> None: + text = API_SKILL.read_text() + assert "JS frontends" not in text + assert "server credential" in text + + +def test_tools_skill_pattern_b_uses_the_dashboard_api() -> None: + text = TOOLS_SKILL.read_text() + pattern_b = re.search(r"^- \*\*B — .*?(?=^- \*\*C — )", text, re.DOTALL | re.MULTILINE) + assert pattern_b, "the tools skill has no Pattern B entry" + assert "@policyengine/api-client" in pattern_b.group(0) + assert "https://api.policyengine.org" not in pattern_b.group(0) From b6f3e857870c503a73e7e037d81027f61d654b9d Mon Sep 17 00:00:00 2001 From: Anthony Volk <14987227+anth-volk@users.noreply.github.com> Date: Tue, 10 Nov 2026 22:10:25 +0400 Subject: [PATCH 04/16] Send dashboard and app guidance through the dashboard API, not the Public API The Public API is becoming callable only by PolicyEngine's servers, so the catalog stops telling browser code to call api.policyengine.org: - policyengine-api says who may call v1 (servers with their own credential), that pages use the dashboard API, and lists /health and /v2/openapi.json instead of the removed /specification and liveness and readiness checks; - policyengine-tools' Pattern B is the dashboard API through @policyengine/api-client, and a Pattern C backend that calls the Public API gets its own client and cached token; - policyengine-app says the calculator's direct browser calls are moving to app.policyengine.org's own allow-listed route, and new code goes through it; - backend-builder and new-tool build Pattern B on @policyengine/api-client; the dashboard planner, scaffold and integrator load policyengine-api-access and describe the pattern by what the dashboard API offers; - the policyengine skill, the app-v2 Codex routing and docs/when-to-use.md point to policyengine-api-access; the guide's catalog counts are current. The data_pattern value policyengine-api is kept, so existing plan.yaml files still validate. Co-Authored-By: Claude Opus 5.5 --- docs/when-to-use.md | 3 +- skills/policyengine-api/SKILL.md | 34 ++++--- skills/policyengine-app/SKILL.md | 16 +++- skills/policyengine-tools/SKILL.md | 26 +++-- skills/policyengine/SKILL.md | 3 +- .../agents/dashboard/backend-builder.md | 94 ++++++++++--------- .../agents/dashboard/dashboard-integrator.md | 2 + .../agents/dashboard/dashboard-planner.md | 10 +- .../agents/dashboard/dashboard-scaffold.md | 6 +- targets/claude/commands/new-tool.md | 25 ++--- .../agents/policyengine-app-v2/AGENTS.md | 1 + 11 files changed, 131 insertions(+), 89 deletions(-) diff --git a/docs/when-to-use.md b/docs/when-to-use.md index eccf768..d160fa0 100644 --- a/docs/when-to-use.md +++ b/docs/when-to-use.md @@ -1,6 +1,6 @@ # When to use what -The PolicyEngine plugin ships 20 command files, 36 agents, and 23 skills (20 knowledge skills plus the three workflow skills, consolidated from 53 in the July 2026 rebuild). The `/encode-policy-v2`, `/review-program`, and `/fix-pr` entries are provided directly by skills: each name resolves to a skill whose `references/workflow.md` is the canonical definition, with no duplicate command stub. Most days you'll only use 3-5 entry points. This guide maps common work to the right one. +The PolicyEngine plugin ships 20 command files, 36 agents, and 25 skills (22 knowledge skills plus the three workflow skills, consolidated from 53 in the July 2026 rebuild). The `/encode-policy-v2`, `/review-program`, and `/fix-pr` entries are provided directly by skills: each name resolves to a skill whose `references/workflow.md` is the canonical definition, with no duplicate command stub. Most days you'll only use 3-5 entry points. This guide maps common work to the right one. ## Quick decision matrix @@ -95,6 +95,7 @@ These get pulled in automatically by their trigger keywords, but useful to know **API integration**: - `policyengine-api` — REST endpoints (v1 production, api-v2 alpha); analysts calling from Python should use the `policyengine` skill instead +- `policyengine-api-access` — reaching the Public API from a dashboard page (the dashboard API through `@policyengine/api-client`) or from a server (its own Auth0 client); browser code never calls api.policyengine.org ## Common workflows (recipes) diff --git a/skills/policyengine-api/SKILL.md b/skills/policyengine-api/SKILL.md index f7133bc..69e7546 100644 --- a/skills/policyengine-api/SKILL.md +++ b/skills/policyengine-api/SKILL.md @@ -1,15 +1,15 @@ --- name: policyengine-api description: | - Load when consuming or developing the PolicyEngine REST APIs — the v1 Flask API at - api.policyengine.org (production today) or the v2 alpha microservices in policyengine-api-v2. - Covers the v1 endpoint surface (household calc, economy-over-baseline polling), the v2 - architecture (three services, uv/Docker/Cloud Run, OpenAPI client-gen), and when to use REST - vs the Python package. + Load when developing the PolicyEngine REST APIs or writing server code against them — the v1 + Flask API at api.policyengine.org (the Public API, production today, callable only with a + server credential) or the v2 alpha microservices in policyengine-api-v2. Covers the v1 + endpoint surface (household calc, economy-over-baseline polling), the v2 architecture (three + services, uv/Docker/Cloud Run, OpenAPI client-gen), and when to use REST vs the Python package. Triggers: PolicyEngine API, api.policyengine.org, REST endpoint, household calculate, economy over baseline, v2 API, api-full, api-simulation, api-tagger, OpenAPI client, v2.api.policyengine.org. - NOT for: Python analysis (use the policyengine skill) or calling the API from the app - frontend (policyengine-app). + NOT for: Python analysis (use the policyengine skill), or reaching the API from a dashboard + page or your own server (policyengine-api-access). metadata: category: apps --- @@ -22,13 +22,19 @@ Two APIs coexist: **v1** (`PolicyEngine/policyengine-api`, Flask) is production **Pick the right client first.** If you are computing policy impacts **from Python**, use the `policyengine` package (`pe.us.calculate_household`, `Simulation`, `economic_impact_analysis`) — see the **policyengine** skill. It pins a certified model + data bundle and is reproducible. -Reach for REST only for **apps and external integrations** (JS frontends, third parties) that -need HTTP. + +**Who may call v1.** The Public API is becoming callable only by PolicyEngine's own servers, +each with its own Auth0 client-credentials token (a server credential) in +`Authorization: Bearer`. Once that requirement is on, every other request gets 401. Browser +code never calls it: dashboard pages use www.policyengine.org's dashboard API through +`@policyengine/api-client`. The **policyengine-api-access** skill covers both routes, getting a +client, and the errors. ## v1 API — production (`https://api.policyengine.org`) Flask (`policyengine_api`, Python 3.10/3.11). Country id (`us`, `uk`, `ca`, …) is the first -path segment. Verified route surface (`policyengine_api/routes/`, `api.py`): +path segment. Every route except the public ones below needs a server credential once the +requirement is on. Verified route surface (`policyengine_api/routes/`, `api.py`): | Route | Method | Purpose | |---|---|---| @@ -41,7 +47,8 @@ path segment. Verified route surface (`policyengine_api/routes/`, `api.py`): | `/{country}/policy` · `/{country}/policy/{id}` | POST · GET | store / fetch a reform policy | | `/{country}/economy/{policyId}/over/{baselinePolicyId}` | GET | society-wide reform impact | | `/{country}/simulation`, `/{country}/report` | POST/GET/PATCH | stored simulations / report output | -| `/specification` | GET | OpenAPI spec (also `/liveness-check`, `/readiness-check`) | +| `/health` | GET, HEAD | health check; public | +| `/v2/openapi.json` | GET | OpenAPI schema; public | **The economy endpoint is asynchronous — poll it.** The same GET is re-issued until the job finishes; the response is a status envelope, not the result on the first call: @@ -90,11 +97,12 @@ app-v2 already carries a **v2 alpha adapter** in `app/src/api/v2/` (`API_V2_BASE_URL = process.env.NEXT_PUBLIC_API_V2_URL || 'https://v2.api.policyengine.org'`), with endpoints per **policyengine-api-v2-alpha PR #77**. v2 calculations are **async job + poll**, and it adds CRUD for households/policies/simulations. **Variation/axes household -calculations are not in v2** and remain on v1. Until v2 is promoted, keep new REST consumers on -v1 unless you specifically need a v2 capability. +calculations are not in v2** and remain on v1. Until v2 is promoted, keep new server-side REST +consumers on v1 unless you specifically need a v2 capability. ## Related skills - policyengine — Python analysis (the preferred path for computing impacts from Python) +- policyengine-api-access — reaching v1 from dashboard pages (the dashboard API) and from servers (a server credential) - policyengine-app — how the app-v2 frontend calls v1 and the v2 adapter - policyengine-tools — Modal backends for computations the API doesn't expose diff --git a/skills/policyengine-app/SKILL.md b/skills/policyengine-app/SKILL.md index 18218d1..a23fc12 100644 --- a/skills/policyengine-app/SKILL.md +++ b/skills/policyengine-app/SKILL.md @@ -90,8 +90,16 @@ that add country-prefixed `*.vercel.app` rewrites to `vercel.json`. Full zone me ## Calling the API -The legacy calculator calls the **v1 API** (`app/src/constants.ts`: -`BASE_URL = 'https://api.policyengine.org'`). Verified shapes: +The calculator's browser code reaches the **v1 API** (the Public API) through `BASE_URL` +(`app/src/constants.ts`: `VITE_API_URL`, falling back to `https://api.policyengine.org`). The +Public API is becoming callable only by PolicyEngine's servers, so those calls are moving to +app.policyengine.org's own same-origin route, `/api/policyengine/{Public API path}` +(`calculator-app/src/app/api/policyengine/[...path]/route.ts`). The route adds the calculator's +server credential and forwards only the operations in `app/src/libs/publicApiRoute/allowList.ts`; +anything else gets 404. New calculator code goes through that route, and an operation the app +has not called before needs an allow-list entry in the same PR. Never add a browser call to +api.policyengine.org. Dashboards use the website's dashboard API (`website/src/app/api/`) +instead; see policyengine-api-access. Verified shapes (the route keeps these paths): - `GET {BASE_URL}/{country}/household/{id}` and `.../household/{id}/policy/{policyId}` — household calc - `POST {BASE_URL}/{country}/household` — create household @@ -127,6 +135,9 @@ policyengine-api skill for both APIs. | `website/src/data/appZoneRoutes.ts` | Registry of external Next zones | | `website/src/app/[countryId]//page.tsx` | Server page + client split | | `app/src/constants.ts` | `BASE_URL` (v1 API) | +| `app/src/libs/publicApiRoute/allowList.ts` | Operations app.policyengine.org's own route forwards to the Public API | +| `website/src/app/api/` | The dashboard API dashboards call (policyengine-api-access) | +| `packages/public-api-forwarding/` | Server-side forwarding both routes use: token cache, headers, errors | | `app/src/api/` and `app/src/api/v2/` | v1 fetchers and v2 alpha adapter | | `app/src/designTokens/` | Local JS token shim (re-exported by website) | | `vercel.json` (root) | Legacy config — do not add new zone rewrites here | @@ -136,4 +147,5 @@ policyengine-api skill for both APIs. - policyengine-tools — standalone embedded tools + full multizone zone config - policyengine-design — ui-kit 0.4.0 components and design tokens - policyengine-api — v1 and v2 API surfaces +- policyengine-api-access — the dashboard API and server credentials for the Public API - policyengine-writing — content and copy style diff --git a/skills/policyengine-tools/SKILL.md b/skills/policyengine-tools/SKILL.md index 9da8762..a47a5d1 100644 --- a/skills/policyengine-tools/SKILL.md +++ b/skills/policyengine-tools/SKILL.md @@ -9,8 +9,9 @@ description: | Triggers: new tool, standalone calculator, dashboard, embed in policyengine.org, multizone, basePath, assetPrefix, appZoneRoutes, Modal backend, scale to zero, vercel --scope policy-engine, ui-kit theme.css, recharts colors. - NOT for: developing policyengine.org itself (use policyengine-app) or token values - (policyengine-design). + NOT for: developing policyengine.org itself (use policyengine-app), token values + (policyengine-design), or how a page or backend reaches api.policyengine.org + (policyengine-api-access). metadata: category: apps --- @@ -132,11 +133,19 @@ Never paste ad-hoc computed numbers into source. Always: Python script → data - **A — Precomputed JSON/CSV**: finite scenarios (legislative trackers, static analyses). A `scripts/*.py` microsimulation writes to `public/data/`; the frontend imports it. Zero latency, works offline. -- **B — v1 PolicyEngine API** (`https://api.policyengine.org`): household-level calc across - user-entered income/family/state. `POST /{country}/calculate` with a household payload, or - the stateful household/economy flow. Always up to date; network latency. See policyengine-api. -- **C — Custom Modal backend**: only when the v1 API can't do it (society-wide microsim, - custom reform params, non-standard entities). Pattern below. +- **B — the dashboard API** (`@policyengine/api-client`): household-level calc across + user-entered income/family/state, plus storing a reform and comparing it across the economy, + and country metadata. The page calls www.policyengine.org's dashboard API + (`POST /api/household/calculate`, `POST /api/policies`, `GET /api/economy/compare`, + `GET /api/metadata/{country}`), whose server adds PolicyEngine's credential and forwards to + the Public API. Always up to date; network latency. Never call the Public API + (api.policyengine.org) from the page. See policyengine-api-access for the operations, + polling, allowed origins and errors, and policyengine-api for the household shapes. +- **C — Custom Modal backend**: only when the dashboard API can't do it (society-wide microsim, + custom reform params, non-standard entities). Pattern below. A backend that itself calls the + Public API needs its own Auth0 client and a cached server token (policyengine-api-access, + `templates/public_api_token.py`); one that runs `policyengine` in its own process needs + neither. ### Pattern C: Modal gateway + worker + polling @@ -274,5 +283,6 @@ test, `bun run build`) before launch. - policyengine-app — the host site (policyengine.org) and its multizone registry - policyengine-design — ui-kit 0.4.0 components, tokens, chart colors, Plotly style -- policyengine-api — v1/v2 API surfaces for Pattern B +- policyengine-api-access — Pattern B's dashboard API, and server credentials for backends that call the Public API +- policyengine-api — the Public API's endpoints and household shapes - policyengine (Python) — microsimulation for Pattern A/C data scripts diff --git a/skills/policyengine/SKILL.md b/skills/policyengine/SKILL.md index 32f9080..955820c 100644 --- a/skills/policyengine/SKILL.md +++ b/skills/policyengine/SKILL.md @@ -10,7 +10,8 @@ description: | congressional district, constituency, Microcosm dataset, MicroSeries, ensure_datasets, economic_impact_analysis, managed_microsimulation. NOT for: implementing new variables/parameters inside country models (use - policyengine-model-development) or calling the REST API from JS (use policyengine-api). + policyengine-model-development) or calling the REST API from a page or server (use + policyengine-api-access). metadata: category: analysis --- diff --git a/targets/claude/agents/dashboard/backend-builder.md b/targets/claude/agents/dashboard/backend-builder.md index 6256c1a..d433895 100644 --- a/targets/claude/agents/dashboard/backend-builder.md +++ b/targets/claude/agents/dashboard/backend-builder.md @@ -20,6 +20,7 @@ Builds the data layer for a dashboard based on the approved `plan.yaml`. ## Skills Used - **policyengine-tools** - Data patterns, API integration, and Modal backend architecture +- **policyengine-api-access** - The dashboard API for pages, and server credentials for a backend that calls the Public API (policyengine-api and custom-modal) - **policyengine-us** or **policyengine-uk** - PolicyEngine variables - **policyengine** - Python simulation mechanics, reform dictionaries, and parameter path syntax (custom-modal only) - **policyengine-cloud-costs** - Modal defaults (scale to zero, `max_containers`, measured sizes) and how to declare an exception (custom-modal only) @@ -28,8 +29,8 @@ Builds the data layer for a dashboard based on the approved `plan.yaml`. **Always prefer simpler patterns.** Before building a custom backend: -1. **Can `api.policyengine.org/calculate` handle it?** → Use Pattern B (`policyengine-api`) -2. **Does it need microsimulation or custom reforms?** → Use Pattern C (`custom-modal`) with gateway + polling +1. **Can the dashboard API handle it?** It calculates households, stores a parameter reform and compares it with current law across the economy, and reads country metadata. → Use Pattern B (`policyengine-api`) +2. **Does it need other microsimulation output or structural reforms?** → Use Pattern C (`custom-modal`) with gateway + polling 3. **Is the parameter space finite?** → Use Pattern A/D (`precomputed` / `precomputed-csv`) Pattern C is the most complex and should be the last resort. If the plan specifies `custom-modal`, the plan MUST include a `reason` explaining why Pattern B is insufficient. @@ -39,10 +40,11 @@ Pattern C is the most complex and should be the last resort. If the plan specifi **Before starting ANY work, use the Skill tool to load each required skill:** 1. `Skill: policyengine-tools` -2. `Skill: policyengine-us` (if US dashboard) -3. `Skill: policyengine-uk` (if UK dashboard) -4. `Skill: policyengine` (if custom-modal pattern — **required** for simulation mechanics and correct reform parameter paths) -5. `Skill: policyengine-cloud-costs` (if custom-modal pattern) +2. `Skill: policyengine-api-access` (if policyengine-api pattern, or a custom-modal backend that calls the Public API) +3. `Skill: policyengine-us` (if US dashboard) +4. `Skill: policyengine-uk` (if UK dashboard) +5. `Skill: policyengine` (if custom-modal pattern — **required** for simulation mechanics and correct reform parameter paths) +6. `Skill: policyengine-cloud-costs` (if custom-modal pattern) ## Input @@ -115,59 +117,62 @@ Create `lib/api/__tests__/client.test.ts`: - Test that data matches expected TypeScript types - Test that all expected keys/dimensions are present -## Pattern B: PolicyEngine API (`policyengine-api`) +## Pattern B: the dashboard API (`policyengine-api`) -When `data_pattern: policyengine-api`, the dashboard calls `api.policyengine.org` directly for household calculations. No custom backend needed. +When `data_pattern: policyengine-api`, the page calls www.policyengine.org's dashboard API through `@policyengine/api-client`. The website's server adds PolicyEngine's credential and forwards each operation to the Public API, so no custom backend is needed. **The page never calls `api.policyengine.org`**: the Public API is becoming callable only by PolicyEngine's servers. The `policyengine-api-access` skill has the four operations, polling, the origins the dashboard API accepts, and its errors. -### Step 1: Define Types +### Step 1: Install the client and define types -Read the plan's endpoints and generate TypeScript interfaces for the household request and response: +```bash +bun add @policyengine/api-client +``` + +Read the plan's endpoints and write the household and result types. Use `type` aliases: the client takes `Record`, which an `interface` is not assignable to. ```typescript // types.ts -/** Household structure for the PolicyEngine API */ -export interface HouseholdRequest { - household: { - people: Record>>; - tax_units: Record; - spm_units: Record; - households: Record; - }; -} +/** A household in PolicyEngine's situation format: values keyed by year */ +export type Household = { + people: Record>>; + tax_units: Record; + spm_units: Record; + households: Record; +}; -/** API response from /calculate */ -export interface CalculateResponse { - status: 'ok' | 'error'; - message: string | null; - result: Record; -} +/** The calculated household: the same shape, with the requested variables filled in */ +export type CalculatedHousehold = Household; // Add dashboard-specific types for the variables in the plan ``` -### Step 2: Build the API Client +### Step 2: Build the API client Create `lib/api/client.ts`: ```typescript // client.ts -const API_BASE = 'https://api.policyengine.org'; - -export async function calculate( - countryId: string, - household: HouseholdRequest['household'], -): Promise { - const res = await fetch(`${API_BASE}/${countryId}/calculate`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ household }), - }); - if (!res.ok) throw new Error(`API error: ${res.status}`); - return res.json(); +import { createPolicyEngineApiClient } from '@policyengine/api-client'; +import type { CalculatedHousehold, Household } from './types'; + +// The default base URL, https://www.policyengine.org, works from the dashboard's +// www.policyengine.org path, its own *.vercel.app host, its team previews and localhost. +const policyengine = createPolicyEngineApiClient(); + +export function calculate( + countryId: 'us' | 'uk', + household: Household, + signal?: AbortSignal, +): Promise { + return policyengine.calculateHousehold( + { country: countryId, household }, + { signal }, + ); } ``` +For a reform, pass its parameter changes as `policy` to `calculateHousehold`. For an economy-wide comparison, store the reform with `createPolicy` and poll with `compareEconomy` (current law's policy ID is 2 for `us`, 1 for `uk`). + ### Step 3: Build React Query Hooks Create `lib/hooks/useCalculation.ts`: @@ -175,21 +180,20 @@ Create `lib/hooks/useCalculation.ts`: ```typescript import { useMutation } from '@tanstack/react-query'; import { calculate } from '../api/client'; -import type { HouseholdRequest } from '../api/types'; +import type { Household } from '../api/types'; -export function useCalculation(countryId: string) { +export function useCalculation(countryId: 'us' | 'uk') { return useMutation({ - mutationFn: (household: HouseholdRequest['household']) => - calculate(countryId, household), + mutationFn: (household: Household) => calculate(countryId, household), }); } ``` ### Step 4: Write Tests -Create `lib/api/__tests__/client.test.ts`: +Create `lib/api/__tests__/client.test.ts`. Build the client with `createPolicyEngineApiClient({ fetch: fakeFetch })` (or mock the module), so no test calls the network: - Test that request bodies are correctly structured -- Test that the client handles error responses +- Test that `PolicyEngineApiError` from a refused request reaches the UI's error state - Test type conformance of expected response shapes ## Pattern C: Custom API on Modal (`custom-modal`) — Gateway + Polling diff --git a/targets/claude/agents/dashboard/dashboard-integrator.md b/targets/claude/agents/dashboard/dashboard-integrator.md index 6dca4dc..f07018e 100644 --- a/targets/claude/agents/dashboard/dashboard-integrator.md +++ b/targets/claude/agents/dashboard/dashboard-integrator.md @@ -21,12 +21,14 @@ Wires the frontend components to the backend API client and ensures the full dat - **policyengine-tools** - Data flow patterns - **policyengine-design** - Loading/error state styling - **policyengine-api** - v1 API household payload structure (policyengine-api pattern only) +- **policyengine-api-access** - The dashboard API the page calls through `@policyengine/api-client`, and its errors (policyengine-api pattern only) ## First: Load Required Skills 1. `Skill: policyengine-tools` 2. `Skill: policyengine-design` 3. `Skill: policyengine-api` (if `data_pattern: policyengine-api`) +4. `Skill: policyengine-api-access` (if `data_pattern: policyengine-api`) ## Input diff --git a/targets/claude/agents/dashboard/dashboard-planner.md b/targets/claude/agents/dashboard/dashboard-planner.md index 32f9c24..e52b916 100644 --- a/targets/claude/agents/dashboard/dashboard-planner.md +++ b/targets/claude/agents/dashboard/dashboard-planner.md @@ -26,6 +26,7 @@ Produces a structured YAML implementation plan from a natural-language dashboard - **policyengine-us** - US tax/benefit variables and programs - **policyengine-uk** - UK tax/benefit variables and programs - **policyengine-api** - REST API endpoint catalog (v1 production, v2 alpha status) +- **policyengine-api-access** - What the dashboard API offers pages, and when a backend needs its own server credential - **policyengine-cloud-costs** - Worker sizing, maximums and the cost plan (custom-modal only) ## First: Load Required Skills @@ -37,7 +38,8 @@ Produces a structured YAML implementation plan from a natural-language dashboard 3. `Skill: policyengine-us` (if US dashboard) 4. `Skill: policyengine-uk` (if UK dashboard) 5. `Skill: policyengine-api` -6. `Skill: policyengine-cloud-costs` (if custom-modal pattern) +6. `Skill: policyengine-api-access` +7. `Skill: policyengine-cloud-costs` (if custom-modal pattern) ## Input @@ -235,8 +237,8 @@ Choose from the data patterns defined in the `policyengine-tools` skill (loaded **Decision hierarchy (most preferred first):** 1. `precomputed` / `precomputed-csv` — if parameter space is finite -2. `policyengine-api` — if household-level calculations suffice (always prefer this for standard household tools) -3. `custom-modal` — ONLY if microsimulation or custom reforms are needed +2. `policyengine-api` — if the dashboard API suffices: household calculations, a parameter reform compared with current law across the economy, or country metadata (always prefer this for standard household tools). The page calls it through `@policyengine/api-client`, never api.policyengine.org (policyengine-api-access) +3. `custom-modal` — ONLY if other microsimulation output or structural reforms are needed Write the chosen pattern into `data_pattern` in plan.yaml using these identifiers: @@ -244,7 +246,7 @@ Write the chosen pattern into `data_pattern` in plan.yaml using these identifier |---------------|----------------------| | Pattern A: Precomputed JSON | `precomputed` | | Pattern A: Precomputed CSV | `precomputed-csv` | -| Pattern B: PolicyEngine API | `policyengine-api` | +| Pattern B: the dashboard API (`@policyengine/api-client`) | `policyengine-api` | | Pattern C: Custom Modal backend (gateway + polling) | `custom-modal` | If the chosen pattern is `custom-modal`, the plan **must document why** the simpler patterns are insufficient. The plan must also specify which endpoints need long-running computation (microsimulation) vs. fast computation (household), as this determines worker timeout and memory allocation. diff --git a/targets/claude/agents/dashboard/dashboard-scaffold.md b/targets/claude/agents/dashboard/dashboard-scaffold.md index 3cf11b3..5b46caf 100644 --- a/targets/claude/agents/dashboard/dashboard-scaffold.md +++ b/targets/claude/agents/dashboard/dashboard-scaffold.md @@ -65,8 +65,8 @@ Extract key values: **Verify data pattern choice:** If the plan specifies `custom-modal`, confirm it includes a `reason` explaining why simpler patterns are insufficient. The preferred order is: 1. `precomputed` / `precomputed-csv` — if parameter space is finite -2. `policyengine-api` — if household-level calculations suffice (prefer this for standard household tools) -3. `custom-modal` — only if microsimulation or custom reforms are needed +2. `policyengine-api` — if the dashboard API suffices (prefer this for standard household tools): the page calls www.policyengine.org's dashboard API through `@policyengine/api-client`, never api.policyengine.org (policyengine-api-access skill) +3. `custom-modal` — only if other microsimulation output or structural reforms are needed If the plan uses `custom-modal` without a clear justification, flag this to the user before proceeding. @@ -332,7 +332,7 @@ Generate `lib/api/types.ts` with TypeScript interfaces matching the plan's endpo Generate `lib/api/fixtures.ts` with mock data from `plan.yaml`'s `stub_fixtures`. -**For `policyengine-api` or API v2 alpha patterns**, generate `lib/api/client.ts` with synchronous fetch stubs that return fixture data. +**For `policyengine-api` or API v2 alpha patterns**, generate `lib/api/client.ts` with synchronous fetch stubs that return fixture data. For `policyengine-api`, add `@policyengine/api-client` to the dependencies; the backend-builder replaces the stubs with calls through it (policyengine-api-access skill). Never generate a stub or constant that names api.policyengine.org. **For `custom-modal` pattern**, generate `lib/api/client.ts` with the gateway polling pattern: diff --git a/targets/claude/commands/new-tool.md b/targets/claude/commands/new-tool.md index f9151d9..00c83e3 100644 --- a/targets/claude/commands/new-tool.md +++ b/targets/claude/commands/new-tool.md @@ -18,7 +18,7 @@ Ask the user for: 2. **Countries** (us, uk, or both) 3. **Data pattern** — how the tool gets model results: - **A) Precomputed** — Static JSON or CSV shipped with the app (best for finite parameter spaces) - - **B) PolicyEngine API** — Direct calls to `api.policyengine.org/us/calculate` (best for household calculators) + - **B) Dashboard API** — The page calls www.policyengine.org's dashboard API through `@policyengine/api-client` (best for household calculators). Never call `api.policyengine.org` from the page: the Public API is becoming callable only by PolicyEngine's servers (policyengine-api-access skill) - **C) Custom Modal API** — Python serverless function with the top-level `policyengine[us]` / `policyengine[uk]` package (best when main API doesn't support needed variables/reforms) 4. **Brief description** of what the tool calculates @@ -156,28 +156,28 @@ export default function Home() { ## Step 4: Data pattern boilerplate -> **Prefer Pattern B** (PolicyEngine API) unless the tool needs microsimulation, +> **Prefer Pattern B** (the dashboard API) unless the tool needs microsimulation, > custom reforms, or variables not in the API. Pattern C is significantly more complex > and should be the last resort. Based on the user's choice, add the appropriate data fetching code. -**For Pattern B (PolicyEngine API):** Create `lib/api.js`: +**For Pattern B (the dashboard API):** run `bun add @policyengine/api-client`, then create `lib/api.js`: ```js -const API_BASE = "https://api.policyengine.org"; +import { createPolicyEngineApiClient } from "@policyengine/api-client"; -export async function calculate(countryId, household) { - const res = await fetch(`${API_BASE}/${countryId}/calculate`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ household }), - }); - if (!res.ok) throw new Error(`API error: ${res.status}`); - return res.json(); +// www.policyengine.org's dashboard API; its server adds PolicyEngine's credential. +const policyengine = createPolicyEngineApiClient(); + +export function calculate(countryId, household, signal) { + // Resolves with the calculated household; throws PolicyEngineApiError on a refusal. + return policyengine.calculateHousehold({ country: countryId, household }, { signal }); } ``` +The dashboard API answers pages on the tool's www.policyengine.org path, on `localhost`, on the team's Vercel previews and on the tool's own `*.vercel.app` host once its rewrite is in `appZoneRoutes.ts`. The policyengine-api-access skill has the other operations (policies, economy comparisons with polling, metadata) and the errors. + **For Pattern C (Custom Modal API — gateway + polling):** Pattern C uses a **three-file backend structure** mirroring policyengine-api-v2's simulation service: a standalone image setup, a worker app, and pure simulation logic. A lightweight gateway manages job submission/polling. This avoids Modal's ~150s gateway timeout and a common crash-loop where module-level imports fail. @@ -427,5 +427,6 @@ if jq -e '.scripts.test' package.json >/dev/null; then bun run test; fi See these skills for detailed guidance: - `policyengine-tools` — Embedding, hash sync, country detection, Vercel deployment patterns +- `policyengine-api-access` — The dashboard API for Pattern B, and server credentials for a backend that calls the Public API - `policyengine-design` — Token reference - `policyengine-cloud-costs` — Backend defaults, declared exceptions, the README's running costs, and the cost checks diff --git a/targets/codex/agents/policyengine-app-v2/AGENTS.md b/targets/codex/agents/policyengine-app-v2/AGENTS.md index 59e49fc..3d8669e 100644 --- a/targets/codex/agents/policyengine-app-v2/AGENTS.md +++ b/targets/codex/agents/policyengine-app-v2/AGENTS.md @@ -5,6 +5,7 @@ When working in `policyengine-app-v2`, prefer these PolicyEngine skills: - `$policyengine-app` for app architecture, routing, multizone config, and frontend conventions. - `$policyengine-design` for design tokens, `@policyengine/ui-kit` consumption, Tailwind v4 theme setup, and chart styling. - `$policyengine-api` for API integration (v1 endpoints, api-v2 alpha status). +- `$policyengine-api-access` for the website's dashboard API, `@policyengine/api-client`, and the server credential the routes send to the Public API. - `$policyengine-standards` for formatters, CI, and PR conventions. For generic prompts like `/review`, "fix styling", "write tests", or "add a component", load the relevant skills above before editing. From 5e0fbc154ffe1ad68cf6b11b0cb2ce5ab3517cc0 Mon Sep 17 00:00:00 2001 From: Anthony Volk <14987227+anth-volk@users.noreply.github.com> Date: Tue, 10 Nov 2026 22:36:23 +0400 Subject: [PATCH 05/16] Test that the skill describes the dashboard API firewall's 429 The Vercel firewall rate limits on www.policyengine.org are live: over a limit the firewall answers 429 itself, as text/plain "Too Many Requests", with no Retry-After and no CORS headers. The new test fails until the skill says so, names the client's 60-second wait for that case, and gives the firewall and the Public API's load balancer a 429 row each. Co-Authored-By: Claude Opus 5.5 --- tests/test_api_access_skill.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/test_api_access_skill.py b/tests/test_api_access_skill.py index 515a940..d5abc82 100644 --- a/tests/test_api_access_skill.py +++ b/tests/test_api_access_skill.py @@ -412,3 +412,20 @@ def test_template_never_follows_a_redirect() -> None: finally: server.shutdown() server.server_close() + + +def test_skill_describes_the_dashboard_api_firewall_refusal() -> None: + # Vercel's firewall rules on www.policyengine.org (tracker 2.3 · 6), observed in + # production on 2026-11-10: over a limit it answers 429 itself, as text/plain + # "Too Many Requests", with no Retry-After and no CORS headers. + text = skill_text() + for fact in ( + "fixed 60-second windows", + "Too Many Requests", + "no `Retry-After`", + "no CORS headers", + "DEFAULT_RATE_LIMIT_WAIT_MILLISECONDS", + ): + assert fact in text, fact + error_rows = [row for row in text.split("## Errors", 1)[1].splitlines() if row.startswith("| 429 ")] + assert len(error_rows) == 2, "the errors table needs a 429 row for the firewall and one for the load balancer" From e8cf0af1c8992076de027b1335863e32f65eda5a Mon Sep 17 00:00:00 2001 From: Anthony Volk <14987227+anth-volk@users.noreply.github.com> Date: Tue, 10 Nov 2026 22:37:08 +0400 Subject: [PATCH 06/16] Describe the dashboard API firewall's 429 as it answers in production The rate limits on www.policyengine.org are live. The skill now says they are counted per IP address in fixed 60-second windows, per Vercel region, and shared by everyone behind one address; that the firewall answers 429 itself, as text/plain "Too Many Requests", with no Retry-After and no CORS headers, so a page on another origin such as localhost sees a network failure; and that requests are accepted again when the window ends. compareEconomy's polling text covers both client versions: one that exports DEFAULT_RATE_LIMIT_WAIT_MILLISECONDS waits 60 seconds after such a 429, and an earlier one waits one interval. The errors table gives the firewall and the Public API's load balancer a 429 row each. Co-Authored-By: Claude Opus 5.5 --- skills/policyengine-api-access/SKILL.md | 28 +++++++++++++++++-------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/skills/policyengine-api-access/SKILL.md b/skills/policyengine-api-access/SKILL.md index 9eb5583..b3b3784 100644 --- a/skills/policyengine-api-access/SKILL.md +++ b/skills/policyengine-api-access/SKILL.md @@ -109,11 +109,14 @@ const metadata = await policyengine.getMetadata("uk"); (`calculateHousehold(…)`), not checked at run time. **Polling.** `compareEconomy` reads the comparison every 5 seconds until `status` is `ok`, and -gives up after 30 minutes with `EconomyComparisonTimeoutError`. It waits for `Retry-After` on a -429 and one interval after a 502, 503 or 504, and stops after a fourth such answer in a row. A -comparison that failed (502 with `status: "error"` and `retry_after_seconds`) is thrown at once: -the Public API keeps that failure for `retry_after_seconds`, so polling sooner returns it again. -Keep `intervalMilliseconds` at a few seconds. Use `getEconomyComparison` for one read. +gives up after 30 minutes with `EconomyComparisonTimeoutError`. It waits one interval after a +502, 503 or 504, and stops after a fourth such answer in a row. After a 429 it waits for +`Retry-After`; the firewall sends none, so versions that export +`DEFAULT_RATE_LIMIT_WAIT_MILLISECONDS` wait 60 seconds instead, and earlier ones wait one +interval and count the 429 towards those four. A comparison that failed (502 with +`status: "error"` and `retry_after_seconds`) is thrown at once: the Public API keeps that +failure for `retry_after_seconds`, so polling sooner returns it again. Keep +`intervalMilliseconds` at a few seconds. Use `getEconomyComparison` for one read. **Where pages may call it from.** The client's default `baseUrl` is `https://www.policyengine.org`. The dashboard API answers browser requests from: @@ -130,9 +133,15 @@ as a Modal URL, reaches the dashboard API only through its www.policyengine.org request headers are `Content-Type`, `Authorization` and `PolicyEngine-Unauthenticated-User`; the client sends no cookies (`credentials: "omit"`). -**Rate limits.** The dashboard API limits each IP address per minute: 30 household -calculations, 120 economy-comparison reads and 300 other requests. Calculate on a user's -action or after a debounce, not on every keystroke. +**Rate limits.** www.policyengine.org's Vercel firewall limits each IP address in +fixed 60-second windows, counted per Vercel region: 30 household calculations, 120 +economy-comparison reads, and 300 policy creations and metadata reads together. Everyone behind one address, such +as an office network, shares them. Over a limit the firewall answers before the dashboard API +runs: 429, text/plain "Too Many Requests", no `Retry-After` (so `retryAfterSeconds` is `null`) +and no CORS headers. A page on www.policyengine.org reads that 429; a page on another origin, +such as `http://localhost` in development, gets a network failure (`status` `null`). Requests +are accepted again when the window ends. Calculate on a user's action or after a debounce, not +on every keystroke. ## From servers: your own Auth0 client @@ -249,7 +258,8 @@ and the Public API share one shape: `{"status": "error", "message": …, "result | 403 | Public API user routes | A forwarded `PolicyEngine-User-Authorization` token is a machine-to-machine token, not a user's | Forward only a signed-in user's own token there | | 404 | Dashboard API | An unknown country in `/api/metadata/{country}` | Use `us` or `uk` | | 415 | Dashboard API | The body's `Content-Type` is not JSON | Send `Content-Type: application/json`; the client does | -| 429 | Dashboard API firewall, or the Public API's load balancer | Too many requests from one IP address | Wait `Retry-After` when present, otherwise back off (5 s, then doubling); `compareEconomy` already does. The load balancer's 429 is not JSON. A server's requests with a bearer token skip its per-address limits on `/{country}/metadata`, `/{country}/calculate` and `/{country}/calculate-full` | +| 429 | Dashboard API firewall | "Too Many Requests" as text/plain, with no `Retry-After` and no CORS headers: one IP address passed a per-minute limit | Wait for the 60-second window to end before sending again; never retry at once. On another origin (localhost) the page sees a network failure with `status` `null` instead, so treat repeated `null` statuses during heavy use the same way | +| 429 | The Public API's load balancer | Too many requests from one IP address, not JSON | Server: wait `Retry-After` when present, otherwise back off (5 s, then doubling). Requests with a bearer token skip its per-address limits on `/{country}/metadata`, `/{country}/calculate` and `/{country}/calculate-full` | | 502 | Dashboard API | Auth0 or the Public API could not be reached, or the Public API answered with a redirect | Retry later with back-off | | 502 | Public API, economy comparison | `status: "error"` with `retry_after_seconds`: the comparison failed | Show the failure; do not ask again before `retry_after_seconds` | | 503 | Public API | `{"status":"error","message":"Authentication is unavailable"}`: it could not check the token (Auth0's signing keys unreachable, or its own settings) | Keep the token; retry with back-off. It is not a refusal of the client | From 00261a03cfd1a299f7c138a3f9315fba2afb58be Mon Sep 17 00:00:00 2001 From: Anthony Volk <14987227+anth-volk@users.noreply.github.com> Date: Tue, 10 Nov 2026 23:33:12 +0400 Subject: [PATCH 07/16] Test that the dashboard manifest lists policyengine-api-access tests/pipeline/test_when_to_use_guide.py reads skill IDs from the committed dashboard/src/data/manifest.json, so the stacked guidance PR, whose guide names the new skill, failed in CI. This test fails until the manifest is rebuilt with the skill and its five bundles. Co-Authored-By: Claude Opus 5.5 --- tests/test_api_access_skill.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/test_api_access_skill.py b/tests/test_api_access_skill.py index d5abc82..9f05bad 100644 --- a/tests/test_api_access_skill.py +++ b/tests/test_api_access_skill.py @@ -429,3 +429,14 @@ def test_skill_describes_the_dashboard_api_firewall_refusal() -> None: assert fact in text, fact error_rows = [row for row in text.split("## Errors", 1)[1].splitlines() if row.startswith("| 429 ")] assert len(error_rows) == 2, "the errors table needs a 429 row for the firewall and one for the load balancer" + + +def test_dashboard_manifest_lists_the_skill() -> None: + # tests/pipeline/test_when_to_use_guide.py reads skill IDs from this committed + # file, so a guide that names the skill fails until the manifest is rebuilt. + manifest = json.loads((REPO_ROOT / "dashboard" / "src" / "data" / "manifest.json").read_text()) + matches = [entry for entry in manifest["artifacts"] if entry["kind"] == "skill" and entry["id"] == SKILL_NAME] + assert len(matches) == 1, f"dashboard/src/data/manifest.json lists {SKILL_NAME} {len(matches)} times" + artifact = matches[0] + assert artifact["path"] == f"skills/{SKILL_NAME}/SKILL.md" + assert sorted(artifact["bundles"]) == sorted(BUNDLES_WITH_SKILL) From 9ac72caec61766f7b2d84e101d80fdc70132ac8c Mon Sep 17 00:00:00 2001 From: Anthony Volk <14987227+anth-volk@users.noreply.github.com> Date: Tue, 10 Nov 2026 23:33:28 +0400 Subject: [PATCH 08/16] Rebuild the dashboard manifest with policyengine-api-access Regenerated with `uv run python scripts/build_manifest.py`. Besides the new skill, its bundle entries and edges, and the bundles' 4.2.0 version, the rebuild also picks up what earlier merges left unbuilt: the policyengine-data skill's description and target repositories from #108. Co-Authored-By: Claude Opus 5.5 --- dashboard/src/data/manifest.json | 4696 ++++++++++++++++-------------- 1 file changed, 2472 insertions(+), 2224 deletions(-) diff --git a/dashboard/src/data/manifest.json b/dashboard/src/data/manifest.json index 89b5f54..c0e1945 100644 --- a/dashboard/src/data/manifest.json +++ b/dashboard/src/data/manifest.json @@ -1,7 +1,7 @@ { - "generated_at": "2026-11-07T12:00:17.220492Z", + "generated_at": "2026-11-10T19:33:26.900074Z", "counts": { - "skill": 24, + "skill": 25, "agent": 36, "command": 20, "bundle": 8, @@ -341,6 +341,43 @@ "references": {}, "body_length": 4633 }, + { + "id": "policyengine-api-access", + "kind": "skill", + "name": "policyengine-api-access", + "description": "Load before writing or reviewing code that reaches the PolicyEngine Public API\n(api.policyengine.org) from a dashboard, tool, backend, Modal app, Vercel function or CI\njob. The Public API serves only PolicyEngine's servers: pages call www.policyengine.org's\ndashboard API through @policyengine/api-client, and servers send their own Auth0\nclient-credentials token. Covers the rules, the four dashboard operations, polling, allowed\norigins, cached server tokens, getting a client, local development and previews, asking for a\nnew operation, and 401/403/429/503.\nTriggers: api.policyengine.org, Public API, dashboard API, @policyengine/api-client, household\ncalculate from the browser, economy comparison polling, NEXT_PUBLIC_API_URL, VITE_API_URL,\nAuth0 client credentials, server token, PUBLIC_API_SERVER_CLIENT_IDS, Authentication is\nrequired, CORS error from the API.\nNOT for: Python analysis (policyengine skill) or the Public API's own endpoints and code\n(policyengine-api).", + "category": "apps", + "path": "skills/policyengine-api-access/SKILL.md", + "tools": [], + "model": null, + "triggers": [], + "bundles": [ + "analysis-tools", + "api-development", + "app-development", + "complete", + "dashboard-builder" + ], + "target_repos": [ + "policyengine-app-v2", + "policyengine-api", + "policyengine-app", + "policyengine-us" + ], + "functional_role": null, + "functional_summary": null, + "functional_scope": [], + "functional_supersedes": [], + "registry_status": "recommended", + "registry_owner": "Frontend & product", + "recommended_for": [ + "Load this skill for work involving: Load before writing or reviewing code that reaches the PolicyEngine Public API\n(api.policyengine.org) from a dashboard, tool, backend, Modal app, Vercel function or CI\njob. The Public API serves only PolicyEngine's servers: pages call www.policyengine.org's\ndashboard API through @policyengine/api-client, and servers send their own Auth0\nclient-credentials token. Covers the rules, the four dashboard operations, polling, allowed\norigins, cached server tokens, getting a client, local development and previews, asking for a\nnew operation, and 401/403/429/503.\nTriggers: api.policyengine.org, Public API, dashboard API, @policyengine/api-client, household\ncalculate from the browser, economy comparison polling, NEXT_PUBLIC_API_URL, VITE_API_URL,\nAuth0 client credentials, server token, PUBLIC_API_SERVER_CLIENT_IDS, Authentication is\nrequired, CORS error from the API.\nNOT for: Python analysis (policyengine skill) or the Public API's own endpoints and code\n(policyengine-api)." + ], + "use_instead": [], + "registry_notes": "Recommended for the listed scope.", + "references": {}, + "body_length": 17338 + }, { "id": "policyengine-app", "kind": "skill", @@ -572,7 +609,7 @@ "id": "policyengine-data", "kind": "skill", "name": "policyengine-data", - "description": "Load for PolicyEngine's data layer \u2014 how Microcosm builds, calibrates, versions, and names the\nmicrodata behind population runs. Covers the Microcosm stack (Frame kernel, microcosm-fit\nconditional models, microcosm-calibrate weights with opt-in L0 pruning, build/release gates),\nthe certified datasets in policyengine bundles (populace_us_2024 57k-household frozen-support\ndefault, populace_us_2024_acs_local ~1.6M local-area, microcosm_uk_2024_25 private),\nlocal-area runs as one national dataset plus a geography filter, the calibration diagnostics\ndashboard, and where data work goes since PolicyEngine archived policyengine-us-data.\nTriggers: Microcosm, Frame, microcosm-fit, microcosm-calibrate, calibration target, survey\nweights, reweighting, imputation, QRF, quantile loss, L0 sparsity, sparse 57k, dense_no_l0,\nlocal-area data, ACS, FRS, WAS, enhanced microdata, DEFAULT_DATASET.\nNOT for: running simulations (see policyengine) or diagnosing a specific score mismatch (see\npolicyengine-calibration-diagnostics).", + "description": "Load for PolicyEngine's data layer \u2014 how Microcosm builds, calibrates, versions, and names the\nmicrodata behind population runs. Covers the Microcosm stack (Frame kernel, microcosm-fit\nmodels, microcosm-calibrate weights with opt-in L0 pruning, release gates), the certified\ndatasets in policyengine bundles (populace_us_2024 57k-household frozen-support default,\npopulace_us_2024_acs_local ~1.6M local-area, microcosm_uk_2024_25 private), local-area runs as\none national dataset plus a geography filter, the calibration dashboard, and where data work\ngoes since PolicyEngine archived policyengine-us-data.\nTriggers: Microcosm, Frame, microcosm-fit, microcosm-calibrate, microimpute, microcalibrate,\ncalibration target, survey weights, reweighting, imputation, QRF, quantile loss, L0 sparsity,\nsparse 57k, dense_no_l0, local-area data, ACS, FRS, WAS, enhanced microdata, DEFAULT_DATASET.\nNOT for: running simulations (see policyengine) or diagnosing a specific score mismatch (see\npolicyengine-calibration-diagnostics).", "category": "data", "path": "skills/policyengine-data/SKILL.md", "tools": [], @@ -586,8 +623,8 @@ "target_repos": [ "calibration-diagnostics", "policyengine-us-data", + "policyengine-core", "policyengine-us", - "policyengine.py", "microcalibrate", "microimpute", "microunit", @@ -616,7 +653,7 @@ "use_instead": [], "registry_notes": "Recommended for the listed scope.", "references": {}, - "body_length": 21011 + "body_length": 22881 }, { "id": "policyengine-design", @@ -4119,7 +4156,7 @@ "use_instead": [], "registry_notes": "Bundle install profile.", "references": {}, - "body_length": 2135 + "body_length": 2175 }, { "id": "api-development", @@ -4145,7 +4182,7 @@ "use_instead": [], "registry_notes": "Bundle install profile.", "references": {}, - "body_length": 1054 + "body_length": 1094 }, { "id": "app-development", @@ -4171,7 +4208,7 @@ "use_instead": [], "registry_notes": "Bundle install profile.", "references": {}, - "body_length": 1461 + "body_length": 1501 }, { "id": "complete", @@ -4197,7 +4234,7 @@ "use_instead": [], "registry_notes": "Bundle install profile.", "references": {}, - "body_length": 3730 + "body_length": 3770 }, { "id": "country-models", @@ -4249,7 +4286,7 @@ "use_instead": [], "registry_notes": "Bundle install profile.", "references": {}, - "body_length": 1326 + "body_length": 1366 }, { "id": "data-science", @@ -6057,6 +6094,12 @@ "target_kind": "skill", "target": "policyengine" }, + { + "source_kind": "bundle", + "source": "analysis-tools", + "target_kind": "skill", + "target": "policyengine-api-access" + }, { "source_kind": "bundle", "source": "analysis-tools", @@ -6213,6 +6256,12 @@ "target_kind": "skill", "target": "policyengine-api" }, + { + "source_kind": "bundle", + "source": "api-development", + "target_kind": "skill", + "target": "policyengine-api-access" + }, { "source_kind": "bundle", "source": "api-development", @@ -6315,6 +6364,12 @@ "target_kind": "skill", "target": "fix-pr" }, + { + "source_kind": "bundle", + "source": "app-development", + "target_kind": "skill", + "target": "policyengine-api-access" + }, { "source_kind": "bundle", "source": "app-development", @@ -6645,6 +6700,12 @@ "target_kind": "skill", "target": "policyengine-api" }, + { + "source_kind": "bundle", + "source": "complete", + "target_kind": "skill", + "target": "policyengine-api-access" + }, { "source_kind": "bundle", "source": "complete", @@ -7107,6 +7168,12 @@ "target_kind": "skill", "target": "policyengine-api" }, + { + "source_kind": "bundle", + "source": "dashboard-builder", + "target_kind": "skill", + "target": "policyengine-api-access" + }, { "source_kind": "bundle", "source": "dashboard-builder", @@ -7256,7 +7323,7 @@ "kind": "command", "id": "implement-structural" }, - "score": 0.6526, + "score": 0.6532, "shared_terms": [ "structural", "backlog", @@ -7277,7 +7344,7 @@ "kind": "command", "id": "generate-content" }, - "score": 0.6298, + "score": 0.6297, "shared_terms": [ "social", "content", @@ -7298,7 +7365,7 @@ "kind": "command", "id": "generate-content" }, - "score": 0.6287, + "score": 0.6284, "shared_terms": [ "social", "content", @@ -7319,7 +7386,7 @@ "kind": "agent", "id": "review-worker" }, - "score": 0.6233, + "score": 0.6218, "shared_terms": [ "your", "assigned", @@ -7328,7 +7395,7 @@ "coordinator", "executes", "task", - "access" + "test" ] }, { @@ -7340,15 +7407,15 @@ "kind": "skill", "id": "policyengine-uk" }, - "score": 0.6031, + "score": 0.6014, "shared_terms": [ "household", "unit", - "income", "tax", + "income", "poverty", - "age", "person", + "age", "result" ] }, @@ -7361,7 +7428,7 @@ "kind": "command", "id": "prior-scores" }, - "score": 0.5994, + "score": 0.5998, "shared_terms": [ "scorekeepers", "scores", @@ -7403,7 +7470,7 @@ "kind": "command", "id": "audit-multizone" }, - "score": 0.5814, + "score": 0.5818, "shared_terms": [ "zone", "path", @@ -7424,7 +7491,7 @@ "kind": "skill", "id": "policyengine-us" }, - "score": 0.5677, + "score": 0.5678, "shared_terms": [ "unit", "tax", @@ -7445,7 +7512,7 @@ "kind": "skill", "id": "review-program" }, - "score": 0.5651, + "score": 0.5658, "shared_terms": [ "review", "canonical", @@ -7466,7 +7533,7 @@ "kind": "agent", "id": "content-orchestrator" }, - "score": 0.5387, + "score": 0.5389, "shared_terms": [ "social", "content", @@ -7487,7 +7554,7 @@ "kind": "skill", "id": "policyengine-us" }, - "score": 0.5305, + "score": 0.5301, "shared_terms": [ "unit", "tax", @@ -7529,7 +7596,7 @@ "kind": "agent", "id": "calibration-diagnostics" }, - "score": 0.4911, + "score": 0.4919, "shared_terms": [ "calibration", "signature", @@ -7550,7 +7617,7 @@ "kind": "agent", "id": "review-worker" }, - "score": 0.4801, + "score": 0.4813, "shared_terms": [ "review", "canonical", @@ -7571,7 +7638,7 @@ "kind": "agent", "id": "prior-scores-finder" }, - "score": 0.4749, + "score": 0.4751, "shared_terms": [ "prior", "tier", @@ -7592,14 +7659,14 @@ "kind": "skill", "id": "policyengine-tools" }, - "score": 0.4692, + "score": 0.4671, "shared_terms": [ "app", "next", "bun", - "vite", "host", "multizone", + "vite", "router", "vercel" ] @@ -7607,22 +7674,22 @@ { "a": { "kind": "agent", - "id": "dashboard-design-validator" + "id": "edge-case-generator" }, "b": { "kind": "agent", - "id": "dashboard-plan-validator" + "id": "test-creator" }, - "score": 0.4622, + "score": 0.4616, "shared_terms": [ - "grep", - "components", - "include", - "tsx", - "node", - "modules", - "app", - "component" + "test", + "tests", + "cases", + "edge", + "variable", + "month", + "boundary", + "files" ] }, { @@ -7634,7 +7701,7 @@ "kind": "command", "id": "create-new-component" }, - "score": 0.4613, + "score": 0.4601, "shared_terms": [ "component", "kit", @@ -7649,22 +7716,43 @@ { "a": { "kind": "agent", - "id": "edge-case-generator" + "id": "dashboard-design-validator" }, "b": { "kind": "agent", - "id": "test-creator" + "id": "dashboard-plan-validator" }, - "score": 0.4603, + "score": 0.4598, "shared_terms": [ - "test", - "tests", - "cases", - "edge", - "variable", - "month", - "boundary", - "files" + "grep", + "components", + "include", + "tsx", + "node", + "modules", + "app", + "component" + ] + }, + { + "a": { + "kind": "skill", + "id": "policyengine-api" + }, + "b": { + "kind": "skill", + "id": "policyengine-api-access" + }, + "score": 0.4467, + "shared_terms": [ + "api", + "client", + "household", + "org", + "country", + "economy", + "get", + "public" ] }, { @@ -7676,7 +7764,7 @@ "kind": "agent", "id": "reform-classifier" }, - "score": 0.4487, + "score": 0.4459, "shared_terms": [ "parameter", "gov", @@ -7684,8 +7772,8 @@ "deployed", "provision", "lag", - "credits", - "parametric" + "parametric", + "credits" ] }, { @@ -7697,16 +7785,16 @@ "kind": "agent", "id": "dashboard-scaffold" }, - "score": 0.4421, + "score": 0.4402, "shared_terms": [ "plan", "custom", "dashboard", "data", "modal", - "backend", "pattern", - "api" + "api", + "backend" ] }, { @@ -7718,7 +7806,7 @@ "kind": "agent", "id": "dashboard-architecture-validator" }, - "score": 0.4256, + "score": 0.425, "shared_terms": [ "app", "postcss", @@ -7739,7 +7827,7 @@ "kind": "agent", "id": "dashboard-design-validator" }, - "score": 0.4108, + "score": 0.4118, "shared_terms": [ "grep", "app", @@ -7760,7 +7848,7 @@ "kind": "agent", "id": "multizone-validator" }, - "score": 0.4107, + "score": 0.4099, "shared_terms": [ "zone", "basepath", @@ -7772,27 +7860,6 @@ "assetprefix" ] }, - { - "a": { - "kind": "agent", - "id": "backend-builder" - }, - "b": { - "kind": "agent", - "id": "dashboard-integrator" - }, - "score": 0.4032, - "shared_terms": [ - "api", - "data", - "client", - "backend", - "step", - "types", - "hooks", - "pattern" - ] - }, { "a": { "kind": "skill", @@ -7802,7 +7869,7 @@ "kind": "command", "id": "create-pr" }, - "score": 0.402, + "score": 0.4028, "shared_terms": [ "echo", "wait", @@ -7814,6 +7881,27 @@ "completed" ] }, + { + "a": { + "kind": "agent", + "id": "backend-builder" + }, + "b": { + "kind": "agent", + "id": "dashboard-integrator" + }, + "score": 0.4017, + "shared_terms": [ + "api", + "data", + "client", + "backend", + "step", + "types", + "hooks", + "pattern" + ] + }, { "a": { "kind": "agent", @@ -7823,7 +7911,7 @@ "kind": "command", "id": "prior-scores" }, - "score": 0.4, + "score": 0.4001, "shared_terms": [ "tier", "prior", @@ -7844,7 +7932,7 @@ "kind": "command", "id": "prior-analysis" }, - "score": 0.3972, + "score": 0.397, "shared_terms": [ "analyses", "prior", @@ -7856,27 +7944,6 @@ "archived" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-design" - }, - "b": { - "kind": "agent", - "id": "frontend-builder" - }, - "score": 0.3834, - "shared_terms": [ - "kit", - "chart", - "css", - "teal", - "design", - "font", - "colors", - "tailwind" - ] - }, { "a": { "kind": "agent", @@ -7886,7 +7953,7 @@ "kind": "command", "id": "write-tests" }, - "score": 0.3815, + "score": 0.3853, "shared_terms": [ "test", "tests", @@ -7898,6 +7965,27 @@ "unit" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-design" + }, + "b": { + "kind": "agent", + "id": "frontend-builder" + }, + "score": 0.3833, + "shared_terms": [ + "kit", + "chart", + "css", + "teal", + "design", + "font", + "colors", + "tailwind" + ] + }, { "a": { "kind": "agent", @@ -7907,7 +7995,7 @@ "kind": "command", "id": "write-tests" }, - "score": 0.3723, + "score": 0.3743, "shared_terms": [ "test", "tests", @@ -7928,7 +8016,7 @@ "kind": "command", "id": "text-to-reform" }, - "score": 0.3706, + "score": 0.3714, "shared_terms": [ "reform", "provision", @@ -7949,37 +8037,37 @@ "kind": "agent", "id": "reference-validator" }, - "score": 0.3697, + "score": 0.3683, "shared_terms": [ - "page", "href", + "page", "title", "section", "pdf", "manual", - "field", - "yaml" + "yaml", + "field" ] }, { "a": { "kind": "agent", - "id": "dashboard-planner" + "id": "edge-case-generator" }, "b": { "kind": "command", - "id": "create-dashboard" + "id": "write-tests" }, - "score": 0.3673, + "score": 0.368, "shared_terms": [ - "dashboard", - "planner", - "reform", - "plan", - "page", - "validation", - "tabs", - "natural" + "test", + "tests", + "edge", + "files", + "cases", + "file", + "existing", + "write" ] }, { @@ -7991,7 +8079,7 @@ "kind": "command", "id": "household-calc" }, - "score": 0.3668, + "score": 0.3646, "shared_terms": [ "household", "income", @@ -8006,22 +8094,22 @@ { "a": { "kind": "agent", - "id": "edge-case-generator" + "id": "dashboard-planner" }, "b": { "kind": "command", - "id": "write-tests" + "id": "create-dashboard" }, - "score": 0.3653, + "score": 0.3634, "shared_terms": [ - "test", - "tests", - "edge", - "files", - "cases", - "file", - "existing", - "write" + "dashboard", + "planner", + "reform", + "plan", + "page", + "validation", + "tabs", + "natural" ] }, { @@ -8033,7 +8121,7 @@ "kind": "agent", "id": "review-worker" }, - "score": 0.3607, + "score": 0.3614, "shared_terms": [ "review", "canonical", @@ -8048,34 +8136,13 @@ { "a": { "kind": "agent", - "id": "dashboard-design-validator" - }, - "b": { - "kind": "agent", - "id": "frontend-builder" - }, - "score": 0.3554, - "shared_terms": [ - "kit", - "components", - "app", - "design", - "component", - "tsx", - "font", - "css" - ] - }, - { - "a": { - "kind": "agent", - "id": "policy-text-researcher" + "id": "policy-text-researcher" }, "b": { "kind": "command", "id": "text-to-reform" }, - "score": 0.3533, + "score": 0.3542, "shared_terms": [ "bill", "reform", @@ -8093,19 +8160,19 @@ "id": "dashboard-design-validator" }, "b": { - "kind": "command", - "id": "create-new-component" + "kind": "agent", + "id": "frontend-builder" }, - "score": 0.3509, + "score": 0.3534, "shared_terms": [ - "components", "kit", - "grep", - "tsx", - "design", + "components", "app", + "design", "component", - "include" + "tsx", + "font", + "css" ] }, { @@ -8117,7 +8184,7 @@ "kind": "agent", "id": "model-worker" }, - "score": 0.3504, + "score": 0.3514, "shared_terms": [ "encode", "coordinator", @@ -8125,8 +8192,29 @@ "delegation", "canonical", "owned", - "own", - "tests" + "tests", + "own" + ] + }, + { + "a": { + "kind": "agent", + "id": "dashboard-design-validator" + }, + "b": { + "kind": "command", + "id": "create-new-component" + }, + "score": 0.3492, + "shared_terms": [ + "components", + "kit", + "grep", + "tsx", + "design", + "app", + "component", + "include" ] }, { @@ -8138,7 +8226,7 @@ "kind": "skill", "id": "policyengine-user-guide" }, - "score": 0.3479, + "score": 0.3458, "shared_terms": [ "household", "income", @@ -8150,27 +8238,6 @@ "employment" ] }, - { - "a": { - "kind": "agent", - "id": "parameter-locator" - }, - "b": { - "kind": "agent", - "id": "reform-describer" - }, - "score": 0.3477, - "shared_terms": [ - "parameter", - "reform", - "ctc", - "gov", - "state", - "tax", - "credits", - "mechanical" - ] - }, { "a": { "kind": "agent", @@ -8180,7 +8247,7 @@ "kind": "agent", "id": "implementation-validator" }, - "score": 0.3455, + "score": 0.3453, "shared_terms": [ "root", "fix", @@ -8192,6 +8259,27 @@ "fixes" ] }, + { + "a": { + "kind": "agent", + "id": "parameter-locator" + }, + "b": { + "kind": "agent", + "id": "reform-describer" + }, + "score": 0.3453, + "shared_terms": [ + "parameter", + "reform", + "ctc", + "gov", + "state", + "tax", + "credits", + "mechanical" + ] + }, { "a": { "kind": "skill", @@ -8201,7 +8289,7 @@ "kind": "command", "id": "audit-multizone" }, - "score": 0.3451, + "score": 0.3437, "shared_terms": [ "zone", "next", @@ -8222,7 +8310,7 @@ "kind": "agent", "id": "implementation-validator" }, - "score": 0.3345, + "score": 0.3348, "shared_terms": [ "fix", "review", @@ -8234,6 +8322,27 @@ "verification" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-api-access" + }, + "b": { + "kind": "agent", + "id": "dashboard-integrator" + }, + "score": 0.3331, + "shared_terms": [ + "api", + "client", + "household", + "backend", + "dashboard", + "const", + "request", + "function" + ] + }, { "a": { "kind": "agent", @@ -8243,7 +8352,7 @@ "kind": "command", "id": "analyze-policy" }, - "score": 0.3335, + "score": 0.3325, "shared_terms": [ "year", "microsim", @@ -8255,27 +8364,6 @@ "horizon" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-user-guide" - }, - "b": { - "kind": "command", - "id": "household-calc" - }, - "score": 0.3314, - "shared_terms": [ - "household", - "reform", - "income", - "population", - "benefits", - "marginal", - "net", - "taxes" - ] - }, { "a": { "kind": "agent", @@ -8285,7 +8373,7 @@ "kind": "agent", "id": "dashboard-scaffold" }, - "score": 0.3312, + "score": 0.331, "shared_terms": [ "plan", "dashboard", @@ -8297,6 +8385,27 @@ "zone" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-user-guide" + }, + "b": { + "kind": "command", + "id": "household-calc" + }, + "score": 0.3304, + "shared_terms": [ + "household", + "reform", + "income", + "population", + "benefits", + "marginal", + "net", + "taxes" + ] + }, { "a": { "kind": "agent", @@ -8306,7 +8415,7 @@ "kind": "command", "id": "create-new-component" }, - "score": 0.331, + "score": 0.3302, "shared_terms": [ "component", "tsx", @@ -8318,27 +8427,6 @@ "kit" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-calibration-diagnostics" - }, - "b": { - "kind": "skill", - "id": "policyengine-data" - }, - "score": 0.3299, - "shared_terms": [ - "microcosm", - "calibration", - "target", - "diagnostics", - "calibrate", - "weights", - "fit", - "release" - ] - }, { "a": { "kind": "agent", @@ -8348,7 +8436,7 @@ "kind": "command", "id": "encode-reform" }, - "score": 0.3294, + "score": 0.3296, "shared_terms": [ "bill", "reform", @@ -8363,22 +8451,22 @@ { "a": { "kind": "skill", - "id": "policyengine-tools" + "id": "policyengine-api-access" }, "b": { - "kind": "command", - "id": "deploy-dashboard" + "kind": "agent", + "id": "backend-builder" }, - "score": 0.3277, + "score": 0.3262, "shared_terms": [ - "modal", - "host", - "vercel", - "app", + "api", + "client", "dashboard", - "config", - "next", - "zone" + "public", + "backend", + "modal", + "json", + "org" ] }, { @@ -8390,7 +8478,7 @@ "kind": "command", "id": "deploy-dashboard" }, - "score": 0.3251, + "score": 0.326, "shared_terms": [ "host", "zone", @@ -8398,29 +8486,50 @@ "path", "dashboard", "git", - "modal", - "config" + "config", + "modal" ] }, { "a": { - "kind": "agent", - "id": "backend-builder" + "kind": "skill", + "id": "policyengine-tools" }, "b": { "kind": "command", "id": "deploy-dashboard" }, - "score": 0.3185, + "score": 0.3253, "shared_terms": [ "modal", + "host", + "app", + "vercel", "dashboard", - "custom", - "pattern", - "precomputed", - "step", - "backend", - "data" + "config", + "next", + "zone" + ] + }, + { + "a": { + "kind": "skill", + "id": "policyengine-calibration-diagnostics" + }, + "b": { + "kind": "skill", + "id": "policyengine-data" + }, + "score": 0.3211, + "shared_terms": [ + "microcosm", + "calibration", + "target", + "diagnostics", + "calibrate", + "fit", + "weights", + "release" ] }, { @@ -8432,7 +8541,7 @@ "kind": "command", "id": "reform-pipeline" }, - "score": 0.3154, + "score": 0.3163, "shared_terms": [ "bill", "reform", @@ -8444,27 +8553,6 @@ "gov" ] }, - { - "a": { - "kind": "agent", - "id": "issue-manager" - }, - "b": { - "kind": "agent", - "id": "pr-pusher" - }, - "score": 0.3149, - "shared_terms": [ - "repo", - "branch", - "head", - "push", - "issue", - "number", - "repository", - "base" - ] - }, { "a": { "kind": "command", @@ -8474,7 +8562,7 @@ "kind": "command", "id": "text-to-reform" }, - "score": 0.3143, + "score": 0.3155, "shared_terms": [ "bill", "reform", @@ -8488,44 +8576,65 @@ }, { "a": { - "kind": "skill", - "id": "policyengine-healthcare" + "kind": "agent", + "id": "backend-builder" }, "b": { - "kind": "skill", - "id": "policyengine-us" + "kind": "command", + "id": "deploy-dashboard" }, - "score": 0.3092, + "score": 0.315, "shared_terms": [ - "unit", - "tax", - "income", - "medicaid", - "household", - "aca", - "net", - "person" + "modal", + "dashboard", + "custom", + "pattern", + "precomputed", + "step", + "data", + "backend" ] }, { "a": { "kind": "agent", - "id": "dashboard-scaffold" + "id": "issue-manager" }, "b": { - "kind": "command", - "id": "deploy-dashboard" + "kind": "agent", + "id": "pr-pusher" }, - "score": 0.3089, + "score": 0.3139, "shared_terms": [ - "dashboard", - "modal", - "custom", - "plan", - "pattern", - "host", - "step", - "main" + "repo", + "branch", + "push", + "head", + "issue", + "number", + "repository", + "base" + ] + }, + { + "a": { + "kind": "skill", + "id": "policyengine-healthcare" + }, + "b": { + "kind": "skill", + "id": "policyengine-us" + }, + "score": 0.3125, + "shared_terms": [ + "tax", + "unit", + "income", + "medicaid", + "household", + "aca", + "net", + "person" ] }, { @@ -8537,7 +8646,7 @@ "kind": "skill", "id": "policyengine-tools" }, - "score": 0.3083, + "score": 0.3091, "shared_terms": [ "css", "theme", @@ -8552,22 +8661,22 @@ { "a": { "kind": "agent", - "id": "reform-classifier" + "id": "dashboard-scaffold" }, "b": { - "kind": "agent", - "id": "reform-describer" + "kind": "command", + "id": "deploy-dashboard" }, - "score": 0.3073, + "score": 0.3074, "shared_terms": [ - "provisions", - "parameter", - "reform", - "ctc", - "refundable", - "amount", - "credits", - "gov" + "dashboard", + "modal", + "custom", + "plan", + "pattern", + "host", + "step", + "main" ] }, { @@ -8600,7 +8709,7 @@ "kind": "agent", "id": "parameter-locator" }, - "score": 0.3068, + "score": 0.3056, "shared_terms": [ "tax", "income", @@ -8615,22 +8724,22 @@ { "a": { "kind": "agent", - "id": "policy-text-researcher" + "id": "reform-classifier" }, "b": { "kind": "agent", "id": "reform-describer" }, - "score": 0.3041, + "score": 0.3049, "shared_terms": [ - "ctc", "provisions", - "gov", + "parameter", "reform", - "federal", - "ages", - "description", - "text" + "ctc", + "refundable", + "amount", + "credits", + "gov" ] }, { @@ -8642,7 +8751,7 @@ "kind": "agent", "id": "test-creator" }, - "score": 0.3033, + "score": 0.304, "shared_terms": [ "tests", "variable", @@ -8654,6 +8763,27 @@ "year" ] }, + { + "a": { + "kind": "agent", + "id": "policy-text-researcher" + }, + "b": { + "kind": "agent", + "id": "reform-describer" + }, + "score": 0.3033, + "shared_terms": [ + "ctc", + "provisions", + "reform", + "federal", + "ages", + "gov", + "description", + "text" + ] + }, { "a": { "kind": "agent", @@ -8663,7 +8793,7 @@ "kind": "command", "id": "backdate-program" }, - "score": 0.3007, + "score": 0.3009, "shared_terms": [ "program", "worktree", @@ -8684,7 +8814,7 @@ "kind": "command", "id": "household-calc" }, - "score": 0.2998, + "score": 0.2974, "shared_terms": [ "household", "income", @@ -8696,27 +8826,6 @@ "benefits" ] }, - { - "a": { - "kind": "agent", - "id": "parameter-locator" - }, - "b": { - "kind": "command", - "id": "audit-state-tax" - }, - "score": 0.2941, - "shared_terms": [ - "state", - "tax", - "gov", - "income", - "states", - "parameter", - "phase", - "credits" - ] - }, { "a": { "kind": "skill", @@ -8726,7 +8835,7 @@ "kind": "agent", "id": "review-worker" }, - "score": 0.2937, + "score": 0.2946, "shared_terms": [ "review", "canonical", @@ -8741,22 +8850,22 @@ { "a": { "kind": "agent", - "id": "dashboard-planner" + "id": "parameter-locator" }, "b": { - "kind": "agent", - "id": "dashboard-scaffold" + "kind": "command", + "id": "audit-state-tax" }, - "score": 0.2936, + "score": 0.2937, "shared_terms": [ - "dashboard", - "plan", - "data", - "custom", - "design", - "step", - "api", - "costs" + "state", + "tax", + "gov", + "income", + "states", + "parameter", + "phase", + "step" ] }, { @@ -8768,7 +8877,7 @@ "kind": "command", "id": "text-to-reform" }, - "score": 0.2912, + "score": 0.2924, "shared_terms": [ "reform", "dict", @@ -8780,6 +8889,27 @@ "emits" ] }, + { + "a": { + "kind": "agent", + "id": "dashboard-planner" + }, + "b": { + "kind": "agent", + "id": "dashboard-scaffold" + }, + "score": 0.2909, + "shared_terms": [ + "dashboard", + "plan", + "data", + "custom", + "design", + "step", + "api", + "costs" + ] + }, { "a": { "kind": "skill", @@ -8789,7 +8919,7 @@ "kind": "skill", "id": "policyengine-design" }, - "score": 0.2898, + "score": 0.2908, "shared_terms": [ "theme", "teal", @@ -8810,7 +8940,7 @@ "kind": "agent", "id": "implementation-validator" }, - "score": 0.2895, + "score": 0.2898, "shared_terms": [ "mode", "review", @@ -8831,7 +8961,7 @@ "kind": "command", "id": "audit-seo" }, - "score": 0.289, + "score": 0.2896, "shared_terms": [ "audit", "zone", @@ -8852,7 +8982,7 @@ "kind": "agent", "id": "pr-pusher" }, - "score": 0.2871, + "score": 0.2882, "shared_terms": [ "changelog", "repo", @@ -8864,27 +8994,6 @@ "never" ] }, - { - "a": { - "kind": "agent", - "id": "model-corroborator" - }, - "b": { - "kind": "command", - "id": "prior-scores" - }, - "score": 0.2856, - "shared_terms": [ - "shape", - "external", - "reform", - "benchmark", - "scores", - "runs", - "microsim", - "published" - ] - }, { "a": { "kind": "command", @@ -8894,7 +9003,7 @@ "kind": "command", "id": "text-to-reform" }, - "score": 0.2856, + "score": 0.2867, "shared_terms": [ "reform", "dict", @@ -8902,29 +9011,29 @@ "analyze", "entry", "description", - "api", - "microsim" + "microsim", + "api" ] }, { "a": { "kind": "agent", - "id": "dashboard-scaffold" + "id": "model-corroborator" }, "b": { "kind": "command", - "id": "create-dashboard" + "id": "prior-scores" }, - "score": 0.2845, + "score": 0.2857, "shared_terms": [ - "dashboard", - "plan", - "page", - "scaffold", - "repo", - "init", - "directory", - "create" + "shape", + "external", + "reform", + "benchmark", + "scores", + "microsim", + "runs", + "published" ] }, { @@ -8936,7 +9045,7 @@ "kind": "skill", "id": "policyengine-user-guide" }, - "score": 0.2837, + "score": 0.2819, "shared_terms": [ "household", "income", @@ -8948,27 +9057,6 @@ "population" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-app" - }, - "b": { - "kind": "agent", - "id": "dashboard-architecture-validator" - }, - "score": 0.2831, - "shared_terms": [ - "app", - "router", - "tailwindcss", - "vite", - "next", - "kit", - "tsx", - "bun" - ] - }, { "a": { "kind": "agent", @@ -8978,7 +9066,7 @@ "kind": "agent", "id": "reform-comparator" }, - "score": 0.2822, + "score": 0.2816, "shared_terms": [ "prior", "year", @@ -8993,43 +9081,64 @@ { "a": { "kind": "skill", - "id": "policyengine-api" + "id": "policyengine-app" }, "b": { "kind": "agent", - "id": "dashboard-integrator" + "id": "dashboard-architecture-validator" }, - "score": 0.2812, + "score": 0.281, "shared_terms": [ - "api", - "household", - "client", - "data", - "frontend", - "values", - "response", - "policyid" + "app", + "router", + "tailwindcss", + "vite", + "next", + "kit", + "tsx", + "bun" ] }, { "a": { - "kind": "skill", - "id": "policyengine-canada" + "kind": "agent", + "id": "dashboard-scaffold" }, "b": { + "kind": "command", + "id": "create-dashboard" + }, + "score": 0.281, + "shared_terms": [ + "dashboard", + "plan", + "page", + "scaffold", + "repo", + "init", + "directory", + "create" + ] + }, + { + "a": { "kind": "skill", - "id": "policyengine-uk" + "id": "policyengine-api" + }, + "b": { + "kind": "agent", + "id": "dashboard-integrator" }, - "score": 0.2806, + "score": 0.2804, "shared_terms": [ + "api", "household", - "canada", - "income", - "credit", - "benefit", - "tax", - "poverty", - "net" + "client", + "data", + "frontend", + "values", + "response", + "policyid" ] }, { @@ -9041,7 +9150,7 @@ "kind": "agent", "id": "frontend-builder" }, - "score": 0.2806, + "score": 0.2804, "shared_terms": [ "kit", "app", @@ -9055,23 +9164,23 @@ }, { "a": { - "kind": "agent", - "id": "backend-builder" + "kind": "skill", + "id": "policyengine-canada" }, "b": { - "kind": "agent", - "id": "dashboard-planner" + "kind": "skill", + "id": "policyengine-uk" }, - "score": 0.2786, + "score": 0.2792, "shared_terms": [ - "data", - "dashboard", - "plan", - "api", - "modal", - "custom", - "pattern", - "step" + "household", + "canada", + "income", + "credit", + "benefit", + "tax", + "poverty", + "net" ] }, { @@ -9083,7 +9192,7 @@ "kind": "command", "id": "text-to-reform" }, - "score": 0.278, + "score": 0.2787, "shared_terms": [ "bill", "reform", @@ -9104,7 +9213,7 @@ "kind": "command", "id": "implement-structural" }, - "score": 0.2777, + "score": 0.2782, "shared_terms": [ "structural", "backlog", @@ -9119,22 +9228,43 @@ { "a": { "kind": "agent", - "id": "frontend-builder" + "id": "backend-builder" + }, + "b": { + "kind": "agent", + "id": "dashboard-planner" + }, + "score": 0.2777, + "shared_terms": [ + "data", + "dashboard", + "plan", + "api", + "modal", + "custom", + "pattern", + "step" + ] + }, + { + "a": { + "kind": "agent", + "id": "ci-fixer" }, "b": { "kind": "command", - "id": "new-tool" + "id": "backdate-program" }, - "score": 0.2757, + "score": 0.2756, "shared_terms": [ - "kit", - "tailwind", - "app", - "font", - "css", - "import", - "design", - "colors" + "worktree", + "root", + "files", + "prefix", + "program", + "git", + "read", + "run" ] }, { @@ -9146,14 +9276,14 @@ "kind": "agent", "id": "dashboard-plan-validator" }, - "score": 0.2754, + "score": 0.2756, "shared_terms": [ "grep", "app", "fail", "include", - "components", "tsx", + "components", "test", "node" ] @@ -9161,22 +9291,22 @@ { "a": { "kind": "agent", - "id": "ci-fixer" + "id": "frontend-builder" }, "b": { "kind": "command", - "id": "backdate-program" + "id": "new-tool" }, - "score": 0.2751, + "score": 0.2753, "shared_terms": [ - "worktree", - "root", - "files", - "prefix", - "program", - "git", - "run", - "read" + "kit", + "tailwind", + "app", + "font", + "css", + "import", + "design", + "colors" ] }, { @@ -9188,7 +9318,7 @@ "kind": "command", "id": "reform-pipeline" }, - "score": 0.2741, + "score": 0.2748, "shared_terms": [ "bill", "reform", @@ -9209,7 +9339,7 @@ "kind": "command", "id": "new-tool" }, - "score": 0.2724, + "score": 0.272, "shared_terms": [ "app", "calculator", @@ -9217,8 +9347,8 @@ "countryid", "bun", "kit", - "page", - "next" + "next", + "page" ] }, { @@ -9230,7 +9360,7 @@ "kind": "agent", "id": "dashboard-architecture-validator" }, - "score": 0.2712, + "score": 0.2716, "shared_terms": [ "css", "postcss", @@ -9251,7 +9381,7 @@ "kind": "agent", "id": "implementation-validator" }, - "score": 0.2711, + "score": 0.2715, "shared_terms": [ "review", "root", @@ -9263,27 +9393,6 @@ "code" ] }, - { - "a": { - "kind": "agent", - "id": "microsim-runner" - }, - "b": { - "kind": "agent", - "id": "reform-comparator" - }, - "score": 0.2695, - "shared_terms": [ - "version", - "result", - "dataset", - "year", - "baseline", - "cps", - "enhanced", - "microsim" - ] - }, { "a": { "kind": "agent", @@ -9293,7 +9402,7 @@ "kind": "agent", "id": "test-creator" }, - "score": 0.2691, + "score": 0.2697, "shared_terms": [ "test", "tests", @@ -9305,27 +9414,6 @@ "aggregation" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine" - }, - "b": { - "kind": "agent", - "id": "parameter-locator" - }, - "score": 0.2681, - "shared_terms": [ - "income", - "tax", - "state", - "ctc", - "reform", - "filing", - "household", - "model" - ] - }, { "a": { "kind": "skill", @@ -9335,7 +9423,7 @@ "kind": "command", "id": "new-tool" }, - "score": 0.2681, + "score": 0.2685, "shared_terms": [ "css", "theme", @@ -9347,6 +9435,48 @@ "colors" ] }, + { + "a": { + "kind": "agent", + "id": "microsim-runner" + }, + "b": { + "kind": "agent", + "id": "reform-comparator" + }, + "score": 0.2685, + "shared_terms": [ + "version", + "result", + "dataset", + "year", + "cps", + "baseline", + "enhanced", + "microsim" + ] + }, + { + "a": { + "kind": "skill", + "id": "policyengine" + }, + "b": { + "kind": "agent", + "id": "parameter-locator" + }, + "score": 0.268, + "shared_terms": [ + "income", + "tax", + "state", + "ctc", + "reform", + "filing", + "household", + "model" + ] + }, { "a": { "kind": "skill", @@ -9356,7 +9486,7 @@ "kind": "agent", "id": "reform-comparator" }, - "score": 0.2665, + "score": 0.2671, "shared_terms": [ "prior", "anchor", @@ -9377,7 +9507,7 @@ "kind": "command", "id": "text-to-reform" }, - "score": 0.2651, + "score": 0.2655, "shared_terms": [ "reform", "dict", @@ -9389,6 +9519,27 @@ "parameter" ] }, + { + "a": { + "kind": "agent", + "id": "ci-fixer" + }, + "b": { + "kind": "agent", + "id": "pr-pusher" + }, + "score": 0.2607, + "shared_terms": [ + "caller", + "git", + "files", + "formatting", + "fix", + "run", + "sources", + "commit" + ] + }, { "a": { "kind": "skill", @@ -9398,7 +9549,7 @@ "kind": "command", "id": "household-calc" }, - "score": 0.2625, + "score": 0.2606, "shared_terms": [ "household", "tax", @@ -9413,37 +9564,16 @@ { "a": { "kind": "agent", - "id": "ci-fixer" + "id": "issue-manager" }, "b": { - "kind": "agent", - "id": "pr-pusher" + "kind": "command", + "id": "create-pr" }, - "score": 0.2621, + "score": 0.2605, "shared_terms": [ - "caller", - "git", - "files", - "formatting", - "fix", - "run", - "sources", - "commit" - ] - }, - { - "a": { - "kind": "agent", - "id": "issue-manager" - }, - "b": { - "kind": "command", - "id": "create-pr" - }, - "score": 0.2609, - "shared_terms": [ - "branch", - "number", + "branch", + "number", "git", "base", "create", @@ -9455,22 +9585,22 @@ { "a": { "kind": "agent", - "id": "dashboard-architecture-validator" + "id": "ci-fixer" }, "b": { - "kind": "agent", - "id": "frontend-builder" + "kind": "command", + "id": "write-tests" }, - "score": 0.2604, + "score": 0.2598, "shared_terms": [ - "app", - "kit", - "tailwind", - "css", - "components", - "import", - "system", - "design" + "test", + "files", + "tests", + "run", + "file", + "fix", + "failures", + "write" ] }, { @@ -9482,7 +9612,7 @@ "kind": "agent", "id": "frontend-builder" }, - "score": 0.2598, + "score": 0.2589, "shared_terms": [ "app", "kit", @@ -9497,43 +9627,22 @@ { "a": { "kind": "agent", - "id": "ci-fixer" + "id": "dashboard-architecture-validator" }, "b": { - "kind": "command", - "id": "write-tests" - }, - "score": 0.2591, - "shared_terms": [ - "test", - "files", - "tests", - "run", - "file", - "fix", - "failures", - "write" - ] - }, - { - "a": { "kind": "agent", - "id": "dashboard-scaffold" - }, - "b": { - "kind": "command", - "id": "new-tool" + "id": "frontend-builder" }, "score": 0.2587, "shared_terms": [ - "project", - "dashboard", - "scaffold", + "app", "kit", + "tailwind", "css", - "plan", - "page", - "import" + "components", + "import", + "system", + "design" ] }, { @@ -9545,7 +9654,7 @@ "kind": "command", "id": "text-to-reform" }, - "score": 0.2586, + "score": 0.2585, "shared_terms": [ "reform", "scorekeepers", @@ -9553,29 +9662,29 @@ "analyze", "presets", "bill", - "runs", - "consult" + "consult", + "runs" ] }, { "a": { "kind": "agent", - "id": "parameter-locator" + "id": "dashboard-scaffold" }, "b": { - "kind": "agent", - "id": "policy-text-researcher" + "kind": "command", + "id": "new-tool" }, - "score": 0.2584, + "score": 0.2582, "shared_terms": [ - "gov", - "state", - "ctc", - "federal", - "reform", - "amount", - "brackets", - "legislative" + "project", + "dashboard", + "scaffold", + "kit", + "css", + "plan", + "page", + "import" ] }, { @@ -9587,7 +9696,7 @@ "kind": "agent", "id": "model-corroborator" }, - "score": 0.2576, + "score": 0.2579, "shared_terms": [ "reform", "scores", @@ -9599,6 +9708,27 @@ "stage" ] }, + { + "a": { + "kind": "agent", + "id": "parameter-locator" + }, + "b": { + "kind": "agent", + "id": "policy-text-researcher" + }, + "score": 0.2564, + "shared_terms": [ + "gov", + "state", + "ctc", + "federal", + "reform", + "brackets", + "amount", + "legislative" + ] + }, { "a": { "kind": "agent", @@ -9608,7 +9738,7 @@ "kind": "command", "id": "analyze-policy" }, - "score": 0.2573, + "score": 0.2559, "shared_terms": [ "log", "archive", @@ -9629,7 +9759,7 @@ "kind": "agent", "id": "frontend-builder" }, - "score": 0.2571, + "score": 0.2555, "shared_terms": [ "component", "plan", @@ -9641,27 +9771,6 @@ "embedding" ] }, - { - "a": { - "kind": "agent", - "id": "dashboard-scaffold" - }, - "b": { - "kind": "agent", - "id": "frontend-builder" - }, - "score": 0.2555, - "shared_terms": [ - "plan", - "kit", - "design", - "components", - "app", - "css", - "component", - "tsx" - ] - }, { "a": { "kind": "command", @@ -9671,18 +9780,39 @@ "kind": "command", "id": "encode-reform" }, - "score": 0.2553, + "score": 0.2552, "shared_terms": [ "prefix", "arguments", "short", "orchestrator", - "page", "files", + "page", "agents", "review" ] }, + { + "a": { + "kind": "agent", + "id": "dashboard-scaffold" + }, + "b": { + "kind": "agent", + "id": "frontend-builder" + }, + "score": 0.2549, + "shared_terms": [ + "plan", + "kit", + "design", + "components", + "css", + "app", + "component", + "tsx" + ] + }, { "a": { "kind": "skill", @@ -9692,7 +9822,7 @@ "kind": "command", "id": "text-to-reform" }, - "score": 0.2546, + "score": 0.2548, "shared_terms": [ "reform", "preset", @@ -9713,7 +9843,7 @@ "kind": "agent", "id": "implementation-validator" }, - "score": 0.2538, + "score": 0.254, "shared_terms": [ "review", "fix", @@ -9721,50 +9851,29 @@ "encode", "structural", "read", - "code", - "mode" - ] - }, - { - "a": { - "kind": "agent", - "id": "dashboard-architecture-validator" - }, - "b": { - "kind": "agent", - "id": "dashboard-scaffold" - }, - "score": 0.2536, - "shared_terms": [ - "css", - "backend", - "config", - "modal", - "custom", - "tsx", - "app", - "dashboard" + "mode", + "worktree" ] }, { "a": { "kind": "skill", - "id": "policyengine-app" + "id": "review-program" }, "b": { "kind": "command", - "id": "create-new-component" + "id": "backdate-program" }, "score": 0.2531, "shared_terms": [ - "app", - "component", - "design", - "src", - "kit", - "tsx", - "react", - "website" + "review", + "program", + "root", + "prefix", + "pdf", + "read", + "workflow", + "phase" ] }, { @@ -9776,7 +9885,7 @@ "kind": "agent", "id": "model-worker" }, - "score": 0.2526, + "score": 0.2528, "shared_terms": [ "canonical", "delegation", @@ -9791,43 +9900,43 @@ { "a": { "kind": "skill", - "id": "review-program" + "id": "policyengine-app" }, "b": { "kind": "command", - "id": "backdate-program" + "id": "create-new-component" }, - "score": 0.2521, + "score": 0.2525, "shared_terms": [ - "review", - "program", - "root", - "prefix", - "pdf", - "read", - "workflow", - "phase" + "app", + "component", + "design", + "src", + "kit", + "tsx", + "react", + "website" ] }, { "a": { "kind": "agent", - "id": "model-corroborator" + "id": "dashboard-architecture-validator" }, "b": { "kind": "agent", - "id": "reform-comparator" + "id": "dashboard-scaffold" }, - "score": 0.2486, + "score": 0.2518, "shared_terms": [ - "our", - "microsim", - "baseline", - "comparator", - "result", - "reform", - "scores", - "anchor" + "css", + "backend", + "config", + "custom", + "modal", + "tsx", + "app", + "dashboard" ] }, { @@ -9839,7 +9948,7 @@ "kind": "command", "id": "prior-analysis" }, - "score": 0.2486, + "score": 0.2493, "shared_terms": [ "archive", "analyses", @@ -9853,23 +9962,23 @@ }, { "a": { - "kind": "command", - "id": "create-dashboard" + "kind": "agent", + "id": "model-corroborator" }, "b": { - "kind": "command", - "id": "new-tool" + "kind": "agent", + "id": "reform-comparator" }, - "score": 0.2481, + "score": 0.2484, "shared_terms": [ - "dashboard", - "create", - "page", - "calculator", - "multi", - "widget", - "purpose", - "scaffold" + "our", + "microsim", + "comparator", + "baseline", + "result", + "reform", + "scores", + "anchor" ] }, { @@ -9881,7 +9990,7 @@ "kind": "command", "id": "prior-analysis" }, - "score": 0.2479, + "score": 0.2476, "shared_terms": [ "prior", "scripts", @@ -9895,23 +10004,23 @@ }, { "a": { - "kind": "agent", - "id": "backend-builder" + "kind": "command", + "id": "create-dashboard" }, "b": { - "kind": "agent", - "id": "dashboard-plan-validator" + "kind": "command", + "id": "new-tool" }, - "score": 0.2451, + "score": 0.2474, "shared_terms": [ - "plan", - "api", - "data", "dashboard", - "lib", - "yaml", - "types", - "test" + "create", + "page", + "calculator", + "multi", + "widget", + "purpose", + "scaffold" ] }, { @@ -9923,7 +10032,7 @@ "kind": "command", "id": "create-pr" }, - "score": 0.245, + "score": 0.2456, "shared_terms": [ "branch", "git", @@ -9937,44 +10046,23 @@ }, { "a": { - "kind": "skill", - "id": "policyengine-tools" + "kind": "agent", + "id": "backend-builder" }, "b": { "kind": "agent", - "id": "dashboard-scaffold" + "id": "dashboard-plan-validator" }, - "score": 0.2424, + "score": 0.2455, "shared_terms": [ + "plan", + "api", + "data", "dashboard", - "kit", - "css", - "config", - "basepath", - "next", - "modal", - "app" - ] - }, - { - "a": { - "kind": "skill", - "id": "policyengine-app" - }, - "b": { - "kind": "command", - "id": "audit-multizone" - }, - "score": 0.2421, - "shared_terms": [ - "app", - "host", - "next", - "website", - "multizone", - "rewrites", - "zone", - "vercel" + "lib", + "yaml", + "types", + "test" ] }, { @@ -9986,7 +10074,7 @@ "kind": "agent", "id": "test-creator" }, - "score": 0.242, + "score": 0.2433, "shared_terms": [ "tests", "test", @@ -10012,9 +10100,9 @@ "pdf", "reference", "source", - "page", "number", "full", + "page", "parameter", "audit" ] @@ -10022,22 +10110,43 @@ { "a": { "kind": "skill", - "id": "policyengine-cloud-costs" + "id": "policyengine-tools" }, "b": { - "kind": "command", - "id": "deploy-dashboard" + "kind": "agent", + "id": "dashboard-scaffold" }, - "score": 0.2389, + "score": 0.241, "shared_terms": [ + "kit", + "dashboard", + "css", + "config", + "basepath", + "next", "modal", - "deploy", + "app" + ] + }, + { + "a": { + "kind": "skill", + "id": "policyengine-app" + }, + "b": { + "kind": "command", + "id": "audit-multizone" + }, + "score": 0.2401, + "shared_terms": [ "app", - "dashboard", - "run", - "backend", - "cloud", - "merge" + "host", + "next", + "multizone", + "website", + "rewrites", + "zone", + "vercel" ] }, { @@ -10049,7 +10158,7 @@ "kind": "command", "id": "audit-multizone" }, - "score": 0.2389, + "score": 0.2391, "shared_terms": [ "zone", "path", @@ -10058,7 +10167,7 @@ "app", "fail", "validator", - "dashboard" + "report" ] }, { @@ -10070,7 +10179,7 @@ "kind": "command", "id": "text-to-reform" }, - "score": 0.2383, + "score": 0.2382, "shared_terms": [ "bill", "microsim", @@ -10079,28 +10188,28 @@ "year", "url", "log", - "api" + "description" ] }, { "a": { "kind": "skill", - "id": "policyengine" + "id": "policyengine-cloud-costs" }, "b": { - "kind": "skill", - "id": "policyengine-api" + "kind": "command", + "id": "deploy-dashboard" }, - "score": 0.2338, + "score": 0.2351, "shared_terms": [ - "household", - "api", - "python", - "country", - "rest", - "result", - "analysis", - "bundle" + "modal", + "deploy", + "app", + "dashboard", + "run", + "backend", + "cloud", + "merge" ] }, { @@ -10112,7 +10221,7 @@ "kind": "command", "id": "text-to-reform" }, - "score": 0.2332, + "score": 0.2338, "shared_terms": [ "reform", "description", @@ -10120,29 +10229,29 @@ "parameter", "provisions", "federal", - "ctc", - "text" + "text", + "ctc" ] }, { "a": { - "kind": "agent", - "id": "dashboard-architecture-validator" + "kind": "skill", + "id": "policyengine" }, "b": { - "kind": "command", - "id": "new-tool" + "kind": "skill", + "id": "policyengine-healthcare" }, - "score": 0.2329, + "score": 0.2334, "shared_terms": [ - "css", - "app", - "tailwind", - "kit", - "import", - "bash", - "function", - "globals" + "household", + "income", + "tax", + "unit", + "net", + "person", + "age", + "benefits" ] }, { @@ -10154,7 +10263,7 @@ "kind": "agent", "id": "edge-case-generator" }, - "score": 0.2324, + "score": 0.2329, "shared_terms": [ "test", "files", @@ -10166,6 +10275,27 @@ "name" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine" + }, + "b": { + "kind": "skill", + "id": "policyengine-api" + }, + "score": 0.2325, + "shared_terms": [ + "household", + "api", + "python", + "country", + "rest", + "result", + "analysis", + "bundle" + ] + }, { "a": { "kind": "agent", @@ -10175,7 +10305,7 @@ "kind": "agent", "id": "program-reviewer" }, - "score": 0.2323, + "score": 0.2322, "shared_terms": [ "implementations", "regulations", @@ -10196,14 +10326,14 @@ "kind": "command", "id": "deploy-dashboard" }, - "score": 0.2316, + "score": 0.232, "shared_terms": [ "app", "host", "rewrites", "website", - "vercel", "workspace", + "vercel", "bun", "modal" ] @@ -10211,43 +10341,22 @@ { "a": { "kind": "agent", - "id": "dashboard-integrator" - }, - "b": { - "kind": "agent", - "id": "dashboard-scaffold" - }, - "score": 0.2315, - "shared_terms": [ - "api", - "components", - "data", - "plan", - "client", - "backend", - "dashboard", - "structure" - ] - }, - { - "a": { - "kind": "skill", - "id": "policyengine" + "id": "dashboard-architecture-validator" }, "b": { - "kind": "skill", - "id": "policyengine-healthcare" + "kind": "command", + "id": "new-tool" }, - "score": 0.2314, + "score": 0.2318, "shared_terms": [ - "household", - "income", - "tax", - "unit", - "net", - "person", - "age", - "year" + "css", + "app", + "tailwind", + "kit", + "import", + "bash", + "function", + "globals" ] }, { @@ -10273,27 +10382,48 @@ }, { "a": { - "kind": "skill", - "id": "policyengine-app" + "kind": "agent", + "id": "component-test-writer" }, "b": { "kind": "agent", - "id": "multizone-validator" + "id": "test-creator" }, - "score": 0.2302, + "score": 0.2297, "shared_terms": [ - "app", - "host", - "next", - "legacy", - "website", - "zone", - "rewrites", - "server" - ] - }, - { - "a": { + "test", + "tests", + "testing", + "expect", + "comprehensive", + "descriptive", + "names", + "integration" + ] + }, + { + "a": { + "kind": "agent", + "id": "dashboard-integrator" + }, + "b": { + "kind": "agent", + "id": "dashboard-scaffold" + }, + "score": 0.2294, + "shared_terms": [ + "api", + "data", + "components", + "plan", + "client", + "backend", + "structure", + "dashboard" + ] + }, + { + "a": { "kind": "skill", "id": "policyengine-canada" }, @@ -10301,7 +10431,7 @@ "kind": "command", "id": "household-calc" }, - "score": 0.2302, + "score": 0.2289, "shared_terms": [ "household", "canada", @@ -10313,6 +10443,27 @@ "microsimulation" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-app" + }, + "b": { + "kind": "agent", + "id": "multizone-validator" + }, + "score": 0.2287, + "shared_terms": [ + "app", + "host", + "next", + "legacy", + "website", + "zone", + "rewrites", + "server" + ] + }, { "a": { "kind": "skill", @@ -10322,16 +10473,37 @@ "kind": "agent", "id": "dashboard-integrator" }, - "score": 0.2286, + "score": 0.2279, "shared_terms": [ "household", "api", "income", "data", - "result", "tax", "unit", - "age" + "result", + "person" + ] + }, + { + "a": { + "kind": "command", + "id": "analyze-policy" + }, + "b": { + "kind": "command", + "id": "reform-pipeline" + }, + "score": 0.2277, + "shared_terms": [ + "bill", + "auto", + "horizon", + "reform", + "window", + "pipeline", + "phase", + "default" ] }, { @@ -10343,7 +10515,7 @@ "kind": "agent", "id": "frontend-builder" }, - "score": 0.2285, + "score": 0.2274, "shared_terms": [ "component", "button", @@ -10355,6 +10527,27 @@ "import" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-api-access" + }, + "b": { + "kind": "skill", + "id": "policyengine-app" + }, + "score": 0.2273, + "shared_terms": [ + "api", + "app", + "server", + "vite", + "client", + "org", + "page", + "next" + ] + }, { "a": { "kind": "skill", @@ -10364,7 +10557,7 @@ "kind": "agent", "id": "backend-builder" }, - "score": 0.2277, + "score": 0.2263, "shared_terms": [ "api", "client", @@ -10378,44 +10571,23 @@ }, { "a": { - "kind": "agent", - "id": "component-test-writer" + "kind": "skill", + "id": "encode-policy-v2" }, "b": { "kind": "agent", - "id": "test-creator" + "id": "pr-pusher" }, - "score": 0.2275, + "score": 0.2258, "shared_terms": [ - "test", + "review", + "push", + "contract", + "encode", "tests", - "testing", - "expect", - "comprehensive", - "descriptive", - "names", - "integration" - ] - }, - { - "a": { - "kind": "command", - "id": "analyze-policy" - }, - "b": { - "kind": "command", - "id": "reform-pipeline" - }, - "score": 0.227, - "shared_terms": [ - "bill", - "auto", - "horizon", - "reform", - "window", - "pipeline", - "phase", - "default" + "draft", + "commit", + "approved" ] }, { @@ -10427,7 +10599,7 @@ "kind": "skill", "id": "policyengine-user-guide" }, - "score": 0.2256, + "score": 0.2243, "shared_terms": [ "household", "tax", @@ -10442,22 +10614,22 @@ { "a": { "kind": "skill", - "id": "encode-policy-v2" + "id": "policyengine-healthcare" }, "b": { - "kind": "agent", - "id": "pr-pusher" + "kind": "skill", + "id": "policyengine-uk" }, - "score": 0.2249, + "score": 0.2239, "shared_terms": [ - "review", - "push", - "contract", - "encode", - "tests", - "draft", - "commit", - "approved" + "household", + "income", + "tax", + "unit", + "net", + "person", + "credit", + "benefits" ] }, { @@ -10469,7 +10641,7 @@ "kind": "agent", "id": "dashboard-plan-validator" }, - "score": 0.2238, + "score": 0.2227, "shared_terms": [ "api", "components", @@ -10484,43 +10656,22 @@ { "a": { "kind": "skill", - "id": "policyengine" - }, - "b": { - "kind": "skill", - "id": "policyengine-canada" - }, - "score": 0.2231, - "shared_terms": [ - "household", - "income", - "tax", - "age", - "microsimulation", - "net", - "assert", - "analysis" - ] - }, - { - "a": { - "kind": "skill", - "id": "policyengine-healthcare" + "id": "fix-pr" }, "b": { - "kind": "skill", - "id": "policyengine-uk" + "kind": "agent", + "id": "ci-fixer" }, - "score": 0.2223, + "score": 0.222, "shared_terms": [ - "household", - "income", - "tax", - "unit", - "net", - "person", - "credit", - "benefits" + "fix", + "files", + "failures", + "workflow", + "review", + "worktree", + "root", + "local" ] }, { @@ -10532,7 +10683,7 @@ "kind": "command", "id": "reform-pipeline" }, - "score": 0.2223, + "score": 0.2218, "shared_terms": [ "dashboard", "reform", @@ -10547,22 +10698,22 @@ { "a": { "kind": "skill", - "id": "fix-pr" + "id": "policyengine" }, "b": { - "kind": "agent", - "id": "ci-fixer" + "kind": "skill", + "id": "policyengine-canada" }, - "score": 0.2218, + "score": 0.221, "shared_terms": [ - "fix", - "files", - "failures", - "workflow", - "review", - "worktree", - "local", - "root" + "household", + "income", + "tax", + "age", + "microsimulation", + "net", + "assert", + "credit" ] }, { @@ -10574,7 +10725,7 @@ "kind": "skill", "id": "policyengine-writing" }, - "score": 0.2216, + "score": 0.2209, "shared_terms": [ "posts", "blog", @@ -10586,27 +10737,6 @@ "descriptions" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-writing" - }, - "b": { - "kind": "command", - "id": "generate-content" - }, - "score": 0.2215, - "shared_terms": [ - "social", - "blog", - "posts", - "post", - "copy", - "content", - "writing", - "neutrality" - ] - }, { "a": { "kind": "agent", @@ -10616,7 +10746,7 @@ "kind": "agent", "id": "dashboard-plan-validator" }, - "score": 0.2202, + "score": 0.2209, "shared_terms": [ "zone", "path", @@ -10631,64 +10761,43 @@ { "a": { "kind": "agent", - "id": "dashboard-architecture-validator" + "id": "multizone-validator" }, "b": { "kind": "command", "id": "deploy-dashboard" }, - "score": 0.2201, + "score": 0.2209, "shared_terms": [ - "modal", + "host", + "zone", "app", - "bash", + "path", + "modal", + "next", "config", - "dashboard", - "backend", - "custom", - "next" + "rewrites" ] }, { "a": { - "kind": "agent", - "id": "parameter-locator" - }, - "b": { - "kind": "command", - "id": "household-calc" - }, - "score": 0.22, - "shared_terms": [ - "reform", - "income", - "tax", - "rate", - "dict", - "household", - "state", - "api" - ] - }, - { - "a": { - "kind": "agent", - "id": "multizone-validator" + "kind": "skill", + "id": "policyengine-writing" }, "b": { "kind": "command", - "id": "deploy-dashboard" + "id": "generate-content" }, - "score": 0.2199, + "score": 0.2206, "shared_terms": [ - "host", - "zone", - "app", - "modal", - "path", - "next", - "config", - "rewrites" + "social", + "blog", + "posts", + "post", + "copy", + "content", + "writing", + "neutrality" ] }, { @@ -10700,18 +10809,39 @@ "kind": "agent", "id": "program-reviewer" }, - "score": 0.2199, + "score": 0.2203, "shared_terms": [ "income", "tests", "test", "edge", "program", - "review", "mode", + "review", "cases" ] }, + { + "a": { + "kind": "agent", + "id": "parameter-locator" + }, + "b": { + "kind": "command", + "id": "household-calc" + }, + "score": 0.2203, + "shared_terms": [ + "reform", + "income", + "tax", + "rate", + "dict", + "state", + "household", + "api" + ] + }, { "a": { "kind": "agent", @@ -10721,7 +10851,7 @@ "kind": "agent", "id": "review-worker" }, - "score": 0.2195, + "score": 0.2196, "shared_terms": [ "review", "program", @@ -10742,7 +10872,7 @@ "kind": "command", "id": "create-new-component" }, - "score": 0.2188, + "score": 0.2185, "shared_terms": [ "kit", "app", @@ -10754,6 +10884,48 @@ "components" ] }, + { + "a": { + "kind": "agent", + "id": "dashboard-architecture-validator" + }, + "b": { + "kind": "command", + "id": "deploy-dashboard" + }, + "score": 0.2166, + "shared_terms": [ + "modal", + "app", + "bash", + "config", + "dashboard", + "backend", + "custom", + "next" + ] + }, + { + "a": { + "kind": "command", + "id": "prior-analysis" + }, + "b": { + "kind": "command", + "id": "prior-scores" + }, + "score": 0.2164, + "shared_terms": [ + "analyses", + "prior", + "analyze", + "scripts", + "archive", + "change", + "runs", + "scores" + ] + }, { "a": { "kind": "agent", @@ -10763,7 +10935,7 @@ "kind": "command", "id": "create-new-component" }, - "score": 0.2174, + "score": 0.216, "shared_terms": [ "component", "components", @@ -10784,7 +10956,7 @@ "kind": "agent", "id": "microsim-runner" }, - "score": 0.2171, + "score": 0.2148, "shared_terms": [ "api", "economy", @@ -10796,27 +10968,6 @@ "org" ] }, - { - "a": { - "kind": "command", - "id": "prior-analysis" - }, - "b": { - "kind": "command", - "id": "prior-scores" - }, - "score": 0.2165, - "shared_terms": [ - "analyses", - "prior", - "analyze", - "scripts", - "archive", - "runs", - "change", - "scores" - ] - }, { "a": { "kind": "agent", @@ -10826,7 +10977,7 @@ "kind": "agent", "id": "program-reviewer" }, - "score": 0.2141, + "score": 0.2144, "shared_terms": [ "mode", "program", @@ -10847,7 +10998,7 @@ "kind": "agent", "id": "ci-fixer" }, - "score": 0.2133, + "score": 0.2137, "shared_terms": [ "review", "contract", @@ -10859,27 +11010,6 @@ "scope" ] }, - { - "a": { - "kind": "agent", - "id": "dashboard-architecture-validator" - }, - "b": { - "kind": "command", - "id": "create-new-component" - }, - "score": 0.2121, - "shared_terms": [ - "app", - "kit", - "grep", - "tailwind", - "components", - "tsx", - "css", - "design" - ] - }, { "a": { "kind": "skill", @@ -10889,7 +11019,7 @@ "kind": "agent", "id": "program-reviewer" }, - "score": 0.2119, + "score": 0.2129, "shared_terms": [ "review", "program", @@ -10901,6 +11031,27 @@ "coordinator" ] }, + { + "a": { + "kind": "agent", + "id": "dashboard-architecture-validator" + }, + "b": { + "kind": "command", + "id": "create-new-component" + }, + "score": 0.211, + "shared_terms": [ + "app", + "kit", + "grep", + "tailwind", + "tsx", + "components", + "css", + "design" + ] + }, { "a": { "kind": "skill", @@ -10910,7 +11061,7 @@ "kind": "command", "id": "create-new-component" }, - "score": 0.2115, + "score": 0.2109, "shared_terms": [ "kit", "design", @@ -10931,7 +11082,7 @@ "kind": "agent", "id": "neutrality-reviewer" }, - "score": 0.2108, + "score": 0.2109, "shared_terms": [ "neutral", "blog", @@ -10943,27 +11094,6 @@ "sided" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-us" - }, - "b": { - "kind": "command", - "id": "audit-state-tax" - }, - "score": 0.2103, - "shared_terms": [ - "tax", - "state", - "gov", - "income", - "year", - "wrong", - "states", - "parameter" - ] - }, { "a": { "kind": "skill", @@ -10973,7 +11103,7 @@ "kind": "agent", "id": "program-reviewer" }, - "score": 0.2098, + "score": 0.2103, "shared_terms": [ "review", "program", @@ -10987,23 +11117,23 @@ }, { "a": { - "kind": "command", - "id": "create-new-component" + "kind": "skill", + "id": "policyengine-us" }, "b": { "kind": "command", - "id": "new-tool" + "id": "audit-state-tax" }, - "score": 0.2096, + "score": 0.2101, "shared_terms": [ - "kit", - "app", - "const", - "tailwind", - "design", - "export", - "src", - "import" + "tax", + "state", + "gov", + "income", + "year", + "wrong", + "states", + "parameter" ] }, { @@ -11015,7 +11145,7 @@ "kind": "command", "id": "backdate-program" }, - "score": 0.2093, + "score": 0.2098, "shared_terms": [ "program", "review", @@ -11036,7 +11166,7 @@ "kind": "agent", "id": "ci-fixer" }, - "score": 0.2086, + "score": 0.2087, "shared_terms": [ "root", "review", @@ -11048,6 +11178,27 @@ "read" ] }, + { + "a": { + "kind": "command", + "id": "create-new-component" + }, + "b": { + "kind": "command", + "id": "new-tool" + }, + "score": 0.2086, + "shared_terms": [ + "kit", + "app", + "tailwind", + "const", + "design", + "export", + "src", + "import" + ] + }, { "a": { "kind": "agent", @@ -11057,7 +11208,7 @@ "kind": "agent", "id": "dashboard-planner" }, - "score": 0.2059, + "score": 0.2049, "shared_terms": [ "plan", "dashboard", @@ -11078,7 +11229,7 @@ "kind": "command", "id": "audit-state-tax" }, - "score": 0.2045, + "score": 0.2048, "shared_terms": [ "pdf", "state", @@ -11099,7 +11250,7 @@ "kind": "agent", "id": "model-corroborator" }, - "score": 0.2039, + "score": 0.2044, "shared_terms": [ "calibration", "reform", @@ -11113,35 +11264,56 @@ }, { "a": { - "kind": "skill", - "id": "policyengine-content" + "kind": "agent", + "id": "ci-fixer" }, "b": { - "kind": "skill", - "id": "policyengine-writing" + "kind": "agent", + "id": "model-worker" }, - "score": 0.2039, + "score": 0.2027, "shared_terms": [ - "social", - "post", - "blog", - "copy", - "writing", - "neutrality", - "chart", - "content" + "test", + "root", + "run", + "blocked", + "role", + "contract", + "manifest", + "encode" ] }, { "a": { "kind": "agent", - "id": "parameter-locator" + "id": "structural-implementer" + }, + "b": { + "kind": "agent", + "id": "reform-classifier" + }, + "score": 0.2023, + "shared_terms": [ + "structural", + "backlog", + "parameter", + "model", + "amount", + "verdict", + "issue", + "reform" + ] + }, + { + "a": { + "kind": "agent", + "id": "parameter-locator" }, "b": { "kind": "command", "id": "implement-structural" }, - "score": 0.2028, + "score": 0.2023, "shared_terms": [ "gov", "reform", @@ -11160,39 +11332,39 @@ }, "b": { "kind": "agent", - "id": "reform-classifier" + "id": "report-logger" }, - "score": 0.2025, + "score": 0.2022, "shared_terms": [ + "issue", + "draft", + "country", "structural", - "backlog", - "parameter", - "model", - "amount", + "repo", "verdict", - "issue", - "reform" + "report", + "body" ] }, { "a": { - "kind": "agent", - "id": "structural-implementer" + "kind": "skill", + "id": "policyengine-content" }, "b": { - "kind": "agent", - "id": "report-logger" + "kind": "skill", + "id": "policyengine-writing" }, - "score": 0.2018, + "score": 0.202, "shared_terms": [ - "issue", - "country", - "draft", - "structural", - "repo", - "verdict", - "report", - "body" + "social", + "post", + "blog", + "copy", + "writing", + "neutrality", + "chart", + "content" ] }, { @@ -11204,7 +11376,7 @@ "kind": "agent", "id": "review-worker" }, - "score": 0.2017, + "score": 0.2019, "shared_terms": [ "review", "program", @@ -11216,27 +11388,6 @@ "verification" ] }, - { - "a": { - "kind": "agent", - "id": "ci-fixer" - }, - "b": { - "kind": "agent", - "id": "model-worker" - }, - "score": 0.2016, - "shared_terms": [ - "test", - "root", - "run", - "blocked", - "role", - "contract", - "manifest", - "encode" - ] - }, { "a": { "kind": "skill", @@ -11246,7 +11397,7 @@ "kind": "agent", "id": "parameter-locator" }, - "score": 0.2015, + "score": 0.1996, "shared_terms": [ "gov", "parameter", @@ -11260,23 +11411,23 @@ }, { "a": { - "kind": "command", - "id": "create-dashboard" + "kind": "agent", + "id": "report-logger" }, "b": { "kind": "command", - "id": "deploy-dashboard" + "id": "implement-structural" }, - "score": 0.1989, + "score": 0.1987, "shared_terms": [ - "dashboard", - "repo", - "multi", - "step", - "plan", - "clone", - "confirm", - "path" + "issue", + "structural", + "country", + "draft", + "verdict", + "archive", + "report", + "analyze" ] }, { @@ -11288,7 +11439,7 @@ "kind": "agent", "id": "report-logger" }, - "score": 0.1984, + "score": 0.1982, "shared_terms": [ "posts", "articles", @@ -11300,27 +11451,6 @@ "json" ] }, - { - "a": { - "kind": "agent", - "id": "report-logger" - }, - "b": { - "kind": "command", - "id": "implement-structural" - }, - "score": 0.1979, - "shared_terms": [ - "issue", - "structural", - "country", - "draft", - "verdict", - "archive", - "report", - "analyze" - ] - }, { "a": { "kind": "agent", @@ -11330,7 +11460,7 @@ "kind": "agent", "id": "reference-validator" }, - "score": 0.1978, + "score": 0.1982, "shared_terms": [ "requirements", "program", @@ -11338,50 +11468,29 @@ "correct", "missing", "review", - "implementations", - "manual" + "reference", + "implementations" ] }, { "a": { - "kind": "agent", - "id": "backend-builder" + "kind": "command", + "id": "create-dashboard" }, "b": { - "kind": "agent", - "id": "dashboard-architecture-validator" + "kind": "command", + "id": "deploy-dashboard" }, - "score": 0.1957, + "score": 0.1977, "shared_terms": [ - "backend", - "modal", - "json", - "custom", - "test", - "data", "dashboard", - "pattern" - ] - }, - { - "a": { - "kind": "agent", - "id": "component-test-writer" - }, - "b": { - "kind": "agent", - "id": "dashboard-design-validator" - }, - "score": 0.1955, - "shared_terms": [ - "tsx", - "components", - "button", - "kit", - "app", - "component", - "classname", - "test" + "repo", + "multi", + "step", + "plan", + "clone", + "confirm", + "path" ] }, { @@ -11393,18 +11502,39 @@ "kind": "agent", "id": "structural-implementer" }, - "score": 0.1948, + "score": 0.1953, "shared_terms": [ "changelog", "issue", "draft", "commit", "push", - "caller", "tests", + "caller", "repo" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-user-guide" + }, + "b": { + "kind": "command", + "id": "create-dashboard" + }, + "score": 0.195, + "shared_terms": [ + "reform", + "calculator", + "household", + "charts", + "impact", + "poverty", + "build", + "income" + ] + }, { "a": { "kind": "command", @@ -11414,7 +11544,7 @@ "kind": "command", "id": "backdate-program" }, - "score": 0.1944, + "score": 0.1945, "shared_terms": [ "pdf", "state", @@ -11428,23 +11558,23 @@ }, { "a": { - "kind": "skill", - "id": "policyengine-user-guide" + "kind": "agent", + "id": "component-test-writer" }, "b": { - "kind": "command", - "id": "create-dashboard" + "kind": "agent", + "id": "dashboard-design-validator" }, - "score": 0.1938, + "score": 0.1944, "shared_terms": [ - "reform", - "calculator", - "household", - "charts", - "impact", - "poverty", - "income", - "build" + "tsx", + "components", + "button", + "kit", + "app", + "component", + "classname", + "test" ] }, { @@ -11456,7 +11586,7 @@ "kind": "command", "id": "audit-seo" }, - "score": 0.1935, + "score": 0.1937, "shared_terms": [ "zone", "repo", @@ -11477,7 +11607,7 @@ "kind": "agent", "id": "parameter-locator" }, - "score": 0.1929, + "score": 0.1932, "shared_terms": [ "reform", "income", @@ -11498,7 +11628,7 @@ "kind": "command", "id": "write-tests" }, - "score": 0.1926, + "score": 0.1931, "shared_terms": [ "test", "tests", @@ -11512,23 +11642,23 @@ }, { "a": { - "kind": "skill", - "id": "policyengine-tools" + "kind": "agent", + "id": "backend-builder" }, "b": { - "kind": "command", - "id": "audit-seo" + "kind": "agent", + "id": "dashboard-architecture-validator" }, - "score": 0.1926, + "score": 0.1922, "shared_terms": [ - "vercel", - "seo", - "zone", - "bun", - "org", - "standalone", - "url", - "app" + "backend", + "modal", + "json", + "custom", + "test", + "data", + "pattern", + "dashboard" ] }, { @@ -11540,7 +11670,7 @@ "kind": "agent", "id": "dashboard-design-validator" }, - "score": 0.1918, + "score": 0.1919, "shared_terms": [ "kit", "app", @@ -11552,6 +11682,27 @@ "required" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-model-development" + }, + "b": { + "kind": "agent", + "id": "edge-case-generator" + }, + "score": 0.1918, + "shared_terms": [ + "tests", + "test", + "yaml", + "variable", + "year", + "parameters", + "periods", + "add" + ] + }, { "a": { "kind": "agent", @@ -11561,7 +11712,7 @@ "kind": "agent", "id": "prior-scores-finder" }, - "score": 0.1914, + "score": 0.1911, "shared_terms": [ "analyses", "comparator", @@ -11576,43 +11727,22 @@ { "a": { "kind": "skill", - "id": "policyengine-model-development" - }, - "b": { - "kind": "agent", - "id": "edge-case-generator" - }, - "score": 0.1913, - "shared_terms": [ - "tests", - "test", - "yaml", - "variable", - "year", - "parameters", - "periods", - "add" - ] - }, - { - "a": { - "kind": "skill", - "id": "policyengine-uk" + "id": "policyengine-tools" }, "b": { - "kind": "agent", - "id": "parameter-locator" + "kind": "command", + "id": "audit-seo" }, - "score": 0.1899, + "score": 0.1906, "shared_terms": [ - "income", - "tax", - "reform", - "model", - "canada", - "personal", - "household", - "gov" + "vercel", + "seo", + "zone", + "bun", + "org", + "standalone", + "url", + "app" ] }, { @@ -11624,7 +11754,7 @@ "kind": "command", "id": "backdate-program" }, - "score": 0.1891, + "score": 0.1895, "shared_terms": [ "review", "files", @@ -11636,6 +11766,27 @@ "fix" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-uk" + }, + "b": { + "kind": "agent", + "id": "parameter-locator" + }, + "score": 0.1895, + "shared_terms": [ + "income", + "tax", + "reform", + "model", + "canada", + "personal", + "household", + "gov" + ] + }, { "a": { "kind": "agent", @@ -11645,7 +11796,7 @@ "kind": "agent", "id": "structural-implementer" }, - "score": 0.1889, + "score": 0.1891, "shared_terms": [ "issue", "repo", @@ -11657,27 +11808,6 @@ "open" ] }, - { - "a": { - "kind": "agent", - "id": "dashboard-planner" - }, - "b": { - "kind": "command", - "id": "deploy-dashboard" - }, - "score": 0.1873, - "shared_terms": [ - "dashboard", - "modal", - "step", - "plan", - "custom", - "pattern", - "data", - "cloud" - ] - }, { "a": { "kind": "agent", @@ -11687,7 +11817,7 @@ "kind": "command", "id": "prior-scores" }, - "score": 0.1871, + "score": 0.1874, "shared_terms": [ "microsim", "prior", @@ -11696,7 +11826,7 @@ "cost", "dataset", "cbo", - "baseline" + "published" ] }, { @@ -11708,58 +11838,58 @@ "kind": "command", "id": "household-calc" }, - "score": 0.1864, + "score": 0.1866, "shared_terms": [ "reform", - "baseline", "dict", + "baseline", "external", "single", "cap", - "household", - "sources" + "sources", + "household" ] }, { "a": { - "kind": "skill", - "id": "policyengine" + "kind": "agent", + "id": "component-test-writer" }, "b": { - "kind": "skill", - "id": "policyengine-model-development" + "kind": "agent", + "id": "edge-case-generator" }, - "score": 0.1858, + "score": 0.1864, "shared_terms": [ - "household", - "age", - "analysis", - "microsimulation", - "variables", - "income", - "year", - "model" + "test", + "tests", + "edge", + "testing", + "case", + "cases", + "file", + "boundary" ] }, { "a": { - "kind": "agent", - "id": "rules-engineer" + "kind": "command", + "id": "create-pr" }, "b": { "kind": "command", - "id": "backdate-program" + "id": "deploy-dashboard" }, - "score": 0.1857, + "score": 0.186, "shared_terms": [ - "page", - "program", - "tanf", - "files", - "href", - "pdf", - "yaml", - "only" + "branch", + "git", + "main", + "check", + "step", + "bash", + "feature", + "json" ] }, { @@ -11771,7 +11901,7 @@ "kind": "skill", "id": "policyengine-plugin-maintenance" }, - "score": 0.1849, + "score": 0.1854, "shared_terms": [ "claude", "codex", @@ -11792,7 +11922,7 @@ "kind": "agent", "id": "frontend-builder" }, - "score": 0.1848, + "score": 0.1854, "shared_terms": [ "kit", "teal", @@ -11806,23 +11936,23 @@ }, { "a": { - "kind": "skill", - "id": "policyengine-data" + "kind": "agent", + "id": "dashboard-planner" }, "b": { - "kind": "agent", - "id": "calibration-diagnostics" + "kind": "command", + "id": "deploy-dashboard" }, - "score": 0.1848, + "score": 0.185, "shared_terms": [ - "microcosm", - "calibration", - "diagnostics", - "imputation", - "weights", - "calibrated", + "dashboard", + "modal", + "step", + "plan", + "custom", + "pattern", "data", - "target" + "cloud" ] }, { @@ -11832,39 +11962,18 @@ }, "b": { "kind": "command", - "id": "audit-state-tax" + "id": "backdate-program" }, "score": 0.1848, "shared_terms": [ - "pdf", - "oregon", "page", - "gov", - "full", - "https", - "income", - "parameter" - ] - }, - { - "a": { - "kind": "agent", - "id": "component-test-writer" - }, - "b": { - "kind": "agent", - "id": "edge-case-generator" - }, - "score": 0.1846, - "shared_terms": [ - "test", - "tests", - "edge", - "testing", - "case", - "cases", - "file", - "boundary" + "program", + "tanf", + "files", + "href", + "pdf", + "yaml", + "only" ] }, { @@ -11876,7 +11985,7 @@ "kind": "command", "id": "household-calc" }, - "score": 0.1843, + "score": 0.1847, "shared_terms": [ "reform", "preset", @@ -11890,65 +11999,44 @@ }, { "a": { - "kind": "command", - "id": "create-pr" + "kind": "skill", + "id": "policyengine" }, "b": { - "kind": "command", - "id": "deploy-dashboard" - }, - "score": 0.1842, - "shared_terms": [ - "branch", - "git", - "main", - "check", - "bash", - "step", - "feature", - "json" - ] - }, - { - "a": { "kind": "skill", "id": "policyengine-model-development" }, - "b": { - "kind": "command", - "id": "implement-structural" - }, - "score": 0.1839, + "score": 0.1842, "shared_terms": [ - "formula", - "contrib", - "gov", - "bracket", - "parameters", - "reform", - "run", + "household", + "age", + "analysis", + "microsimulation", + "variables", + "income", + "year", "model" ] }, { "a": { "kind": "agent", - "id": "dashboard-integrator" + "id": "rules-engineer" }, "b": { - "kind": "agent", - "id": "frontend-builder" + "kind": "command", + "id": "audit-state-tax" }, - "score": 0.1832, + "score": 0.1837, "shared_terms": [ - "components", - "frontend", - "component", - "api", - "builder", - "design", - "step", - "chart" + "pdf", + "oregon", + "page", + "gov", + "full", + "https", + "income", + "parameter" ] }, { @@ -11960,7 +12048,7 @@ "kind": "command", "id": "create-dashboard" }, - "score": 0.183, + "score": 0.1836, "shared_terms": [ "repo", "multi", @@ -11972,6 +12060,27 @@ "arguments" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-model-development" + }, + "b": { + "kind": "command", + "id": "implement-structural" + }, + "score": 0.1833, + "shared_terms": [ + "formula", + "contrib", + "gov", + "bracket", + "parameters", + "reform", + "run", + "model" + ] + }, { "a": { "kind": "command", @@ -11981,7 +12090,7 @@ "kind": "command", "id": "audit-state-tax" }, - "score": 0.183, + "score": 0.1824, "shared_terms": [ "audit", "url", @@ -11993,6 +12102,27 @@ "check" ] }, + { + "a": { + "kind": "agent", + "id": "dashboard-integrator" + }, + "b": { + "kind": "agent", + "id": "frontend-builder" + }, + "score": 0.1823, + "shared_terms": [ + "components", + "frontend", + "component", + "api", + "builder", + "design", + "step", + "chart" + ] + }, { "a": { "kind": "skill", @@ -12002,7 +12132,7 @@ "kind": "command", "id": "audit-state-tax" }, - "score": 0.1819, + "score": 0.1818, "shared_terms": [ "pdf", "audit", @@ -12023,15 +12153,15 @@ "kind": "agent", "id": "pr-pusher" }, - "score": 0.181, + "score": 0.1815, "shared_terms": [ "fix", "review", "push", "workflow", "pusher", - "local", "files", + "local", "never" ] }, @@ -12044,18 +12174,39 @@ "kind": "agent", "id": "reference-validator" }, - "score": 0.181, + "score": 0.1812, "shared_terms": [ "pdf", "citation", "text", - "page", "source", + "page", "doc", "authoritative", "references" ] }, + { + "a": { + "kind": "skill", + "id": "fix-pr" + }, + "b": { + "kind": "skill", + "id": "policyengine-plugin-maintenance" + }, + "score": 0.1811, + "shared_terms": [ + "claude", + "codex", + "fix", + "plugin", + "skills", + "verification", + "references", + "edit" + ] + }, { "a": { "kind": "agent", @@ -12077,46 +12228,25 @@ "government" ] }, - { - "a": { - "kind": "agent", - "id": "dashboard-architecture-validator" - }, - "b": { - "kind": "command", - "id": "audit-multizone" - }, - "score": 0.181, - "shared_terms": [ - "app", - "config", - "path", - "next", - "bash", - "package", - "json", - "validator" - ] - }, { "a": { "kind": "skill", - "id": "fix-pr" + "id": "policyengine-writing" }, "b": { - "kind": "skill", - "id": "policyengine-plugin-maintenance" + "kind": "agent", + "id": "reform-describer" }, - "score": 0.1809, + "score": 0.1806, "shared_terms": [ - "claude", - "codex", - "fix", - "plugin", - "skills", - "verification", - "references", - "edit" + "sentence", + "blog", + "descriptions", + "description", + "writing", + "posts", + "neutral", + "advocacy" ] }, { @@ -12128,7 +12258,7 @@ "kind": "command", "id": "implement-structural" }, - "score": 0.1805, + "score": 0.1804, "shared_terms": [ "reform", "contrib", @@ -12152,8 +12282,8 @@ "score": 0.1802, "shared_terms": [ "url", - "issue", "repo", + "issue", "title", "open", "search", @@ -12161,27 +12291,6 @@ "group" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-writing" - }, - "b": { - "kind": "agent", - "id": "reform-describer" - }, - "score": 0.1801, - "shared_terms": [ - "sentence", - "blog", - "descriptions", - "description", - "writing", - "posts", - "neutral", - "advocacy" - ] - }, { "a": { "kind": "skill", @@ -12191,7 +12300,7 @@ "kind": "agent", "id": "calibration-diagnostics" }, - "score": 0.1799, + "score": 0.18, "shared_terms": [ "unit", "tax", @@ -12206,64 +12315,43 @@ { "a": { "kind": "agent", - "id": "prior-scores-finder" - }, - "b": { - "kind": "command", - "id": "analyze-policy" - }, - "score": 0.1791, - "shared_terms": [ - "year", - "microsim", - "prior", - "archive", - "horizon", - "reform", - "scores", - "window" - ] - }, - { - "a": { - "kind": "command", - "id": "implement-structural" + "id": "dashboard-architecture-validator" }, "b": { "kind": "command", - "id": "text-to-reform" + "id": "audit-multizone" }, - "score": 0.1785, + "score": 0.1793, "shared_terms": [ - "reform", - "structural", - "analyze", - "bill", - "formula", - "deployed", - "extension", - "pre" + "app", + "config", + "path", + "next", + "bash", + "package", + "json", + "validator" ] }, { "a": { "kind": "skill", - "id": "policyengine-canada" + "id": "policyengine-data" }, "b": { - "kind": "skill", - "id": "policyengine-us" + "kind": "agent", + "id": "calibration-diagnostics" }, - "score": 0.1779, + "score": 0.1792, "shared_terms": [ - "tax", - "household", - "income", - "credit", - "net", - "benefit", - "child", - "poverty" + "microcosm", + "calibration", + "imputation", + "weights", + "diagnostics", + "calibrated", + "data", + "target" ] }, { @@ -12275,7 +12363,7 @@ "kind": "command", "id": "create-dashboard" }, - "score": 0.1775, + "score": 0.1789, "shared_terms": [ "auto", "horizon", @@ -12289,44 +12377,44 @@ }, { "a": { - "kind": "agent", - "id": "implementation-validator" + "kind": "command", + "id": "implement-structural" }, "b": { "kind": "command", - "id": "implement-structural" + "id": "text-to-reform" }, - "score": 0.1774, + "score": 0.1789, "shared_terms": [ + "reform", "structural", - "mode", - "run", - "phase", - "verification", - "report", - "issue", - "read" + "analyze", + "bill", + "formula", + "deployed", + "extension", + "pre" ] }, { "a": { "kind": "agent", - "id": "backend-builder" + "id": "prior-scores-finder" }, "b": { "kind": "command", - "id": "create-dashboard" + "id": "analyze-policy" }, - "score": 0.1774, + "score": 0.1783, "shared_terms": [ - "dashboard", - "plan", - "create", - "json", - "api", - "precomputed", - "backend", - "step" + "year", + "microsim", + "prior", + "archive", + "horizon", + "reform", + "scores", + "window" ] }, { @@ -12338,7 +12426,7 @@ "kind": "agent", "id": "test-creator" }, - "score": 0.1771, + "score": 0.1782, "shared_terms": [ "tests", "test", @@ -12350,6 +12438,48 @@ "model" ] }, + { + "a": { + "kind": "agent", + "id": "implementation-validator" + }, + "b": { + "kind": "command", + "id": "implement-structural" + }, + "score": 0.1775, + "shared_terms": [ + "structural", + "mode", + "run", + "phase", + "verification", + "report", + "issue", + "read" + ] + }, + { + "a": { + "kind": "agent", + "id": "program-reviewer" + }, + "b": { + "kind": "command", + "id": "backdate-program" + }, + "score": 0.177, + "shared_terms": [ + "program", + "review", + "tanf", + "research", + "state", + "read", + "you", + "findings" + ] + }, { "a": { "kind": "command", @@ -12359,7 +12489,7 @@ "kind": "command", "id": "encode-reform" }, - "score": 0.177, + "score": 0.1767, "shared_terms": [ "pdf", "state", @@ -12374,43 +12504,22 @@ { "a": { "kind": "skill", - "id": "policyengine-api" + "id": "policyengine-canada" }, "b": { "kind": "skill", - "id": "policyengine-app" + "id": "policyengine-us" }, "score": 0.1766, "shared_terms": [ - "api", - "app", - "org", - "economy", - "calc", - "client", + "tax", "household", - "over" - ] - }, - { - "a": { - "kind": "agent", - "id": "program-reviewer" - }, - "b": { - "kind": "command", - "id": "backdate-program" - }, - "score": 0.1765, - "shared_terms": [ - "program", - "review", - "tanf", - "research", - "state", - "read", - "you", - "findings" + "income", + "credit", + "net", + "benefit", + "child", + "poverty" ] }, { @@ -12422,7 +12531,7 @@ "kind": "agent", "id": "parameter-locator" }, - "score": 0.1761, + "score": 0.1766, "shared_terms": [ "reform", "parameter", @@ -12440,40 +12549,40 @@ "id": "policyengine-api" }, "b": { - "kind": "command", - "id": "household-calc" + "kind": "skill", + "id": "policyengine-app" }, - "score": 0.1758, + "score": 0.1763, "shared_terms": [ - "household", "api", - "get", - "country", - "baseline", - "reform", + "app", + "org", + "economy", "calc", - "simulation" + "household", + "client", + "over" ] }, { "a": { "kind": "agent", - "id": "dashboard-planner" + "id": "backend-builder" }, "b": { "kind": "command", - "id": "text-to-reform" + "id": "create-dashboard" }, - "score": 0.1749, + "score": 0.1759, "shared_terms": [ - "reform", - "natural", - "description", - "language", - "provision", - "bill", - "analyze", - "api" + "dashboard", + "plan", + "create", + "json", + "api", + "precomputed", + "step", + "backend" ] }, { @@ -12485,7 +12594,7 @@ "kind": "agent", "id": "test-creator" }, - "score": 0.1745, + "score": 0.1757, "shared_terms": [ "test", "tests", @@ -12500,22 +12609,43 @@ { "a": { "kind": "agent", - "id": "program-reviewer" + "id": "dashboard-planner" }, "b": { - "kind": "agent", - "id": "parameter-locator" + "kind": "command", + "id": "text-to-reform" }, - "score": 0.173, + "score": 0.1754, "shared_terms": [ - "income", - "state", - "amount", - "deductions", - "step", - "program", - "credits", - "tax" + "reform", + "natural", + "description", + "language", + "provision", + "bill", + "analyze", + "api" + ] + }, + { + "a": { + "kind": "skill", + "id": "policyengine-api" + }, + "b": { + "kind": "command", + "id": "household-calc" + }, + "score": 0.1749, + "shared_terms": [ + "household", + "api", + "get", + "country", + "reform", + "baseline", + "calc", + "simulation" ] }, { @@ -12527,7 +12657,7 @@ "kind": "agent", "id": "parameter-locator" }, - "score": 0.1727, + "score": 0.1731, "shared_terms": [ "state", "income", @@ -12548,14 +12678,14 @@ "kind": "command", "id": "text-to-reform" }, - "score": 0.1721, + "score": 0.1728, "shared_terms": [ "reform", "impact", "analyze", "link", - "org", "reforms", + "org", "parameter", "into" ] @@ -12569,7 +12699,7 @@ "kind": "command", "id": "household-calc" }, - "score": 0.1715, + "score": 0.1725, "shared_terms": [ "household", "net", @@ -12583,23 +12713,86 @@ }, { "a": { - "kind": "agent", - "id": "issue-manager" + "kind": "skill", + "id": "policyengine-model-development" + }, + "b": { + "kind": "command", + "id": "write-tests" + }, + "score": 0.1724, + "shared_terms": [ + "tests", + "test", + "write", + "pytest", + "run", + "repo", + "references", + "path" + ] + }, + { + "a": { + "kind": "agent", + "id": "issue-manager" + }, + "b": { + "kind": "agent", + "id": "report-logger" + }, + "score": 0.1723, + "shared_terms": [ + "issue", + "repo", + "open", + "draft", + "github", + "url", + "git", + "explicit" + ] + }, + { + "a": { + "kind": "agent", + "id": "program-reviewer" + }, + "b": { + "kind": "agent", + "id": "parameter-locator" + }, + "score": 0.1717, + "shared_terms": [ + "income", + "state", + "amount", + "deductions", + "step", + "program", + "credits", + "tax" + ] + }, + { + "a": { + "kind": "skill", + "id": "policyengine-api-access" }, "b": { "kind": "agent", - "id": "report-logger" + "id": "dashboard-scaffold" }, - "score": 0.171, + "score": 0.1716, "shared_terms": [ - "issue", - "repo", - "open", - "draft", - "github", - "url", - "git", - "explicit" + "dashboard", + "api", + "client", + "page", + "backend", + "modal", + "next", + "household" ] }, { @@ -12611,7 +12804,7 @@ "kind": "command", "id": "write-tests" }, - "score": 0.1709, + "score": 0.1706, "shared_terms": [ "test", "app", @@ -12623,27 +12816,6 @@ "config" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-model-development" - }, - "b": { - "kind": "command", - "id": "write-tests" - }, - "score": 0.1704, - "shared_terms": [ - "tests", - "test", - "pytest", - "write", - "run", - "repo", - "references", - "path" - ] - }, { "a": { "kind": "agent", @@ -12653,7 +12825,7 @@ "kind": "command", "id": "analyze-policy" }, - "score": 0.1702, + "score": 0.1704, "shared_terms": [ "bill", "year", @@ -12674,7 +12846,7 @@ "kind": "command", "id": "encode-reform" }, - "score": 0.1698, + "score": 0.17, "shared_terms": [ "reform", "gov", @@ -12695,7 +12867,7 @@ "kind": "agent", "id": "dashboard-integrator" }, - "score": 0.1697, + "score": 0.1693, "shared_terms": [ "household", "unit", @@ -12716,7 +12888,7 @@ "kind": "agent", "id": "content-orchestrator" }, - "score": 0.169, + "score": 0.1687, "shared_terms": [ "social", "blog", @@ -12737,7 +12909,7 @@ "kind": "agent", "id": "dashboard-scaffold" }, - "score": 0.169, + "score": 0.1678, "shared_terms": [ "tsx", "components", @@ -12749,27 +12921,6 @@ "custom" ] }, - { - "a": { - "kind": "agent", - "id": "dashboard-scaffold" - }, - "b": { - "kind": "command", - "id": "create-new-component" - }, - "score": 0.1669, - "shared_terms": [ - "kit", - "design", - "tsx", - "dashboard", - "components", - "component", - "app", - "step" - ] - }, { "a": { "kind": "skill", @@ -12779,7 +12930,7 @@ "kind": "agent", "id": "edge-case-generator" }, - "score": 0.1668, + "score": 0.1677, "shared_terms": [ "review", "tests", @@ -12791,27 +12942,6 @@ "mode" ] }, - { - "a": { - "kind": "agent", - "id": "edge-case-generator" - }, - "b": { - "kind": "command", - "id": "backdate-program" - }, - "score": 0.1668, - "shared_terms": [ - "files", - "program", - "review", - "backdate", - "read", - "existing", - "only", - "root" - ] - }, { "a": { "kind": "command", @@ -12821,7 +12951,7 @@ "kind": "command", "id": "household-calc" }, - "score": 0.1668, + "score": 0.167, "shared_terms": [ "reform", "year", @@ -12842,7 +12972,7 @@ "kind": "command", "id": "household-calc" }, - "score": 0.1664, + "score": 0.1669, "shared_terms": [ "reform", "household", @@ -12854,46 +12984,151 @@ "under" ] }, + { + "a": { + "kind": "agent", + "id": "edge-case-generator" + }, + "b": { + "kind": "command", + "id": "backdate-program" + }, + "score": 0.1667, + "shared_terms": [ + "files", + "program", + "review", + "backdate", + "read", + "existing", + "only", + "root" + ] + }, { "a": { "kind": "skill", - "id": "policyengine-app" + "id": "policyengine-api-access" }, "b": { "kind": "skill", - "id": "policyengine-design" + "id": "policyengine-tools" }, "score": 0.1663, "shared_terms": [ + "public", + "org", + "api", "app", - "tailwindcss", + "dashboard", + "vercel", + "server", + "next" + ] + }, + { + "a": { + "kind": "agent", + "id": "dashboard-scaffold" + }, + "b": { + "kind": "command", + "id": "create-new-component" + }, + "score": 0.1661, + "shared_terms": [ "kit", - "theme", "design", - "vite", - "tokens", - "colors" + "tsx", + "dashboard", + "components", + "component", + "app", + "step" ] }, { "a": { "kind": "agent", - "id": "policy-text-researcher" + "id": "reform-describer" }, "b": { "kind": "command", - "id": "implement-structural" + "id": "household-calc" }, "score": 0.166, "shared_terms": [ - "enacted", - "gov", - "structural", - "effective", - "bill", "reform", - "draft", - "date" + "description", + "baseline", + "tax", + "ctc", + "specific", + "dict", + "income" + ] + }, + { + "a": { + "kind": "skill", + "id": "policyengine-api-access" + }, + "b": { + "kind": "command", + "id": "new-tool" + }, + "score": 0.1659, + "shared_terms": [ + "api", + "dashboard", + "public", + "const", + "client", + "app", + "page", + "function" + ] + }, + { + "a": { + "kind": "agent", + "id": "review-worker" + }, + "b": { + "kind": "command", + "id": "backdate-program" + }, + "score": 0.1659, + "shared_terms": [ + "program", + "review", + "read", + "root", + "only", + "workflow", + "task", + "you" + ] + }, + { + "a": { + "kind": "skill", + "id": "policyengine-app" + }, + "b": { + "kind": "skill", + "id": "policyengine-design" + }, + "score": 0.1657, + "shared_terms": [ + "app", + "tailwindcss", + "kit", + "theme", + "design", + "vite", + "tokens", + "colors" ] }, { @@ -12905,7 +13140,7 @@ "kind": "command", "id": "create-dashboard" }, - "score": 0.166, + "score": 0.1653, "shared_terms": [ "dashboard", "reform", @@ -12926,13 +13161,13 @@ "kind": "agent", "id": "microsim-runner" }, - "score": 0.1658, + "score": 0.1652, "shared_terms": [ "api", "data", "response", - "request", "result", + "request", "year", "state", "step" @@ -12941,64 +13176,64 @@ { "a": { "kind": "agent", - "id": "review-worker" + "id": "component-test-writer" }, "b": { - "kind": "command", - "id": "backdate-program" + "kind": "agent", + "id": "dashboard-architecture-validator" }, - "score": 0.1657, + "score": 0.1651, "shared_terms": [ - "program", - "review", - "read", - "root", - "only", - "you", - "workflow", - "task" + "test", + "app", + "tsx", + "kit", + "import", + "components", + "classname", + "setup" ] }, { "a": { "kind": "agent", - "id": "reform-describer" + "id": "policy-text-researcher" }, "b": { "kind": "command", - "id": "household-calc" + "id": "implement-structural" }, - "score": 0.1657, + "score": 0.1651, "shared_terms": [ + "enacted", + "gov", + "structural", + "effective", + "bill", "reform", - "description", - "baseline", - "ctc", - "tax", - "specific", - "dict", - "income" + "draft", + "date" ] }, { "a": { "kind": "agent", - "id": "component-test-writer" + "id": "model-worker" }, "b": { - "kind": "agent", - "id": "dashboard-architecture-validator" + "kind": "command", + "id": "write-tests" }, - "score": 0.1653, + "score": 0.1648, "shared_terms": [ "test", - "app", - "tsx", - "kit", - "import", - "components", - "classname", - "setup" + "tests", + "run", + "your", + "path", + "write", + "model", + "source" ] }, { @@ -13010,7 +13245,7 @@ "kind": "agent", "id": "policy-text-researcher" }, - "score": 0.1651, + "score": 0.1646, "shared_terms": [ "enacted", "effective", @@ -13031,7 +13266,7 @@ "kind": "agent", "id": "dashboard-design-validator" }, - "score": 0.1643, + "score": 0.1639, "shared_terms": [ "app", "tsx", @@ -13052,7 +13287,7 @@ "kind": "agent", "id": "test-creator" }, - "score": 0.164, + "score": 0.1637, "shared_terms": [ "month", "months", @@ -13064,27 +13299,6 @@ "development" ] }, - { - "a": { - "kind": "agent", - "id": "model-worker" - }, - "b": { - "kind": "command", - "id": "write-tests" - }, - "score": 0.1637, - "shared_terms": [ - "test", - "tests", - "run", - "your", - "path", - "write", - "model", - "source" - ] - }, { "a": { "kind": "agent", @@ -13094,14 +13308,14 @@ "kind": "agent", "id": "pr-pusher" }, - "score": 0.1636, + "score": 0.1637, "shared_terms": [ "fix", "review", "run", "only", - "caller", "git", + "caller", "issues", "program" ] @@ -13115,58 +13329,58 @@ "kind": "agent", "id": "test-creator" }, - "score": 0.1635, + "score": 0.1633, "shared_terms": [ "fix", "program", "test", "read", "not", - "only", "findings", + "only", "variable" ] }, { "a": { "kind": "skill", - "id": "policyengine-canada" + "id": "policyengine-api-access" }, "b": { - "kind": "skill", - "id": "policyengine-user-guide" + "kind": "command", + "id": "create-dashboard" }, - "score": 0.1632, + "score": 0.1631, "shared_terms": [ + "dashboard", + "page", + "api", "household", - "income", - "benefit", - "population", - "canada", - "tax", - "net", - "poverty" + "pages", + "ctc", + "analysis", + "json" ] }, { "a": { "kind": "agent", - "id": "backend-builder" + "id": "calibration-diagnostics" }, "b": { - "kind": "command", - "id": "new-tool" + "kind": "agent", + "id": "model-corroborator" }, - "score": 0.1631, + "score": 0.1629, "shared_terms": [ - "api", - "dashboard", - "create", - "precomputed", - "function", - "modal", - "export", - "step" + "calibration", + "reform", + "stage", + "comparator", + "diagnostics", + "sensitivity", + "family", + "cap" ] }, { @@ -13190,27 +13404,6 @@ "ctc" ] }, - { - "a": { - "kind": "agent", - "id": "calibration-diagnostics" - }, - "b": { - "kind": "agent", - "id": "model-corroborator" - }, - "score": 0.1627, - "shared_terms": [ - "calibration", - "reform", - "stage", - "comparator", - "diagnostics", - "sensitivity", - "family", - "cap" - ] - }, { "a": { "kind": "agent", @@ -13220,7 +13413,7 @@ "kind": "command", "id": "write-tests" }, - "score": 0.1622, + "score": 0.1627, "shared_terms": [ "test", "tests", @@ -13235,43 +13428,22 @@ { "a": { "kind": "skill", - "id": "policyengine" + "id": "policyengine-api-access" }, "b": { "kind": "agent", - "id": "microsim-runner" + "id": "dashboard-planner" }, - "score": 0.1614, + "score": 0.1622, "shared_terms": [ - "result", - "dataset", - "data", - "python", - "microsimulation", - "reform", + "dashboard", "api", - "impact" - ] - }, - { - "a": { - "kind": "skill", - "id": "policyengine-standards" - }, - "b": { - "kind": "agent", - "id": "issue-manager" - }, - "score": 0.1609, - "shared_terms": [ - "repo", - "number", - "create", - "repository", - "draft", - "issue", - "title", - "never" + "public", + "page", + "answer", + "pages", + "modal", + "cloud" ] }, { @@ -13283,7 +13455,7 @@ "kind": "command", "id": "write-tests" }, - "score": 0.1607, + "score": 0.1621, "shared_terms": [ "tests", "test", @@ -13295,6 +13467,48 @@ "shared" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-canada" + }, + "b": { + "kind": "skill", + "id": "policyengine-user-guide" + }, + "score": 0.1621, + "shared_terms": [ + "household", + "income", + "benefit", + "population", + "canada", + "tax", + "net", + "poverty" + ] + }, + { + "a": { + "kind": "agent", + "id": "backend-builder" + }, + "b": { + "kind": "command", + "id": "new-tool" + }, + "score": 0.1618, + "shared_terms": [ + "api", + "dashboard", + "create", + "precomputed", + "export", + "function", + "modal", + "step" + ] + }, { "a": { "kind": "skill", @@ -13304,7 +13518,7 @@ "kind": "agent", "id": "reference-validator" }, - "score": 0.1607, + "score": 0.1616, "shared_terms": [ "pdf", "review", @@ -13316,6 +13530,69 @@ "missing" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-standards" + }, + "b": { + "kind": "agent", + "id": "issue-manager" + }, + "score": 0.1614, + "shared_terms": [ + "repo", + "number", + "create", + "repository", + "draft", + "issue", + "title", + "never" + ] + }, + { + "a": { + "kind": "agent", + "id": "pr-pusher" + }, + "b": { + "kind": "agent", + "id": "test-creator" + }, + "score": 0.1607, + "shared_terms": [ + "tests", + "commit", + "caller", + "pusher", + "files", + "contract", + "fix", + "create" + ] + }, + { + "a": { + "kind": "skill", + "id": "policyengine" + }, + "b": { + "kind": "agent", + "id": "microsim-runner" + }, + "score": 0.1606, + "shared_terms": [ + "result", + "dataset", + "data", + "python", + "microsimulation", + "reform", + "api", + "impact" + ] + }, { "a": { "kind": "agent", @@ -13325,7 +13602,7 @@ "kind": "agent", "id": "reform-describer" }, - "score": 0.1606, + "score": 0.1602, "shared_terms": [ "dashboard", "reform", @@ -13337,27 +13614,6 @@ "ctc" ] }, - { - "a": { - "kind": "agent", - "id": "pr-pusher" - }, - "b": { - "kind": "agent", - "id": "test-creator" - }, - "score": 0.16, - "shared_terms": [ - "tests", - "caller", - "commit", - "pusher", - "files", - "contract", - "fix", - "create" - ] - }, { "a": { "kind": "agent", @@ -13367,11 +13623,11 @@ "kind": "command", "id": "backdate-program" }, - "score": 0.1598, + "score": 0.1594, "shared_terms": [ "page", - "pdf", "reference", + "pdf", "program", "review", "href", @@ -13379,27 +13635,6 @@ "parameter" ] }, - { - "a": { - "kind": "command", - "id": "audit-multizone" - }, - "b": { - "kind": "command", - "id": "write-tests" - }, - "score": 0.159, - "shared_terms": [ - "path", - "target", - "repo", - "test", - "app", - "config", - "bash", - "existing" - ] - }, { "a": { "kind": "agent", @@ -13409,7 +13644,7 @@ "kind": "agent", "id": "review-worker" }, - "score": 0.1587, + "score": 0.1592, "shared_terms": [ "test", "review", @@ -13421,6 +13656,27 @@ "program" ] }, + { + "a": { + "kind": "command", + "id": "audit-multizone" + }, + "b": { + "kind": "command", + "id": "write-tests" + }, + "score": 0.1586, + "shared_terms": [ + "path", + "target", + "repo", + "test", + "app", + "config", + "bash", + "existing" + ] + }, { "a": { "kind": "agent", @@ -13430,7 +13686,7 @@ "kind": "agent", "id": "review-worker" }, - "score": 0.1582, + "score": 0.1583, "shared_terms": [ "review", "test", @@ -13442,27 +13698,6 @@ "model" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-cloud-costs" - }, - "b": { - "kind": "agent", - "id": "backend-builder" - }, - "score": 0.158, - "shared_terms": [ - "modal", - "backend", - "containers", - "api", - "plan", - "dashboard", - "cloud", - "declare" - ] - }, { "a": { "kind": "agent", @@ -13472,10 +13707,10 @@ "kind": "agent", "id": "reference-validator" }, - "score": 0.1574, + "score": 0.1576, "shared_terms": [ - "pdf", "reference", + "pdf", "validator", "review", "mode", @@ -13484,6 +13719,27 @@ "issues" ] }, + { + "a": { + "kind": "command", + "id": "create-dashboard" + }, + "b": { + "kind": "command", + "id": "encode-reform" + }, + "score": 0.1576, + "shared_terms": [ + "reform", + "page", + "multi", + "arguments", + "implement", + "phase", + "skip", + "workflow" + ] + }, { "a": { "kind": "agent", @@ -13493,7 +13749,7 @@ "kind": "command", "id": "text-to-reform" }, - "score": 0.1574, + "score": 0.1573, "shared_terms": [ "reform", "microsim", @@ -13505,27 +13761,6 @@ "not" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-model-development" - }, - "b": { - "kind": "skill", - "id": "policyengine-uk" - }, - "score": 0.1572, - "shared_terms": [ - "household", - "entity", - "age", - "model", - "benunit", - "income", - "person", - "canada" - ] - }, { "a": { "kind": "agent", @@ -13535,7 +13770,7 @@ "kind": "command", "id": "implement-structural" }, - "score": 0.1572, + "score": 0.1571, "shared_terms": [ "reform", "original", @@ -13547,27 +13782,6 @@ "analyze" ] }, - { - "a": { - "kind": "command", - "id": "create-dashboard" - }, - "b": { - "kind": "command", - "id": "encode-reform" - }, - "score": 0.1572, - "shared_terms": [ - "reform", - "page", - "multi", - "arguments", - "implement", - "phase", - "skip", - "workflow" - ] - }, { "a": { "kind": "skill", @@ -13589,27 +13803,6 @@ "node" ] }, - { - "a": { - "kind": "agent", - "id": "reform-comparator" - }, - "b": { - "kind": "command", - "id": "household-calc" - }, - "score": 0.1565, - "shared_terms": [ - "single", - "baseline", - "year", - "reform", - "microsim", - "version", - "cost", - "prior" - ] - }, { "a": { "kind": "skill", @@ -13619,7 +13812,7 @@ "kind": "agent", "id": "model-worker" }, - "score": 0.156, + "score": 0.1566, "shared_terms": [ "role", "canonical", @@ -13631,25 +13824,67 @@ "worker" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine" + }, + "b": { + "kind": "command", + "id": "audit-state-tax" + }, + "score": 0.1562, + "shared_terms": [ + "tax", + "state", + "income", + "year", + "result", + "revenue", + "gov", + "python" + ] + }, { "a": { "kind": "agent", - "id": "dashboard-integrator" + "id": "reform-comparator" }, "b": { "kind": "command", - "id": "new-tool" + "id": "household-calc" }, - "score": 0.156, + "score": 0.1561, "shared_terms": [ - "api", - "const", - "function", - "import", - "countryid", - "export", - "return", - "create" + "single", + "baseline", + "year", + "reform", + "microsim", + "version", + "cost", + "prior" + ] + }, + { + "a": { + "kind": "skill", + "id": "policyengine-model-development" + }, + "b": { + "kind": "skill", + "id": "policyengine-uk" + }, + "score": 0.1559, + "shared_terms": [ + "household", + "entity", + "model", + "age", + "benunit", + "income", + "person", + "canada" ] }, { @@ -13668,9 +13903,30 @@ "program", "model", "needed", - "development", "read", - "actual" + "actual", + "development" + ] + }, + { + "a": { + "kind": "command", + "id": "audit-seo" + }, + "b": { + "kind": "command", + "id": "deploy-dashboard" + }, + "score": 0.1556, + "shared_terms": [ + "vercel", + "deploy", + "url", + "step", + "zone", + "host", + "app", + "check" ] }, { @@ -13682,13 +13938,13 @@ "kind": "skill", "id": "policyengine-uk" }, - "score": 0.1557, + "score": 0.1547, "shared_terms": [ "microcosm", - "unit", "data", "entity", "person", + "unit", "household", "see", "national" @@ -13697,22 +13953,22 @@ { "a": { "kind": "skill", - "id": "policyengine" + "id": "policyengine-uk" }, "b": { - "kind": "command", - "id": "audit-state-tax" + "kind": "agent", + "id": "dashboard-integrator" }, - "score": 0.1554, + "score": 0.1544, "shared_terms": [ - "tax", - "state", + "household", "income", - "year", - "result", - "revenue", - "gov", - "python" + "person", + "unit", + "data", + "tax", + "age", + "spm" ] }, { @@ -13724,7 +13980,7 @@ "kind": "command", "id": "audit-multizone" }, - "score": 0.1552, + "score": 0.1543, "shared_terms": [ "zone", "dashboard", @@ -13738,44 +13994,65 @@ }, { "a": { + "kind": "agent", + "id": "dashboard-integrator" + }, + "b": { "kind": "command", - "id": "audit-seo" + "id": "new-tool" + }, + "score": 0.154, + "shared_terms": [ + "api", + "const", + "function", + "import", + "countryid", + "export", + "return", + "create" + ] + }, + { + "a": { + "kind": "command", + "id": "household-calc" }, "b": { "kind": "command", - "id": "deploy-dashboard" + "id": "prior-scores" }, - "score": 0.1552, + "score": 0.154, "shared_terms": [ - "vercel", - "url", - "deploy", - "step", - "zone", - "host", - "app", - "check" + "reform", + "analyze", + "consult", + "scores", + "presets", + "prior", + "external", + "benchmark" ] }, { "a": { "kind": "skill", - "id": "policyengine-uk" + "id": "policyengine-cloud-costs" }, "b": { "kind": "agent", - "id": "dashboard-integrator" + "id": "backend-builder" }, - "score": 0.1551, + "score": 0.1539, "shared_terms": [ - "household", - "income", - "person", - "unit", - "data", - "tax", - "age", - "spm" + "modal", + "backend", + "containers", + "api", + "plan", + "dashboard", + "cloud", + "declare" ] }, { @@ -13787,7 +14064,7 @@ "kind": "agent", "id": "dashboard-plan-validator" }, - "score": 0.1543, + "score": 0.1537, "shared_terms": [ "component", "tsx", @@ -13817,28 +14094,7 @@ "ready", "issue", "committing", - "version" - ] - }, - { - "a": { - "kind": "command", - "id": "household-calc" - }, - "b": { - "kind": "command", - "id": "prior-scores" - }, - "score": 0.1535, - "shared_terms": [ - "reform", - "analyze", - "consult", - "scores", - "presets", - "prior", - "external", - "benchmark" + "check" ] }, { @@ -13850,7 +14106,7 @@ "kind": "agent", "id": "report-logger" }, - "score": 0.1531, + "score": 0.1533, "shared_terms": [ "analyses", "archive", @@ -13862,48 +14118,6 @@ "reform" ] }, - { - "a": { - "kind": "agent", - "id": "policy-text-researcher" - }, - "b": { - "kind": "agent", - "id": "reform-classifier" - }, - "score": 0.1525, - "shared_terms": [ - "gov", - "ctc", - "reform", - "provisions", - "structural", - "amount", - "refundable", - "provision" - ] - }, - { - "a": { - "kind": "skill", - "id": "policyengine-content" - }, - "b": { - "kind": "skill", - "id": "policyengine-research-lookup" - }, - "score": 0.1523, - "shared_terms": [ - "post", - "blog", - "image", - "published", - "app", - "live", - "tone", - "research" - ] - }, { "a": { "kind": "command", @@ -13913,7 +14127,7 @@ "kind": "command", "id": "household-calc" }, - "score": 0.1518, + "score": 0.1527, "shared_terms": [ "reform", "level", @@ -13921,8 +14135,8 @@ "baseline", "reforms", "tax", - "single", - "file" + "file", + "single" ] }, { @@ -13934,7 +14148,7 @@ "kind": "command", "id": "audit-state-tax" }, - "score": 0.1516, + "score": 0.1522, "shared_terms": [ "state", "number", @@ -13946,27 +14160,6 @@ "phase" ] }, - { - "a": { - "kind": "agent", - "id": "dashboard-plan-validator" - }, - "b": { - "kind": "command", - "id": "create-dashboard" - }, - "score": 0.1511, - "shared_terms": [ - "dashboard", - "plan", - "multi", - "fail", - "path", - "api", - "name", - "validates" - ] - }, { "a": { "kind": "agent", @@ -13976,7 +14169,7 @@ "kind": "command", "id": "encode-reform" }, - "score": 0.151, + "score": 0.1511, "shared_terms": [ "prefix", "test", @@ -13991,22 +14184,22 @@ { "a": { "kind": "agent", - "id": "microsim-runner" + "id": "policy-text-researcher" }, "b": { - "kind": "command", - "id": "household-calc" + "kind": "agent", + "id": "reform-classifier" }, - "score": 0.1509, + "score": 0.1511, "shared_terms": [ + "gov", + "ctc", "reform", - "version", - "baseline", - "dict", - "api", - "microsimulation", - "current", - "raw" + "provisions", + "structural", + "amount", + "refundable", + "provision" ] }, { @@ -14018,7 +14211,7 @@ "kind": "agent", "id": "reform-comparator" }, - "score": 0.1506, + "score": 0.151, "shared_terms": [ "prior", "anchor", @@ -14026,8 +14219,8 @@ "microsim", "comparator", "cost", - "baseline", - "diagnostics" + "diagnostics", + "baseline" ] }, { @@ -14037,18 +14230,60 @@ }, "b": { "kind": "command", - "id": "analyze-policy" + "id": "household-calc" }, - "score": 0.1504, + "score": 0.1508, "shared_terms": [ - "year", - "default", - "economy", - "data", - "microsim", - "baseline", "reform", - "api" + "version", + "baseline", + "dict", + "microsimulation", + "api", + "raw", + "current" + ] + }, + { + "a": { + "kind": "skill", + "id": "policyengine-model-development" + }, + "b": { + "kind": "agent", + "id": "pr-pusher" + }, + "score": 0.1507, + "shared_terms": [ + "changelog", + "add", + "tests", + "never", + "branch", + "run", + "repo", + "references" + ] + }, + { + "a": { + "kind": "agent", + "id": "dashboard-plan-validator" + }, + "b": { + "kind": "command", + "id": "create-dashboard" + }, + "score": 0.1502, + "shared_terms": [ + "dashboard", + "plan", + "multi", + "fail", + "path", + "name", + "api", + "validates" ] }, { @@ -14130,6 +14365,10 @@ "id": "policyengine-api", "path": "skills/policyengine-api/SKILL.md" }, + { + "id": "policyengine-api-access", + "path": "skills/policyengine-api-access/SKILL.md" + }, { "id": "policyengine-app", "path": "skills/policyengine-app/SKILL.md" @@ -14173,7 +14412,7 @@ "name": "analysis-tools", "description": "Policy analysis and research - impact studies, dashboards, notebooks, and visualizations", "category": "analysis", - "version": "4.1.0", + "version": "4.2.0", "keywords": [ "analysis", "research", @@ -14196,6 +14435,7 @@ "./skills/policyengine-canada", "./skills/policyengine-healthcare", "./skills/policyengine-user-guide", + "./skills/policyengine-api-access", "./skills/policyengine-design", "./skills/policyengine-writing", "./skills/policyengine-research-lookup", @@ -14240,7 +14480,7 @@ "name": "api-development", "description": "API development - Flask endpoints, caching, services, and integration patterns", "category": "development", - "version": "4.1.0", + "version": "4.2.0", "keywords": [ "api", "flask", @@ -14256,6 +14496,7 @@ "hooks": null, "skills": [ "./skills/policyengine-api", + "./skills/policyengine-api-access", "./skills/policyengine-model-development", "./skills/policyengine-us", "./skills/policyengine-uk", @@ -14280,7 +14521,7 @@ "name": "app-development", "description": "React app development - app-v2, standalone tools, Vercel deployment, and PolicyEngine-specific patterns", "category": "development", - "version": "4.1.0", + "version": "4.2.0", "keywords": [ "react", "frontend", @@ -14299,6 +14540,7 @@ "skills": [ "./skills/policyengine-app", "./skills/policyengine-tools", + "./skills/policyengine-api-access", "./skills/policyengine-model-development", "./skills/policyengine-us", "./skills/policyengine-uk", @@ -14331,7 +14573,7 @@ "name": "complete", "description": "Complete PolicyEngine knowledge base - all agents, commands, and skills for users, analysts, and contributors", "category": "complete", - "version": "4.1.0", + "version": "4.2.0", "keywords": [ "complete", "all", @@ -14354,6 +14596,7 @@ "./skills/policyengine-tools", "./skills/policyengine-app", "./skills/policyengine-api", + "./skills/policyengine-api-access", "./skills/policyengine-design", "./skills/policyengine-standards", "./skills/policyengine-cloud-costs", @@ -14434,7 +14677,7 @@ "name": "country-models", "description": "Complete multi-agent workflow for implementing government benefit programs in PolicyEngine country packages", "category": "development", - "version": "4.1.0", + "version": "4.2.0", "keywords": [ "tax", "benefits", @@ -14488,7 +14731,7 @@ "name": "dashboard-builder", "description": "Orchestrated AI workflow for creating PolicyEngine dashboards from natural-language descriptions", "category": "development", - "version": "4.1.0", + "version": "4.2.0", "keywords": [ "dashboard", "calculator", @@ -14507,6 +14750,7 @@ "skills": [ "./skills/policyengine-tools", "./skills/policyengine-api", + "./skills/policyengine-api-access", "./skills/policyengine-app", "./skills/policyengine-us", "./skills/policyengine-uk", @@ -14534,7 +14778,7 @@ "name": "data-science", "description": "Data analysis, survey enhancement, imputation, calibration, and microdata utilities", "category": "data", - "version": "4.1.0", + "version": "4.2.0", "keywords": [ "data", "microdata", @@ -14568,7 +14812,7 @@ "name": "essential", "description": "Essential PolicyEngine knowledge for all users - understanding the platform, using the web app, and basic concepts", "category": "getting-started", - "version": "4.1.0", + "version": "4.2.0", "keywords": [ "beginner", "users", @@ -17069,6 +17313,7 @@ "visibility": "PUBLIC", "pushed_at": "2026-05-28T13:10:20Z", "skills": [ + "policyengine-api-access", "policyengine-app", "policyengine-research-lookup", "policyengine-tools", @@ -17087,7 +17332,7 @@ "deploy-dashboard", "write-tests" ], - "total": 13 + "total": 14 }, { "name": "policyengine-canada", @@ -17488,6 +17733,7 @@ "visibility": "PUBLIC", "pushed_at": "2026-05-21T17:59:33Z", "skills": [ + "policyengine-data", "policyengine-model-development", "policyengine-standards", "policyengine-uk" @@ -17498,7 +17744,7 @@ "pr-pusher" ], "commands": [], - "total": 6 + "total": 7 }, { "name": "policyengine-demo", @@ -17658,6 +17904,7 @@ "skills": [ "policyengine", "policyengine-api", + "policyengine-api-access", "policyengine-app", "policyengine-model-development" ], @@ -17673,7 +17920,7 @@ "deploy-dashboard", "new-tool" ], - "total": 12 + "total": 13 }, { "name": "policyengine-app", @@ -17685,6 +17932,7 @@ "pushed_at": "2026-05-25T16:00:28Z", "skills": [ "policyengine-api", + "policyengine-api-access", "policyengine-app", "policyengine-design", "policyengine-plugin-maintenance", @@ -17722,7 +17970,7 @@ "text-to-reform", "write-tests" ], - "total": 33 + "total": 34 }, { "name": "policyengine.dev", @@ -17940,6 +18188,7 @@ "fix-pr", "policyengine", "policyengine-api", + "policyengine-api-access", "policyengine-app", "policyengine-calibration-diagnostics", "policyengine-canada", @@ -18014,7 +18263,7 @@ "text-to-reform", "write-tests" ], - "total": 73 + "total": 74 }, { "name": "policyengine-ve", @@ -18039,13 +18288,12 @@ "pushed_at": "2026-05-28T12:37:26Z", "skills": [ "policyengine", - "policyengine-data", "policyengine-plugin-maintenance", "policyengine-tools" ], "agents": [], "commands": [], - "total": 4 + "total": 3 }, { "name": "tanf-calculator", From a1395681eb11507d26cccd8be2458983fefaf23b Mon Sep 17 00:00:00 2001 From: Anthony Volk <14987227+anth-volk@users.noreply.github.com> Date: Tue, 10 Nov 2026 23:55:03 +0400 Subject: [PATCH 09/16] Test the round-1 review's findings on the skill and its token template - A 401 from the Public API is raised without requesting another token, on every call: a new token would be refused too, and each one counts against the tenant's monthly machine-to-machine allowance. - A redirected token request becomes PublicApiTokenError and stores nothing, and the provider uses the no-redirect opener by default. - The polling text names RATE_LIMIT_WAIT_MILLISECONDS, as merged in PolicyEngine/policyengine-app-v2#1543, and no longer says a 429 counts towards the gateway retries. - The errors table has a 401 row for the server's own token and one for a forwarded user token (error="invalid_token"), and neither says to retry with a new token. Co-Authored-By: Claude Opus 5.5 --- tests/test_api_access_skill.py | 62 ++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 18 deletions(-) diff --git a/tests/test_api_access_skill.py b/tests/test_api_access_skill.py index 9f05bad..e553bcd 100644 --- a/tests/test_api_access_skill.py +++ b/tests/test_api_access_skill.py @@ -339,32 +339,42 @@ def test_template_replaces_the_token_five_minutes_before_it_expires() -> None: assert tokens.access_token() == "token-2" -def test_template_retries_a_refused_request_once_with_a_new_token() -> None: +def test_template_raises_a_refused_request_without_requesting_another_token() -> None: + # A 401 means the client is not on the allow list, or its tenant or audience is + # wrong; a new token would be refused too, and each one counts against the + # tenant's monthly machine-to-machine allowance (app-v2's forwarder never retries). token_module = load_token_module() opener = RecordingOpener() - opener.refuse_next_api_requests = 1 + opener.refuse_next_api_requests = 3 + shared_store: dict = {} tokens = token_module.PublicApiTokenProvider( - make_settings(token_module), shared_store={}, clock=Clock(), opener=opener + make_settings(token_module), shared_store=shared_store, clock=Clock(), opener=opener ) - answer = token_module.call_public_api(tokens, "POST", "/us/calculate", {"household": {}}) - assert answer == {"status": "ok", "message": None, "result": {}} - assert [header for _, _, header in opener.api_requests] == [ - "Bearer token-1", - "Bearer token-2", - ] + for _ in range(3): + with pytest.raises(urllib.error.HTTPError) as refusal: + token_module.call_public_api(tokens, "POST", "/us/calculate", {"household": {}}) + assert refusal.value.code == 401 + assert len(opener.token_requests) == 1 + assert [header for _, _, header in opener.api_requests] == ["Bearer token-1"] * 3 + assert tokens.access_token() == "token-1" -def test_template_stops_after_a_second_refusal() -> None: +def test_template_turns_a_redirected_token_request_into_an_error() -> None: token_module = load_token_module() - opener = RecordingOpener() - opener.refuse_next_api_requests = 2 + + class RedirectingTokenEndpoint(RecordingOpener): + def open(self, request, timeout=None): # noqa: ANN001 - urllib's opener signature + raise urllib.error.HTTPError(request.full_url, 307, "Temporary Redirect", {"Location": "https://elsewhere.test/"}, None) + + shared_store: dict = {} tokens = token_module.PublicApiTokenProvider( - make_settings(token_module), shared_store={}, clock=Clock(), opener=opener + make_settings(token_module), shared_store=shared_store, clock=Clock(), opener=RedirectingTokenEndpoint() ) - with pytest.raises(urllib.error.HTTPError) as refusal: - token_module.call_public_api(tokens, "GET", "/us/metadata") - assert refusal.value.code == 401 - assert len(opener.api_requests) == 2 + with pytest.raises(token_module.PublicApiTokenError, match="307"): + tokens.access_token() + assert shared_store == {} + # By default the provider uses the opener that refuses every redirect. + assert token_module.PublicApiTokenProvider(make_settings(token_module)).opener is token_module.NO_REDIRECT_OPENER def test_template_refuses_partial_settings() -> None: @@ -424,9 +434,13 @@ def test_skill_describes_the_dashboard_api_firewall_refusal() -> None: "Too Many Requests", "no `Retry-After`", "no CORS headers", - "DEFAULT_RATE_LIMIT_WAIT_MILLISECONDS", + "`RATE_LIMIT_WAIT_MILLISECONDS`", ): assert fact in text, fact + # The merged client (PolicyEngine/policyengine-app-v2#1543, in the first publish) + # exports RATE_LIMIT_WAIT_MILLISECONDS and does not count 429s as gateway failures. + assert "DEFAULT_RATE_LIMIT_WAIT_MILLISECONDS" not in text + assert "count the 429" not in text error_rows = [row for row in text.split("## Errors", 1)[1].splitlines() if row.startswith("| 429 ")] assert len(error_rows) == 2, "the errors table needs a 429 row for the firewall and one for the load balancer" @@ -440,3 +454,15 @@ def test_dashboard_manifest_lists_the_skill() -> None: artifact = matches[0] assert artifact["path"] == f"skills/{SKILL_NAME}/SKILL.md" assert sorted(artifact["bundles"]) == sorted(BUNDLES_WITH_SKILL) + + +def test_errors_table_tells_a_refused_server_token_from_a_refused_user_token() -> None: + # API v1's user routes answer an invalid or expired forwarded + # PolicyEngine-User-Authorization token with their own 401 and + # WWW-Authenticate: Bearer error="invalid_token"; the server's own token is + # refused with a plain "WWW-Authenticate: Bearer". + errors = skill_text().split("## Errors", 1)[1] + rows_401 = [row for row in errors.splitlines() if row.startswith("| 401 ")] + assert len(rows_401) == 2, "the errors table needs a 401 row for each credential" + assert any('error="invalid_token"' in row and "PolicyEngine-User-Authorization" in row for row in rows_401) + assert not any("retry once with a new" in row for row in rows_401) From 7e325d3f1d1267b70384060a048d5bdabe52f1a3 Mon Sep 17 00:00:00 2001 From: Anthony Volk <14987227+anth-volk@users.noreply.github.com> Date: Tue, 10 Nov 2026 23:56:29 +0400 Subject: [PATCH 10/16] Fix the round-1 review's findings in the skill and its token template - The token template no longer answers a 401 with a new token. A 401 means the client is not on the allow list in that environment, or its tenant or audience is wrong, so each new token was refused too and used up the tenant's monthly machine-to-machine allowance, once per call per instance. It now raises the 401, as app-v2's forwarder does, and the unused forget() is gone. The shared store's type is a Protocol with get and item assignment, which modal.Dict and dict both satisfy. - The polling text follows the merged client (app-v2#1543, which the first npm publish includes): RATE_LIMIT_WAIT_MILLISECONDS, 429s that never end polling, the fourth gateway failure since the last answer, and polling stopping with status null on another origin. - The errors table has a 401 row for the server's own token and one for a forwarded user token (WWW-Authenticate: Bearer error="invalid_token"), and the 502 row adds Auth0 refusing the token request and a policies answer with no ID. - Smaller corrections: only the comparison route checks query parameters; the Public API's 401 and 503 bodies have no result field; Cloud Run with a few long-lived instances can keep the token in memory; the Vercel Runtime Cache snippet treats a miss as null or undefined and never sets a zero or negative ttl. Co-Authored-By: Claude Opus 5.5 --- skills/policyengine-api-access/SKILL.md | 52 ++++++++++------ .../templates/public_api_token.py | 59 ++++++++----------- 2 files changed, 58 insertions(+), 53 deletions(-) diff --git a/skills/policyengine-api-access/SKILL.md b/skills/policyengine-api-access/SKILL.md index b3b3784..149e7d3 100644 --- a/skills/policyengine-api-access/SKILL.md +++ b/skills/policyengine-api-access/SKILL.md @@ -98,8 +98,9 @@ const metadata = await policyengine.getMetadata("uk"); | `GET /api/economy/compare` | Query `country`, `policy`, `baseline`, `region`, `year`, each exactly once | `{status: "computing" \| "ok" \| "error", result, …}`, never cached | | `GET /api/metadata/{country}` | — | `{status, message, result}`, cached by browsers for an hour (`max-age=3600`) | -- `country` is `us` or `uk`. Any other field or query parameter is refused with 400, and a - body whose `Content-Type` is not JSON with 415. +- `country` is `us` or `uk`. An unknown body field (household calculation, policies) or query + parameter (economy comparison) is refused with 400, and a body whose `Content-Type` is not + JSON with 415. - `policy` and `baseline` are policy IDs (whole numbers). `baseline` is current law's ID: 2 for `us`, 1 for `uk` (`result.current_law_id` in the metadata). `year` is four digits; `region` is `us`, `uk` or a sub-national region such as `state/ca`, at most 200 characters. @@ -109,11 +110,12 @@ const metadata = await policyengine.getMetadata("uk"); (`calculateHousehold(…)`), not checked at run time. **Polling.** `compareEconomy` reads the comparison every 5 seconds until `status` is `ok`, and -gives up after 30 minutes with `EconomyComparisonTimeoutError`. It waits one interval after a -502, 503 or 504, and stops after a fourth such answer in a row. After a 429 it waits for -`Retry-After`; the firewall sends none, so versions that export -`DEFAULT_RATE_LIMIT_WAIT_MILLISECONDS` wait 60 seconds instead, and earlier ones wait one -interval and count the 429 towards those four. A comparison that failed (502 with +gives up after 30 minutes with `EconomyComparisonTimeoutError`. After a 429 it waits for +`Retry-After`, or 60 seconds (`RATE_LIMIT_WAIT_MILLISECONDS`, the firewall's window) when there +is none, and keeps polling. A page on another origin cannot read the firewall's 429 (see rate +limits below), so there polling stops with `status` `null`. After a 502, 503 or 504 it waits +one interval, and the fourth such failure since the last answer ends polling. A comparison +that failed (502 with `status: "error"` and `retry_after_seconds`) is thrown at once: the Public API keeps that failure for `retry_after_seconds`, so polling sooner returns it again. Keep `intervalMilliseconds` at a few seconds. Use `getEconomyComparison` for one read. @@ -167,22 +169,32 @@ Other headers, when a server acts for a browser: - send at most one of each; two `Authorization` headers are refused. **Cache the token across instances.** Tokens last 24 hours, and Auth0 counts the -machine-to-machine tokens it issues per tenant per month. Never request a token per request, -per container start or per cold start: +machine-to-machine tokens it issues per tenant per month. Never request a token per request. +Without a shared store each instance requests one when it starts, which is fine for a few +long-lived instances (a Cloud Run service with a low maximum) but not where instances start +often, such as Modal containers: - **Python (Modal, Cloud Run, scripts):** copy `templates/public_api_token.py`. It keeps the - token in memory and in a store the instances share (a `modal.Dict` on Modal), replaces it five - minutes before it expires, retries a 401 once with a new token, and never follows a - redirect. Its docstring has the Modal wiring. + token in memory and, when given one, in a store the instances share (a `modal.Dict` on Modal; + any object with `get` and item assignment), replaces it five minutes before it expires, + raises a 401 without requesting another token, and never follows a redirect. Its docstring + has the Modal wiring. - **Vercel functions:** keep it in Vercel Runtime Cache, as app-v2's `packages/public-api-forwarding/src/accessToken.ts` does: ```ts import { getCache } from "@vercel/functions"; + type CachedToken = { accessToken: string; refreshAtMilliseconds: number }; const tokenCache = getCache({ namespace: "policyengine-public-api" }); - const cached = (await tokenCache.get(cacheKey)) as { accessToken: string; refreshAt: number } | undefined; - // On a miss, or within five minutes of expiry: request a token, then - await tokenCache.set(cacheKey, { accessToken, refreshAt }, { ttl: expiresIn - 300 }); + + const cached = (await tokenCache.get(cacheKey)) as CachedToken | null | undefined; + if (!cached || Date.now() >= cached.refreshAtMilliseconds) { + // Request a token; accessToken and expiresIn (seconds) come from Auth0's answer. Keep it + // until five minutes before it expires, or halfway through a shorter life. + const keepSeconds = expiresIn - Math.min(300, expiresIn / 2); + const refreshAtMilliseconds = Date.now() + keepSeconds * 1000; + await tokenCache.set(cacheKey, { accessToken, refreshAtMilliseconds }, { ttl: Math.max(1, Math.floor(keepSeconds)) }); + } ``` The key is the tenant, audience and client ID, never the secret. Requests that arrive while a @@ -247,20 +259,22 @@ data, or use a backend with its own client. ## Errors `@policyengine/api-client` throws `PolicyEngineApiError` with `status` (`null` when no answer -could be read), `message`, `body` and `retryAfterSeconds`. Error bodies from the dashboard API -and the Public API share one shape: `{"status": "error", "message": …, "result": null}`. +could be read), `message`, `body` and `retryAfterSeconds`. The dashboard API's own errors are +`{"status": "error", "message": …, "result": null}`; the Public API's 401 and 503 bodies have +`status` and `message` only. Read `message`. | Status | From | Meaning | What to do | |---|---|---|---| | 400 | Dashboard API | A missing or unknown field, or a malformed value | Fix the request; `message` names the field | -| 401 | Public API | `{"status":"error","message":"Authentication is required"}` with `WWW-Authenticate: Bearer`: an invalid or expired token, a client not on the allow list, a client token from another tenant, two `Authorization` headers, or, once the requirement is on, no server credential | Server: drop the cached token and retry once with a new one (the template does this); a second 401 means the client is not listed in that environment, or the tenant or audience is wrong, so stop and report it. Page: the website's own credential failed; show an error, do not retry in a loop | +| 401 | Public API, the server's own token | `{"status":"error","message":"Authentication is required"}` with `WWW-Authenticate: Bearer`: an invalid or expired token, a client not on the allow list, a client token from another tenant, two `Authorization` headers, or, once the requirement is on, no server credential | Server: do not request another token, which would be refused too and counts against the tenant's monthly allowance; check that the client is listed in that environment and that its tenant and audience match, and report it. Page: the website's own credential failed; show an error, do not retry in a loop | +| 401 | Public API user routes | `WWW-Authenticate: Bearer error="invalid_token"` and "The bearer access token is invalid": the forwarded `PolicyEngine-User-Authorization` token is invalid or expired | Keep the server token; the user signs in again | | 403 | Dashboard API | "Pages on this origin may not call the dashboard API." The page's origin is not allowed | Serve the page from an allowed origin. A cross-origin page cannot read this answer: the browser reports a CORS error and the client throws with `status` `null` | | 403 | Public API user routes | A forwarded `PolicyEngine-User-Authorization` token is a machine-to-machine token, not a user's | Forward only a signed-in user's own token there | | 404 | Dashboard API | An unknown country in `/api/metadata/{country}` | Use `us` or `uk` | | 415 | Dashboard API | The body's `Content-Type` is not JSON | Send `Content-Type: application/json`; the client does | | 429 | Dashboard API firewall | "Too Many Requests" as text/plain, with no `Retry-After` and no CORS headers: one IP address passed a per-minute limit | Wait for the 60-second window to end before sending again; never retry at once. On another origin (localhost) the page sees a network failure with `status` `null` instead, so treat repeated `null` statuses during heavy use the same way | | 429 | The Public API's load balancer | Too many requests from one IP address, not JSON | Server: wait `Retry-After` when present, otherwise back off (5 s, then doubling). Requests with a bearer token skip its per-address limits on `/{country}/metadata`, `/{country}/calculate` and `/{country}/calculate-full` | -| 502 | Dashboard API | Auth0 or the Public API could not be reached, or the Public API answered with a redirect | Retry later with back-off | +| 502 | Dashboard API | Auth0 refused or did not answer the website's token request, the Public API could not be reached or answered with a redirect, or the Public API's answer to `POST /api/policies` named no policy ID | Retry later with back-off | | 502 | Public API, economy comparison | `status: "error"` with `retry_after_seconds`: the comparison failed | Show the failure; do not ask again before `retry_after_seconds` | | 503 | Public API | `{"status":"error","message":"Authentication is unavailable"}`: it could not check the token (Auth0's signing keys unreachable, or its own settings) | Keep the token; retry with back-off. It is not a refusal of the client | | 503 | Dashboard API | Its own settings are missing or incomplete, for example on a website preview | Not retryable; report it to the website's maintainers | diff --git a/skills/policyengine-api-access/templates/public_api_token.py b/skills/policyengine-api-access/templates/public_api_token.py index 93f8436..7c659b2 100644 --- a/skills/policyengine-api-access/templates/public_api_token.py +++ b/skills/policyengine-api-access/templates/public_api_token.py @@ -40,6 +40,11 @@ def household(situation: dict) -> dict: plain ``dict`` keeps the token for one process only. Only the token and when to replace it are stored, never the client secret. +A 401 is raised, never answered with a new token: it means the client is not on +the Public API's allow list in this environment, or its tenant or audience is +wrong, so a new token would be refused too and would only use up the tenant's +monthly allowance. + Requests never follow redirects: a followed redirect would send the client secret, or the token, to wherever it points. """ @@ -53,9 +58,9 @@ def household(situation: dict) -> dict: import time import urllib.error import urllib.request -from collections.abc import Callable, Mapping, MutableMapping +from collections.abc import Callable, Mapping from dataclasses import dataclass -from typing import Any +from typing import Any, Protocol LOGGER = logging.getLogger(__name__) @@ -73,6 +78,14 @@ def household(situation: dict) -> dict: } +class SharedTokenStore(Protocol): + """What the provider needs from a shared store: a dict, a modal.Dict, or similar.""" + + def get(self, key: str, default: Any = None) -> Any: ... + + def __setitem__(self, key: str, value: Any) -> None: ... + + class PublicApiSettingsError(ValueError): """A setting is missing or malformed.""" @@ -118,7 +131,7 @@ class PublicApiTokenProvider: def __init__( self, settings: PublicApiSettings, - shared_store: MutableMapping[str, Any] | None = None, + shared_store: SharedTokenStore | None = None, clock: Callable[[], float] = time.time, opener: Any = NO_REDIRECT_OPENER, ) -> None: @@ -145,15 +158,6 @@ def access_token(self) -> str: self._write_shared_token(self._remembered) return self._remembered["access_token"] - def forget(self, access_token: str) -> None: - """Drops a token the Public API refused, so the next call gets a new one.""" - with self._lock: - if self._remembered is not None and self._remembered["access_token"] == access_token: - self._remembered = None - shared_token = self._read_shared_token() - if shared_token is not None and shared_token.get("access_token") == access_token: - self._write_shared_token({"access_token": "", "refresh_at": 0}) - def _is_usable(self, token: dict[str, Any] | None) -> bool: return ( isinstance(token, dict) @@ -234,28 +238,15 @@ def call_public_api( ) -> Any: """Sends one request with the server token and returns the parsed JSON answer. - A 401 means the token was refused: it is dropped and the request is sent once - more with a new token. A second 401 is raised, because the client is then not - on the Public API's allow list for this environment, or its tenant or - audience is wrong; asking Auth0 again would not help. Every other error is - raised as urllib's HTTPError, with the status and the answer's body. + Every error is raised as urllib's HTTPError, with the status and the answer's + body. A 401 is raised too, without asking Auth0 for another token (see the + module docstring). """ opener = tokens.opener if opener is None else opener data = None if body is None else json.dumps(body).encode() - for attempt in (1, 2): - access_token = tokens.access_token() - headers = {"Accept": "application/json", "Authorization": f"Bearer {access_token}"} - if data is not None: - headers["Content-Type"] = "application/json" - request = urllib.request.Request( - f"{tokens.settings.api_url}{path}", data=data, headers=headers, method=method - ) - try: - with opener.open(request, timeout=timeout_seconds) as response: - return json.loads(response.read()) - except urllib.error.HTTPError as error: - if error.code == 401 and attempt == 1: - tokens.forget(access_token) - continue - raise - raise AssertionError("unreachable") + headers = {"Accept": "application/json", "Authorization": f"Bearer {tokens.access_token()}"} + if data is not None: + headers["Content-Type"] = "application/json" + request = urllib.request.Request(f"{tokens.settings.api_url}{path}", data=data, headers=headers, method=method) + with opener.open(request, timeout=timeout_seconds) as response: + return json.loads(response.read()) From f69d880d8294529b778ee7acc9b188305c548cab Mon Sep 17 00:00:00 2001 From: Anthony Volk <14987227+anth-volk@users.noreply.github.com> Date: Tue, 10 Nov 2026 23:58:31 +0400 Subject: [PATCH 11/16] Test the guidance review's findings on the guard and the dashboard agents - The guard's self-test now includes forms it missed: Cloud Run's per-project addresses, ~~~ and four-backtick fences, html, vue, svelte and cjs blocks, a TypeScript block nested in a Markdown block, JSON keys, a || fallback in inline code, and public-prefix names tied to the Public API's client or key. It also includes names it must accept: a browser's own Auth0 sign-in settings, a Mapbox token, and a TypeScript block marked as server code. - The dashboard scaffold must load policyengine-api-access. - The tools skill's Pattern C and /new-tool's advice must not send a parameter reform's economy-wide comparison to a custom Modal backend, since the dashboard API offers it. Co-Authored-By: Claude Opus 5.5 --- tests/test_public_api_browser_guidance.py | 65 +++++++++++++++++++---- 1 file changed, 54 insertions(+), 11 deletions(-) diff --git a/tests/test_public_api_browser_guidance.py b/tests/test_public_api_browser_guidance.py index d3a7724..1ae0f5e 100644 --- a/tests/test_public_api_browser_guidance.py +++ b/tests/test_public_api_browser_guidance.py @@ -100,21 +100,39 @@ def test_no_public_prefix_variable_holds_the_public_api_or_a_credential() -> Non def test_guards_catch_the_patterns_they_name() -> None: - browser_example = "```ts\nconst API_BASE = 'https://api.policyengine.org';\n```\n" - indented_example = " ```js\n fetch(`https://api.policyengine.org/us/calculate`)\n ```\n" - cloud_run_example = "```tsx\nfetch('https://policyengine-api-staging-abc123defg-uc.a.run.app/us/metadata')\n```\n" - shell_example = "```bash\ncurl https://api.policyengine.org/us/metadata\n```\n" - household_api_example = "```ts\nfetch('https://household.api.policyengine.org/us/calculate')\n```\n" - assert browser_blocks_naming_the_public_api(browser_example) - assert browser_blocks_naming_the_public_api(indented_example) - assert browser_blocks_naming_the_public_api(cloud_run_example) - assert not browser_blocks_naming_the_public_api(shell_example) - assert not browser_blocks_naming_the_public_api(household_api_example) + browser_examples = [ + "```ts\nconst API_BASE = 'https://api.policyengine.org';\n```\n", + " ```js\n fetch(`https://api.policyengine.org/us/calculate`)\n ```\n", + "```tsx\nfetch('https://policyengine-api-staging-abc123defg-uc.a.run.app/us/metadata')\n```\n", + "```ts\nfetch('https://policyengine-api-123456789012.us-central1.run.app/us/metadata')\n```\n", + "~~~ts\nfetch('https://api.policyengine.org/us/metadata')\n~~~\n", + "````tsx\nfetch('https://api.policyengine.org/us/metadata')\n````\n", + "```html\n\n```\n", + "```vue\n\n```\n", + "```svelte\n\n```\n", + "```cjs\nfetch('https://api.policyengine.org/uk/metadata')\n```\n", + "````markdown\nAn example:\n```ts\nfetch('https://api.policyengine.org/us/metadata')\n```\n````\n", + ] + for example in browser_examples: + assert browser_blocks_naming_the_public_api(example), example + not_browser_examples = [ + "```bash\ncurl https://api.policyengine.org/us/metadata\n```\n", + "```ts\nfetch('https://household.api.policyengine.org/us/calculate')\n```\n", + # Server-side TypeScript, marked as such, may name the Public API. + "\n```ts\nawait fetch('https://api.policyengine.org/us/calculate', { headers })\n```\n", + ] + for example in not_browser_examples: + assert not browser_blocks_naming_the_public_api(example), example for unsafe in ( "NEXT_PUBLIC_API_URL=https://api.policyengine.org", "VITE_API_URL: 'https://api.policyengine.org'", + '"NEXT_PUBLIC_API_URL": "https://api.policyengine.org"', + "`process.env.NEXT_PUBLIC_API_URL || 'https://api.policyengine.org'`", "NEXT_PUBLIC_POLICYENGINE_API_AUTH0_CLIENT_SECRET", - "VITE_API_TOKEN", + "NEXT_PUBLIC_POLICYENGINE_API_AUTH0_CLIENT_ID", + "VITE_PE_API_KEY", + "VITE_AUTH0_CLIENT_SECRET", + "VITE_API_TOKEN_SECRET", ): assert PUBLIC_PREFIX_SET_TO_PUBLIC_API.search(unsafe) or PUBLIC_PREFIX_CREDENTIAL.search(unsafe), unsafe for safe in ( @@ -122,11 +140,36 @@ def test_guards_catch_the_patterns_they_name() -> None: "never a `NEXT_PUBLIC_*` or `VITE_*` name", "NEXT_PUBLIC_API_V2_URL || 'https://v2.api.policyengine.org'", "VITE_HOUSEHOLD_API_URL=https://household.api.policyengine.org", + # A browser's own sign-in settings, as app-v2 uses them, are public by design. + "VITE_AUTH0_DOMAIN=auth.policyengine.org", + "VITE_AUTH0_CLIENT_ID", + "NEXT_PUBLIC_AUTH0_AUDIENCE", + "NEXT_PUBLIC_MAPBOX_TOKEN", ): assert not PUBLIC_PREFIX_SET_TO_PUBLIC_API.search(safe), safe assert not PUBLIC_PREFIX_CREDENTIAL.search(safe), safe +def test_dashboard_scaffold_loads_the_access_skill() -> None: + text = (REPO_ROOT / "targets/claude/agents/dashboard/dashboard-scaffold.md").read_text() + loading = text.split("## First: Load Required Skills", 1) + assert len(loading) == 2 + assert "`Skill: policyengine-api-access`" in loading[1].split("\n## ", 1)[0] + + +def test_custom_backend_guidance_agrees_with_what_the_dashboard_api_offers() -> None: + # The dashboard API compares a parameter reform with current law across the + # economy, so that alone is no reason for a custom Modal backend. + tools_text = TOOLS_SKILL.read_text() + pattern_c = re.search(r"^- \*\*C — .*?(?=^\S)", tools_text, re.DOTALL | re.MULTILINE) + assert pattern_c, "the tools skill has no Pattern C entry" + assert "society-wide microsim," not in pattern_c.group(0) + assert "structural" in pattern_c.group(0) + new_tool = (REPO_ROOT / "targets/claude/commands/new-tool.md").read_text() + assert "unless the tool needs microsimulation,\n> custom reforms" not in new_tool + assert "structural" in new_tool.split("**Prefer Pattern B**", 1)[1].split("\n\n", 1)[0] + + @pytest.mark.parametrize("relative_path", DASHBOARD_GUIDANCE) def test_dashboard_guidance_points_to_the_access_skill(relative_path: str) -> None: assert ACCESS_SKILL in (REPO_ROOT / relative_path).read_text() From 74182b7565ef5674a505e83731d7a29f63075a66 Mon Sep 17 00:00:00 2001 From: Anthony Volk <14987227+anth-volk@users.noreply.github.com> Date: Wed, 11 Nov 2026 00:00:05 +0400 Subject: [PATCH 12/16] Fix the guidance review's findings on the guard and the dashboard agents - The guard matches Cloud Run's per-project addresses; ``` and ~~~ fences of any length, closed by the same fence; html, vue, svelte, cjs and astro blocks; examples nested in Markdown blocks; JSON keys and || fallbacks; and public-prefix names that hold a secret or are named for the Public API's address or server client. It no longer flags a browser's own Auth0 sign-in settings or other services' public tokens, and a block marked may name the Public API. Code files in the catalog are checked too. - The tools skill's Pattern C and /new-tool no longer send a parameter reform's economy-wide comparison to a custom Modal backend, which the dashboard API offers; they name structural reforms and microsimulation output beyond that comparison. - The dashboard scaffold loads policyengine-api-access. - backend-builder: the household type fits US and UK entities, the comment says when a dashboard's own *.vercel.app host is allowed, and the tests mock the package, since the client is built when the module loads. The integrator says what the policyengine-api pattern passes and gets back. - The app skill says the route keeps the Public API's paths under /api/policyengine. - dashboard/src/data/manifest.json is rebuilt for the changed skills, agents and command. Co-Authored-By: Claude Opus 5.5 --- dashboard/src/data/manifest.json | 5476 +++++++++-------- skills/policyengine-app/SKILL.md | 3 +- skills/policyengine-tools/SKILL.md | 6 +- .../agents/dashboard/backend-builder.md | 18 +- .../agents/dashboard/dashboard-integrator.md | 2 + .../agents/dashboard/dashboard-scaffold.md | 3 +- targets/claude/commands/new-tool.md | 8 +- tests/test_public_api_browser_guidance.py | 56 +- 8 files changed, 2881 insertions(+), 2691 deletions(-) diff --git a/dashboard/src/data/manifest.json b/dashboard/src/data/manifest.json index c0e1945..5b89895 100644 --- a/dashboard/src/data/manifest.json +++ b/dashboard/src/data/manifest.json @@ -1,5 +1,5 @@ { - "generated_at": "2026-11-10T19:33:26.900074Z", + "generated_at": "2026-11-10T19:59:43.915872Z", "counts": { "skill": 25, "agent": 36, @@ -258,7 +258,7 @@ "id": "policyengine", "kind": "skill", "name": "policyengine", - "description": "ALWAYS load this skill before writing any Python that computes taxes, benefits, or policy\nimpacts with PolicyEngine \u2014 household calculations, microsimulation, reform scoring, poverty\nor distributional analysis, state/district/constituency breakdowns.\nTriggers: policyengine, microsimulation, calculate_household, reform impact, budgetary impact,\ncost of a policy, revenue estimate, poverty rate, child poverty, winners and losers, decile,\nGini, inequality, CTC, EITC, SNAP, income tax, universal credit, state-level analysis,\ncongressional district, constituency, Microcosm dataset, MicroSeries, ensure_datasets,\neconomic_impact_analysis, managed_microsimulation.\nNOT for: implementing new variables/parameters inside country models (use\npolicyengine-model-development) or calling the REST API from JS (use policyengine-api).", + "description": "ALWAYS load this skill before writing any Python that computes taxes, benefits, or policy\nimpacts with PolicyEngine \u2014 household calculations, microsimulation, reform scoring, poverty\nor distributional analysis, state/district/constituency breakdowns.\nTriggers: policyengine, microsimulation, calculate_household, reform impact, budgetary impact,\ncost of a policy, revenue estimate, poverty rate, child poverty, winners and losers, decile,\nGini, inequality, CTC, EITC, SNAP, income tax, universal credit, state-level analysis,\ncongressional district, constituency, Microcosm dataset, MicroSeries, ensure_datasets,\neconomic_impact_analysis, managed_microsimulation.\nNOT for: implementing new variables/parameters inside country models (use\npolicyengine-model-development) or calling the REST API from a page or server (use\npolicyengine-api-access).", "category": "analysis", "path": "skills/policyengine/SKILL.md", "tools": [], @@ -303,7 +303,7 @@ "id": "policyengine-api", "kind": "skill", "name": "policyengine-api", - "description": "Load when consuming or developing the PolicyEngine REST APIs \u2014 the v1 Flask API at\napi.policyengine.org (production today) or the v2 alpha microservices in policyengine-api-v2.\nCovers the v1 endpoint surface (household calc, economy-over-baseline polling), the v2\narchitecture (three services, uv/Docker/Cloud Run, OpenAPI client-gen), and when to use REST\nvs the Python package.\nTriggers: PolicyEngine API, api.policyengine.org, REST endpoint, household calculate, economy\nover baseline, v2 API, api-full, api-simulation, api-tagger, OpenAPI client, v2.api.policyengine.org.\nNOT for: Python analysis (use the policyengine skill) or calling the API from the app\nfrontend (policyengine-app).", + "description": "Load when developing the PolicyEngine REST APIs or writing server code against them \u2014 the v1\nFlask API at api.policyengine.org (the Public API, production today, callable only with a\nserver credential) or the v2 alpha microservices in policyengine-api-v2. Covers the v1\nendpoint surface (household calc, economy-over-baseline polling), the v2 architecture (three\nservices, uv/Docker/Cloud Run, OpenAPI client-gen), and when to use REST vs the Python package.\nTriggers: PolicyEngine API, api.policyengine.org, REST endpoint, household calculate, economy\nover baseline, v2 API, api-full, api-simulation, api-tagger, OpenAPI client, v2.api.policyengine.org.\nNOT for: Python analysis (use the policyengine skill), or reaching the API from a dashboard\npage or your own server (policyengine-api-access).", "category": "apps", "path": "skills/policyengine-api/SKILL.md", "tools": [], @@ -339,7 +339,7 @@ "use_instead": [], "registry_notes": "Recommended for the listed scope.", "references": {}, - "body_length": 4633 + "body_length": 5237 }, { "id": "policyengine-api-access", @@ -376,7 +376,7 @@ "use_instead": [], "registry_notes": "Recommended for the listed scope.", "references": {}, - "body_length": 17338 + "body_length": 18550 }, { "id": "policyengine-app", @@ -420,7 +420,7 @@ ], "registry_notes": "A newer artifact explicitly supersedes this one. Prefer the replacement.", "references": {}, - "body_length": 6445 + "body_length": 7734 }, { "id": "policyengine-calibration-diagnostics", @@ -1038,7 +1038,7 @@ "id": "policyengine-tools", "kind": "skill", "name": "policyengine-tools", - "description": "Load when building a standalone PolicyEngine interactive tool, calculator, or dashboard\nthat deploys to Vercel and embeds into policyengine.org as a Next.js multizone.\nCovers the required stack (Next App Router + Tailwind v4 + @policyengine/ui-kit + bun),\nmultizone zone config (basePath/assetPrefix, host rewrites, apps.json), Modal backends\n(gateway + worker + polling), chart patterns, and the dual-mode SEO strategy.\nTriggers: new tool, standalone calculator, dashboard, embed in policyengine.org, multizone,\nbasePath, assetPrefix, appZoneRoutes, Modal backend, scale to zero, vercel --scope\npolicy-engine, ui-kit theme.css, recharts colors.\nNOT for: developing policyengine.org itself (use policyengine-app) or token values\n(policyengine-design).", + "description": "Load when building a standalone PolicyEngine interactive tool, calculator, or dashboard\nthat deploys to Vercel and embeds into policyengine.org as a Next.js multizone.\nCovers the required stack (Next App Router + Tailwind v4 + @policyengine/ui-kit + bun),\nmultizone zone config (basePath/assetPrefix, host rewrites, apps.json), Modal backends\n(gateway + worker + polling), chart patterns, and the dual-mode SEO strategy.\nTriggers: new tool, standalone calculator, dashboard, embed in policyengine.org, multizone,\nbasePath, assetPrefix, appZoneRoutes, Modal backend, scale to zero, vercel --scope\npolicy-engine, ui-kit theme.css, recharts colors.\nNOT for: developing policyengine.org itself (use policyengine-app), token values\n(policyengine-design), or how a page or backend reaches api.policyengine.org\n(policyengine-api-access).", "category": "apps", "path": "skills/policyengine-tools/SKILL.md", "tools": [], @@ -1051,6 +1051,7 @@ ], "target_repos": [ "policyengine-app-v2", + "policyengine-api", "policyengine-app", "policyengine.py", "marriage", @@ -1080,7 +1081,7 @@ "use_instead": [], "registry_notes": "Recommended for the listed scope.", "references": {}, - "body_length": 14583 + "body_length": 15548 }, { "id": "policyengine-uk", @@ -2178,6 +2179,7 @@ "references": { "skill": [ "policyengine-api", + "policyengine-api-access", "policyengine-cloud-costs", "policyengine-tools", "policyengine-uk", @@ -2187,7 +2189,7 @@ "deploy-dashboard" ] }, - "body_length": 22032 + "body_length": 23735 }, { "id": "dashboard-architecture-validator", @@ -2333,11 +2335,12 @@ ], "skill": [ "policyengine-api", + "policyengine-api-access", "policyengine-design", "policyengine-tools" ] }, - "body_length": 6350 + "body_length": 6906 }, { "id": "dashboard-plan-validator", @@ -2434,6 +2437,7 @@ ], "skill": [ "policyengine-api", + "policyengine-api-access", "policyengine-app", "policyengine-cloud-costs", "policyengine-design", @@ -2446,7 +2450,7 @@ "analyze-policy" ] }, - "body_length": 24586 + "body_length": 24997 }, { "id": "dashboard-scaffold", @@ -2492,8 +2496,12 @@ "use_instead": [], "registry_notes": "Agents are usually implementation details of commands; call directly only when maintaining or debugging the workflow.", "references": { + "agent": [ + "backend-builder" + ], "skill": [ "policyengine-api", + "policyengine-api-access", "policyengine-app", "policyengine-cloud-costs", "policyengine-design", @@ -2504,7 +2512,7 @@ "deploy-dashboard" ] }, - "body_length": 25960 + "body_length": 26473 }, { "id": "frontend-builder", @@ -3846,11 +3854,8 @@ "complete" ], "target_repos": [ - "policyengine-api-v2", "policyengine-api", "marriage", - "policyengine-us", - "policyengine-uk", "policyengine-app" ], "functional_role": "workflow:new-tool", @@ -3869,6 +3874,7 @@ "references": { "skill": [ "policyengine-api", + "policyengine-api-access", "policyengine-app", "policyengine-cloud-costs", "policyengine-design", @@ -3879,7 +3885,7 @@ "new-tool" ] }, - "body_length": 15206 + "body_length": 16117 }, { "id": "prior-analysis", @@ -5002,6 +5008,12 @@ "target_kind": "skill", "target": "policyengine-api" }, + { + "source_kind": "command", + "source": "new-tool", + "target_kind": "skill", + "target": "policyengine-api-access" + }, { "source_kind": "command", "source": "new-tool", @@ -5170,6 +5182,12 @@ "target_kind": "skill", "target": "policyengine-api" }, + { + "source_kind": "agent", + "source": "backend-builder", + "target_kind": "skill", + "target": "policyengine-api-access" + }, { "source_kind": "agent", "source": "backend-builder", @@ -5296,6 +5314,12 @@ "target_kind": "skill", "target": "policyengine-api" }, + { + "source_kind": "agent", + "source": "dashboard-integrator", + "target_kind": "skill", + "target": "policyengine-api-access" + }, { "source_kind": "agent", "source": "dashboard-integrator", @@ -5338,6 +5362,12 @@ "target_kind": "skill", "target": "policyengine-api" }, + { + "source_kind": "agent", + "source": "dashboard-planner", + "target_kind": "skill", + "target": "policyengine-api-access" + }, { "source_kind": "agent", "source": "dashboard-planner", @@ -5380,12 +5410,24 @@ "target_kind": "skill", "target": "policyengine-writing" }, + { + "source_kind": "agent", + "source": "dashboard-scaffold", + "target_kind": "agent", + "target": "backend-builder" + }, { "source_kind": "agent", "source": "dashboard-scaffold", "target_kind": "skill", "target": "policyengine-api" }, + { + "source_kind": "agent", + "source": "dashboard-scaffold", + "target_kind": "skill", + "target": "policyengine-api-access" + }, { "source_kind": "agent", "source": "dashboard-scaffold", @@ -7323,7 +7365,7 @@ "kind": "command", "id": "implement-structural" }, - "score": 0.6532, + "score": 0.649, "shared_terms": [ "structural", "backlog", @@ -7344,7 +7386,7 @@ "kind": "command", "id": "generate-content" }, - "score": 0.6297, + "score": 0.6296, "shared_terms": [ "social", "content", @@ -7365,7 +7407,7 @@ "kind": "command", "id": "generate-content" }, - "score": 0.6284, + "score": 0.6283, "shared_terms": [ "social", "content", @@ -7377,6 +7419,27 @@ "blog" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-api" + }, + "b": { + "kind": "skill", + "id": "policyengine-api-access" + }, + "score": 0.6197, + "shared_terms": [ + "api", + "client", + "public", + "server", + "household", + "org", + "credential", + "country" + ] + }, { "a": { "kind": "agent", @@ -7386,7 +7449,7 @@ "kind": "agent", "id": "review-worker" }, - "score": 0.6218, + "score": 0.6191, "shared_terms": [ "your", "assigned", @@ -7407,7 +7470,7 @@ "kind": "skill", "id": "policyengine-uk" }, - "score": 0.6014, + "score": 0.6021, "shared_terms": [ "household", "unit", @@ -7428,7 +7491,7 @@ "kind": "command", "id": "prior-scores" }, - "score": 0.5998, + "score": 0.6004, "shared_terms": [ "scorekeepers", "scores", @@ -7449,7 +7512,7 @@ "kind": "skill", "id": "review-program" }, - "score": 0.588, + "score": 0.5874, "shared_terms": [ "review", "canonical", @@ -7470,14 +7533,14 @@ "kind": "command", "id": "audit-multizone" }, - "score": 0.5818, + "score": 0.5812, "shared_terms": [ "zone", "path", "host", "next", - "config", "repo", + "config", "app", "basepath" ] @@ -7491,7 +7554,7 @@ "kind": "skill", "id": "policyengine-us" }, - "score": 0.5678, + "score": 0.5675, "shared_terms": [ "unit", "tax", @@ -7512,7 +7575,7 @@ "kind": "skill", "id": "review-program" }, - "score": 0.5658, + "score": 0.5661, "shared_terms": [ "review", "canonical", @@ -7533,7 +7596,7 @@ "kind": "agent", "id": "content-orchestrator" }, - "score": 0.5389, + "score": 0.5391, "shared_terms": [ "social", "content", @@ -7554,7 +7617,7 @@ "kind": "skill", "id": "policyengine-us" }, - "score": 0.5301, + "score": 0.5311, "shared_terms": [ "unit", "tax", @@ -7575,7 +7638,7 @@ "kind": "skill", "id": "fix-pr" }, - "score": 0.5007, + "score": 0.5006, "shared_terms": [ "review", "claude", @@ -7587,6 +7650,27 @@ "references" ] }, + { + "a": { + "kind": "agent", + "id": "backend-builder" + }, + "b": { + "kind": "agent", + "id": "dashboard-scaffold" + }, + "score": 0.4933, + "shared_terms": [ + "api", + "plan", + "dashboard", + "custom", + "backend", + "modal", + "data", + "pattern" + ] + }, { "a": { "kind": "skill", @@ -7596,7 +7680,7 @@ "kind": "agent", "id": "calibration-diagnostics" }, - "score": 0.4919, + "score": 0.492, "shared_terms": [ "calibration", "signature", @@ -7617,7 +7701,7 @@ "kind": "agent", "id": "review-worker" }, - "score": 0.4813, + "score": 0.4804, "shared_terms": [ "review", "canonical", @@ -7629,6 +7713,27 @@ "source" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-app" + }, + "b": { + "kind": "skill", + "id": "policyengine-tools" + }, + "score": 0.4755, + "shared_terms": [ + "app", + "next", + "bun", + "vite", + "host", + "multizone", + "router", + "vercel" + ] + }, { "a": { "kind": "skill", @@ -7638,7 +7743,7 @@ "kind": "agent", "id": "prior-scores-finder" }, - "score": 0.4751, + "score": 0.4755, "shared_terms": [ "prior", "tier", @@ -7650,27 +7755,6 @@ "external" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-app" - }, - "b": { - "kind": "skill", - "id": "policyengine-tools" - }, - "score": 0.4671, - "shared_terms": [ - "app", - "next", - "bun", - "host", - "multizone", - "vite", - "router", - "vercel" - ] - }, { "a": { "kind": "agent", @@ -7680,7 +7764,7 @@ "kind": "agent", "id": "test-creator" }, - "score": 0.4616, + "score": 0.4657, "shared_terms": [ "test", "tests", @@ -7701,7 +7785,7 @@ "kind": "command", "id": "create-new-component" }, - "score": 0.4601, + "score": 0.4603, "shared_terms": [ "component", "kit", @@ -7722,7 +7806,7 @@ "kind": "agent", "id": "dashboard-plan-validator" }, - "score": 0.4598, + "score": 0.4594, "shared_terms": [ "grep", "components", @@ -7734,27 +7818,6 @@ "component" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-api" - }, - "b": { - "kind": "skill", - "id": "policyengine-api-access" - }, - "score": 0.4467, - "shared_terms": [ - "api", - "client", - "household", - "org", - "country", - "economy", - "get", - "public" - ] - }, { "a": { "kind": "agent", @@ -7764,7 +7827,7 @@ "kind": "agent", "id": "reform-classifier" }, - "score": 0.4459, + "score": 0.4471, "shared_terms": [ "parameter", "gov", @@ -7776,6 +7839,27 @@ "credits" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-tools" + }, + "b": { + "kind": "agent", + "id": "dashboard-architecture-validator" + }, + "score": 0.4283, + "shared_terms": [ + "app", + "postcss", + "css", + "config", + "kit", + "tailwind", + "tailwindcss", + "backend" + ] + }, { "a": { "kind": "agent", @@ -7783,39 +7867,39 @@ }, "b": { "kind": "agent", - "id": "dashboard-scaffold" + "id": "dashboard-integrator" }, - "score": 0.4402, + "score": 0.4263, "shared_terms": [ - "plan", - "custom", - "dashboard", + "api", "data", - "modal", + "backend", + "client", "pattern", - "api", - "backend" + "step", + "dashboard", + "builder" ] }, { "a": { "kind": "skill", - "id": "policyengine-tools" + "id": "policyengine-api-access" }, "b": { "kind": "agent", - "id": "dashboard-architecture-validator" + "id": "dashboard-integrator" }, - "score": 0.425, + "score": 0.4203, "shared_terms": [ - "app", - "postcss", - "css", - "config", - "kit", - "tailwind", - "tailwindcss", - "next" + "api", + "client", + "household", + "dashboard", + "backend", + "const", + "request", + "result" ] }, { @@ -7827,7 +7911,7 @@ "kind": "agent", "id": "dashboard-design-validator" }, - "score": 0.4118, + "score": 0.4126, "shared_terms": [ "grep", "app", @@ -7848,7 +7932,7 @@ "kind": "agent", "id": "multizone-validator" }, - "score": 0.4099, + "score": 0.4041, "shared_terms": [ "zone", "basepath", @@ -7869,7 +7953,7 @@ "kind": "command", "id": "create-pr" }, - "score": 0.4028, + "score": 0.4029, "shared_terms": [ "echo", "wait", @@ -7881,27 +7965,6 @@ "completed" ] }, - { - "a": { - "kind": "agent", - "id": "backend-builder" - }, - "b": { - "kind": "agent", - "id": "dashboard-integrator" - }, - "score": 0.4017, - "shared_terms": [ - "api", - "data", - "client", - "backend", - "step", - "types", - "hooks", - "pattern" - ] - }, { "a": { "kind": "agent", @@ -7911,7 +7974,7 @@ "kind": "command", "id": "prior-scores" }, - "score": 0.4001, + "score": 0.4011, "shared_terms": [ "tier", "prior", @@ -7932,7 +7995,7 @@ "kind": "command", "id": "prior-analysis" }, - "score": 0.397, + "score": 0.3971, "shared_terms": [ "analyses", "prior", @@ -7953,7 +8016,7 @@ "kind": "command", "id": "write-tests" }, - "score": 0.3853, + "score": 0.3925, "shared_terms": [ "test", "tests", @@ -7961,8 +8024,8 @@ "step", "cases", "file", - "cover", - "unit" + "unit", + "cover" ] }, { @@ -7974,7 +8037,7 @@ "kind": "agent", "id": "frontend-builder" }, - "score": 0.3833, + "score": 0.3834, "shared_terms": [ "kit", "chart", @@ -7995,7 +8058,7 @@ "kind": "command", "id": "write-tests" }, - "score": 0.3743, + "score": 0.3817, "shared_terms": [ "test", "tests", @@ -8009,56 +8072,56 @@ }, { "a": { - "kind": "agent", - "id": "reform-classifier" + "kind": "skill", + "id": "policyengine-api" }, "b": { - "kind": "command", - "id": "text-to-reform" + "kind": "agent", + "id": "dashboard-integrator" }, - "score": 0.3714, + "score": 0.3787, "shared_terms": [ - "reform", - "provision", - "deployed", - "structural", - "possible", - "parametric", - "parameter", - "microsim" + "api", + "client", + "household", + "data", + "values", + "response", + "dashboard", + "request" ] }, { "a": { - "kind": "agent", - "id": "rules-engineer" + "kind": "skill", + "id": "policyengine-api-access" }, "b": { "kind": "agent", - "id": "reference-validator" + "id": "backend-builder" }, - "score": 0.3683, + "score": 0.3768, "shared_terms": [ - "href", - "page", - "title", - "section", - "pdf", - "manual", - "yaml", - "field" - ] - }, - { - "a": { - "kind": "agent", + "api", + "client", + "dashboard", + "public", + "backend", + "modal", + "json", + "server" + ] + }, + { + "a": { + "kind": "agent", "id": "edge-case-generator" }, "b": { "kind": "command", "id": "write-tests" }, - "score": 0.368, + "score": 0.3734, "shared_terms": [ "test", "tests", @@ -8070,6 +8133,27 @@ "write" ] }, + { + "a": { + "kind": "agent", + "id": "reform-classifier" + }, + "b": { + "kind": "command", + "id": "text-to-reform" + }, + "score": 0.3701, + "shared_terms": [ + "reform", + "provision", + "deployed", + "structural", + "possible", + "parametric", + "parameter", + "microsim" + ] + }, { "a": { "kind": "skill", @@ -8079,7 +8163,7 @@ "kind": "command", "id": "household-calc" }, - "score": 0.3646, + "score": 0.3661, "shared_terms": [ "household", "income", @@ -8094,22 +8178,22 @@ { "a": { "kind": "agent", - "id": "dashboard-planner" + "id": "rules-engineer" }, "b": { - "kind": "command", - "id": "create-dashboard" + "kind": "agent", + "id": "reference-validator" }, - "score": 0.3634, + "score": 0.3653, "shared_terms": [ - "dashboard", - "planner", - "reform", - "plan", + "href", "page", - "validation", - "tabs", - "natural" + "title", + "section", + "pdf", + "manual", + "yaml", + "reference" ] }, { @@ -8121,7 +8205,7 @@ "kind": "agent", "id": "review-worker" }, - "score": 0.3614, + "score": 0.3612, "shared_terms": [ "review", "canonical", @@ -8133,27 +8217,6 @@ "independent" ] }, - { - "a": { - "kind": "agent", - "id": "policy-text-researcher" - }, - "b": { - "kind": "command", - "id": "text-to-reform" - }, - "score": 0.3542, - "shared_terms": [ - "bill", - "reform", - "ages", - "description", - "text", - "federal", - "natural", - "arpa" - ] - }, { "a": { "kind": "agent", @@ -8163,7 +8226,7 @@ "kind": "agent", "id": "frontend-builder" }, - "score": 0.3534, + "score": 0.3539, "shared_terms": [ "kit", "components", @@ -8175,6 +8238,27 @@ "css" ] }, + { + "a": { + "kind": "agent", + "id": "policy-text-researcher" + }, + "b": { + "kind": "command", + "id": "text-to-reform" + }, + "score": 0.3539, + "shared_terms": [ + "bill", + "reform", + "ages", + "description", + "text", + "federal", + "natural", + "arpa" + ] + }, { "a": { "kind": "skill", @@ -8184,7 +8268,7 @@ "kind": "agent", "id": "model-worker" }, - "score": 0.3514, + "score": 0.3522, "shared_terms": [ "encode", "coordinator", @@ -8196,6 +8280,27 @@ "own" ] }, + { + "a": { + "kind": "agent", + "id": "dashboard-planner" + }, + "b": { + "kind": "command", + "id": "create-dashboard" + }, + "score": 0.3501, + "shared_terms": [ + "dashboard", + "planner", + "plan", + "reform", + "tabs", + "page", + "natural", + "plans" + ] + }, { "a": { "kind": "agent", @@ -8205,14 +8310,14 @@ "kind": "command", "id": "create-new-component" }, - "score": 0.3492, + "score": 0.3491, "shared_terms": [ "components", "kit", "grep", "tsx", - "design", "app", + "design", "component", "include" ] @@ -8226,7 +8331,7 @@ "kind": "skill", "id": "policyengine-user-guide" }, - "score": 0.3458, + "score": 0.3473, "shared_terms": [ "household", "income", @@ -8235,7 +8340,7 @@ "reform", "poverty", "people", - "employment" + "net" ] }, { @@ -8247,7 +8352,7 @@ "kind": "agent", "id": "implementation-validator" }, - "score": 0.3453, + "score": 0.346, "shared_terms": [ "root", "fix", @@ -8268,7 +8373,7 @@ "kind": "agent", "id": "reform-describer" }, - "score": 0.3453, + "score": 0.3456, "shared_terms": [ "parameter", "reform", @@ -8280,6 +8385,27 @@ "mechanical" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-tools" + }, + "b": { + "kind": "command", + "id": "new-tool" + }, + "score": 0.342, + "shared_terms": [ + "kit", + "css", + "app", + "tailwind", + "next", + "bun", + "calculator", + "dashboard" + ] + }, { "a": { "kind": "skill", @@ -8289,7 +8415,7 @@ "kind": "command", "id": "audit-multizone" }, - "score": 0.3437, + "score": 0.3411, "shared_terms": [ "zone", "next", @@ -8301,6 +8427,27 @@ "vercel" ] }, + { + "a": { + "kind": "agent", + "id": "backend-builder" + }, + "b": { + "kind": "command", + "id": "deploy-dashboard" + }, + "score": 0.3362, + "shared_terms": [ + "modal", + "dashboard", + "custom", + "pattern", + "precomputed", + "step", + "backend", + "data" + ] + }, { "a": { "kind": "skill", @@ -8310,7 +8457,7 @@ "kind": "agent", "id": "implementation-validator" }, - "score": 0.3348, + "score": 0.3351, "shared_terms": [ "fix", "review", @@ -8318,29 +8465,29 @@ "read", "role", "code", - "only", - "verification" + "verification", + "only" ] }, { "a": { "kind": "skill", - "id": "policyengine-api-access" + "id": "policyengine-user-guide" }, "b": { - "kind": "agent", - "id": "dashboard-integrator" + "kind": "command", + "id": "household-calc" }, - "score": 0.3331, + "score": 0.3323, "shared_terms": [ - "api", - "client", "household", - "backend", - "dashboard", - "const", - "request", - "function" + "reform", + "income", + "population", + "benefits", + "net", + "marginal", + "taxes" ] }, { @@ -8352,7 +8499,7 @@ "kind": "command", "id": "analyze-policy" }, - "score": 0.3325, + "score": 0.3321, "shared_terms": [ "year", "microsim", @@ -8364,48 +8511,6 @@ "horizon" ] }, - { - "a": { - "kind": "agent", - "id": "dashboard-plan-validator" - }, - "b": { - "kind": "agent", - "id": "dashboard-scaffold" - }, - "score": 0.331, - "shared_terms": [ - "plan", - "dashboard", - "tsx", - "components", - "yaml", - "embedding", - "api", - "zone" - ] - }, - { - "a": { - "kind": "skill", - "id": "policyengine-user-guide" - }, - "b": { - "kind": "command", - "id": "household-calc" - }, - "score": 0.3304, - "shared_terms": [ - "household", - "reform", - "income", - "population", - "benefits", - "marginal", - "net", - "taxes" - ] - }, { "a": { "kind": "agent", @@ -8415,7 +8520,7 @@ "kind": "command", "id": "create-new-component" }, - "score": 0.3302, + "score": 0.3301, "shared_terms": [ "component", "tsx", @@ -8436,7 +8541,7 @@ "kind": "command", "id": "encode-reform" }, - "score": 0.3296, + "score": 0.3295, "shared_terms": [ "bill", "reform", @@ -8450,23 +8555,44 @@ }, { "a": { - "kind": "skill", - "id": "policyengine-api-access" + "kind": "agent", + "id": "dashboard-planner" }, "b": { "kind": "agent", - "id": "backend-builder" + "id": "dashboard-scaffold" }, - "score": 0.3262, + "score": 0.3289, "shared_terms": [ + "dashboard", + "plan", "api", - "client", + "data", + "custom", + "design", + "step", + "costs" + ] + }, + { + "a": { + "kind": "agent", + "id": "dashboard-scaffold" + }, + "b": { + "kind": "command", + "id": "new-tool" + }, + "score": 0.3281, + "shared_terms": [ "dashboard", - "public", - "backend", - "modal", - "json", - "org" + "project", + "api", + "scaffold", + "kit", + "css", + "page", + "plan" ] }, { @@ -8478,7 +8604,7 @@ "kind": "command", "id": "deploy-dashboard" }, - "score": 0.326, + "score": 0.3263, "shared_terms": [ "host", "zone", @@ -8499,7 +8625,7 @@ "kind": "command", "id": "deploy-dashboard" }, - "score": 0.3253, + "score": 0.3252, "shared_terms": [ "modal", "host", @@ -8520,7 +8646,7 @@ "kind": "skill", "id": "policyengine-data" }, - "score": 0.3211, + "score": 0.3209, "shared_terms": [ "microcosm", "calibration", @@ -8534,14 +8660,56 @@ }, { "a": { - "kind": "command", - "id": "encode-reform" + "kind": "agent", + "id": "dashboard-plan-validator" }, "b": { - "kind": "command", + "kind": "agent", + "id": "dashboard-scaffold" + }, + "score": 0.3179, + "shared_terms": [ + "plan", + "dashboard", + "api", + "components", + "tsx", + "yaml", + "zone", + "embedding" + ] + }, + { + "a": { + "kind": "skill", + "id": "policyengine-healthcare" + }, + "b": { + "kind": "skill", + "id": "policyengine-us" + }, + "score": 0.3164, + "shared_terms": [ + "tax", + "unit", + "income", + "medicaid", + "household", + "aca", + "net", + "person" + ] + }, + { + "a": { + "kind": "command", + "id": "encode-reform" + }, + "b": { + "kind": "command", "id": "reform-pipeline" }, - "score": 0.3163, + "score": 0.3161, "shared_terms": [ "bill", "reform", @@ -8562,7 +8730,7 @@ "kind": "command", "id": "text-to-reform" }, - "score": 0.3155, + "score": 0.3156, "shared_terms": [ "bill", "reform", @@ -8574,27 +8742,6 @@ "description" ] }, - { - "a": { - "kind": "agent", - "id": "backend-builder" - }, - "b": { - "kind": "command", - "id": "deploy-dashboard" - }, - "score": 0.315, - "shared_terms": [ - "modal", - "dashboard", - "custom", - "pattern", - "precomputed", - "step", - "data", - "backend" - ] - }, { "a": { "kind": "agent", @@ -8604,7 +8751,7 @@ "kind": "agent", "id": "pr-pusher" }, - "score": 0.3139, + "score": 0.3138, "shared_terms": [ "repo", "branch", @@ -8612,50 +8759,29 @@ "head", "issue", "number", - "repository", - "base" - ] - }, - { - "a": { - "kind": "skill", - "id": "policyengine-healthcare" - }, - "b": { - "kind": "skill", - "id": "policyengine-us" - }, - "score": 0.3125, - "shared_terms": [ - "tax", - "unit", - "income", - "medicaid", - "household", - "aca", - "net", - "person" + "base", + "repository" ] }, { "a": { - "kind": "skill", - "id": "policyengine-design" + "kind": "agent", + "id": "dashboard-integrator" }, "b": { - "kind": "skill", - "id": "policyengine-tools" + "kind": "agent", + "id": "dashboard-scaffold" }, - "score": 0.3091, + "score": 0.3138, "shared_terms": [ - "css", - "theme", - "postcss", - "kit", - "tailwindcss", - "app", - "tailwind", - "chart" + "api", + "client", + "backend", + "dashboard", + "data", + "components", + "structure", + "pattern" ] }, { @@ -8667,7 +8793,7 @@ "kind": "command", "id": "deploy-dashboard" }, - "score": 0.3074, + "score": 0.3124, "shared_terms": [ "dashboard", "modal", @@ -8682,43 +8808,43 @@ { "a": { "kind": "skill", - "id": "policyengine-tools" + "id": "policyengine-model-development" }, "b": { - "kind": "command", - "id": "new-tool" + "kind": "agent", + "id": "test-creator" }, - "score": 0.3069, + "score": 0.3068, "shared_terms": [ - "kit", - "css", - "app", - "tailwind", - "next", - "bun", - "calculator", - "import" + "tests", + "test", + "variables", + "variable", + "period", + "periods", + "formula", + "year" ] }, { "a": { - "kind": "skill", - "id": "policyengine-us" + "kind": "agent", + "id": "backend-builder" }, "b": { "kind": "agent", - "id": "parameter-locator" + "id": "dashboard-planner" }, - "score": 0.3056, + "score": 0.3065, "shared_terms": [ - "tax", - "income", - "gov", - "state", - "filing", - "eitc", - "ctc", - "states" + "dashboard", + "data", + "api", + "plan", + "modal", + "custom", + "pattern", + "step" ] }, { @@ -8730,7 +8856,7 @@ "kind": "agent", "id": "reform-describer" }, - "score": 0.3049, + "score": 0.3065, "shared_terms": [ "provisions", "parameter", @@ -8745,22 +8871,43 @@ { "a": { "kind": "skill", - "id": "policyengine-model-development" + "id": "policyengine-us" }, "b": { "kind": "agent", - "id": "test-creator" + "id": "parameter-locator" }, - "score": 0.304, + "score": 0.3056, "shared_terms": [ - "tests", - "variable", - "test", - "variables", - "period", - "periods", - "formula", - "year" + "tax", + "income", + "gov", + "state", + "filing", + "eitc", + "ctc", + "states" + ] + }, + { + "a": { + "kind": "skill", + "id": "policyengine-design" + }, + "b": { + "kind": "skill", + "id": "policyengine-tools" + }, + "score": 0.3041, + "shared_terms": [ + "css", + "theme", + "postcss", + "kit", + "tailwindcss", + "app", + "tailwind", + "chart" ] }, { @@ -8772,7 +8919,7 @@ "kind": "agent", "id": "reform-describer" }, - "score": 0.3033, + "score": 0.3034, "shared_terms": [ "ctc", "provisions", @@ -8793,7 +8940,7 @@ "kind": "command", "id": "backdate-program" }, - "score": 0.3009, + "score": 0.3018, "shared_terms": [ "program", "worktree", @@ -8814,7 +8961,7 @@ "kind": "command", "id": "household-calc" }, - "score": 0.2974, + "score": 0.301, "shared_terms": [ "household", "income", @@ -8829,85 +8976,169 @@ { "a": { "kind": "skill", - "id": "fix-pr" + "id": "policyengine-api-access" }, "b": { "kind": "agent", - "id": "review-worker" + "id": "dashboard-scaffold" }, - "score": 0.2946, + "score": 0.2981, "shared_terms": [ - "review", - "canonical", - "role", - "delegation", - "workflow", - "assigned", - "code", - "read" + "api", + "dashboard", + "client", + "public", + "backend", + "org", + "page", + "modal" ] }, { "a": { - "kind": "agent", - "id": "parameter-locator" + "kind": "command", + "id": "create-dashboard" }, "b": { "kind": "command", - "id": "audit-state-tax" + "id": "new-tool" }, - "score": 0.2937, + "score": 0.2972, "shared_terms": [ - "state", - "tax", - "gov", - "income", - "states", - "parameter", - "phase", - "step" + "dashboard", + "create", + "page", + "calculator", + "multi", + "widget", + "purpose", + "scaffold" ] }, { "a": { "kind": "agent", - "id": "parameter-locator" + "id": "dashboard-scaffold" }, "b": { "kind": "command", - "id": "text-to-reform" + "id": "create-dashboard" }, - "score": 0.2924, + "score": 0.2968, "shared_terms": [ - "reform", - "dict", - "provision", - "deployed", - "parameter", - "master", + "dashboard", + "plan", + "page", + "scaffold", + "repo", "api", - "emits" + "init", + "directory" ] }, { "a": { - "kind": "agent", - "id": "dashboard-planner" - }, + "kind": "skill", + "id": "fix-pr" + }, "b": { "kind": "agent", - "id": "dashboard-scaffold" + "id": "review-worker" + }, + "score": 0.2956, + "shared_terms": [ + "review", + "canonical", + "role", + "delegation", + "workflow", + "assigned", + "code", + "read" + ] + }, + { + "a": { + "kind": "skill", + "id": "policyengine-app" + }, + "b": { + "kind": "command", + "id": "new-tool" + }, + "score": 0.2939, + "shared_terms": [ + "app", + "calculator", + "params", + "api", + "page", + "bun", + "kit", + "next" + ] + }, + { + "a": { + "kind": "agent", + "id": "parameter-locator" + }, + "b": { + "kind": "command", + "id": "audit-state-tax" + }, + "score": 0.2937, + "shared_terms": [ + "state", + "tax", + "gov", + "income", + "states", + "parameter", + "phase", + "step" + ] + }, + { + "a": { + "kind": "agent", + "id": "parameter-locator" + }, + "b": { + "kind": "command", + "id": "text-to-reform" + }, + "score": 0.2921, + "shared_terms": [ + "reform", + "dict", + "provision", + "deployed", + "parameter", + "master", + "api", + "emits" + ] + }, + { + "a": { + "kind": "skill", + "id": "policyengine-api" + }, + "b": { + "kind": "agent", + "id": "backend-builder" }, - "score": 0.2909, + "score": 0.2914, "shared_terms": [ + "api", + "client", "dashboard", - "plan", + "public", "data", - "custom", - "design", - "step", - "api", - "costs" + "json", + "simulation", + "cloud" ] }, { @@ -8919,7 +9150,7 @@ "kind": "skill", "id": "policyengine-design" }, - "score": 0.2908, + "score": 0.2906, "shared_terms": [ "theme", "teal", @@ -8940,7 +9171,7 @@ "kind": "agent", "id": "implementation-validator" }, - "score": 0.2898, + "score": 0.29, "shared_terms": [ "mode", "review", @@ -8948,8 +9179,8 @@ "read", "program", "only", - "audit", - "test" + "test", + "audit" ] }, { @@ -8961,7 +9192,7 @@ "kind": "command", "id": "audit-seo" }, - "score": 0.2896, + "score": 0.2898, "shared_terms": [ "audit", "zone", @@ -8982,7 +9213,7 @@ "kind": "agent", "id": "pr-pusher" }, - "score": 0.2882, + "score": 0.2881, "shared_terms": [ "changelog", "repo", @@ -8991,7 +9222,49 @@ "linting", "towncrier", "ruff", - "never" + "committing" + ] + }, + { + "a": { + "kind": "agent", + "id": "frontend-builder" + }, + "b": { + "kind": "command", + "id": "new-tool" + }, + "score": 0.2869, + "shared_terms": [ + "kit", + "app", + "tailwind", + "font", + "css", + "import", + "design", + "colors" + ] + }, + { + "a": { + "kind": "skill", + "id": "policyengine-app" + }, + "b": { + "kind": "agent", + "id": "dashboard-architecture-validator" + }, + "score": 0.2864, + "shared_terms": [ + "app", + "router", + "tailwindcss", + "vite", + "next", + "kit", + "tsx", + "bun" ] }, { @@ -9003,7 +9276,7 @@ "kind": "command", "id": "text-to-reform" }, - "score": 0.2867, + "score": 0.2856, "shared_terms": [ "reform", "dict", @@ -9024,7 +9297,7 @@ "kind": "command", "id": "prior-scores" }, - "score": 0.2857, + "score": 0.2845, "shared_terms": [ "shape", "external", @@ -9045,7 +9318,7 @@ "kind": "skill", "id": "policyengine-user-guide" }, - "score": 0.2819, + "score": 0.2841, "shared_terms": [ "household", "income", @@ -9066,7 +9339,7 @@ "kind": "agent", "id": "reform-comparator" }, - "score": 0.2816, + "score": 0.2815, "shared_terms": [ "prior", "year", @@ -9081,64 +9354,22 @@ { "a": { "kind": "skill", - "id": "policyengine-app" - }, - "b": { - "kind": "agent", - "id": "dashboard-architecture-validator" - }, - "score": 0.281, - "shared_terms": [ - "app", - "router", - "tailwindcss", - "vite", - "next", - "kit", - "tsx", - "bun" - ] - }, - { - "a": { - "kind": "agent", - "id": "dashboard-scaffold" + "id": "policyengine-canada" }, "b": { - "kind": "command", - "id": "create-dashboard" - }, - "score": 0.281, - "shared_terms": [ - "dashboard", - "plan", - "page", - "scaffold", - "repo", - "init", - "directory", - "create" - ] - }, - { - "a": { "kind": "skill", - "id": "policyengine-api" - }, - "b": { - "kind": "agent", - "id": "dashboard-integrator" + "id": "policyengine-uk" }, - "score": 0.2804, + "score": 0.2807, "shared_terms": [ - "api", "household", - "client", - "data", - "frontend", - "values", - "response", - "policyid" + "canada", + "income", + "credit", + "benefit", + "tax", + "poverty", + "net" ] }, { @@ -9150,7 +9381,7 @@ "kind": "agent", "id": "frontend-builder" }, - "score": 0.2804, + "score": 0.2798, "shared_terms": [ "kit", "app", @@ -9165,22 +9396,22 @@ { "a": { "kind": "skill", - "id": "policyengine-canada" + "id": "policyengine-design" }, "b": { - "kind": "skill", - "id": "policyengine-uk" + "kind": "command", + "id": "new-tool" }, - "score": 0.2792, + "score": 0.2786, "shared_terms": [ - "household", - "canada", - "income", - "credit", - "benefit", - "tax", - "poverty", - "net" + "css", + "theme", + "kit", + "var", + "font", + "import", + "tailwind", + "colors" ] }, { @@ -9192,7 +9423,7 @@ "kind": "command", "id": "text-to-reform" }, - "score": 0.2787, + "score": 0.2783, "shared_terms": [ "bill", "reform", @@ -9207,76 +9438,34 @@ { "a": { "kind": "agent", - "id": "reform-classifier" + "id": "ci-fixer" }, "b": { "kind": "command", - "id": "implement-structural" + "id": "backdate-program" }, - "score": 0.2782, + "score": 0.2758, "shared_terms": [ - "structural", - "backlog", - "reform", - "model", - "gov", - "deployed", - "formula", - "stop" + "worktree", + "root", + "files", + "prefix", + "program", + "git", + "read", + "run" ] }, { "a": { "kind": "agent", - "id": "backend-builder" + "id": "dashboard-architecture-validator" }, "b": { "kind": "agent", - "id": "dashboard-planner" + "id": "dashboard-plan-validator" }, - "score": 0.2777, - "shared_terms": [ - "data", - "dashboard", - "plan", - "api", - "modal", - "custom", - "pattern", - "step" - ] - }, - { - "a": { - "kind": "agent", - "id": "ci-fixer" - }, - "b": { - "kind": "command", - "id": "backdate-program" - }, - "score": 0.2756, - "shared_terms": [ - "worktree", - "root", - "files", - "prefix", - "program", - "git", - "read", - "run" - ] - }, - { - "a": { - "kind": "agent", - "id": "dashboard-architecture-validator" - }, - "b": { - "kind": "agent", - "id": "dashboard-plan-validator" - }, - "score": 0.2756, + "score": 0.2755, "shared_terms": [ "grep", "app", @@ -9288,27 +9477,6 @@ "node" ] }, - { - "a": { - "kind": "agent", - "id": "frontend-builder" - }, - "b": { - "kind": "command", - "id": "new-tool" - }, - "score": 0.2753, - "shared_terms": [ - "kit", - "tailwind", - "app", - "font", - "css", - "import", - "design", - "colors" - ] - }, { "a": { "kind": "agent", @@ -9318,7 +9486,7 @@ "kind": "command", "id": "reform-pipeline" }, - "score": 0.2748, + "score": 0.2744, "shared_terms": [ "bill", "reform", @@ -9333,22 +9501,22 @@ { "a": { "kind": "skill", - "id": "policyengine-app" + "id": "review-program" }, "b": { - "kind": "command", - "id": "new-tool" + "kind": "agent", + "id": "implementation-validator" }, - "score": 0.272, + "score": 0.2722, "shared_terms": [ - "app", - "calculator", - "params", - "countryid", - "bun", - "kit", - "next", - "page" + "review", + "root", + "program", + "read", + "prefix", + "pdf", + "only", + "code" ] }, { @@ -9360,7 +9528,7 @@ "kind": "agent", "id": "dashboard-architecture-validator" }, - "score": 0.2716, + "score": 0.2717, "shared_terms": [ "css", "postcss", @@ -9372,27 +9540,6 @@ "import" ] }, - { - "a": { - "kind": "skill", - "id": "review-program" - }, - "b": { - "kind": "agent", - "id": "implementation-validator" - }, - "score": 0.2715, - "shared_terms": [ - "review", - "root", - "program", - "read", - "prefix", - "pdf", - "only", - "code" - ] - }, { "a": { "kind": "agent", @@ -9402,7 +9549,7 @@ "kind": "agent", "id": "test-creator" }, - "score": 0.2697, + "score": 0.2716, "shared_terms": [ "test", "tests", @@ -9414,27 +9561,6 @@ "aggregation" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-design" - }, - "b": { - "kind": "command", - "id": "new-tool" - }, - "score": 0.2685, - "shared_terms": [ - "css", - "theme", - "kit", - "var", - "font", - "import", - "tailwind", - "colors" - ] - }, { "a": { "kind": "agent", @@ -9444,7 +9570,7 @@ "kind": "agent", "id": "reform-comparator" }, - "score": 0.2685, + "score": 0.2688, "shared_terms": [ "version", "result", @@ -9458,23 +9584,23 @@ }, { "a": { - "kind": "skill", - "id": "policyengine" + "kind": "agent", + "id": "reform-classifier" }, "b": { - "kind": "agent", - "id": "parameter-locator" + "kind": "command", + "id": "implement-structural" }, - "score": 0.268, + "score": 0.2684, "shared_terms": [ - "income", - "tax", - "state", - "ctc", + "structural", + "backlog", "reform", - "filing", - "household", - "model" + "model", + "gov", + "deployed", + "formula", + "stop" ] }, { @@ -9498,6 +9624,27 @@ "stage" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine" + }, + "b": { + "kind": "agent", + "id": "parameter-locator" + }, + "score": 0.2665, + "shared_terms": [ + "income", + "tax", + "state", + "ctc", + "reform", + "filing", + "household", + "model" + ] + }, { "a": { "kind": "agent", @@ -9507,7 +9654,7 @@ "kind": "command", "id": "text-to-reform" }, - "score": 0.2655, + "score": 0.2657, "shared_terms": [ "reform", "dict", @@ -9521,23 +9668,23 @@ }, { "a": { - "kind": "agent", - "id": "ci-fixer" + "kind": "skill", + "id": "policyengine-app" }, "b": { "kind": "agent", - "id": "pr-pusher" + "id": "frontend-builder" }, - "score": 0.2607, + "score": 0.2638, "shared_terms": [ - "caller", - "git", - "files", - "formatting", - "fix", - "run", - "sources", - "commit" + "app", + "kit", + "design", + "component", + "react", + "frontend", + "tokens", + "next" ] }, { @@ -9549,7 +9696,7 @@ "kind": "command", "id": "household-calc" }, - "score": 0.2606, + "score": 0.2634, "shared_terms": [ "household", "tax", @@ -9570,7 +9717,7 @@ "kind": "command", "id": "create-pr" }, - "score": 0.2605, + "score": 0.2618, "shared_terms": [ "branch", "number", @@ -9582,6 +9729,27 @@ "head" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-api-access" + }, + "b": { + "kind": "command", + "id": "new-tool" + }, + "score": 0.2615, + "shared_terms": [ + "api", + "dashboard", + "public", + "client", + "const", + "page", + "app", + "org" + ] + }, { "a": { "kind": "agent", @@ -9591,11 +9759,11 @@ "kind": "command", "id": "write-tests" }, - "score": 0.2598, + "score": 0.2615, "shared_terms": [ "test", - "files", "tests", + "files", "run", "file", "fix", @@ -9605,23 +9773,23 @@ }, { "a": { - "kind": "skill", - "id": "policyengine-app" + "kind": "agent", + "id": "ci-fixer" }, "b": { "kind": "agent", - "id": "frontend-builder" + "id": "pr-pusher" }, - "score": 0.2589, + "score": 0.2607, "shared_terms": [ - "app", - "kit", - "design", - "component", - "react", - "tokens", - "frontend", - "next" + "caller", + "git", + "files", + "formatting", + "fix", + "run", + "sources", + "commit" ] }, { @@ -9633,7 +9801,7 @@ "kind": "agent", "id": "frontend-builder" }, - "score": 0.2587, + "score": 0.2598, "shared_terms": [ "app", "kit", @@ -9647,65 +9815,86 @@ }, { "a": { - "kind": "command", - "id": "prior-scores" + "kind": "skill", + "id": "policyengine-prior-scores" }, "b": { - "kind": "command", - "id": "text-to-reform" + "kind": "agent", + "id": "model-corroborator" }, - "score": 0.2585, + "score": 0.2591, "shared_terms": [ "reform", - "scorekeepers", - "microsim", - "analyze", - "presets", - "bill", - "consult", - "runs" + "external", + "scores", + "published", + "scored", + "benchmark", + "shape", + "stage" ] }, { "a": { + "kind": "skill", + "id": "policyengine-tools" + }, + "b": { "kind": "agent", "id": "dashboard-scaffold" }, - "b": { - "kind": "command", - "id": "new-tool" - }, - "score": 0.2582, + "score": 0.2581, "shared_terms": [ - "project", "dashboard", - "scaffold", + "api", "kit", "css", - "plan", - "page", - "import" + "basepath", + "backend", + "next", + "modal" ] }, { "a": { - "kind": "skill", - "id": "policyengine-prior-scores" + "kind": "command", + "id": "prior-scores" }, "b": { - "kind": "agent", - "id": "model-corroborator" + "kind": "command", + "id": "text-to-reform" }, - "score": 0.2579, + "score": 0.258, "shared_terms": [ "reform", - "scores", - "external", - "published", - "scored", - "shape", - "benchmark", - "stage" + "scorekeepers", + "microsim", + "analyze", + "presets", + "bill", + "consult", + "runs" + ] + }, + { + "a": { + "kind": "agent", + "id": "report-logger" + }, + "b": { + "kind": "command", + "id": "analyze-policy" + }, + "score": 0.2565, + "shared_terms": [ + "log", + "archive", + "auto", + "analyst", + "country", + "prompt", + "data", + "default" ] }, { @@ -9731,23 +9920,23 @@ }, { "a": { - "kind": "agent", - "id": "report-logger" + "kind": "skill", + "id": "policyengine-app" }, "b": { "kind": "command", - "id": "analyze-policy" + "id": "create-new-component" }, - "score": 0.2559, + "score": 0.2562, "shared_terms": [ - "log", - "archive", - "auto", - "analyst", - "country", - "prompt", - "data", - "default" + "app", + "component", + "src", + "design", + "kit", + "tsx", + "react", + "website" ] }, { @@ -9759,7 +9948,7 @@ "kind": "agent", "id": "frontend-builder" }, - "score": 0.2555, + "score": 0.2553, "shared_terms": [ "component", "plan", @@ -9771,6 +9960,27 @@ "embedding" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-prior-scores" + }, + "b": { + "kind": "command", + "id": "text-to-reform" + }, + "score": 0.2547, + "shared_terms": [ + "reform", + "preset", + "presets", + "scorekeepers", + "scores", + "prior", + "dict", + "microsim" + ] + }, { "a": { "kind": "command", @@ -9780,58 +9990,37 @@ "kind": "command", "id": "encode-reform" }, - "score": 0.2552, + "score": 0.2542, "shared_terms": [ "prefix", "arguments", "short", "orchestrator", "files", - "page", "agents", + "page", "review" ] }, - { - "a": { - "kind": "agent", - "id": "dashboard-scaffold" - }, - "b": { - "kind": "agent", - "id": "frontend-builder" - }, - "score": 0.2549, - "shared_terms": [ - "plan", - "kit", - "design", - "components", - "css", - "app", - "component", - "tsx" - ] - }, { "a": { "kind": "skill", - "id": "policyengine-prior-scores" + "id": "review-program" }, "b": { "kind": "command", - "id": "text-to-reform" + "id": "backdate-program" }, - "score": 0.2548, + "score": 0.2535, "shared_terms": [ - "reform", - "preset", - "presets", - "scorekeepers", - "scores", - "prior", - "dict", - "microsim" + "review", + "program", + "root", + "prefix", + "pdf", + "read", + "workflow", + "phase" ] }, { @@ -9843,37 +10032,37 @@ "kind": "agent", "id": "implementation-validator" }, - "score": 0.254, + "score": 0.253, "shared_terms": [ "review", "fix", "program", "encode", - "structural", "read", + "structural", "mode", "worktree" ] }, { "a": { - "kind": "skill", - "id": "review-program" + "kind": "agent", + "id": "dashboard-scaffold" }, "b": { - "kind": "command", - "id": "backdate-program" + "kind": "agent", + "id": "frontend-builder" }, - "score": 0.2531, + "score": 0.2527, "shared_terms": [ - "review", - "program", - "root", - "prefix", - "pdf", - "read", - "workflow", - "phase" + "kit", + "plan", + "design", + "components", + "app", + "css", + "component", + "api" ] }, { @@ -9885,58 +10074,37 @@ "kind": "agent", "id": "model-worker" }, - "score": 0.2528, + "score": 0.2511, "shared_terms": [ "canonical", "delegation", "coordinator", "work", "role", - "own", "model", + "own", "root" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-app" - }, - "b": { - "kind": "command", - "id": "create-new-component" - }, - "score": 0.2525, - "shared_terms": [ - "app", - "component", - "design", - "src", - "kit", - "tsx", - "react", - "website" - ] - }, { "a": { "kind": "agent", - "id": "dashboard-architecture-validator" + "id": "model-corroborator" }, "b": { "kind": "agent", - "id": "dashboard-scaffold" + "id": "reform-comparator" }, - "score": 0.2518, + "score": 0.2492, "shared_terms": [ - "css", - "backend", - "config", - "custom", - "modal", - "tsx", - "app", - "dashboard" + "our", + "microsim", + "comparator", + "baseline", + "result", + "reform", + "scores", + "anchor" ] }, { @@ -9948,7 +10116,7 @@ "kind": "command", "id": "prior-analysis" }, - "score": 0.2493, + "score": 0.2486, "shared_terms": [ "archive", "analyses", @@ -9957,28 +10125,7 @@ "local", "country", "analysis", - "jurisdiction" - ] - }, - { - "a": { - "kind": "agent", - "id": "model-corroborator" - }, - "b": { - "kind": "agent", - "id": "reform-comparator" - }, - "score": 0.2484, - "shared_terms": [ - "our", - "microsim", - "comparator", - "baseline", - "result", - "reform", - "scores", - "anchor" + "repo" ] }, { @@ -9990,7 +10137,7 @@ "kind": "command", "id": "prior-analysis" }, - "score": 0.2476, + "score": 0.2475, "shared_terms": [ "prior", "scripts", @@ -10002,27 +10149,6 @@ "score" ] }, - { - "a": { - "kind": "command", - "id": "create-dashboard" - }, - "b": { - "kind": "command", - "id": "new-tool" - }, - "score": 0.2474, - "shared_terms": [ - "dashboard", - "create", - "page", - "calculator", - "multi", - "widget", - "purpose", - "scaffold" - ] - }, { "a": { "kind": "agent", @@ -10032,37 +10158,37 @@ "kind": "command", "id": "create-pr" }, - "score": 0.2456, + "score": 0.2461, "shared_terms": [ "branch", "git", "draft", - "commit", "number", - "head", + "commit", "create", + "head", "changelog" ] }, { "a": { "kind": "agent", - "id": "backend-builder" + "id": "dashboard-architecture-validator" }, "b": { - "kind": "agent", - "id": "dashboard-plan-validator" - }, - "score": 0.2455, + "kind": "command", + "id": "new-tool" + }, + "score": 0.2456, "shared_terms": [ - "plan", - "api", - "data", - "dashboard", - "lib", - "yaml", - "types", - "test" + "css", + "app", + "tailwind", + "kit", + "import", + "bash", + "globals", + "dashboard" ] }, { @@ -10074,7 +10200,7 @@ "kind": "agent", "id": "test-creator" }, - "score": 0.2433, + "score": 0.2452, "shared_terms": [ "tests", "test", @@ -10086,46 +10212,25 @@ "development" ] }, - { - "a": { - "kind": "agent", - "id": "reference-validator" - }, - "b": { - "kind": "command", - "id": "audit-state-tax" - }, - "score": 0.2411, - "shared_terms": [ - "pdf", - "reference", - "source", - "number", - "full", - "page", - "parameter", - "audit" - ] - }, { "a": { "kind": "skill", - "id": "policyengine-tools" + "id": "policyengine-api-access" }, "b": { - "kind": "agent", - "id": "dashboard-scaffold" + "kind": "skill", + "id": "policyengine-app" }, - "score": 0.241, + "score": 0.243, "shared_terms": [ - "kit", - "dashboard", - "css", - "config", - "basepath", - "next", - "modal", - "app" + "api", + "app", + "server", + "vite", + "client", + "page", + "org", + "next" ] }, { @@ -10137,7 +10242,7 @@ "kind": "command", "id": "audit-multizone" }, - "score": 0.2401, + "score": 0.242, "shared_terms": [ "app", "host", @@ -10149,6 +10254,27 @@ "vercel" ] }, + { + "a": { + "kind": "agent", + "id": "reference-validator" + }, + "b": { + "kind": "command", + "id": "audit-state-tax" + }, + "score": 0.2412, + "shared_terms": [ + "pdf", + "reference", + "source", + "number", + "full", + "page", + "parameter", + "audit" + ] + }, { "a": { "kind": "agent", @@ -10158,7 +10284,7 @@ "kind": "command", "id": "audit-multizone" }, - "score": 0.2391, + "score": 0.239, "shared_terms": [ "zone", "path", @@ -10170,67 +10296,46 @@ "report" ] }, - { - "a": { - "kind": "command", - "id": "analyze-policy" - }, - "b": { - "kind": "command", - "id": "text-to-reform" - }, - "score": 0.2382, - "shared_terms": [ - "bill", - "microsim", - "reform", - "analyze", - "year", - "url", - "log", - "description" - ] - }, { "a": { "kind": "skill", - "id": "policyengine-cloud-costs" + "id": "policyengine" }, "b": { - "kind": "command", - "id": "deploy-dashboard" + "kind": "skill", + "id": "policyengine-api" }, - "score": 0.2351, + "score": 0.2386, "shared_terms": [ - "modal", - "deploy", - "app", - "dashboard", - "run", - "backend", - "cloud", - "merge" + "household", + "api", + "python", + "country", + "server", + "rest", + "result", + "analysis" ] }, { "a": { - "kind": "agent", - "id": "reform-describer" + "kind": "command", + "id": "analyze-policy" }, "b": { "kind": "command", "id": "text-to-reform" }, - "score": 0.2338, + "score": 0.2381, "shared_terms": [ + "bill", + "microsim", "reform", - "description", - "dict", - "parameter", - "provisions", - "federal", - "text", - "ctc" + "analyze", + "year", + "url", + "log", + "description" ] }, { @@ -10242,7 +10347,7 @@ "kind": "skill", "id": "policyengine-healthcare" }, - "score": 0.2334, + "score": 0.2368, "shared_terms": [ "household", "income", @@ -10254,6 +10359,27 @@ "benefits" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-app" + }, + "b": { + "kind": "command", + "id": "deploy-dashboard" + }, + "score": 0.2355, + "shared_terms": [ + "app", + "host", + "rewrites", + "website", + "workspace", + "vercel", + "bun", + "next" + ] + }, { "a": { "kind": "agent", @@ -10263,7 +10389,7 @@ "kind": "agent", "id": "edge-case-generator" }, - "score": 0.2329, + "score": 0.2349, "shared_terms": [ "test", "files", @@ -10272,91 +10398,70 @@ "tests", "root", "fix", - "name" + "read" ] }, { "a": { "kind": "skill", - "id": "policyengine" + "id": "policyengine-cloud-costs" }, "b": { - "kind": "skill", - "id": "policyengine-api" + "kind": "command", + "id": "deploy-dashboard" }, - "score": 0.2325, + "score": 0.2347, "shared_terms": [ - "household", - "api", - "python", - "country", - "rest", - "result", - "analysis", - "bundle" + "modal", + "deploy", + "app", + "dashboard", + "run", + "backend", + "cloud", + "merge" ] }, { "a": { "kind": "agent", - "id": "document-collector" + "id": "component-test-writer" }, "b": { "kind": "agent", - "id": "program-reviewer" - }, - "score": 0.2322, - "shared_terms": [ - "implementations", - "regulations", - "program", - "income", - "disregards", - "government", - "benefit", - "deductions" - ] - }, - { - "a": { - "kind": "skill", - "id": "policyengine-app" - }, - "b": { - "kind": "command", - "id": "deploy-dashboard" + "id": "test-creator" }, - "score": 0.232, + "score": 0.2346, "shared_terms": [ - "app", - "host", - "rewrites", - "website", - "workspace", - "vercel", - "bun", - "modal" + "test", + "tests", + "testing", + "expect", + "comprehensive", + "descriptive", + "names", + "integration" ] }, { "a": { "kind": "agent", - "id": "dashboard-architecture-validator" + "id": "reform-describer" }, "b": { "kind": "command", - "id": "new-tool" + "id": "text-to-reform" }, - "score": 0.2318, + "score": 0.2339, "shared_terms": [ - "css", - "app", - "tailwind", - "kit", - "import", - "bash", - "function", - "globals" + "reform", + "description", + "dict", + "parameter", + "provisions", + "federal", + "text", + "ctc" ] }, { @@ -10368,7 +10473,7 @@ "kind": "agent", "id": "prior-scores-finder" }, - "score": 0.2305, + "score": 0.2325, "shared_terms": [ "reform", "external", @@ -10383,43 +10488,22 @@ { "a": { "kind": "agent", - "id": "component-test-writer" + "id": "document-collector" }, "b": { "kind": "agent", - "id": "test-creator" + "id": "program-reviewer" }, - "score": 0.2297, + "score": 0.2322, "shared_terms": [ - "test", - "tests", - "testing", - "expect", - "comprehensive", - "descriptive", - "names", - "integration" - ] - }, - { - "a": { - "kind": "agent", - "id": "dashboard-integrator" - }, - "b": { - "kind": "agent", - "id": "dashboard-scaffold" - }, - "score": 0.2294, - "shared_terms": [ - "api", - "data", - "components", - "plan", - "client", - "backend", - "structure", - "dashboard" + "implementations", + "regulations", + "program", + "income", + "disregards", + "government", + "benefit", + "deductions" ] }, { @@ -10431,79 +10515,79 @@ "kind": "command", "id": "household-calc" }, - "score": 0.2289, + "score": 0.2309, "shared_terms": [ "household", "canada", "benefit", "level", "income", - "population", "net", - "microsimulation" + "population", + "not" ] }, { "a": { - "kind": "skill", - "id": "policyengine-app" + "kind": "command", + "id": "analyze-policy" }, "b": { - "kind": "agent", - "id": "multizone-validator" + "kind": "command", + "id": "reform-pipeline" }, - "score": 0.2287, + "score": 0.2294, "shared_terms": [ - "app", - "host", - "next", - "legacy", - "website", - "zone", - "rewrites", - "server" + "auto", + "bill", + "horizon", + "reform", + "window", + "pipeline", + "phase", + "default" ] }, { "a": { - "kind": "skill", - "id": "policyengine" + "kind": "agent", + "id": "dashboard-architecture-validator" }, "b": { "kind": "agent", - "id": "dashboard-integrator" + "id": "dashboard-scaffold" }, - "score": 0.2279, + "score": 0.2284, "shared_terms": [ - "household", - "api", - "income", - "data", - "tax", - "unit", - "result", - "person" + "backend", + "css", + "dashboard", + "custom", + "modal", + "app", + "kit", + "tsx" ] }, { "a": { - "kind": "command", - "id": "analyze-policy" + "kind": "skill", + "id": "policyengine-healthcare" }, "b": { - "kind": "command", - "id": "reform-pipeline" + "kind": "skill", + "id": "policyengine-uk" }, - "score": 0.2277, + "score": 0.2276, "shared_terms": [ - "bill", - "auto", - "horizon", - "reform", - "window", - "pipeline", - "phase", - "default" + "household", + "income", + "tax", + "unit", + "net", + "person", + "credit", + "benefits" ] }, { @@ -10515,7 +10599,7 @@ "kind": "agent", "id": "frontend-builder" }, - "score": 0.2274, + "score": 0.2275, "shared_terms": [ "component", "button", @@ -10530,22 +10614,22 @@ { "a": { "kind": "skill", - "id": "policyengine-api-access" + "id": "policyengine-app" }, "b": { - "kind": "skill", - "id": "policyengine-app" + "kind": "agent", + "id": "multizone-validator" }, - "score": 0.2273, + "score": 0.2268, "shared_terms": [ - "api", "app", - "server", - "vite", - "client", - "org", - "page", - "next" + "host", + "next", + "legacy", + "website", + "zone", + "rewrites", + "served" ] }, { @@ -10555,18 +10639,18 @@ }, "b": { "kind": "agent", - "id": "backend-builder" + "id": "dashboard-scaffold" }, - "score": 0.2263, + "score": 0.2267, "shared_terms": [ "api", "client", - "data", - "simulation", - "cloud", - "json", + "dashboard", + "alpha", "org", - "household" + "cloud", + "household", + "public" ] }, { @@ -10578,13 +10662,13 @@ "kind": "agent", "id": "pr-pusher" }, - "score": 0.2258, + "score": 0.2261, "shared_terms": [ "review", "push", "contract", - "encode", "tests", + "encode", "draft", "commit", "approved" @@ -10599,7 +10683,7 @@ "kind": "skill", "id": "policyengine-user-guide" }, - "score": 0.2243, + "score": 0.2257, "shared_terms": [ "household", "tax", @@ -10611,67 +10695,25 @@ "population" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-healthcare" - }, - "b": { - "kind": "skill", - "id": "policyengine-uk" - }, - "score": 0.2239, - "shared_terms": [ - "household", - "income", - "tax", - "unit", - "net", - "person", - "credit", - "benefits" - ] - }, { "a": { "kind": "agent", - "id": "dashboard-integrator" + "id": "backend-builder" }, "b": { "kind": "agent", "id": "dashboard-plan-validator" }, - "score": 0.2227, + "score": 0.2242, "shared_terms": [ - "api", - "components", "plan", + "api", "data", - "loading", - "component", - "chart", - "lib" - ] - }, - { - "a": { - "kind": "skill", - "id": "fix-pr" - }, - "b": { - "kind": "agent", - "id": "ci-fixer" - }, - "score": 0.222, - "shared_terms": [ - "fix", - "files", - "failures", - "workflow", - "review", - "worktree", - "root", - "local" + "dashboard", + "lib", + "yaml", + "client", + "contract" ] }, { @@ -10683,7 +10725,7 @@ "kind": "command", "id": "reform-pipeline" }, - "score": 0.2218, + "score": 0.2227, "shared_terms": [ "dashboard", "reform", @@ -10695,6 +10737,27 @@ "dry" ] }, + { + "a": { + "kind": "agent", + "id": "edge-case-generator" + }, + "b": { + "kind": "agent", + "id": "program-reviewer" + }, + "score": 0.2219, + "shared_terms": [ + "income", + "tests", + "test", + "edge", + "program", + "mode", + "review", + "cases" + ] + }, { "a": { "kind": "skill", @@ -10704,37 +10767,58 @@ "kind": "skill", "id": "policyengine-canada" }, - "score": 0.221, + "score": 0.2217, "shared_terms": [ "household", "income", "tax", "age", - "microsimulation", "net", + "microsimulation", "assert", "credit" ] }, { "a": { - "kind": "skill", - "id": "policyengine-research-lookup" + "kind": "agent", + "id": "multizone-validator" }, "b": { + "kind": "command", + "id": "deploy-dashboard" + }, + "score": 0.2217, + "shared_terms": [ + "host", + "zone", + "app", + "path", + "modal", + "next", + "config", + "rewrites" + ] + }, + { + "a": { "kind": "skill", - "id": "policyengine-writing" + "id": "fix-pr" + }, + "b": { + "kind": "agent", + "id": "ci-fixer" }, - "score": 0.2209, + "score": 0.2215, "shared_terms": [ - "posts", - "blog", - "post", - "research", - "writing", - "published", - "about", - "descriptions" + "fix", + "files", + "failures", + "workflow", + "review", + "worktree", + "root", + "local" ] }, { @@ -10746,7 +10830,7 @@ "kind": "agent", "id": "dashboard-plan-validator" }, - "score": 0.2209, + "score": 0.221, "shared_terms": [ "zone", "path", @@ -10760,65 +10844,65 @@ }, { "a": { - "kind": "agent", - "id": "multizone-validator" + "kind": "skill", + "id": "policyengine-writing" }, "b": { "kind": "command", - "id": "deploy-dashboard" + "id": "generate-content" }, - "score": 0.2209, + "score": 0.2205, "shared_terms": [ - "host", - "zone", - "app", - "path", - "modal", - "next", - "config", - "rewrites" + "social", + "blog", + "posts", + "post", + "copy", + "content", + "writing", + "neutrality" ] }, { "a": { "kind": "skill", - "id": "policyengine-writing" + "id": "policyengine-research-lookup" }, "b": { - "kind": "command", - "id": "generate-content" + "kind": "skill", + "id": "policyengine-writing" }, - "score": 0.2206, + "score": 0.2202, "shared_terms": [ - "social", - "blog", "posts", + "blog", "post", - "copy", - "content", + "research", "writing", - "neutrality" + "published", + "about", + "descriptions" ] }, { "a": { "kind": "agent", - "id": "edge-case-generator" + "id": "program-reviewer" }, "b": { "kind": "agent", - "id": "program-reviewer" + "id": "review-worker" }, - "score": 0.2203, + "score": 0.22, "shared_terms": [ - "income", - "tests", - "test", - "edge", - "program", - "mode", "review", - "cases" + "program", + "your", + "code", + "assigned", + "requirements", + "test", + "task" ] }, { @@ -10830,58 +10914,37 @@ "kind": "command", "id": "household-calc" }, - "score": 0.2203, + "score": 0.2196, "shared_terms": [ "reform", "income", "tax", "rate", "dict", - "state", "household", + "state", "api" ] }, { "a": { "kind": "agent", - "id": "program-reviewer" + "id": "dashboard-integrator" }, "b": { "kind": "agent", - "id": "review-worker" - }, - "score": 0.2196, - "shared_terms": [ - "review", - "program", - "your", - "code", - "assigned", - "requirements", - "test", - "task" - ] - }, - { - "a": { - "kind": "skill", - "id": "policyengine-tools" - }, - "b": { - "kind": "command", - "id": "create-new-component" + "id": "dashboard-plan-validator" }, - "score": 0.2185, + "score": 0.2175, "shared_terms": [ - "kit", - "app", - "design", - "tailwind", - "export", - "css", + "api", + "components", + "data", + "loading", "component", - "components" + "chart", + "plan", + "lib" ] }, { @@ -10893,7 +10956,7 @@ "kind": "command", "id": "deploy-dashboard" }, - "score": 0.2166, + "score": 0.2167, "shared_terms": [ "modal", "app", @@ -10914,7 +10977,7 @@ "kind": "command", "id": "prior-scores" }, - "score": 0.2164, + "score": 0.2163, "shared_terms": [ "analyses", "prior", @@ -10935,7 +10998,7 @@ "kind": "command", "id": "create-new-component" }, - "score": 0.216, + "score": 0.2159, "shared_terms": [ "component", "components", @@ -10950,22 +11013,43 @@ { "a": { "kind": "skill", - "id": "policyengine-api" + "id": "policyengine-tools" }, "b": { + "kind": "command", + "id": "create-new-component" + }, + "score": 0.2155, + "shared_terms": [ + "kit", + "app", + "design", + "tailwind", + "export", + "css", + "component", + "components" + ] + }, + { + "a": { "kind": "agent", - "id": "microsim-runner" + "id": "backend-builder" + }, + "b": { + "kind": "command", + "id": "new-tool" }, "score": 0.2148, "shared_terms": [ "api", - "economy", - "version", - "over", - "country", - "python", - "baseline", - "org" + "dashboard", + "create", + "client", + "modal", + "precomputed", + "export", + "public" ] }, { @@ -10977,7 +11061,7 @@ "kind": "agent", "id": "program-reviewer" }, - "score": 0.2144, + "score": 0.2145, "shared_terms": [ "mode", "program", @@ -10998,7 +11082,7 @@ "kind": "agent", "id": "ci-fixer" }, - "score": 0.2137, + "score": 0.2144, "shared_terms": [ "review", "contract", @@ -11010,6 +11094,27 @@ "scope" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-api-access" + }, + "b": { + "kind": "agent", + "id": "dashboard-planner" + }, + "score": 0.2144, + "shared_terms": [ + "api", + "dashboard", + "public", + "server", + "pages", + "credential", + "answer", + "modal" + ] + }, { "a": { "kind": "skill", @@ -11019,7 +11124,7 @@ "kind": "agent", "id": "program-reviewer" }, - "score": 0.2129, + "score": 0.214, "shared_terms": [ "review", "program", @@ -11031,6 +11136,90 @@ "coordinator" ] }, + { + "a": { + "kind": "command", + "id": "create-new-component" + }, + "b": { + "kind": "command", + "id": "new-tool" + }, + "score": 0.2136, + "shared_terms": [ + "kit", + "app", + "tailwind", + "design", + "dashboard", + "export", + "src", + "import" + ] + }, + { + "a": { + "kind": "skill", + "id": "policyengine" + }, + "b": { + "kind": "agent", + "id": "dashboard-integrator" + }, + "score": 0.2135, + "shared_terms": [ + "household", + "api", + "result", + "data", + "unit", + "tax", + "age", + "income" + ] + }, + { + "a": { + "kind": "skill", + "id": "policyengine-api" + }, + "b": { + "kind": "agent", + "id": "microsim-runner" + }, + "score": 0.2134, + "shared_terms": [ + "api", + "economy", + "version", + "over", + "country", + "python", + "baseline", + "org" + ] + }, + { + "a": { + "kind": "agent", + "id": "dashboard-plan-validator" + }, + "b": { + "kind": "agent", + "id": "dashboard-planner" + }, + "score": 0.2122, + "shared_terms": [ + "plan", + "dashboard", + "api", + "data", + "implementation", + "embedding", + "yaml", + "components" + ] + }, { "a": { "kind": "agent", @@ -11040,7 +11229,7 @@ "kind": "command", "id": "create-new-component" }, - "score": 0.211, + "score": 0.2121, "shared_terms": [ "app", "kit", @@ -11061,7 +11250,7 @@ "kind": "command", "id": "create-new-component" }, - "score": 0.2109, + "score": 0.211, "shared_terms": [ "kit", "design", @@ -11082,7 +11271,7 @@ "kind": "agent", "id": "neutrality-reviewer" }, - "score": 0.2109, + "score": 0.211, "shared_terms": [ "neutral", "blog", @@ -11103,7 +11292,7 @@ "kind": "agent", "id": "program-reviewer" }, - "score": 0.2103, + "score": 0.2104, "shared_terms": [ "review", "program", @@ -11124,7 +11313,7 @@ "kind": "command", "id": "audit-state-tax" }, - "score": 0.2101, + "score": 0.21, "shared_terms": [ "tax", "state", @@ -11145,7 +11334,7 @@ "kind": "command", "id": "backdate-program" }, - "score": 0.2098, + "score": 0.2099, "shared_terms": [ "program", "review", @@ -11166,79 +11355,37 @@ "kind": "agent", "id": "ci-fixer" }, - "score": 0.2087, + "score": 0.2089, "shared_terms": [ "root", "review", "prefix", "workflow", "run", - "local", "test", + "local", "read" ] }, { "a": { - "kind": "command", - "id": "create-new-component" + "kind": "skill", + "id": "policyengine-api-access" }, "b": { - "kind": "command", - "id": "new-tool" + "kind": "skill", + "id": "policyengine-tools" }, - "score": 0.2086, + "score": 0.2074, "shared_terms": [ - "kit", + "api", + "public", + "org", "app", - "tailwind", - "const", - "design", - "export", - "src", - "import" - ] - }, - { - "a": { - "kind": "agent", - "id": "dashboard-plan-validator" - }, - "b": { - "kind": "agent", - "id": "dashboard-planner" - }, - "score": 0.2049, - "shared_terms": [ - "plan", "dashboard", - "data", - "api", - "implementation", - "embedding", - "yaml", - "components" - ] - }, - { - "a": { - "kind": "agent", - "id": "document-collector" - }, - "b": { - "kind": "command", - "id": "audit-state-tax" - }, - "score": 0.2048, - "shared_terms": [ - "pdf", - "state", - "source", - "tmp", - "sources", - "income", - "documents", - "official" + "vercel", + "next", + "server" ] }, { @@ -11250,7 +11397,7 @@ "kind": "agent", "id": "model-corroborator" }, - "score": 0.2044, + "score": 0.2052, "shared_terms": [ "calibration", "reform", @@ -11271,7 +11418,7 @@ "kind": "agent", "id": "model-worker" }, - "score": 0.2027, + "score": 0.205, "shared_terms": [ "test", "root", @@ -11286,22 +11433,22 @@ { "a": { "kind": "agent", - "id": "structural-implementer" + "id": "document-collector" }, "b": { - "kind": "agent", - "id": "reform-classifier" + "kind": "command", + "id": "audit-state-tax" }, - "score": 0.2023, + "score": 0.2044, "shared_terms": [ - "structural", - "backlog", - "parameter", - "model", - "amount", - "verdict", - "issue", - "reform" + "pdf", + "state", + "source", + "tmp", + "sources", + "income", + "documents", + "document" ] }, { @@ -11313,14 +11460,14 @@ "kind": "command", "id": "implement-structural" }, - "score": 0.2023, + "score": 0.2032, "shared_terms": [ "gov", "reform", "states", "rate", - "structural", "phase", + "structural", "change", "deployed" ] @@ -11328,22 +11475,22 @@ { "a": { "kind": "agent", - "id": "structural-implementer" + "id": "implementation-validator" }, "b": { "kind": "agent", - "id": "report-logger" + "id": "review-worker" }, - "score": 0.2022, + "score": 0.2031, "shared_terms": [ - "issue", - "draft", - "country", - "structural", - "repo", - "verdict", - "report", - "body" + "review", + "program", + "role", + "read", + "code", + "root", + "verification", + "only" ] }, { @@ -11370,22 +11517,22 @@ { "a": { "kind": "agent", - "id": "implementation-validator" + "id": "structural-implementer" }, "b": { "kind": "agent", - "id": "review-worker" + "id": "report-logger" }, - "score": 0.2019, + "score": 0.1998, "shared_terms": [ - "review", - "program", - "role", - "read", - "code", - "root", - "only", - "verification" + "issue", + "draft", + "country", + "structural", + "repo", + "verdict", + "report", + "body" ] }, { @@ -11409,27 +11556,6 @@ "canada" ] }, - { - "a": { - "kind": "agent", - "id": "report-logger" - }, - "b": { - "kind": "command", - "id": "implement-structural" - }, - "score": 0.1987, - "shared_terms": [ - "issue", - "structural", - "country", - "draft", - "verdict", - "archive", - "report", - "analyze" - ] - }, { "a": { "kind": "skill", @@ -11439,7 +11565,7 @@ "kind": "agent", "id": "report-logger" }, - "score": 0.1982, + "score": 0.1992, "shared_terms": [ "posts", "articles", @@ -11460,39 +11586,18 @@ "kind": "agent", "id": "reference-validator" }, - "score": 0.1982, + "score": 0.1984, "shared_terms": [ "requirements", "program", "income", "correct", "missing", - "review", "reference", + "review", "implementations" ] }, - { - "a": { - "kind": "command", - "id": "create-dashboard" - }, - "b": { - "kind": "command", - "id": "deploy-dashboard" - }, - "score": 0.1977, - "shared_terms": [ - "dashboard", - "repo", - "multi", - "step", - "plan", - "clone", - "confirm", - "path" - ] - }, { "a": { "kind": "agent", @@ -11502,7 +11607,7 @@ "kind": "agent", "id": "structural-implementer" }, - "score": 0.1953, + "score": 0.197, "shared_terms": [ "changelog", "issue", @@ -11523,7 +11628,7 @@ "kind": "command", "id": "create-dashboard" }, - "score": 0.195, + "score": 0.1966, "shared_terms": [ "reform", "calculator", @@ -11535,88 +11640,25 @@ "income" ] }, - { - "a": { - "kind": "command", - "id": "audit-state-tax" - }, - "b": { - "kind": "command", - "id": "backdate-program" - }, - "score": 0.1945, - "shared_terms": [ - "pdf", - "state", - "audit", - "phase", - "arguments", - "files", - "page", - "only" - ] - }, - { - "a": { - "kind": "agent", - "id": "component-test-writer" - }, - "b": { - "kind": "agent", - "id": "dashboard-design-validator" - }, - "score": 0.1944, - "shared_terms": [ - "tsx", - "components", - "button", - "kit", - "app", - "component", - "classname", - "test" - ] - }, { "a": { "kind": "agent", - "id": "multizone-validator" + "id": "report-logger" }, "b": { "kind": "command", - "id": "audit-seo" - }, - "score": 0.1937, - "shared_terms": [ - "zone", - "repo", - "url", - "path", - "legacy", - "zones", - "host", - "mounted" - ] - }, - { - "a": { - "kind": "skill", - "id": "policyengine-user-guide" - }, - "b": { - "kind": "agent", - "id": "parameter-locator" + "id": "implement-structural" }, - "score": 0.1932, + "score": 0.1964, "shared_terms": [ - "reform", - "income", - "tax", - "states", - "parameter", - "state", - "rate", - "org" + "issue", + "structural", + "country", + "draft", + "verdict", + "archive", + "report", + "analyze" ] }, { @@ -11628,7 +11670,7 @@ "kind": "command", "id": "write-tests" }, - "score": 0.1931, + "score": 0.1952, "shared_terms": [ "test", "tests", @@ -11643,43 +11685,106 @@ { "a": { "kind": "agent", - "id": "backend-builder" + "id": "dashboard-integrator" }, "b": { - "kind": "agent", - "id": "dashboard-architecture-validator" + "kind": "command", + "id": "new-tool" }, - "score": 0.1922, + "score": 0.1946, "shared_terms": [ - "backend", - "modal", - "json", - "custom", - "test", - "data", - "pattern", - "dashboard" + "api", + "const", + "client", + "dashboard", + "function", + "import", + "countryid", + "return" ] }, { "a": { - "kind": "skill", - "id": "policyengine-tools" + "kind": "command", + "id": "create-dashboard" + }, + "b": { + "kind": "command", + "id": "deploy-dashboard" + }, + "score": 0.1946, + "shared_terms": [ + "dashboard", + "repo", + "multi", + "step", + "plan", + "clone", + "confirm", + "path" + ] + }, + { + "a": { + "kind": "agent", + "id": "structural-implementer" + }, + "b": { + "kind": "agent", + "id": "reform-classifier" + }, + "score": 0.1945, + "shared_terms": [ + "structural", + "backlog", + "parameter", + "model", + "amount", + "verdict", + "issue", + "reform" + ] + }, + { + "a": { + "kind": "command", + "id": "audit-state-tax" + }, + "b": { + "kind": "command", + "id": "backdate-program" + }, + "score": 0.1942, + "shared_terms": [ + "pdf", + "state", + "audit", + "phase", + "arguments", + "files", + "only", + "page" + ] + }, + { + "a": { + "kind": "agent", + "id": "component-test-writer" }, "b": { "kind": "agent", "id": "dashboard-design-validator" }, - "score": 0.1919, + "score": 0.194, "shared_terms": [ + "tsx", + "components", + "button", "kit", "app", - "css", - "components", - "tsx", - "design", - "dashboard", - "required" + "component", + "classname", + "test" ] }, { @@ -11691,7 +11796,7 @@ "kind": "agent", "id": "edge-case-generator" }, - "score": 0.1918, + "score": 0.1938, "shared_terms": [ "tests", "test", @@ -11706,22 +11811,43 @@ { "a": { "kind": "agent", - "id": "outcome-predictor" + "id": "multizone-validator" + }, + "b": { + "kind": "command", + "id": "audit-seo" + }, + "score": 0.1937, + "shared_terms": [ + "zone", + "repo", + "url", + "path", + "legacy", + "zones", + "host", + "mounted" + ] + }, + { + "a": { + "kind": "skill", + "id": "policyengine-user-guide" }, "b": { "kind": "agent", - "id": "prior-scores-finder" + "id": "parameter-locator" }, - "score": 0.1911, + "score": 0.1932, "shared_terms": [ - "analyses", - "comparator", - "prior", "reform", - "scores", - "blind", - "magnitude", - "you" + "income", + "tax", + "states", + "parameter", + "state", + "rate", + "org" ] }, { @@ -11733,18 +11859,81 @@ "kind": "command", "id": "audit-seo" }, - "score": 0.1906, + "score": 0.1924, "shared_terms": [ "vercel", "seo", "zone", - "bun", "org", + "bun", "standalone", "url", "app" ] }, + { + "a": { + "kind": "agent", + "id": "outcome-predictor" + }, + "b": { + "kind": "agent", + "id": "prior-scores-finder" + }, + "score": 0.1913, + "shared_terms": [ + "analyses", + "comparator", + "prior", + "reform", + "scores", + "blind", + "magnitude", + "you" + ] + }, + { + "a": { + "kind": "agent", + "id": "component-test-writer" + }, + "b": { + "kind": "agent", + "id": "edge-case-generator" + }, + "score": 0.1907, + "shared_terms": [ + "test", + "tests", + "edge", + "testing", + "case", + "cases", + "file", + "boundary" + ] + }, + { + "a": { + "kind": "agent", + "id": "issue-manager" + }, + "b": { + "kind": "agent", + "id": "structural-implementer" + }, + "score": 0.1906, + "shared_terms": [ + "issue", + "repo", + "branch", + "base", + "draft", + "push", + "url", + "number" + ] + }, { "a": { "kind": "skill", @@ -11754,7 +11943,7 @@ "kind": "command", "id": "backdate-program" }, - "score": 0.1895, + "score": 0.1896, "shared_terms": [ "review", "files", @@ -11768,44 +11957,86 @@ }, { "a": { - "kind": "skill", - "id": "policyengine-uk" + "kind": "agent", + "id": "backend-builder" }, "b": { "kind": "agent", - "id": "parameter-locator" + "id": "dashboard-architecture-validator" + }, + "score": 0.1896, + "shared_terms": [ + "backend", + "modal", + "json", + "custom", + "data", + "dashboard", + "pattern", + "api" + ] + }, + { + "a": { + "kind": "agent", + "id": "dashboard-planner" + }, + "b": { + "kind": "command", + "id": "deploy-dashboard" }, "score": 0.1895, "shared_terms": [ - "income", - "tax", - "reform", - "model", - "canada", - "personal", - "household", - "gov" + "dashboard", + "modal", + "step", + "plan", + "custom", + "pattern", + "data", + "needs" ] }, { "a": { + "kind": "skill", + "id": "policyengine-tools" + }, + "b": { "kind": "agent", - "id": "issue-manager" + "id": "dashboard-design-validator" + }, + "score": 0.1894, + "shared_terms": [ + "kit", + "app", + "css", + "components", + "tsx", + "design", + "dashboard", + "required" + ] + }, + { + "a": { + "kind": "skill", + "id": "policyengine-uk" }, "b": { "kind": "agent", - "id": "structural-implementer" + "id": "parameter-locator" }, - "score": 0.1891, + "score": 0.1893, "shared_terms": [ - "issue", - "repo", - "branch", - "base", - "draft", - "push", - "url", - "open" + "income", + "tax", + "reform", + "model", + "canada", + "personal", + "household", + "gov" ] }, { @@ -11817,7 +12048,7 @@ "kind": "command", "id": "prior-scores" }, - "score": 0.1874, + "score": 0.1872, "shared_terms": [ "microsim", "prior", @@ -11838,7 +12069,7 @@ "kind": "command", "id": "household-calc" }, - "score": 0.1866, + "score": 0.1871, "shared_terms": [ "reform", "dict", @@ -11846,29 +12077,8 @@ "external", "single", "cap", - "sources", - "household" - ] - }, - { - "a": { - "kind": "agent", - "id": "component-test-writer" - }, - "b": { - "kind": "agent", - "id": "edge-case-generator" - }, - "score": 0.1864, - "shared_terms": [ - "test", - "tests", - "edge", - "testing", - "case", - "cases", - "file", - "boundary" + "household", + "sources" ] }, { @@ -11880,7 +12090,7 @@ "kind": "command", "id": "deploy-dashboard" }, - "score": 0.186, + "score": 0.1864, "shared_terms": [ "branch", "git", @@ -11901,79 +12111,142 @@ "kind": "skill", "id": "policyengine-plugin-maintenance" }, - "score": 0.1854, + "score": 0.1861, "shared_terms": [ "claude", "codex", "routing", "catalog", "skills", - "source", "tests", + "source", "test" ] }, { "a": { "kind": "skill", - "id": "policyengine-content" + "id": "policyengine-api" }, "b": { - "kind": "agent", - "id": "frontend-builder" + "kind": "command", + "id": "new-tool" }, - "score": 0.1854, + "score": 0.1859, "shared_terms": [ - "kit", - "teal", - "design", - "chart", - "system", - "css", - "app", - "import" + "api", + "client", + "dashboard", + "org", + "public", + "calc", + "country", + "economy" ] }, { "a": { "kind": "agent", - "id": "dashboard-planner" + "id": "backend-builder" }, "b": { "kind": "command", - "id": "deploy-dashboard" + "id": "create-dashboard" }, - "score": 0.185, + "score": 0.1859, "shared_terms": [ "dashboard", - "modal", - "step", "plan", - "custom", - "pattern", + "create", + "json", + "api", + "reform", + "precomputed", + "backend" + ] + }, + { + "a": { + "kind": "agent", + "id": "dashboard-integrator" + }, + "b": { + "kind": "agent", + "id": "dashboard-planner" + }, + "score": 0.1858, + "shared_terms": [ + "api", "data", - "cloud" + "dashboard", + "step", + "backend", + "components", + "input", + "pattern" + ] + }, + { + "a": { + "kind": "skill", + "id": "policyengine-model-development" + }, + "b": { + "kind": "command", + "id": "implement-structural" + }, + "score": 0.1856, + "shared_terms": [ + "formula", + "contrib", + "gov", + "bracket", + "parameters", + "reform", + "run", + "model" ] }, { "a": { + "kind": "skill", + "id": "policyengine-content" + }, + "b": { "kind": "agent", - "id": "rules-engineer" + "id": "frontend-builder" + }, + "score": 0.1851, + "shared_terms": [ + "kit", + "teal", + "design", + "chart", + "system", + "css", + "app", + "import" + ] + }, + { + "a": { + "kind": "command", + "id": "audit-multizone" }, "b": { "kind": "command", - "id": "backdate-program" + "id": "create-dashboard" }, "score": 0.1848, "shared_terms": [ - "page", - "program", - "tanf", - "files", - "href", - "pdf", - "yaml", - "only" + "repo", + "multi", + "dashboard", + "path", + "phase", + "clone", + "create", + "arguments" ] }, { @@ -11985,7 +12258,7 @@ "kind": "command", "id": "household-calc" }, - "score": 0.1847, + "score": 0.1843, "shared_terms": [ "reform", "preset", @@ -12006,13 +12279,13 @@ "kind": "skill", "id": "policyengine-model-development" }, - "score": 0.1842, + "score": 0.1837, "shared_terms": [ "household", "age", "analysis", - "microsimulation", "variables", + "microsimulation", "income", "year", "model" @@ -12027,7 +12300,7 @@ "kind": "command", "id": "audit-state-tax" }, - "score": 0.1837, + "score": 0.183, "shared_terms": [ "pdf", "oregon", @@ -12042,85 +12315,64 @@ { "a": { "kind": "command", - "id": "audit-multizone" + "id": "audit-seo" }, "b": { "kind": "command", - "id": "create-dashboard" + "id": "audit-state-tax" }, - "score": 0.1836, + "score": 0.1827, "shared_terms": [ - "repo", - "multi", - "dashboard", - "path", - "phase", - "clone", - "create", - "arguments" + "audit", + "url", + "github", + "local", + "body", + "step", + "state", + "check" ] }, { "a": { - "kind": "skill", - "id": "policyengine-model-development" + "kind": "command", + "id": "encode-reform" }, "b": { "kind": "command", "id": "implement-structural" }, - "score": 0.1833, + "score": 0.1826, "shared_terms": [ - "formula", + "reform", "contrib", + "implement", + "bill", "gov", - "bracket", - "parameters", - "reform", - "run", - "model" - ] - }, - { - "a": { - "kind": "command", - "id": "audit-seo" - }, - "b": { - "kind": "command", - "id": "audit-state-tax" - }, - "score": 0.1824, - "shared_terms": [ - "audit", - "url", - "github", - "local", - "body", - "step", - "state", - "check" + "arguments", + "encode", + "phase" ] }, { "a": { "kind": "agent", - "id": "dashboard-integrator" + "id": "program-reviewer" }, "b": { "kind": "agent", - "id": "frontend-builder" + "id": "rules-engineer" }, - "score": 0.1823, + "score": 0.1825, "shared_terms": [ - "components", - "frontend", - "component", - "api", - "builder", - "design", - "step", - "chart" + "program", + "tanf", + "manual", + "income", + "amount", + "standards", + "payment", + "government" ] }, { @@ -12132,7 +12384,7 @@ "kind": "command", "id": "audit-state-tax" }, - "score": 0.1818, + "score": 0.182, "shared_terms": [ "pdf", "audit", @@ -12146,44 +12398,86 @@ }, { "a": { - "kind": "skill", - "id": "fix-pr" + "kind": "command", + "id": "analyze-policy" }, "b": { - "kind": "agent", - "id": "pr-pusher" + "kind": "command", + "id": "create-dashboard" }, - "score": 0.1815, + "score": 0.1819, "shared_terms": [ - "fix", - "review", - "push", - "workflow", - "pusher", - "files", - "local", - "never" + "auto", + "horizon", + "phase", + "reform", + "single", + "confirm", + "multi", + "skip" ] }, { "a": { "kind": "agent", - "id": "document-collector" + "id": "issue-manager" }, "b": { + "kind": "command", + "id": "audit-seo" + }, + "score": 0.1818, + "shared_terms": [ + "url", + "repo", + "issue", + "title", + "open", + "search", + "github", + "group" + ] + }, + { + "a": { "kind": "agent", - "id": "reference-validator" + "id": "rules-engineer" }, - "score": 0.1812, + "b": { + "kind": "command", + "id": "backdate-program" + }, + "score": 0.1811, "shared_terms": [ - "pdf", - "citation", - "text", - "source", "page", - "doc", - "authoritative", - "references" + "program", + "tanf", + "files", + "href", + "pdf", + "yaml", + "only" + ] + }, + { + "a": { + "kind": "agent", + "id": "dashboard-architecture-validator" + }, + "b": { + "kind": "command", + "id": "audit-multizone" + }, + "score": 0.1811, + "shared_terms": [ + "app", + "config", + "path", + "next", + "bash", + "package", + "json", + "validator" ] }, { @@ -12195,7 +12489,7 @@ "kind": "skill", "id": "policyengine-plugin-maintenance" }, - "score": 0.1811, + "score": 0.1809, "shared_terms": [ "claude", "codex", @@ -12209,23 +12503,44 @@ }, { "a": { + "kind": "skill", + "id": "fix-pr" + }, + "b": { "kind": "agent", - "id": "program-reviewer" + "id": "pr-pusher" + }, + "score": 0.1809, + "shared_terms": [ + "fix", + "review", + "push", + "workflow", + "pusher", + "files", + "local", + "never" + ] + }, + { + "a": { + "kind": "skill", + "id": "encode-policy-v2" }, "b": { "kind": "agent", - "id": "rules-engineer" + "id": "test-creator" }, - "score": 0.181, + "score": 0.1807, "shared_terms": [ + "tests", + "test", "program", - "tanf", - "manual", - "income", - "amount", - "standards", - "payment", - "government" + "contract", + "development", + "references", + "not", + "model" ] }, { @@ -12237,7 +12552,7 @@ "kind": "agent", "id": "reform-describer" }, - "score": 0.1806, + "score": 0.1805, "shared_terms": [ "sentence", "blog", @@ -12249,46 +12564,25 @@ "advocacy" ] }, - { - "a": { - "kind": "command", - "id": "encode-reform" - }, - "b": { - "kind": "command", - "id": "implement-structural" - }, - "score": 0.1804, - "shared_terms": [ - "reform", - "contrib", - "implement", - "bill", - "gov", - "arguments", - "encode", - "phase" - ] - }, { "a": { "kind": "agent", - "id": "issue-manager" + "id": "document-collector" }, "b": { - "kind": "command", - "id": "audit-seo" + "kind": "agent", + "id": "reference-validator" }, - "score": 0.1802, + "score": 0.1804, "shared_terms": [ - "url", - "repo", - "issue", - "title", - "open", - "search", - "github", - "group" + "pdf", + "citation", + "text", + "source", + "page", + "doc", + "authoritative", + "references" ] }, { @@ -12300,7 +12594,7 @@ "kind": "agent", "id": "calibration-diagnostics" }, - "score": 0.18, + "score": 0.1801, "shared_terms": [ "unit", "tax", @@ -12312,27 +12606,6 @@ "eitc" ] }, - { - "a": { - "kind": "agent", - "id": "dashboard-architecture-validator" - }, - "b": { - "kind": "command", - "id": "audit-multizone" - }, - "score": 0.1793, - "shared_terms": [ - "app", - "config", - "path", - "next", - "bash", - "package", - "json", - "validator" - ] - }, { "a": { "kind": "skill", @@ -12356,44 +12629,65 @@ }, { "a": { - "kind": "command", - "id": "analyze-policy" + "kind": "agent", + "id": "model-worker" }, "b": { - "kind": "command", - "id": "create-dashboard" + "kind": "agent", + "id": "test-creator" }, - "score": 0.1789, + "score": 0.1792, "shared_terms": [ - "auto", - "horizon", - "phase", - "reform", - "single", - "confirm", - "multi", - "skip" + "test", + "tests", + "assigned", + "model", + "contract", + "cases", + "owned", + "manifest" ] }, { "a": { - "kind": "command", - "id": "implement-structural" + "kind": "agent", + "id": "dashboard-integrator" }, "b": { - "kind": "command", - "id": "text-to-reform" + "kind": "agent", + "id": "microsim-runner" }, - "score": 0.1789, + "score": 0.179, "shared_terms": [ - "reform", - "structural", - "analyze", - "bill", - "formula", - "deployed", - "extension", - "pre" + "api", + "data", + "response", + "result", + "request", + "year", + "client", + "state" + ] + }, + { + "a": { + "kind": "skill", + "id": "policyengine-canada" + }, + "b": { + "kind": "skill", + "id": "policyengine-us" + }, + "score": 0.178, + "shared_terms": [ + "tax", + "household", + "income", + "credit", + "net", + "benefit", + "child", + "poverty" ] }, { @@ -12405,7 +12699,7 @@ "kind": "command", "id": "analyze-policy" }, - "score": 0.1783, + "score": 0.178, "shared_terms": [ "year", "microsim", @@ -12417,46 +12711,25 @@ "window" ] }, - { - "a": { - "kind": "skill", - "id": "encode-policy-v2" - }, - "b": { - "kind": "agent", - "id": "test-creator" - }, - "score": 0.1782, - "shared_terms": [ - "tests", - "test", - "program", - "contract", - "development", - "references", - "not", - "model" - ] - }, { "a": { "kind": "agent", - "id": "implementation-validator" + "id": "model-corroborator" }, "b": { - "kind": "command", - "id": "implement-structural" + "kind": "agent", + "id": "parameter-locator" }, - "score": 0.1775, + "score": 0.1772, "shared_terms": [ - "structural", - "mode", - "run", + "reform", + "parameter", + "family", + "model", + "dict", + "amount", "phase", - "verification", - "report", - "issue", - "read" + "ctc" ] }, { @@ -12468,14 +12741,14 @@ "kind": "command", "id": "backdate-program" }, - "score": 0.177, + "score": 0.1769, "shared_terms": [ "program", "review", "tanf", "research", - "state", "read", + "state", "you", "findings" ] @@ -12483,64 +12756,64 @@ { "a": { "kind": "command", - "id": "audit-state-tax" + "id": "implement-structural" }, "b": { "kind": "command", - "id": "encode-reform" + "id": "text-to-reform" }, - "score": 0.1767, + "score": 0.1765, "shared_terms": [ - "pdf", - "state", - "gov", - "arguments", - "full", - "tax", - "phase", - "page" + "reform", + "structural", + "analyze", + "bill", + "formula", + "deployed", + "extension", + "pre" ] }, { "a": { "kind": "skill", - "id": "policyengine-canada" + "id": "policyengine-healthcare" }, "b": { - "kind": "skill", - "id": "policyengine-us" + "kind": "command", + "id": "household-calc" }, - "score": 0.1766, + "score": 0.1764, "shared_terms": [ - "tax", "household", - "income", - "credit", "net", - "benefit", - "child", - "poverty" + "income", + "reform", + "benefits", + "tax", + "year", + "single" ] }, { "a": { - "kind": "agent", - "id": "model-corroborator" + "kind": "command", + "id": "audit-state-tax" }, "b": { - "kind": "agent", - "id": "parameter-locator" + "kind": "command", + "id": "encode-reform" }, - "score": 0.1766, + "score": 0.1763, "shared_terms": [ - "reform", - "parameter", - "family", - "model", - "dict", - "amount", + "pdf", + "state", + "gov", + "arguments", + "full", + "tax", "phase", - "ctc" + "audit" ] }, { @@ -12549,103 +12822,82 @@ "id": "policyengine-api" }, "b": { - "kind": "skill", - "id": "policyengine-app" - }, - "score": 0.1763, - "shared_terms": [ - "api", - "app", - "org", - "economy", - "calc", - "household", - "client", - "over" - ] - }, - { - "a": { "kind": "agent", - "id": "backend-builder" - }, - "b": { - "kind": "command", - "id": "create-dashboard" + "id": "dashboard-planner" }, - "score": 0.1759, + "score": 0.176, "shared_terms": [ - "dashboard", - "plan", - "create", - "json", "api", - "precomputed", - "step", - "backend" + "dashboard", + "cloud", + "server", + "rest", + "credential", + "alpha", + "household" ] }, { "a": { - "kind": "agent", - "id": "model-worker" + "kind": "skill", + "id": "policyengine-model-development" }, "b": { - "kind": "agent", - "id": "test-creator" + "kind": "command", + "id": "write-tests" }, "score": 0.1757, "shared_terms": [ - "test", "tests", - "assigned", - "model", - "contract", - "cases", - "owned", - "manifest" + "test", + "write", + "pytest", + "run", + "repo", + "references", + "path" ] }, { "a": { "kind": "agent", - "id": "dashboard-planner" + "id": "dashboard-integrator" }, "b": { - "kind": "command", - "id": "text-to-reform" + "kind": "agent", + "id": "frontend-builder" }, - "score": 0.1754, + "score": 0.1749, "shared_terms": [ - "reform", - "natural", - "description", - "language", - "provision", - "bill", - "analyze", - "api" + "components", + "frontend", + "api", + "builder", + "component", + "design", + "chart", + "step" ] }, { "a": { - "kind": "skill", - "id": "policyengine-api" + "kind": "agent", + "id": "issue-manager" }, "b": { - "kind": "command", - "id": "household-calc" + "kind": "agent", + "id": "report-logger" }, - "score": 0.1749, + "score": 0.1736, "shared_terms": [ - "household", - "api", - "get", - "country", - "reform", - "baseline", - "calc", - "simulation" + "issue", + "repo", + "open", + "draft", + "github", + "url", + "git", + "explicit" ] }, { @@ -12657,7 +12909,7 @@ "kind": "agent", "id": "parameter-locator" }, - "score": 0.1731, + "score": 0.1732, "shared_terms": [ "state", "income", @@ -12678,79 +12930,37 @@ "kind": "command", "id": "text-to-reform" }, - "score": 0.1728, + "score": 0.1726, "shared_terms": [ "reform", "impact", "analyze", - "link", - "reforms", - "org", - "parameter", - "into" - ] - }, - { - "a": { - "kind": "skill", - "id": "policyengine-healthcare" - }, - "b": { - "kind": "command", - "id": "household-calc" - }, - "score": 0.1725, - "shared_terms": [ - "household", - "net", - "income", - "reform", - "benefits", - "tax", - "year", - "single" - ] - }, - { - "a": { - "kind": "skill", - "id": "policyengine-model-development" - }, - "b": { - "kind": "command", - "id": "write-tests" - }, - "score": 0.1724, - "shared_terms": [ - "tests", - "test", - "write", - "pytest", - "run", - "repo", - "references", - "path" + "link", + "reforms", + "org", + "parameter", + "into" ] }, { "a": { "kind": "agent", - "id": "issue-manager" + "id": "implementation-validator" }, "b": { - "kind": "agent", - "id": "report-logger" + "kind": "command", + "id": "implement-structural" }, - "score": 0.1723, + "score": 0.1722, "shared_terms": [ + "structural", + "mode", + "run", + "phase", + "verification", + "report", "issue", - "repo", - "open", - "draft", - "github", - "url", - "git", - "explicit" + "read" ] }, { @@ -12762,7 +12972,7 @@ "kind": "agent", "id": "parameter-locator" }, - "score": 0.1717, + "score": 0.1718, "shared_terms": [ "income", "state", @@ -12774,27 +12984,6 @@ "tax" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-api-access" - }, - "b": { - "kind": "agent", - "id": "dashboard-scaffold" - }, - "score": 0.1716, - "shared_terms": [ - "dashboard", - "api", - "client", - "page", - "backend", - "modal", - "next", - "household" - ] - }, { "a": { "kind": "agent", @@ -12804,7 +12993,7 @@ "kind": "command", "id": "write-tests" }, - "score": 0.1706, + "score": 0.1716, "shared_terms": [ "test", "app", @@ -12816,6 +13005,27 @@ "config" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-api" + }, + "b": { + "kind": "command", + "id": "household-calc" + }, + "score": 0.1711, + "shared_terms": [ + "household", + "api", + "get", + "country", + "reform", + "baseline", + "calc", + "simulation" + ] + }, { "a": { "kind": "agent", @@ -12825,7 +13035,7 @@ "kind": "command", "id": "analyze-policy" }, - "score": 0.1704, + "score": 0.1705, "shared_terms": [ "bill", "year", @@ -12834,7 +13044,7 @@ "reform", "ctc", "text", - "phase" + "number" ] }, { @@ -12846,7 +13056,7 @@ "kind": "command", "id": "encode-reform" }, - "score": 0.17, + "score": 0.1701, "shared_terms": [ "reform", "gov", @@ -12861,22 +13071,22 @@ { "a": { "kind": "skill", - "id": "policyengine-us" + "id": "encode-policy-v2" }, "b": { "kind": "agent", - "id": "dashboard-integrator" + "id": "edge-case-generator" }, - "score": 0.1693, + "score": 0.1698, "shared_terms": [ - "household", - "unit", - "tax", - "income", - "spm", - "person", - "year", - "state" + "tests", + "review", + "test", + "program", + "cases", + "read", + "existing", + "mode" ] }, { @@ -12888,7 +13098,7 @@ "kind": "agent", "id": "content-orchestrator" }, - "score": 0.1687, + "score": 0.169, "shared_terms": [ "social", "blog", @@ -12900,69 +13110,6 @@ "audience" ] }, - { - "a": { - "kind": "agent", - "id": "dashboard-design-validator" - }, - "b": { - "kind": "agent", - "id": "dashboard-scaffold" - }, - "score": 0.1678, - "shared_terms": [ - "tsx", - "components", - "dashboard", - "kit", - "design", - "app", - "css", - "custom" - ] - }, - { - "a": { - "kind": "skill", - "id": "encode-policy-v2" - }, - "b": { - "kind": "agent", - "id": "edge-case-generator" - }, - "score": 0.1677, - "shared_terms": [ - "review", - "tests", - "test", - "program", - "cases", - "read", - "existing", - "mode" - ] - }, - { - "a": { - "kind": "command", - "id": "analyze-policy" - }, - "b": { - "kind": "command", - "id": "household-calc" - }, - "score": 0.167, - "shared_terms": [ - "reform", - "year", - "yyyy", - "single", - "cost", - "analyze", - "microsim", - "baseline" - ] - }, { "a": { "kind": "command", @@ -12972,7 +13119,7 @@ "kind": "command", "id": "household-calc" }, - "score": 0.1669, + "score": 0.1685, "shared_terms": [ "reform", "household", @@ -12987,127 +13134,106 @@ { "a": { "kind": "agent", - "id": "edge-case-generator" + "id": "model-worker" }, "b": { "kind": "command", - "id": "backdate-program" + "id": "write-tests" }, - "score": 0.1667, + "score": 0.1682, "shared_terms": [ - "files", - "program", - "review", - "backdate", - "read", - "existing", - "only", - "root" + "test", + "tests", + "run", + "your", + "path", + "write", + "model", + "source" ] }, { "a": { "kind": "skill", - "id": "policyengine-api-access" + "id": "policyengine-app" }, "b": { "kind": "skill", - "id": "policyengine-tools" + "id": "policyengine-design" }, - "score": 0.1663, + "score": 0.1671, "shared_terms": [ - "public", - "org", - "api", "app", - "dashboard", - "vercel", - "server", - "next" - ] - }, - { - "a": { - "kind": "agent", - "id": "dashboard-scaffold" - }, - "b": { - "kind": "command", - "id": "create-new-component" - }, - "score": 0.1661, - "shared_terms": [ + "tailwindcss", "kit", + "theme", + "vite", "design", - "tsx", - "dashboard", - "components", - "component", - "app", - "step" + "tokens", + "colors" ] }, { "a": { "kind": "agent", - "id": "reform-describer" + "id": "review-worker" }, "b": { "kind": "command", - "id": "household-calc" + "id": "backdate-program" }, - "score": 0.166, + "score": 0.1668, "shared_terms": [ - "reform", - "description", - "baseline", - "tax", - "ctc", - "specific", - "dict", - "income" + "program", + "review", + "read", + "root", + "only", + "workflow", + "task", + "you" ] }, { "a": { - "kind": "skill", - "id": "policyengine-api-access" + "kind": "agent", + "id": "component-test-writer" }, "b": { - "kind": "command", - "id": "new-tool" + "kind": "agent", + "id": "dashboard-architecture-validator" }, - "score": 0.1659, + "score": 0.1667, "shared_terms": [ - "api", - "dashboard", - "public", - "const", - "client", + "test", "app", - "page", - "function" + "tsx", + "kit", + "import", + "components", + "classname", + "setup" ] }, { "a": { "kind": "agent", - "id": "review-worker" + "id": "edge-case-generator" }, "b": { "kind": "command", "id": "backdate-program" }, - "score": 0.1659, + "score": 0.1664, "shared_terms": [ + "files", "program", "review", + "backdate", "read", - "root", - "only", - "workflow", - "task", - "you" + "existing", + "only", + "root" ] }, { @@ -13116,82 +13242,82 @@ "id": "policyengine-app" }, "b": { - "kind": "skill", - "id": "policyengine-design" + "kind": "agent", + "id": "dashboard-design-validator" }, - "score": 0.1657, + "score": 0.1661, "shared_terms": [ "app", - "tailwindcss", + "tsx", "kit", - "theme", "design", - "vite", - "tokens", + "components", + "component", + "typography", "colors" ] }, { "a": { - "kind": "agent", - "id": "reform-describer" + "kind": "command", + "id": "analyze-policy" }, "b": { "kind": "command", - "id": "create-dashboard" + "id": "household-calc" }, - "score": 0.1653, + "score": 0.166, "shared_terms": [ - "dashboard", "reform", - "ctc", - "provisions", - "description", - "child", - "json", - "multi" + "year", + "yyyy", + "single", + "cost", + "analyze", + "microsim", + "baseline" ] }, { "a": { "kind": "agent", - "id": "dashboard-integrator" + "id": "reform-describer" }, "b": { - "kind": "agent", - "id": "microsim-runner" + "kind": "command", + "id": "household-calc" }, - "score": 0.1652, + "score": 0.1656, "shared_terms": [ - "api", - "data", - "response", - "result", - "request", - "year", - "state", - "step" + "reform", + "description", + "baseline", + "tax", + "ctc", + "specific", + "dict", + "income" ] }, { "a": { - "kind": "agent", - "id": "component-test-writer" + "kind": "skill", + "id": "encode-policy-v2" }, "b": { - "kind": "agent", - "id": "dashboard-architecture-validator" + "kind": "command", + "id": "write-tests" }, - "score": 0.1651, + "score": 0.1653, "shared_terms": [ + "tests", "test", - "app", - "tsx", - "kit", - "import", - "components", - "classname", - "setup" + "source", + "run", + "fix", + "claude", + "existing", + "shared" ] }, { @@ -13203,7 +13329,7 @@ "kind": "command", "id": "implement-structural" }, - "score": 0.1651, + "score": 0.1652, "shared_terms": [ "enacted", "gov", @@ -13218,22 +13344,43 @@ { "a": { "kind": "agent", - "id": "model-worker" + "id": "reform-describer" }, "b": { "kind": "command", - "id": "write-tests" + "id": "create-dashboard" + }, + "score": 0.1649, + "shared_terms": [ + "dashboard", + "reform", + "ctc", + "provisions", + "description", + "child", + "json", + "multi" + ] + }, + { + "a": { + "kind": "skill", + "id": "policyengine-api" + }, + "b": { + "kind": "skill", + "id": "policyengine-app" }, "score": 0.1648, "shared_terms": [ - "test", - "tests", - "run", - "your", - "path", - "write", - "model", - "source" + "api", + "server", + "org", + "client", + "economy", + "calc", + "household", + "page" ] }, { @@ -13245,13 +13392,13 @@ "kind": "agent", "id": "policy-text-researcher" }, - "score": 0.1646, + "score": 0.1647, "shared_terms": [ "enacted", "effective", - "structural", "draft", "bill", + "structural", "gov", "date", "enrolled" @@ -13259,44 +13406,44 @@ }, { "a": { - "kind": "skill", - "id": "policyengine-app" + "kind": "agent", + "id": "model-corroborator" }, "b": { "kind": "agent", - "id": "dashboard-design-validator" + "id": "reform-classifier" }, - "score": 0.1639, + "score": 0.1643, "shared_terms": [ - "app", - "tsx", - "kit", - "design", - "components", - "component", - "typography", - "colors" + "reform", + "parameter", + "model", + "stage", + "microsim", + "amount", + "deployed", + "ctc" ] }, { "a": { - "kind": "agent", - "id": "document-collector" + "kind": "skill", + "id": "policyengine-tools" }, "b": { "kind": "agent", - "id": "test-creator" + "id": "backend-builder" }, - "score": 0.1637, + "score": 0.1641, "shared_terms": [ - "month", - "months", - "documentation", - "benefit", - "government", - "program", - "document", - "development" + "modal", + "api", + "backend", + "dashboard", + "export", + "public", + "custom", + "static" ] }, { @@ -13308,7 +13455,7 @@ "kind": "agent", "id": "pr-pusher" }, - "score": 0.1637, + "score": 0.1639, "shared_terms": [ "fix", "review", @@ -13329,7 +13476,7 @@ "kind": "agent", "id": "test-creator" }, - "score": 0.1633, + "score": 0.1638, "shared_terms": [ "fix", "program", @@ -13338,28 +13485,7 @@ "not", "findings", "only", - "variable" - ] - }, - { - "a": { - "kind": "skill", - "id": "policyengine-api-access" - }, - "b": { - "kind": "command", - "id": "create-dashboard" - }, - "score": 0.1631, - "shared_terms": [ - "dashboard", - "page", - "api", - "household", - "pages", - "ctc", - "analysis", - "json" + "variables" ] }, { @@ -13371,7 +13497,7 @@ "kind": "agent", "id": "model-corroborator" }, - "score": 0.1629, + "score": 0.1636, "shared_terms": [ "calibration", "reform", @@ -13385,127 +13511,148 @@ }, { "a": { - "kind": "agent", - "id": "model-corroborator" + "kind": "skill", + "id": "policyengine-app" }, "b": { "kind": "agent", - "id": "reform-classifier" + "id": "dashboard-scaffold" }, - "score": 0.1629, + "score": 0.1634, "shared_terms": [ - "reform", - "parameter", - "model", - "stage", - "microsim", - "amount", - "deployed", - "ctc" + "api", + "app", + "page", + "design", + "tsx", + "next", + "router", + "kit" ] }, { "a": { + "kind": "skill", + "id": "policyengine-cloud-costs" + }, + "b": { "kind": "agent", "id": "backend-builder" }, + "score": 0.1634, + "shared_terms": [ + "modal", + "backend", + "containers", + "api", + "dashboard", + "plan", + "cloud", + "declare" + ] + }, + { + "a": { + "kind": "skill", + "id": "policyengine-canada" + }, "b": { - "kind": "command", - "id": "write-tests" + "kind": "skill", + "id": "policyengine-user-guide" }, - "score": 0.1627, + "score": 0.1633, "shared_terms": [ - "test", - "tests", - "step", - "files", - "client", - "api", - "json", - "matching" + "household", + "income", + "benefit", + "population", + "canada", + "tax", + "net", + "poverty" ] }, { "a": { - "kind": "skill", - "id": "policyengine-api-access" + "kind": "agent", + "id": "document-collector" }, "b": { "kind": "agent", - "id": "dashboard-planner" + "id": "test-creator" }, - "score": 0.1622, + "score": 0.1633, "shared_terms": [ - "dashboard", - "api", - "public", - "page", - "answer", - "pages", - "modal", - "cloud" + "month", + "months", + "documentation", + "benefit", + "government", + "program", + "document", + "development" ] }, { "a": { "kind": "skill", - "id": "encode-policy-v2" + "id": "policyengine-standards" }, "b": { - "kind": "command", - "id": "write-tests" + "kind": "agent", + "id": "issue-manager" }, - "score": 0.1621, + "score": 0.1631, "shared_terms": [ - "tests", - "test", - "source", - "run", - "fix", - "claude", - "existing", - "shared" + "repo", + "number", + "create", + "repository", + "draft", + "issue", + "title", + "never" ] }, { "a": { "kind": "skill", - "id": "policyengine-canada" + "id": "policyengine-api-access" }, "b": { - "kind": "skill", - "id": "policyengine-user-guide" + "kind": "command", + "id": "create-dashboard" }, - "score": 0.1621, + "score": 0.1629, "shared_terms": [ + "dashboard", + "api", + "page", "household", - "income", - "benefit", - "population", - "canada", - "tax", - "net", - "poverty" + "pages", + "ctc", + "analysis", + "json" ] }, { "a": { "kind": "agent", - "id": "backend-builder" + "id": "dashboard-scaffold" }, "b": { "kind": "command", - "id": "new-tool" + "id": "create-new-component" }, - "score": 0.1618, + "score": 0.1627, "shared_terms": [ - "api", + "kit", "dashboard", - "create", - "precomputed", - "export", - "function", - "modal", + "design", + "components", + "tsx", + "component", + "app", "step" ] }, @@ -13518,7 +13665,7 @@ "kind": "agent", "id": "reference-validator" }, - "score": 0.1616, + "score": 0.1624, "shared_terms": [ "pdf", "review", @@ -13530,27 +13677,6 @@ "missing" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-standards" - }, - "b": { - "kind": "agent", - "id": "issue-manager" - }, - "score": 0.1614, - "shared_terms": [ - "repo", - "number", - "create", - "repository", - "draft", - "issue", - "title", - "never" - ] - }, { "a": { "kind": "agent", @@ -13560,7 +13686,7 @@ "kind": "agent", "id": "test-creator" }, - "score": 0.1607, + "score": 0.1616, "shared_terms": [ "tests", "commit", @@ -13574,128 +13700,128 @@ }, { "a": { - "kind": "skill", - "id": "policyengine" + "kind": "agent", + "id": "ci-fixer" }, "b": { "kind": "agent", - "id": "microsim-runner" + "id": "review-worker" }, "score": 0.1606, "shared_terms": [ - "result", - "dataset", - "data", - "python", - "microsimulation", - "reform", - "api", - "impact" + "test", + "review", + "blocked", + "root", + "role", + "read", + "evidence", + "program" ] }, { "a": { "kind": "agent", - "id": "dashboard-planner" + "id": "dashboard-design-validator" }, "b": { "kind": "agent", - "id": "reform-describer" + "id": "dashboard-scaffold" }, - "score": 0.1602, + "score": 0.16, "shared_terms": [ + "components", + "tsx", "dashboard", - "reform", - "description", - "explanation", - "parameter", - "structured", - "language", - "ctc" + "kit", + "design", + "app", + "css", + "custom" ] }, { "a": { "kind": "agent", - "id": "reference-validator" + "id": "edge-case-generator" }, "b": { - "kind": "command", - "id": "backdate-program" + "kind": "agent", + "id": "review-worker" }, - "score": 0.1594, + "score": 0.1596, "shared_terms": [ - "page", - "reference", - "pdf", - "program", + "test", "review", - "href", - "phase", - "parameter" + "assigned", + "program", + "read", + "one", + "only", + "model" ] }, { "a": { "kind": "agent", - "id": "ci-fixer" + "id": "dashboard-design-validator" }, "b": { - "kind": "agent", - "id": "review-worker" + "kind": "command", + "id": "new-tool" }, - "score": 0.1592, + "score": 0.1596, "shared_terms": [ - "test", - "review", - "blocked", - "root", - "role", - "evidence", - "read", - "program" + "kit", + "app", + "dashboard", + "css", + "font", + "design", + "node", + "modules" ] }, { "a": { - "kind": "command", - "id": "audit-multizone" + "kind": "skill", + "id": "policyengine" }, "b": { - "kind": "command", - "id": "write-tests" + "kind": "agent", + "id": "microsim-runner" }, - "score": 0.1586, + "score": 0.1593, "shared_terms": [ - "path", - "target", - "repo", - "test", - "app", - "config", - "bash", - "existing" + "result", + "dataset", + "data", + "python", + "microsimulation", + "reform", + "api", + "impact" ] }, { "a": { "kind": "agent", - "id": "edge-case-generator" + "id": "model-corroborator" }, "b": { - "kind": "agent", - "id": "review-worker" + "kind": "command", + "id": "implement-structural" }, - "score": 0.1583, + "score": 0.159, "shared_terms": [ - "review", - "test", - "assigned", - "program", - "read", - "one", - "only", - "model" + "reform", + "original", + "model", + "issue", + "law", + "baseline", + "phase", + "analyze" ] }, { @@ -13707,7 +13833,7 @@ "kind": "agent", "id": "reference-validator" }, - "score": 0.1576, + "score": 0.1583, "shared_terms": [ "reference", "pdf", @@ -13719,109 +13845,130 @@ "issues" ] }, + { + "a": { + "kind": "agent", + "id": "reference-validator" + }, + "b": { + "kind": "command", + "id": "backdate-program" + }, + "score": 0.1582, + "shared_terms": [ + "reference", + "page", + "pdf", + "program", + "review", + "href", + "phase", + "parameter" + ] + }, { "a": { "kind": "command", - "id": "create-dashboard" + "id": "audit-multizone" }, "b": { "kind": "command", - "id": "encode-reform" + "id": "write-tests" }, - "score": 0.1576, + "score": 0.1578, "shared_terms": [ - "reform", - "page", - "multi", - "arguments", - "implement", - "phase", - "skip", - "workflow" + "path", + "target", + "repo", + "test", + "app", + "config", + "bash", + "existing" ] }, { "a": { "kind": "agent", - "id": "prior-scores-finder" + "id": "dashboard-planner" }, "b": { "kind": "command", - "id": "text-to-reform" + "id": "new-tool" }, - "score": 0.1573, + "score": 0.1577, "shared_terms": [ - "reform", - "microsim", - "prior", - "bill", - "scores", - "reforms", - "same", - "not" + "dashboard", + "api", + "description", + "step", + "design", + "plan", + "page", + "purpose" ] }, { "a": { "kind": "agent", - "id": "model-corroborator" + "id": "prior-scores-finder" }, "b": { "kind": "command", - "id": "implement-structural" + "id": "text-to-reform" }, - "score": 0.1571, + "score": 0.1575, "shared_terms": [ "reform", - "original", - "model", - "issue", - "law", - "baseline", - "phase", - "analyze" + "microsim", + "prior", + "bill", + "scores", + "reforms", + "same", + "external" ] }, { "a": { "kind": "skill", - "id": "policyengine-design" + "id": "fix-pr" }, "b": { "kind": "agent", - "id": "dashboard-design-validator" + "id": "model-worker" }, - "score": 0.1567, + "score": 0.1574, "shared_terms": [ - "kit", - "css", - "design", - "app", - "font", - "var", - "colors", - "node" + "role", + "canonical", + "delegation", + "workflow", + "assigned", + "references", + "read", + "worker" ] }, { "a": { - "kind": "skill", - "id": "fix-pr" + "kind": "agent", + "id": "review-worker" }, "b": { "kind": "agent", - "id": "model-worker" + "id": "test-creator" }, - "score": 0.1566, + "score": 0.1573, "shared_terms": [ - "role", - "canonical", - "delegation", - "workflow", + "test", "assigned", - "references", + "program", + "model", + "needed", "read", - "worker" + "actual", + "development" ] }, { @@ -13833,7 +13980,7 @@ "kind": "command", "id": "audit-state-tax" }, - "score": 0.1562, + "score": 0.157, "shared_terms": [ "tax", "state", @@ -13845,67 +13992,46 @@ "python" ] }, - { - "a": { - "kind": "agent", - "id": "reform-comparator" - }, - "b": { - "kind": "command", - "id": "household-calc" - }, - "score": 0.1561, - "shared_terms": [ - "single", - "baseline", - "year", - "reform", - "microsim", - "version", - "cost", - "prior" - ] - }, { "a": { "kind": "skill", - "id": "policyengine-model-development" + "id": "policyengine-design" }, "b": { - "kind": "skill", - "id": "policyengine-uk" + "kind": "agent", + "id": "dashboard-design-validator" }, - "score": 0.1559, + "score": 0.1568, "shared_terms": [ - "household", - "entity", - "model", - "age", - "benunit", - "income", - "person", - "canada" + "kit", + "css", + "design", + "app", + "font", + "var", + "colors", + "node" ] }, { "a": { "kind": "agent", - "id": "review-worker" + "id": "dashboard-planner" }, "b": { - "kind": "agent", - "id": "test-creator" + "kind": "command", + "id": "text-to-reform" }, - "score": 0.1558, + "score": 0.1561, "shared_terms": [ - "test", - "assigned", - "program", - "model", - "needed", - "read", - "actual", - "development" + "natural", + "description", + "language", + "api", + "reform", + "provision", + "bill", + "analyze" ] }, { @@ -13917,11 +14043,11 @@ "kind": "command", "id": "deploy-dashboard" }, - "score": 0.1556, + "score": 0.1561, "shared_terms": [ "vercel", - "deploy", "url", + "deploy", "step", "zone", "host", @@ -13932,85 +14058,127 @@ { "a": { "kind": "skill", - "id": "policyengine-data" + "id": "policyengine" }, "b": { - "kind": "skill", - "id": "policyengine-uk" + "kind": "command", + "id": "create-dashboard" }, - "score": 0.1547, + "score": 0.1558, "shared_terms": [ - "microcosm", - "data", - "entity", - "person", - "unit", "household", - "see", - "national" + "ctc", + "reform", + "poverty", + "analysis", + "tax", + "income", + "page" + ] + }, + { + "a": { + "kind": "command", + "id": "create-dashboard" + }, + "b": { + "kind": "command", + "id": "encode-reform" + }, + "score": 0.1556, + "shared_terms": [ + "reform", + "page", + "multi", + "arguments", + "implement", + "phase", + "skip", + "workflow" ] }, { "a": { "kind": "skill", - "id": "policyengine-uk" + "id": "policyengine-model-development" }, "b": { - "kind": "agent", - "id": "dashboard-integrator" + "kind": "skill", + "id": "policyengine-uk" }, - "score": 0.1544, + "score": 0.1555, "shared_terms": [ "household", + "entity", + "model", + "age", + "benunit", "income", "person", - "unit", - "data", - "tax", - "age", - "spm" + "canada" ] }, { "a": { "kind": "agent", - "id": "dashboard-scaffold" + "id": "reform-comparator" }, "b": { "kind": "command", - "id": "audit-multizone" + "id": "household-calc" + }, + "score": 0.1555, + "shared_terms": [ + "single", + "baseline", + "year", + "reform", + "microsim", + "version", + "cost", + "prior" + ] + }, + { + "a": { + "kind": "skill", + "id": "policyengine-standards" + }, + "b": { + "kind": "agent", + "id": "structural-implementer" }, "score": 0.1543, "shared_terms": [ - "zone", - "dashboard", - "config", - "directory", - "next", - "working", - "host", - "repo" + "draft", + "changelog", + "repo", + "venv", + "ready", + "issue", + "committing", + "check" ] }, { "a": { - "kind": "agent", - "id": "dashboard-integrator" + "kind": "skill", + "id": "policyengine-data" }, "b": { - "kind": "command", - "id": "new-tool" + "kind": "skill", + "id": "policyengine-uk" }, - "score": 0.154, + "score": 0.1542, "shared_terms": [ - "api", - "const", - "function", - "import", - "countryid", - "export", - "return", - "create" + "microcosm", + "data", + "person", + "entity", + "unit", + "household", + "see", + "national" ] }, { @@ -14022,7 +14190,7 @@ "kind": "command", "id": "prior-scores" }, - "score": 0.154, + "score": 0.1539, "shared_terms": [ "reform", "analyze", @@ -14034,27 +14202,6 @@ "benchmark" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-cloud-costs" - }, - "b": { - "kind": "agent", - "id": "backend-builder" - }, - "score": 0.1539, - "shared_terms": [ - "modal", - "backend", - "containers", - "api", - "plan", - "dashboard", - "cloud", - "declare" - ] - }, { "a": { "kind": "agent", @@ -14076,46 +14223,25 @@ "expect" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-standards" - }, - "b": { - "kind": "agent", - "id": "structural-implementer" - }, - "score": 0.1535, - "shared_terms": [ - "draft", - "changelog", - "repo", - "venv", - "ready", - "issue", - "committing", - "check" - ] - }, { "a": { "kind": "agent", - "id": "prior-scores-finder" + "id": "issue-manager" }, "b": { - "kind": "agent", - "id": "report-logger" + "kind": "command", + "id": "audit-state-tax" }, - "score": 0.1533, + "score": 0.1529, "shared_terms": [ - "analyses", - "archive", - "verdict", - "country", - "local", - "jurisdiction", - "tracker", - "reform" + "state", + "number", + "url", + "abbreviation", + "search", + "mode", + "discover", + "phase" ] }, { @@ -14127,7 +14253,7 @@ "kind": "command", "id": "household-calc" }, - "score": 0.1527, + "score": 0.1529, "shared_terms": [ "reform", "level", @@ -14142,22 +14268,22 @@ { "a": { "kind": "agent", - "id": "issue-manager" + "id": "prior-scores-finder" }, "b": { - "kind": "command", - "id": "audit-state-tax" + "kind": "agent", + "id": "report-logger" }, - "score": 0.1522, + "score": 0.1528, "shared_terms": [ - "state", - "number", - "url", - "abbreviation", - "search", - "mode", - "discover", - "phase" + "analyses", + "archive", + "verdict", + "country", + "local", + "jurisdiction", + "tracker", + "reform" ] }, { @@ -14169,7 +14295,7 @@ "kind": "command", "id": "encode-reform" }, - "score": 0.1511, + "score": 0.1515, "shared_terms": [ "prefix", "test", @@ -14183,23 +14309,44 @@ }, { "a": { + "kind": "skill", + "id": "policyengine-model-development" + }, + "b": { "kind": "agent", - "id": "policy-text-researcher" + "id": "structural-implementer" + }, + "score": 0.1514, + "shared_terms": [ + "tests", + "parameter", + "changelog", + "formula", + "encoding", + "bracket", + "contrib", + "model" + ] + }, + { + "a": { + "kind": "skill", + "id": "policyengine-model-development" }, "b": { "kind": "agent", - "id": "reform-classifier" + "id": "pr-pusher" }, "score": 0.1511, "shared_terms": [ - "gov", - "ctc", - "reform", - "provisions", - "structural", - "amount", - "refundable", - "provision" + "changelog", + "tests", + "add", + "never", + "branch", + "run", + "repo", + "references" ] }, { @@ -14211,7 +14358,7 @@ "kind": "agent", "id": "reform-comparator" }, - "score": 0.151, + "score": 0.1511, "shared_terms": [ "prior", "anchor", @@ -14225,86 +14372,86 @@ }, { "a": { - "kind": "agent", - "id": "microsim-runner" + "kind": "command", + "id": "deploy-dashboard" }, "b": { "kind": "command", - "id": "household-calc" + "id": "new-tool" }, - "score": 0.1508, + "score": 0.1511, "shared_terms": [ - "reform", - "version", - "baseline", - "dict", - "microsimulation", - "api", - "raw", - "current" + "dashboard", + "app", + "modal", + "step", + "bash", + "embedding", + "bun", + "next" ] }, { "a": { - "kind": "skill", - "id": "policyengine-model-development" + "kind": "agent", + "id": "backend-builder" }, "b": { "kind": "agent", - "id": "pr-pusher" + "id": "microsim-runner" }, - "score": 0.1507, + "score": 0.1506, "shared_terms": [ - "changelog", - "add", - "tests", - "never", - "branch", - "run", - "repo", - "references" + "data", + "api", + "json", + "reform", + "client", + "results", + "economy", + "step" ] }, { "a": { "kind": "agent", - "id": "dashboard-plan-validator" + "id": "policy-text-researcher" }, "b": { - "kind": "command", - "id": "create-dashboard" + "kind": "agent", + "id": "reform-classifier" }, - "score": 0.1502, + "score": 0.1503, "shared_terms": [ - "dashboard", - "plan", - "multi", - "fail", - "path", - "name", - "api", - "validates" + "gov", + "ctc", + "reform", + "provisions", + "structural", + "amount", + "refundable", + "provision" ] }, { "a": { "kind": "skill", - "id": "policyengine-model-development" + "id": "policyengine" }, "b": { - "kind": "agent", - "id": "structural-implementer" + "kind": "skill", + "id": "policyengine-api-access" }, - "score": 0.15, + "score": 0.1502, "shared_terms": [ - "tests", - "parameter", - "changelog", - "formula", - "encoding", - "bracket", - "contrib", - "model" + "household", + "api", + "result", + "server", + "age", + "analysis", + "country", + "python" ] } ], @@ -17299,10 +17446,8 @@ "agents": [ "dashboard-architecture-validator" ], - "commands": [ - "new-tool" - ], - "total": 4 + "commands": [], + "total": 3 }, { "name": "policyengine-app-v2", @@ -17906,7 +18051,8 @@ "policyengine-api", "policyengine-api-access", "policyengine-app", - "policyengine-model-development" + "policyengine-model-development", + "policyengine-tools" ], "agents": [ "backend-builder", @@ -17920,7 +18066,7 @@ "deploy-dashboard", "new-tool" ], - "total": 13 + "total": 14 }, { "name": "policyengine-app", @@ -18166,14 +18312,13 @@ "generate-content", "household-calc", "implement-structural", - "new-tool", "prior-analysis", "prior-scores", "reform-pipeline", "text-to-reform", "write-tests" ], - "total": 31 + "total": 30 }, { "name": "policyengine-us", @@ -18256,14 +18401,13 @@ "generate-content", "household-calc", "implement-structural", - "new-tool", "prior-analysis", "reform-pipeline", "setup-verbs", "text-to-reform", "write-tests" ], - "total": 74 + "total": 73 }, { "name": "policyengine-ve", diff --git a/skills/policyengine-app/SKILL.md b/skills/policyengine-app/SKILL.md index a23fc12..cb6e9e6 100644 --- a/skills/policyengine-app/SKILL.md +++ b/skills/policyengine-app/SKILL.md @@ -99,7 +99,8 @@ server credential and forwards only the operations in `app/src/libs/publicApiRou anything else gets 404. New calculator code goes through that route, and an operation the app has not called before needs an allow-list entry in the same PR. Never add a browser call to api.policyengine.org. Dashboards use the website's dashboard API (`website/src/app/api/`) -instead; see policyengine-api-access. Verified shapes (the route keeps these paths): +instead; see policyengine-api-access. Verified shapes, as Public API paths (through the route, +each sits under `/api/policyengine`, for example `/api/policyengine/us/household/{id}`): - `GET {BASE_URL}/{country}/household/{id}` and `.../household/{id}/policy/{policyId}` — household calc - `POST {BASE_URL}/{country}/household` — create household diff --git a/skills/policyengine-tools/SKILL.md b/skills/policyengine-tools/SKILL.md index a47a5d1..ab11b23 100644 --- a/skills/policyengine-tools/SKILL.md +++ b/skills/policyengine-tools/SKILL.md @@ -141,8 +141,10 @@ Never paste ad-hoc computed numbers into source. Always: Python script → data the Public API. Always up to date; network latency. Never call the Public API (api.policyengine.org) from the page. See policyengine-api-access for the operations, polling, allowed origins and errors, and policyengine-api for the household shapes. -- **C — Custom Modal backend**: only when the dashboard API can't do it (society-wide microsim, - custom reform params, non-standard entities). Pattern below. A backend that itself calls the +- **C — Custom Modal backend**: only when the dashboard API can't do it: microsimulation output + its economy comparison doesn't give (custom breakdowns, datasets or years), structural + reforms that parameter changes can't express, or non-standard entities. A parameter reform's + economy-wide comparison with current law is Pattern B. Pattern below. A backend that itself calls the Public API needs its own Auth0 client and a cached server token (policyengine-api-access, `templates/public_api_token.py`); one that runs `policyengine` in its own process needs neither. diff --git a/targets/claude/agents/dashboard/backend-builder.md b/targets/claude/agents/dashboard/backend-builder.md index d433895..2fbdc64 100644 --- a/targets/claude/agents/dashboard/backend-builder.md +++ b/targets/claude/agents/dashboard/backend-builder.md @@ -132,12 +132,17 @@ Read the plan's endpoints and write the household and result types. Use `type` a ```typescript // types.ts -/** A household in PolicyEngine's situation format: values keyed by year */ +/** A group entity: its members, and its variables keyed by year */ +export type GroupEntity = { members: string[]; [variable: string]: unknown }; + +/** + * A household in PolicyEngine's situation format: values keyed by year. The group + * entities differ by country (US: tax_units, spm_units, families, marital_units, + * households; UK: benunits, households); read them from the country's metadata. + */ export type Household = { people: Record>>; - tax_units: Record; - spm_units: Record; - households: Record; + [groupEntities: string]: Record; }; /** The calculated household: the same shape, with the requested variables filled in */ @@ -156,7 +161,8 @@ import { createPolicyEngineApiClient } from '@policyengine/api-client'; import type { CalculatedHousehold, Household } from './types'; // The default base URL, https://www.policyengine.org, works from the dashboard's -// www.policyengine.org path, its own *.vercel.app host, its team previews and localhost. +// www.policyengine.org path, its team previews (*-policy-engine.vercel.app), localhost, and +// its own *.vercel.app host once website/src/data/appZoneRoutes.ts names it. const policyengine = createPolicyEngineApiClient(); export function calculate( @@ -191,7 +197,7 @@ export function useCalculation(countryId: 'us' | 'uk') { ### Step 4: Write Tests -Create `lib/api/__tests__/client.test.ts`. Build the client with `createPolicyEngineApiClient({ fetch: fakeFetch })` (or mock the module), so no test calls the network: +Create `lib/api/__tests__/client.test.ts`. `client.ts` builds its client when it loads, so mock the package (`vi.mock('@policyengine/api-client', …)`) before importing it; no test calls the network: - Test that request bodies are correctly structured - Test that `PolicyEngineApiError` from a refused request reaches the UI's error state - Test type conformance of expected response shapes diff --git a/targets/claude/agents/dashboard/dashboard-integrator.md b/targets/claude/agents/dashboard/dashboard-integrator.md index f07018e..2d306ab 100644 --- a/targets/claude/agents/dashboard/dashboard-integrator.md +++ b/targets/claude/agents/dashboard/dashboard-integrator.md @@ -106,6 +106,8 @@ function buildHouseholdDict(values: FormValues): Record { } ``` +For `data_pattern: policyengine-api`, pass `buildHouseholdDict(values)` to the backend-builder's `useCalculation(countryId)` mutation: `@policyengine/api-client` takes the country and the household, not `buildHouseholdRequest`'s shape. Its result is the calculated household itself, keyed by entity, not `HouseholdSimulationResult`. + ### Step 3: Build Response Transformers Create functions that extract chart-ready data from API responses: diff --git a/targets/claude/agents/dashboard/dashboard-scaffold.md b/targets/claude/agents/dashboard/dashboard-scaffold.md index 5b46caf..04242f4 100644 --- a/targets/claude/agents/dashboard/dashboard-scaffold.md +++ b/targets/claude/agents/dashboard/dashboard-scaffold.md @@ -31,7 +31,8 @@ Generates complete project structure from an approved `plan.yaml` into the curre 1. `Skill: policyengine-tools` 2. `Skill: policyengine-design` 3. `Skill: policyengine-standards` -4. `Skill: policyengine-cloud-costs` (if custom backend) +4. `Skill: policyengine-api-access` (if `data_pattern: policyengine-api`, or a custom backend that calls the Public API) +5. `Skill: policyengine-cloud-costs` (if custom backend) **CRITICAL: The `policyengine-tools` skill's "Required stack" defines the project structure, framework, and styling approach. Follow its specifications for project scaffolding. Where this document conflicts with the spec, THE SPEC WINS.** diff --git a/targets/claude/commands/new-tool.md b/targets/claude/commands/new-tool.md index 00c83e3..9f5f05d 100644 --- a/targets/claude/commands/new-tool.md +++ b/targets/claude/commands/new-tool.md @@ -19,7 +19,7 @@ Ask the user for: 3. **Data pattern** — how the tool gets model results: - **A) Precomputed** — Static JSON or CSV shipped with the app (best for finite parameter spaces) - **B) Dashboard API** — The page calls www.policyengine.org's dashboard API through `@policyengine/api-client` (best for household calculators). Never call `api.policyengine.org` from the page: the Public API is becoming callable only by PolicyEngine's servers (policyengine-api-access skill) - - **C) Custom Modal API** — Python serverless function with the top-level `policyengine[us]` / `policyengine[uk]` package (best when main API doesn't support needed variables/reforms) + - **C) Custom Modal API** — Python serverless function with the top-level `policyengine[us]` / `policyengine[uk]` package (best when the dashboard API doesn't cover it: structural reforms, microsimulation output beyond its economy comparison, or variables it doesn't return) 4. **Brief description** of what the tool calculates ## Step 2: Create the project @@ -156,9 +156,9 @@ export default function Home() { ## Step 4: Data pattern boilerplate -> **Prefer Pattern B** (the dashboard API) unless the tool needs microsimulation, -> custom reforms, or variables not in the API. Pattern C is significantly more complex -> and should be the last resort. +> **Prefer Pattern B** (the dashboard API) unless the tool needs structural reforms, +> microsimulation output beyond the dashboard API's economy comparison, or variables it +> doesn't return. Pattern C is significantly more complex and should be the last resort. Based on the user's choice, add the appropriate data fetching code. diff --git a/tests/test_public_api_browser_guidance.py b/tests/test_public_api_browser_guidance.py index 1ae0f5e..c1cc7e6 100644 --- a/tests/test_public_api_browser_guidance.py +++ b/tests/test_public_api_browser_guidance.py @@ -27,22 +27,38 @@ REPO_ROOT = Path(__file__).resolve().parent.parent SCAN_DIRS = ("skills", "targets", "docs") -TEXT_SUFFIXES = {".md", ".json", ".yaml", ".yml", ".py", ".sh", ".ts", ".tsx", ".js", ".mjs"} - -BROWSER_LANGUAGES = {"ts", "tsx", "js", "jsx", "javascript", "typescript", "mjs"} +TEXT_SUFFIXES = {".md", ".json", ".yaml", ".yml", ".py", ".sh", ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".html"} +BROWSER_FILE_SUFFIXES = {".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".html", ".vue", ".svelte"} + +BROWSER_LANGUAGES = { + "ts", "tsx", "js", "jsx", "javascript", "typescript", "mjs", "cjs", "html", "htm", "vue", "svelte", "astro", +} +# A fenced example of server-side TypeScript or JavaScript may name the Public API +# when the line before its fence is this marker. +SERVER_CODE_MARKER = "" # The Public API only: not household.api.policyengine.org (the household API) or # v2.api.policyengine.org (the v2 alpha), hence the left boundary. PUBLIC_API_HOST = re.compile( r"(?`{3,}|~{3,})(?P[A-Za-z0-9_+-]*)[^\n]*\n(?P.*?)^[ \t]*(?P=fence)[ \t]*$", + re.DOTALL | re.MULTILINE, ) -FENCE = re.compile(r"^[ \t]*```([A-Za-z0-9_+-]*)[^\n]*\n(.*?)^[ \t]*```", re.DOTALL | re.MULTILINE) PUBLIC_PREFIX_SET_TO_PUBLIC_API = re.compile( - r"\b(?:NEXT_PUBLIC|VITE)_[A-Z0-9_]+\s*[=:]\s*[\"'`]?https?://" + r"\b(?:NEXT_PUBLIC|VITE|REACT_APP)_[A-Z0-9_]+[\"']?\s*(?:[=:]|\|\|)\s*[\"'`]?https?://" r"(?:api\.policyengine\.org|(?:[a-z0-9-]+---)?policyengine-api[a-z0-9-]*\.[a-z0-9.-]*run\.app)" ) +# A public-prefix name that holds a secret, or that is named for the Public API's +# address or server client. A browser's own sign-in settings (VITE_AUTH0_DOMAIN, +# VITE_AUTH0_CLIENT_ID, NEXT_PUBLIC_AUTH0_AUDIENCE) and other services' public +# tokens are public by design. PUBLIC_PREFIX_CREDENTIAL = re.compile( - r"\b(?:NEXT_PUBLIC|VITE)_[A-Z0-9_]*(?:AUTH0|SECRET|TOKEN|CREDENTIAL)[A-Z0-9_]*" + r"\b(?:NEXT_PUBLIC|VITE|REACT_APP)_(?=[A-Z0-9_]*(?:SECRET|PASSWORD|PRIVATE_KEY|CREDENTIAL" + r"|(? list[Path]: def browser_blocks_naming_the_public_api(text: str) -> list[str]: - return [ - body - for language, body in FENCE.findall(text) - if language.lower() in BROWSER_LANGUAGES and PUBLIC_API_HOST.search(body) - ] + offenders: list[str] = [] + for block in FENCE.finditer(text): + line_before = text[: block.start()].rstrip("\n").rsplit("\n", 1)[-1] + if SERVER_CODE_MARKER in line_before: + continue + body = block.group("body") + if block.group("language").lower() in BROWSER_LANGUAGES: + if PUBLIC_API_HOST.search(body): + offenders.append(body) + else: + # A Markdown or text block can hold a nested example. + offenders.extend(browser_blocks_naming_the_public_api(body)) + return offenders def test_no_browser_language_example_names_the_public_api() -> None: @@ -90,6 +114,16 @@ def test_no_browser_language_example_names_the_public_api() -> None: assert offenders == [], f"browser-language examples that call the Public API: {offenders}" +def test_no_code_file_in_the_catalog_names_the_public_api() -> None: + # Templates and examples shipped as files (for example under skills/*/templates/). + offenders = [ + path.relative_to(REPO_ROOT).as_posix() + for path in scanned_files() + if path.suffix in BROWSER_FILE_SUFFIXES and PUBLIC_API_HOST.search(path.read_text()) + ] + assert offenders == [] + + def test_no_public_prefix_variable_holds_the_public_api_or_a_credential() -> None: offenders = [] for path in scanned_files(): From 68e4eaa3c1b4281c9ecec7f8a07cd976a9c02ac2 Mon Sep 17 00:00:00 2001 From: Anthony Volk <14987227+anth-volk@users.noreply.github.com> Date: Wed, 11 Nov 2026 00:25:43 +0400 Subject: [PATCH 13/16] Test the round-2 review's findings - The token template's Modal wiring adds its module to the image, which Modal 1.0 no longer does on its own; its settings never print the client secret; it keeps working when the shared store fails; a short token is replaced halfway through its life. - The skill says the dashboard API's calculation returns only the variables the household asks for, with null for the year. - The guard catches a fence with a space before its language, ?? fallbacks and unqualified public-prefix token and key names, scans .vue and .svelte files, and accepts the browser sign-in audience and a qualified Mapbox access token. - The integrator varies a household in one calculation with axes, types buildHouseholdDict as Household, and CONTRIBUTING.md documents the server-code marker. Co-Authored-By: Claude Opus 5.5 --- tests/test_api_access_skill.py | 59 +++++++++++++++++++++++ tests/test_public_api_browser_guidance.py | 36 ++++++++++++++ 2 files changed, 95 insertions(+) diff --git a/tests/test_api_access_skill.py b/tests/test_api_access_skill.py index e553bcd..5ef6f02 100644 --- a/tests/test_api_access_skill.py +++ b/tests/test_api_access_skill.py @@ -466,3 +466,62 @@ def test_errors_table_tells_a_refused_server_token_from_a_refused_user_token() - assert len(rows_401) == 2, "the errors table needs a 401 row for each credential" assert any('error="invalid_token"' in row and "PolicyEngine-User-Authorization" in row for row in rows_401) assert not any("retry once with a new" in row for row in rows_401) + + +# --- Review round 2 ------------------------------------------------------------ + + +def test_template_modal_wiring_adds_the_module_to_the_image() -> None: + # Modal 1.0 stopped copying imported local modules into containers, so the + # image must add the template's module, or the function fails at start. + token_module = load_token_module() + docstring = token_module.__doc__ + assert 'add_local_python_source("public_api_token")' in docstring + assert "image=" in docstring + + +def test_template_settings_never_print_the_client_secret() -> None: + token_module = load_token_module() + settings = make_settings(token_module) + assert "placeholder-client-secret" not in repr(settings) + assert settings.client_secret == "placeholder-client-secret" + + +def test_template_keeps_working_when_the_shared_store_fails() -> None: + token_module = load_token_module() + + class FailingStore: + def get(self, key, default=None): # noqa: ANN001, ANN201 + raise ConnectionError("store unavailable") + + def __setitem__(self, key, value): # noqa: ANN001 + raise ConnectionError("store unavailable") + + opener = RecordingOpener() + tokens = token_module.PublicApiTokenProvider( + make_settings(token_module), shared_store=FailingStore(), clock=Clock(), opener=opener + ) + assert [tokens.access_token() for _ in range(3)] == ["token-1"] * 3 + assert len(opener.token_requests) == 1 + + +def test_template_replaces_a_short_token_halfway_through_its_life() -> None: + token_module = load_token_module() + clock = Clock() + opener = RecordingOpener(token_lifetime_seconds=400) + tokens = token_module.PublicApiTokenProvider( + make_settings(token_module), shared_store={}, clock=clock, opener=opener + ) + assert tokens.access_token() == "token-1" + clock.now += 199 + assert tokens.access_token() == "token-1" + clock.now += 2 + assert tokens.access_token() == "token-2" + + +def test_skill_says_the_calculation_returns_only_the_variables_asked_for() -> None: + # The dashboard API's calculation is API v1's /{country}/calculate, which adds no + # omitted variables (add_missing=False): outputs are asked for with null. + text = skill_text() + assert "/{country}/calculate" in text + assert "with `null` for the year" in text diff --git a/tests/test_public_api_browser_guidance.py b/tests/test_public_api_browser_guidance.py index c1cc7e6..8938748 100644 --- a/tests/test_public_api_browser_guidance.py +++ b/tests/test_public_api_browser_guidance.py @@ -146,6 +146,7 @@ def test_guards_catch_the_patterns_they_name() -> None: "```svelte\n\n```\n", "```cjs\nfetch('https://api.policyengine.org/uk/metadata')\n```\n", "````markdown\nAn example:\n```ts\nfetch('https://api.policyengine.org/us/metadata')\n```\n````\n", + "``` ts\nfetch('https://api.policyengine.org/us/metadata')\n```\n", ] for example in browser_examples: assert browser_blocks_naming_the_public_api(example), example @@ -167,6 +168,12 @@ def test_guards_catch_the_patterns_they_name() -> None: "VITE_PE_API_KEY", "VITE_AUTH0_CLIENT_SECRET", "VITE_API_TOKEN_SECRET", + "`process.env.NEXT_PUBLIC_API_URL ?? 'https://api.policyengine.org'`", + "NEXT_PUBLIC_API_KEY", + "NEXT_PUBLIC_API_TOKEN", + "NEXT_PUBLIC_BEARER_TOKEN", + "VITE_ACCESS_TOKEN", + "VITE_POLICYENGINE_TOKEN", ): assert PUBLIC_PREFIX_SET_TO_PUBLIC_API.search(unsafe) or PUBLIC_PREFIX_CREDENTIAL.search(unsafe), unsafe for safe in ( @@ -179,6 +186,10 @@ def test_guards_catch_the_patterns_they_name() -> None: "VITE_AUTH0_CLIENT_ID", "NEXT_PUBLIC_AUTH0_AUDIENCE", "NEXT_PUBLIC_MAPBOX_TOKEN", + "NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN", + # The browser sign-in audience is API v1's identifier, not an address to call. + "NEXT_PUBLIC_AUTH0_AUDIENCE=https://api.policyengine.org/", + "VITE_AUTH0_AUDIENCE: 'https://api.policyengine.org/'", ): assert not PUBLIC_PREFIX_SET_TO_PUBLIC_API.search(safe), safe assert not PUBLIC_PREFIX_CREDENTIAL.search(safe), safe @@ -230,3 +241,28 @@ def test_tools_skill_pattern_b_uses_the_dashboard_api() -> None: assert pattern_b, "the tools skill has no Pattern B entry" assert "@policyengine/api-client" in pattern_b.group(0) assert "https://api.policyengine.org" not in pattern_b.group(0) + + +def test_vue_and_svelte_files_are_scanned() -> None: + assert {".vue", ".svelte"} <= TEXT_SUFFIXES + + +INTEGRATOR = REPO_ROOT / "targets/claude/agents/dashboard/dashboard-integrator.md" + + +def test_integrator_varies_a_household_in_one_calculation() -> None: + # The dashboard API allows 30 household calculations a minute from one address, + # so a chart over 20 incomes is one calculation with axes, not 20. + step = INTEGRATOR.read_text().split("### Step 6", 1) + assert len(step) == 2 + variation = step[1].split("\n### ", 1)[0] + assert "axes" in variation + assert "30 household calculations a minute" in variation + + +def test_integrator_types_the_household_for_the_client() -> None: + assert "`buildHouseholdDict` returns `Household`" in INTEGRATOR.read_text() + + +def test_contributing_documents_the_server_code_marker() -> None: + assert SERVER_CODE_MARKER in (REPO_ROOT / "CONTRIBUTING.md").read_text() From 95936b482cb92633b35e3c4295009dde736f4efa Mon Sep 17 00:00:00 2001 From: Anthony Volk <14987227+anth-volk@users.noreply.github.com> Date: Wed, 11 Nov 2026 00:27:53 +0400 Subject: [PATCH 14/16] Fix the round-2 review's findings - Token template: the Modal wiring adds the module to the image with add_local_python_source, which Modal 1.0 no longer does on its own; the settings' repr leaves out the client secret; the opener has a Protocol type, and call_public_api lists every error it raises. - Skill: the dashboard API's calculation adds no omitted variables, so outputs are asked for with null, and a chart varies an input in one calculation with axes, not one per point (30 a minute); the polling waits match the merged client; the first 401 row also names a user route that received no forwarded user credential. - Integrator: a variation chart for the policyengine-api pattern is one calculation with axes, buildHouseholdDict returns Household, and the transformers read the calculated household's own shape. backend-builder's Household type takes axes and any entity group; the scaffold declares client types as type aliases. - Guard: a fence may have a space before its language, ?? fallbacks and unqualified token and key names are caught, .vue and .svelte files are scanned, and *_AUDIENCE names, which hold the sign-in audience, are accepted. The skill's own test module drops its divergent copy of these checks; the guard already scans every skill. CONTRIBUTING.md documents the rule and the marker. - The API skill cites fastapi_routes for its public routes, and the dashboard manifest is rebuilt. Co-Authored-By: Claude Opus 5.5 --- CONTRIBUTING.md | 5 + dashboard/src/data/manifest.json | 1839 +++++++++-------- skills/policyengine-api-access/SKILL.md | 15 +- .../templates/public_api_token.py | 32 +- skills/policyengine-api/SKILL.md | 3 +- .../agents/dashboard/backend-builder.md | 13 +- .../agents/dashboard/dashboard-integrator.md | 26 +- .../agents/dashboard/dashboard-scaffold.md | 2 +- tests/test_api_access_skill.py | 41 +- tests/test_public_api_browser_guidance.py | 21 +- 10 files changed, 1040 insertions(+), 957 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e92a79e..6151c24 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -49,6 +49,11 @@ See [skills/README.md](skills/README.md) for the full list. The load-bearing one Deliberate history notes — and explicitly-scoped engine-development examples of patterns banned for analysis — take `` on the preceding line. 4. Descriptions stay ≤1024 characters (Codex hard limit). +5. **No browser call to the Public API**: `tests/test_public_api_browser_guidance.py` fails on a + TypeScript, JavaScript, HTML, Vue or Svelte example that names `api.policyengine.org` or its + Cloud Run addresses, and on a `NEXT_PUBLIC_*`, `VITE_*` or `REACT_APP_*` variable that holds + its address or a credential (see the policyengine-api-access skill). A server-side example + that must name it takes `` on the line before its fence. ## Testing diff --git a/dashboard/src/data/manifest.json b/dashboard/src/data/manifest.json index 5b89895..314e437 100644 --- a/dashboard/src/data/manifest.json +++ b/dashboard/src/data/manifest.json @@ -1,5 +1,5 @@ { - "generated_at": "2026-11-10T19:59:43.915872Z", + "generated_at": "2026-11-10T20:27:31.433668Z", "counts": { "skill": 25, "agent": 36, @@ -339,7 +339,7 @@ "use_instead": [], "registry_notes": "Recommended for the listed scope.", "references": {}, - "body_length": 5237 + "body_length": 5327 }, { "id": "policyengine-api-access", @@ -376,7 +376,7 @@ "use_instead": [], "registry_notes": "Recommended for the listed scope.", "references": {}, - "body_length": 18550 + "body_length": 19369 }, { "id": "policyengine-app", @@ -2189,7 +2189,7 @@ "deploy-dashboard" ] }, - "body_length": 23735 + "body_length": 23770 }, { "id": "dashboard-architecture-validator", @@ -2340,7 +2340,7 @@ "policyengine-tools" ] }, - "body_length": 6906 + "body_length": 8220 }, { "id": "dashboard-plan-validator", @@ -2512,7 +2512,7 @@ "deploy-dashboard" ] }, - "body_length": 26473 + "body_length": 26646 }, { "id": "frontend-builder", @@ -7365,7 +7365,7 @@ "kind": "command", "id": "implement-structural" }, - "score": 0.649, + "score": 0.6489, "shared_terms": [ "structural", "backlog", @@ -7386,7 +7386,7 @@ "kind": "command", "id": "generate-content" }, - "score": 0.6296, + "score": 0.6295, "shared_terms": [ "social", "content", @@ -7419,27 +7419,6 @@ "blog" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-api" - }, - "b": { - "kind": "skill", - "id": "policyengine-api-access" - }, - "score": 0.6197, - "shared_terms": [ - "api", - "client", - "public", - "server", - "household", - "org", - "credential", - "country" - ] - }, { "a": { "kind": "agent", @@ -7449,7 +7428,7 @@ "kind": "agent", "id": "review-worker" }, - "score": 0.6191, + "score": 0.619, "shared_terms": [ "your", "assigned", @@ -7461,6 +7440,27 @@ "test" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-api" + }, + "b": { + "kind": "skill", + "id": "policyengine-api-access" + }, + "score": 0.6147, + "shared_terms": [ + "api", + "client", + "public", + "server", + "household", + "org", + "credential", + "country" + ] + }, { "a": { "kind": "skill", @@ -7470,7 +7470,7 @@ "kind": "skill", "id": "policyengine-uk" }, - "score": 0.6021, + "score": 0.6019, "shared_terms": [ "household", "unit", @@ -7491,7 +7491,7 @@ "kind": "command", "id": "prior-scores" }, - "score": 0.6004, + "score": 0.6005, "shared_terms": [ "scorekeepers", "scores", @@ -7554,7 +7554,7 @@ "kind": "skill", "id": "policyengine-us" }, - "score": 0.5675, + "score": 0.5673, "shared_terms": [ "unit", "tax", @@ -7617,7 +7617,7 @@ "kind": "skill", "id": "policyengine-us" }, - "score": 0.5311, + "score": 0.5309, "shared_terms": [ "unit", "tax", @@ -7701,7 +7701,7 @@ "kind": "agent", "id": "review-worker" }, - "score": 0.4804, + "score": 0.4805, "shared_terms": [ "review", "canonical", @@ -7713,6 +7713,27 @@ "source" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-prior-scores" + }, + "b": { + "kind": "agent", + "id": "prior-scores-finder" + }, + "score": 0.4756, + "shared_terms": [ + "prior", + "tier", + "scores", + "scripts", + "reform", + "scored", + "python3", + "external" + ] + }, { "a": { "kind": "skill", @@ -7734,27 +7755,6 @@ "vercel" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-prior-scores" - }, - "b": { - "kind": "agent", - "id": "prior-scores-finder" - }, - "score": 0.4755, - "shared_terms": [ - "prior", - "tier", - "scores", - "scripts", - "reform", - "scored", - "python3", - "external" - ] - }, { "a": { "kind": "agent", @@ -7785,7 +7785,7 @@ "kind": "command", "id": "create-new-component" }, - "score": 0.4603, + "score": 0.4602, "shared_terms": [ "component", "kit", @@ -7869,7 +7869,7 @@ "kind": "agent", "id": "dashboard-integrator" }, - "score": 0.4263, + "score": 0.4254, "shared_terms": [ "api", "data", @@ -7878,7 +7878,7 @@ "pattern", "step", "dashboard", - "builder" + "plan" ] }, { @@ -7890,16 +7890,16 @@ "kind": "agent", "id": "dashboard-integrator" }, - "score": 0.4203, + "score": 0.4177, "shared_terms": [ "api", "client", "household", "dashboard", "backend", - "const", "request", - "result" + "result", + "through" ] }, { @@ -7932,7 +7932,7 @@ "kind": "agent", "id": "multizone-validator" }, - "score": 0.4041, + "score": 0.4042, "shared_terms": [ "zone", "basepath", @@ -7974,7 +7974,7 @@ "kind": "command", "id": "prior-scores" }, - "score": 0.4011, + "score": 0.4009, "shared_terms": [ "tier", "prior", @@ -7995,7 +7995,7 @@ "kind": "command", "id": "prior-analysis" }, - "score": 0.3971, + "score": 0.3972, "shared_terms": [ "analyses", "prior", @@ -8016,7 +8016,7 @@ "kind": "command", "id": "write-tests" }, - "score": 0.3925, + "score": 0.3924, "shared_terms": [ "test", "tests", @@ -8037,7 +8037,7 @@ "kind": "agent", "id": "frontend-builder" }, - "score": 0.3834, + "score": 0.3833, "shared_terms": [ "kit", "chart", @@ -8049,6 +8049,27 @@ "tailwind" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-api" + }, + "b": { + "kind": "agent", + "id": "dashboard-integrator" + }, + "score": 0.3827, + "shared_terms": [ + "api", + "household", + "client", + "data", + "values", + "response", + "dashboard", + "request" + ] + }, { "a": { "kind": "agent", @@ -8058,7 +8079,7 @@ "kind": "command", "id": "write-tests" }, - "score": 0.3817, + "score": 0.381, "shared_terms": [ "test", "tests", @@ -8070,27 +8091,6 @@ "component" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-api" - }, - "b": { - "kind": "agent", - "id": "dashboard-integrator" - }, - "score": 0.3787, - "shared_terms": [ - "api", - "client", - "household", - "data", - "values", - "response", - "dashboard", - "request" - ] - }, { "a": { "kind": "skill", @@ -8142,7 +8142,7 @@ "kind": "command", "id": "text-to-reform" }, - "score": 0.3701, + "score": 0.37, "shared_terms": [ "reform", "provision", @@ -8163,7 +8163,7 @@ "kind": "command", "id": "household-calc" }, - "score": 0.3661, + "score": 0.3657, "shared_terms": [ "household", "income", @@ -8205,7 +8205,7 @@ "kind": "agent", "id": "review-worker" }, - "score": 0.3612, + "score": 0.3613, "shared_terms": [ "review", "canonical", @@ -8217,27 +8217,6 @@ "independent" ] }, - { - "a": { - "kind": "agent", - "id": "dashboard-design-validator" - }, - "b": { - "kind": "agent", - "id": "frontend-builder" - }, - "score": 0.3539, - "shared_terms": [ - "kit", - "components", - "app", - "design", - "component", - "tsx", - "font", - "css" - ] - }, { "a": { "kind": "agent", @@ -8259,6 +8238,27 @@ "arpa" ] }, + { + "a": { + "kind": "agent", + "id": "dashboard-design-validator" + }, + "b": { + "kind": "agent", + "id": "frontend-builder" + }, + "score": 0.3538, + "shared_terms": [ + "kit", + "components", + "app", + "design", + "component", + "tsx", + "font", + "css" + ] + }, { "a": { "kind": "skill", @@ -8268,7 +8268,7 @@ "kind": "agent", "id": "model-worker" }, - "score": 0.3522, + "score": 0.3523, "shared_terms": [ "encode", "coordinator", @@ -8331,7 +8331,7 @@ "kind": "skill", "id": "policyengine-user-guide" }, - "score": 0.3473, + "score": 0.3471, "shared_terms": [ "household", "income", @@ -8340,7 +8340,7 @@ "reform", "poverty", "people", - "net" + "employment" ] }, { @@ -8394,7 +8394,7 @@ "kind": "command", "id": "new-tool" }, - "score": 0.342, + "score": 0.3419, "shared_terms": [ "kit", "css", @@ -8469,27 +8469,6 @@ "only" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-user-guide" - }, - "b": { - "kind": "command", - "id": "household-calc" - }, - "score": 0.3323, - "shared_terms": [ - "household", - "reform", - "income", - "population", - "benefits", - "net", - "marginal", - "taxes" - ] - }, { "a": { "kind": "agent", @@ -8511,6 +8490,27 @@ "horizon" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-user-guide" + }, + "b": { + "kind": "command", + "id": "household-calc" + }, + "score": 0.332, + "shared_terms": [ + "household", + "reform", + "income", + "population", + "benefits", + "marginal", + "net", + "taxes" + ] + }, { "a": { "kind": "agent", @@ -8625,7 +8625,7 @@ "kind": "command", "id": "deploy-dashboard" }, - "score": 0.3252, + "score": 0.3251, "shared_terms": [ "modal", "host", @@ -8658,6 +8658,27 @@ "release" ] }, + { + "a": { + "kind": "agent", + "id": "dashboard-integrator" + }, + "b": { + "kind": "agent", + "id": "dashboard-scaffold" + }, + "score": 0.3199, + "shared_terms": [ + "api", + "client", + "backend", + "dashboard", + "data", + "components", + "plan", + "structure" + ] + }, { "a": { "kind": "agent", @@ -8688,7 +8709,7 @@ "kind": "skill", "id": "policyengine-us" }, - "score": 0.3164, + "score": 0.3159, "shared_terms": [ "tax", "unit", @@ -8709,7 +8730,7 @@ "kind": "command", "id": "reform-pipeline" }, - "score": 0.3161, + "score": 0.3155, "shared_terms": [ "bill", "reform", @@ -8730,7 +8751,7 @@ "kind": "command", "id": "text-to-reform" }, - "score": 0.3156, + "score": 0.3155, "shared_terms": [ "bill", "reform", @@ -8751,7 +8772,7 @@ "kind": "agent", "id": "pr-pusher" }, - "score": 0.3138, + "score": 0.3139, "shared_terms": [ "repo", "branch", @@ -8763,27 +8784,6 @@ "repository" ] }, - { - "a": { - "kind": "agent", - "id": "dashboard-integrator" - }, - "b": { - "kind": "agent", - "id": "dashboard-scaffold" - }, - "score": 0.3138, - "shared_terms": [ - "api", - "client", - "backend", - "dashboard", - "data", - "components", - "structure", - "pattern" - ] - }, { "a": { "kind": "agent", @@ -8835,7 +8835,7 @@ "kind": "agent", "id": "dashboard-planner" }, - "score": 0.3065, + "score": 0.3066, "shared_terms": [ "dashboard", "data", @@ -8898,7 +8898,7 @@ "kind": "skill", "id": "policyengine-tools" }, - "score": 0.3041, + "score": 0.304, "shared_terms": [ "css", "theme", @@ -8961,7 +8961,7 @@ "kind": "command", "id": "household-calc" }, - "score": 0.301, + "score": 0.3005, "shared_terms": [ "household", "income", @@ -9045,7 +9045,7 @@ "kind": "agent", "id": "review-worker" }, - "score": 0.2956, + "score": 0.2957, "shared_terms": [ "review", "canonical", @@ -9108,7 +9108,7 @@ "kind": "command", "id": "text-to-reform" }, - "score": 0.2921, + "score": 0.2919, "shared_terms": [ "reform", "dict", @@ -9123,34 +9123,13 @@ { "a": { "kind": "skill", - "id": "policyengine-api" + "id": "policyengine-content" }, "b": { - "kind": "agent", - "id": "backend-builder" + "kind": "skill", + "id": "policyengine-design" }, - "score": 0.2914, - "shared_terms": [ - "api", - "client", - "dashboard", - "public", - "data", - "json", - "simulation", - "cloud" - ] - }, - { - "a": { - "kind": "skill", - "id": "policyengine-content" - }, - "b": { - "kind": "skill", - "id": "policyengine-design" - }, - "score": 0.2906, + "score": 0.2906, "shared_terms": [ "theme", "teal", @@ -9204,6 +9183,27 @@ "host" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-api" + }, + "b": { + "kind": "agent", + "id": "backend-builder" + }, + "score": 0.2897, + "shared_terms": [ + "api", + "client", + "public", + "dashboard", + "json", + "data", + "simulation", + "cloud" + ] + }, { "a": { "kind": "skill", @@ -9234,7 +9234,7 @@ "kind": "command", "id": "new-tool" }, - "score": 0.2869, + "score": 0.2868, "shared_terms": [ "kit", "app", @@ -9255,7 +9255,7 @@ "kind": "agent", "id": "dashboard-architecture-validator" }, - "score": 0.2864, + "score": 0.2863, "shared_terms": [ "app", "router", @@ -9276,7 +9276,7 @@ "kind": "command", "id": "text-to-reform" }, - "score": 0.2856, + "score": 0.2857, "shared_terms": [ "reform", "dict", @@ -9297,7 +9297,7 @@ "kind": "command", "id": "prior-scores" }, - "score": 0.2845, + "score": 0.2844, "shared_terms": [ "shape", "external", @@ -9318,7 +9318,7 @@ "kind": "skill", "id": "policyengine-user-guide" }, - "score": 0.2841, + "score": 0.2838, "shared_terms": [ "household", "income", @@ -9339,7 +9339,7 @@ "kind": "agent", "id": "reform-comparator" }, - "score": 0.2815, + "score": 0.2814, "shared_terms": [ "prior", "year", @@ -9360,7 +9360,7 @@ "kind": "skill", "id": "policyengine-uk" }, - "score": 0.2807, + "score": 0.2803, "shared_terms": [ "household", "canada", @@ -9381,7 +9381,7 @@ "kind": "agent", "id": "frontend-builder" }, - "score": 0.2798, + "score": 0.2797, "shared_terms": [ "kit", "app", @@ -9423,7 +9423,7 @@ "kind": "command", "id": "text-to-reform" }, - "score": 0.2783, + "score": 0.2777, "shared_terms": [ "bill", "reform", @@ -9444,7 +9444,7 @@ "kind": "command", "id": "backdate-program" }, - "score": 0.2758, + "score": 0.276, "shared_terms": [ "worktree", "root", @@ -9486,7 +9486,7 @@ "kind": "command", "id": "reform-pipeline" }, - "score": 0.2744, + "score": 0.2739, "shared_terms": [ "bill", "reform", @@ -9570,7 +9570,7 @@ "kind": "agent", "id": "reform-comparator" }, - "score": 0.2688, + "score": 0.2687, "shared_terms": [ "version", "result", @@ -9654,7 +9654,7 @@ "kind": "command", "id": "text-to-reform" }, - "score": 0.2657, + "score": 0.2656, "shared_terms": [ "reform", "dict", @@ -9675,7 +9675,7 @@ "kind": "agent", "id": "frontend-builder" }, - "score": 0.2638, + "score": 0.2637, "shared_terms": [ "app", "kit", @@ -9696,7 +9696,7 @@ "kind": "command", "id": "household-calc" }, - "score": 0.2634, + "score": 0.263, "shared_terms": [ "household", "tax", @@ -9729,6 +9729,27 @@ "head" ] }, + { + "a": { + "kind": "agent", + "id": "ci-fixer" + }, + "b": { + "kind": "command", + "id": "write-tests" + }, + "score": 0.2616, + "shared_terms": [ + "test", + "tests", + "files", + "run", + "file", + "fix", + "failures", + "write" + ] + }, { "a": { "kind": "skill", @@ -9750,27 +9771,6 @@ "org" ] }, - { - "a": { - "kind": "agent", - "id": "ci-fixer" - }, - "b": { - "kind": "command", - "id": "write-tests" - }, - "score": 0.2615, - "shared_terms": [ - "test", - "tests", - "files", - "run", - "file", - "fix", - "failures", - "write" - ] - }, { "a": { "kind": "agent", @@ -9843,7 +9843,7 @@ "kind": "agent", "id": "dashboard-scaffold" }, - "score": 0.2581, + "score": 0.258, "shared_terms": [ "dashboard", "api", @@ -9864,7 +9864,7 @@ "kind": "command", "id": "text-to-reform" }, - "score": 0.258, + "score": 0.2578, "shared_terms": [ "reform", "scorekeepers", @@ -9885,7 +9885,7 @@ "kind": "command", "id": "analyze-policy" }, - "score": 0.2565, + "score": 0.2566, "shared_terms": [ "log", "archive", @@ -9927,7 +9927,7 @@ "kind": "command", "id": "create-new-component" }, - "score": 0.2562, + "score": 0.2561, "shared_terms": [ "app", "component", @@ -9948,7 +9948,7 @@ "kind": "agent", "id": "frontend-builder" }, - "score": 0.2553, + "score": 0.2552, "shared_terms": [ "component", "plan", @@ -9969,7 +9969,7 @@ "kind": "command", "id": "text-to-reform" }, - "score": 0.2547, + "score": 0.2546, "shared_terms": [ "reform", "preset", @@ -9990,7 +9990,7 @@ "kind": "command", "id": "encode-reform" }, - "score": 0.2542, + "score": 0.2543, "shared_terms": [ "prefix", "arguments", @@ -10053,7 +10053,7 @@ "kind": "agent", "id": "frontend-builder" }, - "score": 0.2527, + "score": 0.2529, "shared_terms": [ "kit", "plan", @@ -10233,6 +10233,27 @@ "next" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine" + }, + "b": { + "kind": "agent", + "id": "dashboard-integrator" + }, + "score": 0.2423, + "shared_terms": [ + "household", + "api", + "income", + "data", + "tax", + "unit", + "result", + "year" + ] + }, { "a": { "kind": "skill", @@ -10296,27 +10317,6 @@ "report" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine" - }, - "b": { - "kind": "skill", - "id": "policyengine-api" - }, - "score": 0.2386, - "shared_terms": [ - "household", - "api", - "python", - "country", - "server", - "rest", - "result", - "analysis" - ] - }, { "a": { "kind": "command", @@ -10347,7 +10347,7 @@ "kind": "skill", "id": "policyengine-healthcare" }, - "score": 0.2368, + "score": 0.2361, "shared_terms": [ "household", "income", @@ -10368,7 +10368,7 @@ "kind": "command", "id": "deploy-dashboard" }, - "score": 0.2355, + "score": 0.2354, "shared_terms": [ "app", "host", @@ -10382,23 +10382,23 @@ }, { "a": { - "kind": "agent", - "id": "ci-fixer" + "kind": "skill", + "id": "policyengine" }, "b": { - "kind": "agent", - "id": "edge-case-generator" + "kind": "skill", + "id": "policyengine-api" }, "score": 0.2349, "shared_terms": [ - "test", - "files", - "case", - "cases", - "tests", - "root", - "fix", - "read" + "household", + "api", + "python", + "country", + "server", + "rest", + "result", + "analysis" ] }, { @@ -10410,7 +10410,7 @@ "kind": "command", "id": "deploy-dashboard" }, - "score": 0.2347, + "score": 0.2349, "shared_terms": [ "modal", "deploy", @@ -10422,6 +10422,27 @@ "merge" ] }, + { + "a": { + "kind": "agent", + "id": "ci-fixer" + }, + "b": { + "kind": "agent", + "id": "edge-case-generator" + }, + "score": 0.2349, + "shared_terms": [ + "test", + "files", + "case", + "cases", + "tests", + "root", + "fix", + "read" + ] + }, { "a": { "kind": "agent", @@ -10431,7 +10452,7 @@ "kind": "agent", "id": "test-creator" }, - "score": 0.2346, + "score": 0.2342, "shared_terms": [ "test", "tests", @@ -10473,7 +10494,7 @@ "kind": "agent", "id": "prior-scores-finder" }, - "score": 0.2325, + "score": 0.2324, "shared_terms": [ "reform", "external", @@ -10515,15 +10536,15 @@ "kind": "command", "id": "household-calc" }, - "score": 0.2309, + "score": 0.2303, "shared_terms": [ "household", "canada", "benefit", "level", "income", - "net", "population", + "net", "not" ] }, @@ -10536,7 +10557,7 @@ "kind": "command", "id": "reform-pipeline" }, - "score": 0.2294, + "score": 0.229, "shared_terms": [ "auto", "bill", @@ -10569,27 +10590,6 @@ "tsx" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-healthcare" - }, - "b": { - "kind": "skill", - "id": "policyengine-uk" - }, - "score": 0.2276, - "shared_terms": [ - "household", - "income", - "tax", - "unit", - "net", - "person", - "credit", - "benefits" - ] - }, { "a": { "kind": "agent", @@ -10599,7 +10599,7 @@ "kind": "agent", "id": "frontend-builder" }, - "score": 0.2275, + "score": 0.227, "shared_terms": [ "component", "button", @@ -10611,6 +10611,27 @@ "import" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-healthcare" + }, + "b": { + "kind": "skill", + "id": "policyengine-uk" + }, + "score": 0.2269, + "shared_terms": [ + "household", + "income", + "tax", + "unit", + "net", + "person", + "credit", + "benefits" + ] + }, { "a": { "kind": "skill", @@ -10632,27 +10653,6 @@ "served" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-api" - }, - "b": { - "kind": "agent", - "id": "dashboard-scaffold" - }, - "score": 0.2267, - "shared_terms": [ - "api", - "client", - "dashboard", - "alpha", - "org", - "cloud", - "household", - "public" - ] - }, { "a": { "kind": "skill", @@ -10674,6 +10674,27 @@ "approved" ] }, + { + "a": { + "kind": "agent", + "id": "dashboard-integrator" + }, + "b": { + "kind": "agent", + "id": "dashboard-plan-validator" + }, + "score": 0.226, + "shared_terms": [ + "api", + "components", + "data", + "plan", + "loading", + "component", + "chart", + "lib" + ] + }, { "a": { "kind": "skill", @@ -10683,7 +10704,7 @@ "kind": "skill", "id": "policyengine-user-guide" }, - "score": 0.2257, + "score": 0.2255, "shared_terms": [ "household", "tax", @@ -10725,7 +10746,7 @@ "kind": "command", "id": "reform-pipeline" }, - "score": 0.2227, + "score": 0.2223, "shared_terms": [ "dashboard", "reform", @@ -10760,29 +10781,8 @@ }, { "a": { - "kind": "skill", - "id": "policyengine" - }, - "b": { - "kind": "skill", - "id": "policyengine-canada" - }, - "score": 0.2217, - "shared_terms": [ - "household", - "income", - "tax", - "age", - "net", - "microsimulation", - "assert", - "credit" - ] - }, - { - "a": { - "kind": "agent", - "id": "multizone-validator" + "kind": "agent", + "id": "multizone-validator" }, "b": { "kind": "command", @@ -10809,7 +10809,7 @@ "kind": "agent", "id": "ci-fixer" }, - "score": 0.2215, + "score": 0.2216, "shared_terms": [ "fix", "files", @@ -10821,6 +10821,27 @@ "local" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine" + }, + "b": { + "kind": "skill", + "id": "policyengine-canada" + }, + "score": 0.2213, + "shared_terms": [ + "household", + "income", + "tax", + "age", + "net", + "microsimulation", + "assert", + "credit" + ] + }, { "a": { "kind": "agent", @@ -10842,6 +10863,27 @@ "pass" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-api" + }, + "b": { + "kind": "agent", + "id": "dashboard-scaffold" + }, + "score": 0.2209, + "shared_terms": [ + "api", + "client", + "dashboard", + "alpha", + "org", + "cloud", + "household", + "public" + ] + }, { "a": { "kind": "skill", @@ -10914,7 +10956,7 @@ "kind": "command", "id": "household-calc" }, - "score": 0.2196, + "score": 0.2197, "shared_terms": [ "reform", "income", @@ -10926,27 +10968,6 @@ "api" ] }, - { - "a": { - "kind": "agent", - "id": "dashboard-integrator" - }, - "b": { - "kind": "agent", - "id": "dashboard-plan-validator" - }, - "score": 0.2175, - "shared_terms": [ - "api", - "components", - "data", - "loading", - "component", - "chart", - "plan", - "lib" - ] - }, { "a": { "kind": "agent", @@ -10998,7 +11019,7 @@ "kind": "command", "id": "create-new-component" }, - "score": 0.2159, + "score": 0.2158, "shared_terms": [ "component", "components", @@ -11019,7 +11040,7 @@ "kind": "command", "id": "create-new-component" }, - "score": 0.2155, + "score": 0.2154, "shared_terms": [ "kit", "app", @@ -11145,7 +11166,7 @@ "kind": "command", "id": "new-tool" }, - "score": 0.2136, + "score": 0.2135, "shared_terms": [ "kit", "app", @@ -11157,48 +11178,6 @@ "import" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine" - }, - "b": { - "kind": "agent", - "id": "dashboard-integrator" - }, - "score": 0.2135, - "shared_terms": [ - "household", - "api", - "result", - "data", - "unit", - "tax", - "age", - "income" - ] - }, - { - "a": { - "kind": "skill", - "id": "policyengine-api" - }, - "b": { - "kind": "agent", - "id": "microsim-runner" - }, - "score": 0.2134, - "shared_terms": [ - "api", - "economy", - "version", - "over", - "country", - "python", - "baseline", - "org" - ] - }, { "a": { "kind": "agent", @@ -11241,6 +11220,27 @@ "design" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-api" + }, + "b": { + "kind": "agent", + "id": "microsim-runner" + }, + "score": 0.2118, + "shared_terms": [ + "api", + "economy", + "version", + "over", + "country", + "baseline", + "org", + "python" + ] + }, { "a": { "kind": "skill", @@ -11376,7 +11376,7 @@ "kind": "skill", "id": "policyengine-tools" }, - "score": 0.2074, + "score": 0.2073, "shared_terms": [ "api", "public", @@ -11418,7 +11418,7 @@ "kind": "agent", "id": "model-worker" }, - "score": 0.205, + "score": 0.2051, "shared_terms": [ "test", "root", @@ -11448,28 +11448,7 @@ "sources", "income", "documents", - "document" - ] - }, - { - "a": { - "kind": "agent", - "id": "parameter-locator" - }, - "b": { - "kind": "command", - "id": "implement-structural" - }, - "score": 0.2032, - "shared_terms": [ - "gov", - "reform", - "states", - "rate", - "phase", - "structural", - "change", - "deployed" + "official" ] }, { @@ -11493,6 +11472,27 @@ "only" ] }, + { + "a": { + "kind": "agent", + "id": "parameter-locator" + }, + "b": { + "kind": "command", + "id": "implement-structural" + }, + "score": 0.2031, + "shared_terms": [ + "gov", + "reform", + "states", + "rate", + "phase", + "structural", + "change", + "deployed" + ] + }, { "a": { "kind": "skill", @@ -11523,7 +11523,7 @@ "kind": "agent", "id": "report-logger" }, - "score": 0.1998, + "score": 0.1999, "shared_terms": [ "issue", "draft", @@ -11565,7 +11565,7 @@ "kind": "agent", "id": "report-logger" }, - "score": 0.1992, + "score": 0.1991, "shared_terms": [ "posts", "articles", @@ -11607,7 +11607,7 @@ "kind": "agent", "id": "structural-implementer" }, - "score": 0.197, + "score": 0.1969, "shared_terms": [ "changelog", "issue", @@ -11628,7 +11628,7 @@ "kind": "command", "id": "create-dashboard" }, - "score": 0.1966, + "score": 0.1967, "shared_terms": [ "reform", "calculator", @@ -11670,7 +11670,7 @@ "kind": "command", "id": "write-tests" }, - "score": 0.1952, + "score": 0.1951, "shared_terms": [ "test", "tests", @@ -11682,27 +11682,6 @@ "path" ] }, - { - "a": { - "kind": "agent", - "id": "dashboard-integrator" - }, - "b": { - "kind": "command", - "id": "new-tool" - }, - "score": 0.1946, - "shared_terms": [ - "api", - "const", - "client", - "dashboard", - "function", - "import", - "countryid", - "return" - ] - }, { "a": { "kind": "command", @@ -11712,7 +11691,7 @@ "kind": "command", "id": "deploy-dashboard" }, - "score": 0.1946, + "score": 0.1945, "shared_terms": [ "dashboard", "repo", @@ -11733,7 +11712,7 @@ "kind": "agent", "id": "reform-classifier" }, - "score": 0.1945, + "score": 0.1944, "shared_terms": [ "structural", "backlog", @@ -11754,7 +11733,7 @@ "kind": "command", "id": "backdate-program" }, - "score": 0.1942, + "score": 0.1941, "shared_terms": [ "pdf", "state", @@ -11766,27 +11745,6 @@ "page" ] }, - { - "a": { - "kind": "agent", - "id": "component-test-writer" - }, - "b": { - "kind": "agent", - "id": "dashboard-design-validator" - }, - "score": 0.194, - "shared_terms": [ - "tsx", - "components", - "button", - "kit", - "app", - "component", - "classname", - "test" - ] - }, { "a": { "kind": "skill", @@ -11796,7 +11754,7 @@ "kind": "agent", "id": "edge-case-generator" }, - "score": 0.1938, + "score": 0.1937, "shared_terms": [ "tests", "test", @@ -11829,6 +11787,27 @@ "mounted" ] }, + { + "a": { + "kind": "agent", + "id": "component-test-writer" + }, + "b": { + "kind": "agent", + "id": "dashboard-design-validator" + }, + "score": 0.1936, + "shared_terms": [ + "tsx", + "components", + "button", + "kit", + "app", + "component", + "classname", + "test" + ] + }, { "a": { "kind": "skill", @@ -11838,7 +11817,7 @@ "kind": "agent", "id": "parameter-locator" }, - "score": 0.1932, + "score": 0.1931, "shared_terms": [ "reform", "income", @@ -11874,43 +11853,43 @@ { "a": { "kind": "agent", - "id": "outcome-predictor" + "id": "dashboard-integrator" }, "b": { "kind": "agent", - "id": "prior-scores-finder" + "id": "dashboard-planner" }, - "score": 0.1913, + "score": 0.1923, "shared_terms": [ - "analyses", - "comparator", - "prior", - "reform", - "scores", - "blind", - "magnitude", - "you" - ] + "api", + "data", + "dashboard", + "step", + "plan", + "backend", + "components", + "input" + ] }, { "a": { "kind": "agent", - "id": "component-test-writer" + "id": "outcome-predictor" }, "b": { "kind": "agent", - "id": "edge-case-generator" + "id": "prior-scores-finder" }, - "score": 0.1907, + "score": 0.1912, "shared_terms": [ - "test", - "tests", - "edge", - "testing", - "case", - "cases", - "file", - "boundary" + "analyses", + "comparator", + "prior", + "reform", + "scores", + "blind", + "magnitude", + "you" ] }, { @@ -11922,7 +11901,7 @@ "kind": "agent", "id": "structural-implementer" }, - "score": 0.1906, + "score": 0.1905, "shared_terms": [ "issue", "repo", @@ -11936,23 +11915,23 @@ }, { "a": { - "kind": "skill", - "id": "fix-pr" + "kind": "agent", + "id": "component-test-writer" }, "b": { - "kind": "command", - "id": "backdate-program" + "kind": "agent", + "id": "edge-case-generator" }, - "score": 0.1896, + "score": 0.1903, "shared_terms": [ - "review", - "files", - "program", - "workflow", - "read", - "worktree", - "only", - "fix" + "test", + "tests", + "edge", + "testing", + "case", + "cases", + "file", + "boundary" ] }, { @@ -11964,7 +11943,7 @@ "kind": "agent", "id": "dashboard-architecture-validator" }, - "score": 0.1896, + "score": 0.1897, "shared_terms": [ "backend", "modal", @@ -11978,23 +11957,23 @@ }, { "a": { - "kind": "agent", - "id": "dashboard-planner" + "kind": "skill", + "id": "fix-pr" }, "b": { "kind": "command", - "id": "deploy-dashboard" + "id": "backdate-program" }, - "score": 0.1895, + "score": 0.1896, "shared_terms": [ - "dashboard", - "modal", - "step", - "plan", - "custom", - "pattern", - "data", - "needs" + "review", + "files", + "program", + "workflow", + "read", + "worktree", + "only", + "fix" ] }, { @@ -12018,6 +11997,27 @@ "required" ] }, + { + "a": { + "kind": "agent", + "id": "dashboard-planner" + }, + "b": { + "kind": "command", + "id": "deploy-dashboard" + }, + "score": 0.1894, + "shared_terms": [ + "dashboard", + "modal", + "step", + "plan", + "custom", + "pattern", + "data", + "needs" + ] + }, { "a": { "kind": "skill", @@ -12042,43 +12042,43 @@ { "a": { "kind": "agent", - "id": "reform-comparator" + "id": "model-corroborator" }, "b": { "kind": "command", - "id": "prior-scores" + "id": "household-calc" }, "score": 0.1872, "shared_terms": [ - "microsim", - "prior", - "scores", - "year", - "cost", - "dataset", - "cbo", - "published" + "reform", + "dict", + "baseline", + "external", + "single", + "cap", + "household", + "sources" ] }, { "a": { "kind": "agent", - "id": "model-corroborator" + "id": "reform-comparator" }, "b": { "kind": "command", - "id": "household-calc" + "id": "prior-scores" }, - "score": 0.1871, + "score": 0.1872, "shared_terms": [ - "reform", - "dict", - "baseline", - "external", - "single", - "cap", - "household", - "sources" + "microsim", + "prior", + "scores", + "year", + "cost", + "dataset", + "cbo", + "published" ] }, { @@ -12123,27 +12123,6 @@ "test" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-api" - }, - "b": { - "kind": "command", - "id": "new-tool" - }, - "score": 0.1859, - "shared_terms": [ - "api", - "client", - "dashboard", - "org", - "public", - "calc", - "country", - "economy" - ] - }, { "a": { "kind": "agent", @@ -12165,27 +12144,6 @@ "backend" ] }, - { - "a": { - "kind": "agent", - "id": "dashboard-integrator" - }, - "b": { - "kind": "agent", - "id": "dashboard-planner" - }, - "score": 0.1858, - "shared_terms": [ - "api", - "data", - "dashboard", - "step", - "backend", - "components", - "input", - "pattern" - ] - }, { "a": { "kind": "skill", @@ -12207,6 +12165,27 @@ "model" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-api" + }, + "b": { + "kind": "command", + "id": "new-tool" + }, + "score": 0.1851, + "shared_terms": [ + "api", + "dashboard", + "public", + "client", + "org", + "calc", + "country", + "economy" + ] + }, { "a": { "kind": "skill", @@ -12237,7 +12216,7 @@ "kind": "command", "id": "create-dashboard" }, - "score": 0.1848, + "score": 0.1847, "shared_terms": [ "repo", "multi", @@ -12258,7 +12237,7 @@ "kind": "command", "id": "household-calc" }, - "score": 0.1843, + "score": 0.1842, "shared_terms": [ "reform", "preset", @@ -12279,7 +12258,7 @@ "kind": "skill", "id": "policyengine-model-development" }, - "score": 0.1837, + "score": 0.1838, "shared_terms": [ "household", "age", @@ -12342,7 +12321,7 @@ "kind": "command", "id": "implement-structural" }, - "score": 0.1826, + "score": 0.1827, "shared_terms": [ "reform", "contrib", @@ -12486,19 +12465,19 @@ "id": "fix-pr" }, "b": { - "kind": "skill", - "id": "policyengine-plugin-maintenance" + "kind": "agent", + "id": "pr-pusher" }, "score": 0.1809, "shared_terms": [ - "claude", - "codex", "fix", - "plugin", - "skills", - "verification", - "references", - "edit" + "review", + "push", + "workflow", + "pusher", + "files", + "local", + "never" ] }, { @@ -12507,19 +12486,19 @@ "id": "fix-pr" }, "b": { - "kind": "agent", - "id": "pr-pusher" + "kind": "skill", + "id": "policyengine-plugin-maintenance" }, - "score": 0.1809, + "score": 0.1808, "shared_terms": [ + "claude", + "codex", "fix", - "review", - "push", - "workflow", - "pusher", - "files", - "local", - "never" + "plugin", + "skills", + "verification", + "references", + "edit" ] }, { @@ -12585,6 +12564,27 @@ "references" ] }, + { + "a": { + "kind": "agent", + "id": "dashboard-integrator" + }, + "b": { + "kind": "agent", + "id": "microsim-runner" + }, + "score": 0.1804, + "shared_terms": [ + "api", + "data", + "response", + "year", + "result", + "request", + "client", + "state" + ] + }, { "a": { "kind": "skill", @@ -12594,7 +12594,7 @@ "kind": "agent", "id": "calibration-diagnostics" }, - "score": 0.1801, + "score": 0.1802, "shared_terms": [ "unit", "tax", @@ -12651,22 +12651,43 @@ { "a": { "kind": "agent", - "id": "dashboard-integrator" + "id": "dashboard-integrator" + }, + "b": { + "kind": "command", + "id": "new-tool" + }, + "score": 0.1788, + "shared_terms": [ + "api", + "client", + "dashboard", + "countryid", + "create", + "function", + "step", + "import" + ] + }, + { + "a": { + "kind": "agent", + "id": "prior-scores-finder" }, "b": { - "kind": "agent", - "id": "microsim-runner" + "kind": "command", + "id": "analyze-policy" }, - "score": 0.179, + "score": 0.178, "shared_terms": [ - "api", - "data", - "response", - "result", - "request", "year", - "client", - "state" + "microsim", + "prior", + "archive", + "horizon", + "reform", + "scores", + "window" ] }, { @@ -12678,7 +12699,7 @@ "kind": "skill", "id": "policyengine-us" }, - "score": 0.178, + "score": 0.1776, "shared_terms": [ "tax", "household", @@ -12690,27 +12711,6 @@ "poverty" ] }, - { - "a": { - "kind": "agent", - "id": "prior-scores-finder" - }, - "b": { - "kind": "command", - "id": "analyze-policy" - }, - "score": 0.178, - "shared_terms": [ - "year", - "microsim", - "prior", - "archive", - "horizon", - "reform", - "scores", - "window" - ] - }, { "a": { "kind": "agent", @@ -12720,7 +12720,7 @@ "kind": "agent", "id": "parameter-locator" }, - "score": 0.1772, + "score": 0.1771, "shared_terms": [ "reform", "parameter", @@ -12741,7 +12741,7 @@ "kind": "command", "id": "backdate-program" }, - "score": 0.1769, + "score": 0.177, "shared_terms": [ "program", "review", @@ -12753,6 +12753,27 @@ "findings" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-api" + }, + "b": { + "kind": "agent", + "id": "dashboard-planner" + }, + "score": 0.1767, + "shared_terms": [ + "api", + "dashboard", + "cloud", + "server", + "rest", + "credential", + "alpha", + "household" + ] + }, { "a": { "kind": "command", @@ -12762,7 +12783,7 @@ "kind": "command", "id": "text-to-reform" }, - "score": 0.1765, + "score": 0.1764, "shared_terms": [ "reform", "structural", @@ -12774,27 +12795,6 @@ "pre" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-healthcare" - }, - "b": { - "kind": "command", - "id": "household-calc" - }, - "score": 0.1764, - "shared_terms": [ - "household", - "net", - "income", - "reform", - "benefits", - "tax", - "year", - "single" - ] - }, { "a": { "kind": "command", @@ -12804,7 +12804,7 @@ "kind": "command", "id": "encode-reform" }, - "score": 0.1763, + "score": 0.1762, "shared_terms": [ "pdf", "state", @@ -12816,27 +12816,6 @@ "audit" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-api" - }, - "b": { - "kind": "agent", - "id": "dashboard-planner" - }, - "score": 0.176, - "shared_terms": [ - "api", - "dashboard", - "cloud", - "server", - "rest", - "credential", - "alpha", - "household" - ] - }, { "a": { "kind": "skill", @@ -12846,7 +12825,7 @@ "kind": "command", "id": "write-tests" }, - "score": 0.1757, + "score": 0.1758, "shared_terms": [ "tests", "test", @@ -12858,6 +12837,27 @@ "path" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-healthcare" + }, + "b": { + "kind": "command", + "id": "household-calc" + }, + "score": 0.1752, + "shared_terms": [ + "household", + "net", + "income", + "reform", + "benefits", + "tax", + "year", + "single" + ] + }, { "a": { "kind": "agent", @@ -12867,7 +12867,7 @@ "kind": "agent", "id": "frontend-builder" }, - "score": 0.1749, + "score": 0.1743, "shared_terms": [ "components", "frontend", @@ -12909,7 +12909,7 @@ "kind": "agent", "id": "parameter-locator" }, - "score": 0.1732, + "score": 0.1731, "shared_terms": [ "state", "income", @@ -12930,7 +12930,7 @@ "kind": "command", "id": "text-to-reform" }, - "score": 0.1726, + "score": 0.1725, "shared_terms": [ "reform", "impact", @@ -13005,6 +13005,27 @@ "config" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-us" + }, + "b": { + "kind": "agent", + "id": "dashboard-integrator" + }, + "score": 0.1712, + "shared_terms": [ + "household", + "unit", + "tax", + "year", + "income", + "spm", + "head", + "state" + ] + }, { "a": { "kind": "skill", @@ -13014,7 +13035,7 @@ "kind": "command", "id": "household-calc" }, - "score": 0.1711, + "score": 0.1707, "shared_terms": [ "household", "api", @@ -13203,7 +13224,7 @@ "kind": "agent", "id": "dashboard-architecture-validator" }, - "score": 0.1667, + "score": 0.1664, "shared_terms": [ "test", "app", @@ -13266,7 +13287,7 @@ "kind": "command", "id": "household-calc" }, - "score": 0.166, + "score": 0.1661, "shared_terms": [ "reform", "year", @@ -13287,7 +13308,7 @@ "kind": "command", "id": "household-calc" }, - "score": 0.1656, + "score": 0.1657, "shared_terms": [ "reform", "description", @@ -13362,27 +13383,6 @@ "multi" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-api" - }, - "b": { - "kind": "skill", - "id": "policyengine-app" - }, - "score": 0.1648, - "shared_terms": [ - "api", - "server", - "org", - "client", - "economy", - "calc", - "household", - "page" - ] - }, { "a": { "kind": "agent", @@ -13392,7 +13392,7 @@ "kind": "agent", "id": "policy-text-researcher" }, - "score": 0.1647, + "score": 0.1646, "shared_terms": [ "enacted", "effective", @@ -13488,27 +13488,6 @@ "variables" ] }, - { - "a": { - "kind": "agent", - "id": "calibration-diagnostics" - }, - "b": { - "kind": "agent", - "id": "model-corroborator" - }, - "score": 0.1636, - "shared_terms": [ - "calibration", - "reform", - "stage", - "comparator", - "diagnostics", - "sensitivity", - "family", - "cap" - ] - }, { "a": { "kind": "skill", @@ -13518,7 +13497,7 @@ "kind": "agent", "id": "dashboard-scaffold" }, - "score": 0.1634, + "score": 0.1636, "shared_terms": [ "api", "app", @@ -13532,44 +13511,23 @@ }, { "a": { - "kind": "skill", - "id": "policyengine-cloud-costs" - }, - "b": { "kind": "agent", - "id": "backend-builder" - }, - "score": 0.1634, - "shared_terms": [ - "modal", - "backend", - "containers", - "api", - "dashboard", - "plan", - "cloud", - "declare" - ] - }, - { - "a": { - "kind": "skill", - "id": "policyengine-canada" + "id": "calibration-diagnostics" }, "b": { - "kind": "skill", - "id": "policyengine-user-guide" + "kind": "agent", + "id": "model-corroborator" }, - "score": 0.1633, + "score": 0.1636, "shared_terms": [ - "household", - "income", - "benefit", - "population", - "canada", - "tax", - "net", - "poverty" + "calibration", + "reform", + "stage", + "comparator", + "diagnostics", + "sensitivity", + "family", + "cap" ] }, { @@ -13581,7 +13539,7 @@ "kind": "agent", "id": "test-creator" }, - "score": 0.1633, + "score": 0.1632, "shared_terms": [ "month", "months", @@ -13593,6 +13551,27 @@ "development" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-api" + }, + "b": { + "kind": "skill", + "id": "policyengine-app" + }, + "score": 0.1631, + "shared_terms": [ + "api", + "server", + "org", + "economy", + "client", + "calc", + "household", + "page" + ] + }, { "a": { "kind": "skill", @@ -13614,6 +13593,27 @@ "never" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-cloud-costs" + }, + "b": { + "kind": "agent", + "id": "backend-builder" + }, + "score": 0.163, + "shared_terms": [ + "modal", + "backend", + "containers", + "api", + "dashboard", + "plan", + "cloud", + "max" + ] + }, { "a": { "kind": "skill", @@ -13635,6 +13635,27 @@ "json" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-canada" + }, + "b": { + "kind": "skill", + "id": "policyengine-user-guide" + }, + "score": 0.1629, + "shared_terms": [ + "household", + "income", + "benefit", + "population", + "canada", + "tax", + "net", + "poverty" + ] + }, { "a": { "kind": "agent", @@ -13749,7 +13770,7 @@ "kind": "agent", "id": "review-worker" }, - "score": 0.1596, + "score": 0.1597, "shared_terms": [ "test", "review", @@ -13791,7 +13812,7 @@ "kind": "agent", "id": "microsim-runner" }, - "score": 0.1593, + "score": 0.1594, "shared_terms": [ "result", "dataset", @@ -13824,6 +13845,27 @@ "analyze" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-uk" + }, + "b": { + "kind": "agent", + "id": "dashboard-integrator" + }, + "score": 0.1583, + "shared_terms": [ + "household", + "income", + "data", + "unit", + "tax", + "year", + "age", + "person" + ] + }, { "a": { "kind": "agent", @@ -13908,27 +13950,6 @@ "purpose" ] }, - { - "a": { - "kind": "agent", - "id": "prior-scores-finder" - }, - "b": { - "kind": "command", - "id": "text-to-reform" - }, - "score": 0.1575, - "shared_terms": [ - "reform", - "microsim", - "prior", - "bill", - "scores", - "reforms", - "same", - "external" - ] - }, { "a": { "kind": "skill", @@ -13971,6 +13992,27 @@ "development" ] }, + { + "a": { + "kind": "agent", + "id": "prior-scores-finder" + }, + "b": { + "kind": "command", + "id": "text-to-reform" + }, + "score": 0.1571, + "shared_terms": [ + "reform", + "microsim", + "prior", + "bill", + "scores", + "reforms", + "same", + "external" + ] + }, { "a": { "kind": "skill", @@ -14013,27 +14055,6 @@ "node" ] }, - { - "a": { - "kind": "agent", - "id": "dashboard-planner" - }, - "b": { - "kind": "command", - "id": "text-to-reform" - }, - "score": 0.1561, - "shared_terms": [ - "natural", - "description", - "language", - "api", - "reform", - "provision", - "bill", - "analyze" - ] - }, { "a": { "kind": "command", @@ -14055,6 +14076,27 @@ "check" ] }, + { + "a": { + "kind": "agent", + "id": "dashboard-planner" + }, + "b": { + "kind": "command", + "id": "text-to-reform" + }, + "score": 0.156, + "shared_terms": [ + "natural", + "description", + "language", + "api", + "reform", + "provision", + "bill", + "analyze" + ] + }, { "a": { "kind": "skill", @@ -14076,27 +14118,6 @@ "page" ] }, - { - "a": { - "kind": "command", - "id": "create-dashboard" - }, - "b": { - "kind": "command", - "id": "encode-reform" - }, - "score": 0.1556, - "shared_terms": [ - "reform", - "page", - "multi", - "arguments", - "implement", - "phase", - "skip", - "workflow" - ] - }, { "a": { "kind": "skill", @@ -14106,7 +14127,7 @@ "kind": "skill", "id": "policyengine-uk" }, - "score": 0.1555, + "score": 0.1556, "shared_terms": [ "household", "entity", @@ -14127,7 +14148,7 @@ "kind": "command", "id": "household-calc" }, - "score": 0.1555, + "score": 0.1556, "shared_terms": [ "single", "baseline", @@ -14141,23 +14162,23 @@ }, { "a": { - "kind": "skill", - "id": "policyengine-standards" + "kind": "command", + "id": "create-dashboard" }, "b": { - "kind": "agent", - "id": "structural-implementer" + "kind": "command", + "id": "encode-reform" }, - "score": 0.1543, + "score": 0.1556, "shared_terms": [ - "draft", - "changelog", - "repo", - "venv", - "ready", - "issue", - "committing", - "check" + "reform", + "page", + "multi", + "arguments", + "implement", + "phase", + "skip", + "workflow" ] }, { @@ -14181,6 +14202,27 @@ "national" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-standards" + }, + "b": { + "kind": "agent", + "id": "structural-implementer" + }, + "score": 0.1542, + "shared_terms": [ + "draft", + "changelog", + "repo", + "venv", + "ready", + "issue", + "committing", + "check" + ] + }, { "a": { "kind": "command", @@ -14190,7 +14232,7 @@ "kind": "command", "id": "prior-scores" }, - "score": 0.1539, + "score": 0.154, "shared_terms": [ "reform", "analyze", @@ -14211,7 +14253,7 @@ "kind": "agent", "id": "dashboard-plan-validator" }, - "score": 0.1537, + "score": 0.1534, "shared_terms": [ "component", "tsx", @@ -14295,7 +14337,7 @@ "kind": "command", "id": "encode-reform" }, - "score": 0.1515, + "score": 0.1517, "shared_terms": [ "prefix", "test", @@ -14316,7 +14358,7 @@ "kind": "agent", "id": "structural-implementer" }, - "score": 0.1514, + "score": 0.1513, "shared_terms": [ "tests", "parameter", @@ -14337,7 +14379,7 @@ "kind": "agent", "id": "pr-pusher" }, - "score": 0.1511, + "score": 0.1512, "shared_terms": [ "changelog", "tests", @@ -14352,22 +14394,22 @@ { "a": { "kind": "agent", - "id": "calibration-diagnostics" + "id": "dashboard-integrator" }, "b": { "kind": "agent", - "id": "reform-comparator" + "id": "parameter-locator" }, "score": 0.1511, "shared_terms": [ - "prior", - "anchor", - "calibration", - "microsim", - "comparator", - "cost", - "diagnostics", - "baseline" + "api", + "state", + "income", + "values", + "tax", + "states", + "step", + "household" ] }, { @@ -14391,6 +14433,27 @@ "next" ] }, + { + "a": { + "kind": "agent", + "id": "calibration-diagnostics" + }, + "b": { + "kind": "agent", + "id": "reform-comparator" + }, + "score": 0.151, + "shared_terms": [ + "prior", + "anchor", + "calibration", + "microsim", + "comparator", + "cost", + "diagnostics", + "baseline" + ] + }, { "a": { "kind": "agent", diff --git a/skills/policyengine-api-access/SKILL.md b/skills/policyengine-api-access/SKILL.md index 149e7d3..b069503 100644 --- a/skills/policyengine-api-access/SKILL.md +++ b/skills/policyengine-api-access/SKILL.md @@ -106,15 +106,22 @@ const metadata = await policyengine.getMetadata("uk"); `region` is `us`, `uk` or a sub-national region such as `state/ca`, at most 200 characters. - The household and parameter shapes are the Public API's (`household` nests values by year; read variable and parameter names from the metadata). See the policyengine-api skill. +- `POST /api/household/calculate` is the Public API's `/{country}/calculate`, which adds no + variables the household leaves out: ask for each output by naming it on its entity + with `null` for the year (`income_tax: { 2026: null }`). To vary an input for a chart, send + one household with `axes` (`[[{ name: "employment_income", period: "2026", min: 0, max: + 200000, count: 41 }]]`) and its value `null`; each output comes back as a list over the + points. Never send one calculation per point: the limit is 30 a minute. - Each method takes `{ signal }` to cancel. The result type is a type argument (`calculateHousehold(…)`), not checked at run time. **Polling.** `compareEconomy` reads the comparison every 5 seconds until `status` is `ok`, and gives up after 30 minutes with `EconomyComparisonTimeoutError`. After a 429 it waits for `Retry-After`, or 60 seconds (`RATE_LIMIT_WAIT_MILLISECONDS`, the firewall's window) when there -is none, and keeps polling. A page on another origin cannot read the firewall's 429 (see rate -limits below), so there polling stops with `status` `null`. After a 502, 503 or 504 it waits -one interval, and the fourth such failure since the last answer ends polling. A comparison +is none, but never less than one interval or one second, and keeps polling. A page on another +origin cannot read the firewall's 429 (see rate limits below), so there polling stops with +`status` `null`. After a 502, 503 or 504 it waits for `Retry-After`, or one interval, and the +fourth such failure since the last answer ends polling. A comparison that failed (502 with `status: "error"` and `retry_after_seconds`) is thrown at once: the Public API keeps that failure for `retry_after_seconds`, so polling sooner returns it again. Keep @@ -266,7 +273,7 @@ could be read), `message`, `body` and `retryAfterSeconds`. The dashboard API's o | Status | From | Meaning | What to do | |---|---|---|---| | 400 | Dashboard API | A missing or unknown field, or a malformed value | Fix the request; `message` names the field | -| 401 | Public API, the server's own token | `{"status":"error","message":"Authentication is required"}` with `WWW-Authenticate: Bearer`: an invalid or expired token, a client not on the allow list, a client token from another tenant, two `Authorization` headers, or, once the requirement is on, no server credential | Server: do not request another token, which would be refused too and counts against the tenant's monthly allowance; check that the client is listed in that environment and that its tenant and audience match, and report it. Page: the website's own credential failed; show an error, do not retry in a loop | +| 401 | Public API | `{"status":"error","message":"Authentication is required"}` with `WWW-Authenticate: Bearer`. Usually the server's own token: an invalid or expired token, a client not on the allow list, a client token from another tenant, two `Authorization` headers, or, once the requirement is on, no server credential. A user route answers the same when the server forwards no user credential, or a malformed `PolicyEngine-Unauthenticated-User` | Server: do not request another token, which would be refused too and counts against the tenant's monthly allowance. On a user route, check first that the request forwarded the user's credential; otherwise check that the client is listed in that environment and that its tenant and audience match, and report it. Page: the website's own credential failed; show an error, do not retry in a loop | | 401 | Public API user routes | `WWW-Authenticate: Bearer error="invalid_token"` and "The bearer access token is invalid": the forwarded `PolicyEngine-User-Authorization` token is invalid or expired | Keep the server token; the user signs in again | | 403 | Dashboard API | "Pages on this origin may not call the dashboard API." The page's origin is not allowed | Serve the page from an allowed origin. A cross-origin page cannot read this answer: the browser reports a CORS error and the client throws with `status` `null` | | 403 | Public API user routes | A forwarded `PolicyEngine-User-Authorization` token is a machine-to-machine token, not a user's | Forward only a signed-in user's own token there | diff --git a/skills/policyengine-api-access/templates/public_api_token.py b/skills/policyengine-api-access/templates/public_api_token.py index 7c659b2..f8fbe5e 100644 --- a/skills/policyengine-api-access/templates/public_api_token.py +++ b/skills/policyengine-api-access/templates/public_api_token.py @@ -19,20 +19,22 @@ POLICYENGINE_API_AUTH0_CLIENT_SECRET that client's secret On Modal, the shared store is a Dict, and each container builds one provider the -first time it needs one (the secret's variables exist only inside the container): +first time it needs one (the secret's variables exist only inside the container). +Modal copies only the app's own module into containers, so the image adds this one: import functools import modal from public_api_token import PublicApiSettings, PublicApiTokenProvider, call_public_api + image = modal.Image.debian_slim().add_local_python_source("public_api_token") TOKEN_STORE = modal.Dict.from_name("TOOL_NAME-public-api-token", create_if_missing=True) @functools.cache def public_api_tokens() -> PublicApiTokenProvider: return PublicApiTokenProvider(PublicApiSettings.from_environment(), shared_store=TOKEN_STORE) - @app.function(secrets=[modal.Secret.from_name("TOOL_NAME-policyengine-api")]) + @app.function(image=image, secrets=[modal.Secret.from_name("TOOL_NAME-policyengine-api")]) def household(situation: dict) -> dict: return call_public_api(public_api_tokens(), "POST", "/us/calculate", {"household": situation}) @@ -59,7 +61,7 @@ def household(situation: dict) -> dict: import urllib.error import urllib.request from collections.abc import Callable, Mapping -from dataclasses import dataclass +from dataclasses import dataclass, field from typing import Any, Protocol LOGGER = logging.getLogger(__name__) @@ -86,6 +88,12 @@ def get(self, key: str, default: Any = None) -> Any: ... def __setitem__(self, key: str, value: Any) -> None: ... +class Opener(Protocol): + """What the provider needs to send a request: urllib's OpenerDirector, or a fake in tests.""" + + def open(self, request: urllib.request.Request, timeout: float) -> Any: ... + + class PublicApiSettingsError(ValueError): """A setting is missing or malformed.""" @@ -108,7 +116,8 @@ class PublicApiSettings: token_endpoint_host: str audience: str client_id: str - client_secret: str + # Kept out of repr(), so a logged or printed settings object never shows it. + client_secret: str = field(repr=False) @classmethod def from_environment(cls, environment: Mapping[str, str] | None = None) -> PublicApiSettings: @@ -133,7 +142,7 @@ def __init__( settings: PublicApiSettings, shared_store: SharedTokenStore | None = None, clock: Callable[[], float] = time.time, - opener: Any = NO_REDIRECT_OPENER, + opener: Opener = NO_REDIRECT_OPENER, ) -> None: self.settings = settings self.shared_store = shared_store @@ -233,14 +242,19 @@ def call_public_api( path: str, body: Any = None, *, - opener: Any = None, + opener: Opener | None = None, timeout_seconds: float = PUBLIC_API_TIMEOUT_SECONDS, ) -> Any: """Sends one request with the server token and returns the parsed JSON answer. - Every error is raised as urllib's HTTPError, with the status and the answer's - body. A 401 is raised too, without asking Auth0 for another token (see the - module docstring). + Raises: + PublicApiTokenError: no token could be obtained from Auth0. + urllib.error.HTTPError: the Public API answered 3xx (never followed) or an + error status; ``error.code`` is the status and ``error.read()`` the body. + A 401 is raised without asking Auth0 for another token (see the module + docstring). + urllib.error.URLError, TimeoutError: the Public API could not be reached in time. + ValueError: the answer was not JSON. """ opener = tokens.opener if opener is None else opener data = None if body is None else json.dumps(body).encode() diff --git a/skills/policyengine-api/SKILL.md b/skills/policyengine-api/SKILL.md index 69e7546..cabba92 100644 --- a/skills/policyengine-api/SKILL.md +++ b/skills/policyengine-api/SKILL.md @@ -34,7 +34,8 @@ client, and the errors. Flask (`policyengine_api`, Python 3.10/3.11). Country id (`us`, `uk`, `ca`, …) is the first path segment. Every route except the public ones below needs a server credential once the -requirement is on. Verified route surface (`policyengine_api/routes/`, `api.py`): +requirement is on. Verified route surface (`policyengine_api/routes/` and `api.py`; the public +`/health` and `/v2/openapi.json` are in `policyengine_api/fastapi_routes/`): | Route | Method | Purpose | |---|---|---| diff --git a/targets/claude/agents/dashboard/backend-builder.md b/targets/claude/agents/dashboard/backend-builder.md index 2fbdc64..e89609a 100644 --- a/targets/claude/agents/dashboard/backend-builder.md +++ b/targets/claude/agents/dashboard/backend-builder.md @@ -132,17 +132,16 @@ Read the plan's endpoints and write the household and result types. Use `type` a ```typescript // types.ts -/** A group entity: its members, and its variables keyed by year */ -export type GroupEntity = { members: string[]; [variable: string]: unknown }; - /** - * A household in PolicyEngine's situation format: values keyed by year. The group - * entities differ by country (US: tax_units, spm_units, families, marital_units, - * households; UK: benunits, households); read them from the country's metadata. + * A household in PolicyEngine's situation format: values keyed by year, and null for + * each output to calculate. The group entities differ by country (US: tax_units, + * spm_units, families, marital_units, households; UK: benunits, households); read them + * from the country's metadata. `axes` varies one input over a range (integrator Step 6). */ export type Household = { people: Record>>; - [groupEntities: string]: Record; + axes?: Array>; + [groupEntities: string]: unknown; }; /** The calculated household: the same shape, with the requested variables filled in */ diff --git a/targets/claude/agents/dashboard/dashboard-integrator.md b/targets/claude/agents/dashboard/dashboard-integrator.md index 2d306ab..42955e8 100644 --- a/targets/claude/agents/dashboard/dashboard-integrator.md +++ b/targets/claude/agents/dashboard/dashboard-integrator.md @@ -106,7 +106,7 @@ function buildHouseholdDict(values: FormValues): Record { } ``` -For `data_pattern: policyengine-api`, pass `buildHouseholdDict(values)` to the backend-builder's `useCalculation(countryId)` mutation: `@policyengine/api-client` takes the country and the household, not `buildHouseholdRequest`'s shape. Its result is the calculated household itself, keyed by entity, not `HouseholdSimulationResult`. +For `data_pattern: policyengine-api`, declare it so that `buildHouseholdDict` returns `Household` (from `lib/api/types`), with each output the plan needs named on its entity as `null` for the year, and pass it to the backend-builder's `useCalculation(countryId)` mutation: `@policyengine/api-client` takes the country and the household, not `buildHouseholdRequest`'s shape. The result is the calculated household in the same shape, so the transformers read `result.people.head.income_tax[year]` and `result.households.household.household_net_income[year]` rather than `HouseholdSimulationResult`'s `household[0]` and `person[0]`. ### Step 3: Build Response Transformers @@ -194,7 +194,29 @@ For every component that displays data: ### Step 6: Variation Calculations (if applicable) -If the plan includes charts that vary a parameter (e.g., "tax by income"), implement the variation logic: +If the plan includes charts that vary a parameter (e.g., "tax by income"), implement the variation logic. + +For `data_pattern: policyengine-api`, send one calculation with `axes`, never one per point: the dashboard API allows 30 household calculations a minute from one address, and a refused one shows as `status` `null` on localhost and previews. Each output then comes back as a list over the points: + +```typescript +export function useIncomeVariation(baseValues: FormValues, countryId: 'us' | 'uk') { + return useQuery({ + queryKey: ['income-variation', countryId, baseValues], + queryFn: ({ signal }) => { + const year = String(baseValues.year); + const household = buildHouseholdDict(baseValues); + household.people.head.employment_income = { [year]: null }; + household.axes = [[{ name: 'employment_income', period: year, min: 0, max: 500000, count: 21 }]]; + return calculate(countryId, household, signal); + }, + enabled: !!baseValues.state, // Only run when required inputs are set + retry: 1, + staleTime: 30 * 60 * 1000, + }); +} +``` + +For a custom backend, which has no such limit: ```typescript export function useIncomeVariation(baseValues: FormValues, countryId: string) { diff --git a/targets/claude/agents/dashboard/dashboard-scaffold.md b/targets/claude/agents/dashboard/dashboard-scaffold.md index 04242f4..ccff223 100644 --- a/targets/claude/agents/dashboard/dashboard-scaffold.md +++ b/targets/claude/agents/dashboard/dashboard-scaffold.md @@ -329,7 +329,7 @@ export function Providers({ children }: { children: React.ReactNode }) { #### API Client Stubs -Generate `lib/api/types.ts` with TypeScript interfaces matching the plan's endpoint inputs/outputs. +Generate `lib/api/types.ts` with TypeScript types matching the plan's endpoint inputs/outputs. Declare anything passed to `@policyengine/api-client` as a `type` alias, not an `interface`: the client takes `Record`, which an interface is not assignable to. Generate `lib/api/fixtures.ts` with mock data from `plan.yaml`'s `stub_fixtures`. diff --git a/tests/test_api_access_skill.py b/tests/test_api_access_skill.py index 5ef6f02..fda8f48 100644 --- a/tests/test_api_access_skill.py +++ b/tests/test_api_access_skill.py @@ -88,14 +88,6 @@ ) HANDLED_STATUSES = ("401", "403", "429", "503") -BROWSER_LANGUAGES = {"ts", "tsx", "js", "jsx", "javascript", "typescript"} -PUBLIC_API_HOST = re.compile(r"api\.policyengine\.org|policyengine-api[a-z0-9-]*\.[a-z0-9.-]*run\.app") -# A credential-looking name with a prefix that bundlers put into browser code. -PUBLIC_PREFIX_CREDENTIAL = re.compile( - r"\b(?:NEXT_PUBLIC|VITE)_[A-Z0-9_]*(?:AUTH0|SECRET|TOKEN|CLIENT|CREDENTIAL|POLICYENGINE_API)[A-Z0-9_]*" -) -FENCE = re.compile(r"^```([A-Za-z0-9_+-]*)\n(.*?)^```", re.DOTALL | re.MULTILINE) - def skill_text() -> str: assert SKILL_FILE.is_file(), f"{SKILL_FILE.relative_to(REPO_ROOT)} is missing" @@ -109,10 +101,6 @@ def skill_frontmatter() -> dict: return yaml.safe_load(match.group(1)) -def fenced_blocks(text: str) -> list[tuple[str, str]]: - return [(language.lower(), body) for language, body in FENCE.findall(text)] - - def test_frontmatter_names_the_skill_and_its_category() -> None: frontmatter = skill_frontmatter() assert frontmatter["name"] == SKILL_NAME @@ -182,31 +170,6 @@ def test_skill_says_how_to_handle_each_refusal(status_code: str) -> None: ) -def test_no_browser_language_example_names_a_public_api_host() -> None: - offenders = [ - body - for language, body in fenced_blocks(skill_text()) - if language in BROWSER_LANGUAGES and PUBLIC_API_HOST.search(body) - ] - assert offenders == [] - - -def test_skill_never_puts_a_credential_in_a_public_prefix_variable() -> None: - assert PUBLIC_PREFIX_CREDENTIAL.findall(skill_text()) == [] - - -def test_public_prefix_credential_pattern_catches_bundled_names() -> None: - for unsafe in ( - "NEXT_PUBLIC_POLICYENGINE_API_AUTH0_CLIENT_SECRET", - "VITE_AUTH0_CLIENT_ID", - "NEXT_PUBLIC_API_TOKEN", - "VITE_POLICYENGINE_API_URL", - ): - assert PUBLIC_PREFIX_CREDENTIAL.search(unsafe), unsafe - for safe in ("NEXT_PUBLIC_*", "VITE_*", "NEXT_PUBLIC_MODAL_URL", "POLICYENGINE_API_AUTH0_CLIENT_SECRET"): - assert not PUBLIC_PREFIX_CREDENTIAL.search(safe), safe - - def test_skill_points_servers_at_the_token_template() -> None: assert "templates/public_api_token.py" in skill_text() @@ -364,7 +327,9 @@ def test_template_turns_a_redirected_token_request_into_an_error() -> None: class RedirectingTokenEndpoint(RecordingOpener): def open(self, request, timeout=None): # noqa: ANN001 - urllib's opener signature - raise urllib.error.HTTPError(request.full_url, 307, "Temporary Redirect", {"Location": "https://elsewhere.test/"}, None) + raise urllib.error.HTTPError( + request.full_url, 307, "Temporary Redirect", {"Location": "https://elsewhere.test/"}, None + ) shared_store: dict = {} tokens = token_module.PublicApiTokenProvider( diff --git a/tests/test_public_api_browser_guidance.py b/tests/test_public_api_browser_guidance.py index 8938748..e313fa6 100644 --- a/tests/test_public_api_browser_guidance.py +++ b/tests/test_public_api_browser_guidance.py @@ -27,7 +27,9 @@ REPO_ROOT = Path(__file__).resolve().parent.parent SCAN_DIRS = ("skills", "targets", "docs") -TEXT_SUFFIXES = {".md", ".json", ".yaml", ".yml", ".py", ".sh", ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".html"} +TEXT_SUFFIXES = { + ".md", ".json", ".yaml", ".yml", ".py", ".sh", ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".html", ".vue", ".svelte", +} BROWSER_FILE_SUFFIXES = {".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".html", ".vue", ".svelte"} BROWSER_LANGUAGES = { @@ -45,20 +47,25 @@ ) # ``` or ~~~ fences of three or more characters, closed by the same fence. FENCE = re.compile( - r"^[ \t]*(?P`{3,}|~{3,})(?P[A-Za-z0-9_+-]*)[^\n]*\n(?P.*?)^[ \t]*(?P=fence)[ \t]*$", + r"^[ \t]*(?P`{3,}|~{3,})[ \t]*(?P[A-Za-z0-9_+-]*)[^\n]*\n(?P.*?)^[ \t]*(?P=fence)[ \t]*$", re.DOTALL | re.MULTILINE, ) +# An *_AUDIENCE name holds API v1's Auth0 identifier for a browser's sign-in, not an +# address to call, so it is left out. PUBLIC_PREFIX_SET_TO_PUBLIC_API = re.compile( - r"\b(?:NEXT_PUBLIC|VITE|REACT_APP)_[A-Z0-9_]+[\"']?\s*(?:[=:]|\|\|)\s*[\"'`]?https?://" + r"\b(?:NEXT_PUBLIC|VITE|REACT_APP)_(?![A-Z0-9_]*AUDIENCE)[A-Z0-9_]+[\"']?\s*(?:[=:]|\|\||\?\?)\s*[\"'`]?https?://" r"(?:api\.policyengine\.org|(?:[a-z0-9-]+---)?policyengine-api[a-z0-9-]*\.[a-z0-9.-]*run\.app)" ) -# A public-prefix name that holds a secret, or that is named for the Public API's +# A public-prefix name that holds a secret, that is an unqualified token or key +# (NEXT_PUBLIC_API_KEY, VITE_ACCESS_TOKEN), or that is named for the Public API's # address or server client. A browser's own sign-in settings (VITE_AUTH0_DOMAIN, # VITE_AUTH0_CLIENT_ID, NEXT_PUBLIC_AUTH0_AUDIENCE) and other services' public -# tokens are public by design. +# tokens named for their service (NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN) are public by design. PUBLIC_PREFIX_CREDENTIAL = re.compile( - r"\b(?:NEXT_PUBLIC|VITE|REACT_APP)_(?=[A-Z0-9_]*(?:SECRET|PASSWORD|PRIVATE_KEY|CREDENTIAL" - r"|(? Date: Wed, 11 Nov 2026 01:59:05 +0400 Subject: [PATCH 15/16] Test the round-3 review's findings - The token template's Opener Protocol takes the request positionally and the timeout by keyword, as urllib's opener does, and its docstring says how to drop a revoked token. - The skill's household example asks for an output with null. - The guard catches API_ACCESS_TOKEN and API_BEARER_TOKEN names and accepts app-v2's NEXT_PUBLIC_POLICYENGINE_API_V2_URL and a token named for another service. - backend-builder offers a typed readVariable() for the calculated household and the integrator uses it; the integrator debounces form values before calculating and runs the variation chart for the UK too. - The first 401 row no longer says a malformed PolicyEngine-Unauthenticated-User gets the same answer. Co-Authored-By: Claude Opus 5.5 --- tests/test_api_access_skill.py | 24 ++++++++++++++++++ tests/test_public_api_browser_guidance.py | 31 +++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/tests/test_api_access_skill.py b/tests/test_api_access_skill.py index fda8f48..d86c08b 100644 --- a/tests/test_api_access_skill.py +++ b/tests/test_api_access_skill.py @@ -490,3 +490,27 @@ def test_skill_says_the_calculation_returns_only_the_variables_asked_for() -> No text = skill_text() assert "/{country}/calculate" in text assert "with `null` for the year" in text + + +# --- Review round 3 ------------------------------------------------------------ + + +def test_template_opener_protocol_takes_the_request_positionally_and_timeout_by_keyword() -> None: + # urllib's OpenerDirector.open(fullurl, data=None, timeout=...) has data second, + # so a Protocol with timeout second does not fit it under mypy. + import inspect + + token_module = load_token_module() + parameters = inspect.signature(token_module.Opener.open).parameters + assert parameters["request"].kind is inspect.Parameter.POSITIONAL_ONLY + assert parameters["timeout"].kind is inspect.Parameter.KEYWORD_ONLY + + +def test_template_says_how_to_drop_a_revoked_token() -> None: + assert "revoked" in load_token_module().__doc__ + + +def test_skill_household_example_asks_for_an_output() -> None: + # The calculation adds no omitted variables, so an example that names no + # output would get its inputs back unchanged. + assert "household_net_income: { 2026: null }" in skill_text() diff --git a/tests/test_public_api_browser_guidance.py b/tests/test_public_api_browser_guidance.py index e313fa6..8cb4937 100644 --- a/tests/test_public_api_browser_guidance.py +++ b/tests/test_public_api_browser_guidance.py @@ -181,6 +181,8 @@ def test_guards_catch_the_patterns_they_name() -> None: "NEXT_PUBLIC_BEARER_TOKEN", "VITE_ACCESS_TOKEN", "VITE_POLICYENGINE_TOKEN", + "VITE_API_ACCESS_TOKEN", + "NEXT_PUBLIC_API_BEARER_TOKEN", ): assert PUBLIC_PREFIX_SET_TO_PUBLIC_API.search(unsafe) or PUBLIC_PREFIX_CREDENTIAL.search(unsafe), unsafe for safe in ( @@ -197,6 +199,9 @@ def test_guards_catch_the_patterns_they_name() -> None: # The browser sign-in audience is API v1's identifier, not an address to call. "NEXT_PUBLIC_AUTH0_AUDIENCE=https://api.policyengine.org/", "VITE_AUTH0_AUDIENCE: 'https://api.policyengine.org/'", + # app-v2's v2 alpha address, and a token named for another service. + "NEXT_PUBLIC_POLICYENGINE_API_V2_URL", + "VITE_POLICYENGINE_MAPBOX_TOKEN", ): assert not PUBLIC_PREFIX_SET_TO_PUBLIC_API.search(safe), safe assert not PUBLIC_PREFIX_CREDENTIAL.search(safe), safe @@ -273,3 +278,29 @@ def test_integrator_types_the_household_for_the_client() -> None: def test_contributing_documents_the_server_code_marker() -> None: assert SERVER_CODE_MARKER in (REPO_ROOT / "CONTRIBUTING.md").read_text() + + +BACKEND_BUILDER = REPO_ROOT / "targets/claude/agents/dashboard/backend-builder.md" + + +def test_calculated_household_is_read_through_a_typed_helper() -> None: + # With an `unknown` index signature, result.households.household... does not + # compile under strict mode, so transformers read through readVariable(). + assert "export function readVariable(" in BACKEND_BUILDER.read_text() + integrator = INTEGRATOR.read_text() + assert "readVariable(" in integrator + assert "result.households.household.household_net_income[year]" not in integrator + + +def test_integrator_debounces_calculations_and_runs_for_every_country() -> None: + integrator = INTEGRATOR.read_text() + assert "useDebouncedValue" in integrator.split("### Step 4", 1)[1].split("\n### ", 1)[0] + variation = integrator.split("### Step 6", 1)[1].split("\n### ", 1)[0] + assert "useDebouncedValue" in variation + assert "countryId === 'uk'" in variation + + +def test_first_401_row_does_not_claim_a_malformed_anonymous_header_gets_the_same_answer() -> None: + skill = (REPO_ROOT / "skills/policyengine-api-access/SKILL.md").read_text() + rows_401 = [row for row in skill.split("## Errors", 1)[1].splitlines() if row.startswith("| 401 ")] + assert rows_401 and not any("malformed `PolicyEngine-Unauthenticated-User`" in row for row in rows_401) From 2e751e5eb1e296e288ac8ba4f808d2c87f53a6f3 Mon Sep 17 00:00:00 2001 From: Anthony Volk <14987227+anth-volk@users.noreply.github.com> Date: Wed, 11 Nov 2026 02:02:07 +0400 Subject: [PATCH 16/16] Fix the round-3 review's findings - backend-builder: CalculatedHousehold is Record with a typed readVariable() helper, since result.households.household... does not compile against an unknown index signature (TS18046 under strict); CalculatedValue includes the lists axes return. The integrator reads results through readVariable(). - Integrator: the policyengine-api pattern calculates from debounced form values (useDebouncedValue, compared by content), keyed in React Query, so typing or dragging sends one calculation per pause instead of one per keystroke against the 30-a-minute limit; the variation chart is debounced too and runs for UK households, which have no state. - Token template: the Opener Protocol takes the request by position and the timeout by keyword, as urllib's opener does; _is_usable is a TypeGuard and the template passes mypy --strict. Its docstring says how to drop a token that Auth0 has revoked. - Skill: the household example asks for household_net_income with null; the first 401 row no longer claims a malformed PolicyEngine-Unauthenticated-User gets the same answer. - Guard: API_ACCESS_TOKEN and API_BEARER_TOKEN names are caught; NEXT_PUBLIC_POLICYENGINE_API_V2_URL and tokens named for another service are accepted. - The dashboard manifest is rebuilt. The examples in backend-builder's Pattern B and the integrator's Steps 4 and 6 type-check together under strict against @policyengine/api-client 0.1.0's source (TypeScript 5.9). Co-Authored-By: Claude Opus 5.5 --- dashboard/src/data/manifest.json | 1378 ++++++++--------- skills/policyengine-api-access/SKILL.md | 4 +- .../templates/public_api_token.py | 31 +- .../agents/dashboard/backend-builder.md | 24 +- .../agents/dashboard/dashboard-integrator.md | 41 +- tests/test_public_api_browser_guidance.py | 5 +- 6 files changed, 771 insertions(+), 712 deletions(-) diff --git a/dashboard/src/data/manifest.json b/dashboard/src/data/manifest.json index 314e437..f088f21 100644 --- a/dashboard/src/data/manifest.json +++ b/dashboard/src/data/manifest.json @@ -1,5 +1,5 @@ { - "generated_at": "2026-11-10T20:27:31.433668Z", + "generated_at": "2026-11-10T22:02:06.973729Z", "counts": { "skill": 25, "agent": 36, @@ -376,7 +376,7 @@ "use_instead": [], "registry_notes": "Recommended for the listed scope.", "references": {}, - "body_length": 19369 + "body_length": 19355 }, { "id": "policyengine-app", @@ -2189,7 +2189,7 @@ "deploy-dashboard" ] }, - "body_length": 23770 + "body_length": 24570 }, { "id": "dashboard-architecture-validator", @@ -2340,7 +2340,7 @@ "policyengine-tools" ] }, - "body_length": 8220 + "body_length": 9815 }, { "id": "dashboard-plan-validator", @@ -7428,7 +7428,7 @@ "kind": "agent", "id": "review-worker" }, - "score": 0.619, + "score": 0.6191, "shared_terms": [ "your", "assigned", @@ -7449,7 +7449,7 @@ "kind": "skill", "id": "policyengine-api-access" }, - "score": 0.6147, + "score": 0.6187, "shared_terms": [ "api", "client", @@ -7617,7 +7617,7 @@ "kind": "skill", "id": "policyengine-us" }, - "score": 0.5309, + "score": 0.5307, "shared_terms": [ "unit", "tax", @@ -7722,7 +7722,7 @@ "kind": "agent", "id": "prior-scores-finder" }, - "score": 0.4756, + "score": 0.4757, "shared_terms": [ "prior", "tier", @@ -7749,8 +7749,8 @@ "next", "bun", "vite", - "host", "multizone", + "host", "router", "vercel" ] @@ -7764,7 +7764,7 @@ "kind": "agent", "id": "test-creator" }, - "score": 0.4657, + "score": 0.4656, "shared_terms": [ "test", "tests", @@ -7806,7 +7806,7 @@ "kind": "agent", "id": "dashboard-plan-validator" }, - "score": 0.4594, + "score": 0.4595, "shared_terms": [ "grep", "components", @@ -7869,7 +7869,7 @@ "kind": "agent", "id": "dashboard-integrator" }, - "score": 0.4254, + "score": 0.4217, "shared_terms": [ "api", "data", @@ -7878,7 +7878,7 @@ "pattern", "step", "dashboard", - "plan" + "builder" ] }, { @@ -7890,13 +7890,13 @@ "kind": "agent", "id": "dashboard-integrator" }, - "score": 0.4177, + "score": 0.4204, "shared_terms": [ "api", "client", "household", - "dashboard", "backend", + "dashboard", "request", "result", "through" @@ -7953,7 +7953,7 @@ "kind": "command", "id": "create-pr" }, - "score": 0.4029, + "score": 0.4031, "shared_terms": [ "echo", "wait", @@ -7995,7 +7995,7 @@ "kind": "command", "id": "prior-analysis" }, - "score": 0.3972, + "score": 0.3971, "shared_terms": [ "analyses", "prior", @@ -8049,27 +8049,6 @@ "tailwind" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-api" - }, - "b": { - "kind": "agent", - "id": "dashboard-integrator" - }, - "score": 0.3827, - "shared_terms": [ - "api", - "household", - "client", - "data", - "values", - "response", - "dashboard", - "request" - ] - }, { "a": { "kind": "agent", @@ -8079,7 +8058,7 @@ "kind": "command", "id": "write-tests" }, - "score": 0.381, + "score": 0.3809, "shared_terms": [ "test", "tests", @@ -8091,6 +8070,27 @@ "component" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-api" + }, + "b": { + "kind": "agent", + "id": "dashboard-integrator" + }, + "score": 0.3799, + "shared_terms": [ + "api", + "household", + "client", + "data", + "values", + "dashboard", + "request", + "response" + ] + }, { "a": { "kind": "skill", @@ -8100,7 +8100,7 @@ "kind": "agent", "id": "backend-builder" }, - "score": 0.3768, + "score": 0.3755, "shared_terms": [ "api", "client", @@ -8121,7 +8121,7 @@ "kind": "command", "id": "write-tests" }, - "score": 0.3734, + "score": 0.3733, "shared_terms": [ "test", "tests", @@ -8163,15 +8163,15 @@ "kind": "command", "id": "household-calc" }, - "score": 0.3657, + "score": 0.3654, "shared_terms": [ "household", "income", "microsimulation", "tax", "reform", - "net", "level", + "net", "result" ] }, @@ -8217,27 +8217,6 @@ "independent" ] }, - { - "a": { - "kind": "agent", - "id": "policy-text-researcher" - }, - "b": { - "kind": "command", - "id": "text-to-reform" - }, - "score": 0.3539, - "shared_terms": [ - "bill", - "reform", - "ages", - "description", - "text", - "federal", - "natural", - "arpa" - ] - }, { "a": { "kind": "agent", @@ -8259,6 +8238,27 @@ "css" ] }, + { + "a": { + "kind": "agent", + "id": "policy-text-researcher" + }, + "b": { + "kind": "command", + "id": "text-to-reform" + }, + "score": 0.3538, + "shared_terms": [ + "bill", + "reform", + "ages", + "description", + "text", + "federal", + "natural", + "arpa" + ] + }, { "a": { "kind": "skill", @@ -8331,7 +8331,7 @@ "kind": "skill", "id": "policyengine-user-guide" }, - "score": 0.3471, + "score": 0.347, "shared_terms": [ "household", "income", @@ -8352,7 +8352,7 @@ "kind": "agent", "id": "implementation-validator" }, - "score": 0.346, + "score": 0.3459, "shared_terms": [ "root", "fix", @@ -8394,7 +8394,7 @@ "kind": "command", "id": "new-tool" }, - "score": 0.3419, + "score": 0.342, "shared_terms": [ "kit", "css", @@ -8499,7 +8499,7 @@ "kind": "command", "id": "household-calc" }, - "score": 0.332, + "score": 0.3317, "shared_terms": [ "household", "reform", @@ -8667,7 +8667,7 @@ "kind": "agent", "id": "dashboard-scaffold" }, - "score": 0.3199, + "score": 0.3189, "shared_terms": [ "api", "client", @@ -8700,6 +8700,27 @@ "embedding" ] }, + { + "a": { + "kind": "command", + "id": "encode-reform" + }, + "b": { + "kind": "command", + "id": "text-to-reform" + }, + "score": 0.3156, + "shared_terms": [ + "bill", + "reform", + "reforms", + "federal", + "full", + "arguments", + "analyze", + "description" + ] + }, { "a": { "kind": "skill", @@ -8709,7 +8730,7 @@ "kind": "skill", "id": "policyengine-us" }, - "score": 0.3159, + "score": 0.3155, "shared_terms": [ "tax", "unit", @@ -8742,27 +8763,6 @@ "gov" ] }, - { - "a": { - "kind": "command", - "id": "encode-reform" - }, - "b": { - "kind": "command", - "id": "text-to-reform" - }, - "score": 0.3155, - "shared_terms": [ - "bill", - "reform", - "reforms", - "federal", - "full", - "arguments", - "analyze", - "description" - ] - }, { "a": { "kind": "agent", @@ -8772,7 +8772,7 @@ "kind": "agent", "id": "pr-pusher" }, - "score": 0.3139, + "score": 0.3138, "shared_terms": [ "repo", "branch", @@ -8814,7 +8814,7 @@ "kind": "agent", "id": "test-creator" }, - "score": 0.3068, + "score": 0.3067, "shared_terms": [ "tests", "test", @@ -8877,7 +8877,7 @@ "kind": "agent", "id": "parameter-locator" }, - "score": 0.3056, + "score": 0.3057, "shared_terms": [ "tax", "income", @@ -8961,7 +8961,7 @@ "kind": "command", "id": "household-calc" }, - "score": 0.3005, + "score": 0.3, "shared_terms": [ "household", "income", @@ -8982,7 +8982,7 @@ "kind": "agent", "id": "dashboard-scaffold" }, - "score": 0.2981, + "score": 0.2977, "shared_terms": [ "api", "dashboard", @@ -9003,7 +9003,7 @@ "kind": "command", "id": "new-tool" }, - "score": 0.2972, + "score": 0.2971, "shared_terms": [ "dashboard", "create", @@ -9045,7 +9045,7 @@ "kind": "agent", "id": "review-worker" }, - "score": 0.2957, + "score": 0.2956, "shared_terms": [ "review", "canonical", @@ -9066,7 +9066,7 @@ "kind": "command", "id": "new-tool" }, - "score": 0.2939, + "score": 0.2937, "shared_terms": [ "app", "calculator", @@ -9162,6 +9162,27 @@ "audit" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-api" + }, + "b": { + "kind": "agent", + "id": "backend-builder" + }, + "score": 0.2899, + "shared_terms": [ + "api", + "client", + "public", + "dashboard", + "json", + "data", + "simulation", + "cloud" + ] + }, { "a": { "kind": "command", @@ -9183,27 +9204,6 @@ "host" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-api" - }, - "b": { - "kind": "agent", - "id": "backend-builder" - }, - "score": 0.2897, - "shared_terms": [ - "api", - "client", - "public", - "dashboard", - "json", - "data", - "simulation", - "cloud" - ] - }, { "a": { "kind": "skill", @@ -9213,7 +9213,7 @@ "kind": "agent", "id": "pr-pusher" }, - "score": 0.2881, + "score": 0.2884, "shared_terms": [ "changelog", "repo", @@ -9234,7 +9234,7 @@ "kind": "command", "id": "new-tool" }, - "score": 0.2868, + "score": 0.2869, "shared_terms": [ "kit", "app", @@ -9255,7 +9255,7 @@ "kind": "agent", "id": "dashboard-architecture-validator" }, - "score": 0.2863, + "score": 0.2864, "shared_terms": [ "app", "router", @@ -9276,7 +9276,7 @@ "kind": "command", "id": "text-to-reform" }, - "score": 0.2857, + "score": 0.2858, "shared_terms": [ "reform", "dict", @@ -9318,7 +9318,7 @@ "kind": "skill", "id": "policyengine-user-guide" }, - "score": 0.2838, + "score": 0.2836, "shared_terms": [ "household", "income", @@ -9360,7 +9360,7 @@ "kind": "skill", "id": "policyengine-uk" }, - "score": 0.2803, + "score": 0.28, "shared_terms": [ "household", "canada", @@ -9369,7 +9369,7 @@ "benefit", "tax", "poverty", - "net" + "age" ] }, { @@ -9402,7 +9402,7 @@ "kind": "command", "id": "new-tool" }, - "score": 0.2786, + "score": 0.2787, "shared_terms": [ "css", "theme", @@ -9423,7 +9423,7 @@ "kind": "command", "id": "text-to-reform" }, - "score": 0.2777, + "score": 0.2776, "shared_terms": [ "bill", "reform", @@ -9444,7 +9444,7 @@ "kind": "command", "id": "backdate-program" }, - "score": 0.276, + "score": 0.2759, "shared_terms": [ "worktree", "root", @@ -9465,7 +9465,7 @@ "kind": "agent", "id": "dashboard-plan-validator" }, - "score": 0.2755, + "score": 0.2756, "shared_terms": [ "grep", "app", @@ -9519,6 +9519,27 @@ "code" ] }, + { + "a": { + "kind": "agent", + "id": "ci-fixer" + }, + "b": { + "kind": "agent", + "id": "test-creator" + }, + "score": 0.2719, + "shared_terms": [ + "test", + "tests", + "files", + "variable", + "cases", + "not", + "fix", + "aggregation" + ] + }, { "a": { "kind": "skill", @@ -9540,27 +9561,6 @@ "import" ] }, - { - "a": { - "kind": "agent", - "id": "ci-fixer" - }, - "b": { - "kind": "agent", - "id": "test-creator" - }, - "score": 0.2716, - "shared_terms": [ - "test", - "tests", - "files", - "variable", - "cases", - "not", - "fix", - "aggregation" - ] - }, { "a": { "kind": "agent", @@ -9570,7 +9570,7 @@ "kind": "agent", "id": "reform-comparator" }, - "score": 0.2687, + "score": 0.2688, "shared_terms": [ "version", "result", @@ -9612,7 +9612,7 @@ "kind": "agent", "id": "reform-comparator" }, - "score": 0.2671, + "score": 0.2672, "shared_terms": [ "prior", "anchor", @@ -9633,7 +9633,7 @@ "kind": "agent", "id": "parameter-locator" }, - "score": 0.2665, + "score": 0.2666, "shared_terms": [ "income", "tax", @@ -9687,6 +9687,27 @@ "next" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-api-access" + }, + "b": { + "kind": "command", + "id": "new-tool" + }, + "score": 0.2628, + "shared_terms": [ + "api", + "dashboard", + "public", + "client", + "const", + "page", + "app", + "org" + ] + }, { "a": { "kind": "skill", @@ -9696,7 +9717,7 @@ "kind": "command", "id": "household-calc" }, - "score": 0.263, + "score": 0.2626, "shared_terms": [ "household", "tax", @@ -9750,27 +9771,6 @@ "write" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-api-access" - }, - "b": { - "kind": "command", - "id": "new-tool" - }, - "score": 0.2615, - "shared_terms": [ - "api", - "dashboard", - "public", - "client", - "const", - "page", - "app", - "org" - ] - }, { "a": { "kind": "agent", @@ -9780,7 +9780,7 @@ "kind": "agent", "id": "pr-pusher" }, - "score": 0.2607, + "score": 0.2606, "shared_terms": [ "caller", "git", @@ -9864,7 +9864,7 @@ "kind": "command", "id": "text-to-reform" }, - "score": 0.2578, + "score": 0.2579, "shared_terms": [ "reform", "scorekeepers", @@ -9906,7 +9906,7 @@ "kind": "agent", "id": "policy-text-researcher" }, - "score": 0.2564, + "score": 0.2563, "shared_terms": [ "gov", "state", @@ -9969,7 +9969,7 @@ "kind": "command", "id": "text-to-reform" }, - "score": 0.2546, + "score": 0.2548, "shared_terms": [ "reform", "preset", @@ -10095,7 +10095,7 @@ "kind": "agent", "id": "reform-comparator" }, - "score": 0.2492, + "score": 0.2493, "shared_terms": [ "our", "microsim", @@ -10137,7 +10137,7 @@ "kind": "command", "id": "prior-analysis" }, - "score": 0.2475, + "score": 0.2474, "shared_terms": [ "prior", "scripts", @@ -10151,14 +10151,35 @@ }, { "a": { - "kind": "agent", - "id": "pr-pusher" + "kind": "skill", + "id": "policyengine" }, "b": { - "kind": "command", - "id": "create-pr" - }, - "score": 0.2461, + "kind": "agent", + "id": "dashboard-integrator" + }, + "score": 0.2468, + "shared_terms": [ + "household", + "api", + "income", + "data", + "tax", + "unit", + "result", + "year" + ] + }, + { + "a": { + "kind": "agent", + "id": "pr-pusher" + }, + "b": { + "kind": "command", + "id": "create-pr" + }, + "score": 0.2463, "shared_terms": [ "branch", "git", @@ -10179,7 +10200,7 @@ "kind": "command", "id": "new-tool" }, - "score": 0.2456, + "score": 0.2457, "shared_terms": [ "css", "app", @@ -10200,7 +10221,7 @@ "kind": "agent", "id": "test-creator" }, - "score": 0.2452, + "score": 0.2454, "shared_terms": [ "tests", "test", @@ -10221,7 +10242,7 @@ "kind": "skill", "id": "policyengine-app" }, - "score": 0.243, + "score": 0.2433, "shared_terms": [ "api", "app", @@ -10233,27 +10254,6 @@ "next" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine" - }, - "b": { - "kind": "agent", - "id": "dashboard-integrator" - }, - "score": 0.2423, - "shared_terms": [ - "household", - "api", - "income", - "data", - "tax", - "unit", - "result", - "year" - ] - }, { "a": { "kind": "skill", @@ -10263,7 +10263,7 @@ "kind": "command", "id": "audit-multizone" }, - "score": 0.242, + "score": 0.2421, "shared_terms": [ "app", "host", @@ -10284,7 +10284,7 @@ "kind": "command", "id": "audit-state-tax" }, - "score": 0.2412, + "score": 0.2413, "shared_terms": [ "pdf", "reference", @@ -10347,7 +10347,7 @@ "kind": "skill", "id": "policyengine-healthcare" }, - "score": 0.2361, + "score": 0.2356, "shared_terms": [ "household", "income", @@ -10368,7 +10368,7 @@ "kind": "command", "id": "deploy-dashboard" }, - "score": 0.2354, + "score": 0.2355, "shared_terms": [ "app", "host", @@ -10389,7 +10389,7 @@ "kind": "skill", "id": "policyengine-api" }, - "score": 0.2349, + "score": 0.2352, "shared_terms": [ "household", "api", @@ -10418,8 +10418,8 @@ "dashboard", "run", "backend", - "cloud", - "merge" + "merge", + "cloud" ] }, { @@ -10431,7 +10431,7 @@ "kind": "agent", "id": "edge-case-generator" }, - "score": 0.2349, + "score": 0.2348, "shared_terms": [ "test", "files", @@ -10515,7 +10515,7 @@ "kind": "agent", "id": "program-reviewer" }, - "score": 0.2322, + "score": 0.2321, "shared_terms": [ "implementations", "regulations", @@ -10536,7 +10536,7 @@ "kind": "command", "id": "household-calc" }, - "score": 0.2303, + "score": 0.2298, "shared_terms": [ "household", "canada", @@ -10611,27 +10611,6 @@ "import" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-healthcare" - }, - "b": { - "kind": "skill", - "id": "policyengine-uk" - }, - "score": 0.2269, - "shared_terms": [ - "household", - "income", - "tax", - "unit", - "net", - "person", - "credit", - "benefits" - ] - }, { "a": { "kind": "skill", @@ -10641,7 +10620,7 @@ "kind": "agent", "id": "multizone-validator" }, - "score": 0.2268, + "score": 0.2269, "shared_terms": [ "app", "host", @@ -10653,6 +10632,27 @@ "served" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-healthcare" + }, + "b": { + "kind": "skill", + "id": "policyengine-uk" + }, + "score": 0.2262, + "shared_terms": [ + "household", + "income", + "tax", + "unit", + "net", + "person", + "credit", + "benefits" + ] + }, { "a": { "kind": "skill", @@ -10674,27 +10674,6 @@ "approved" ] }, - { - "a": { - "kind": "agent", - "id": "dashboard-integrator" - }, - "b": { - "kind": "agent", - "id": "dashboard-plan-validator" - }, - "score": 0.226, - "shared_terms": [ - "api", - "components", - "data", - "plan", - "loading", - "component", - "chart", - "lib" - ] - }, { "a": { "kind": "skill", @@ -10704,7 +10683,7 @@ "kind": "skill", "id": "policyengine-user-guide" }, - "score": 0.2255, + "score": 0.2253, "shared_terms": [ "household", "tax", @@ -10809,7 +10788,7 @@ "kind": "agent", "id": "ci-fixer" }, - "score": 0.2216, + "score": 0.2215, "shared_terms": [ "fix", "files", @@ -10821,6 +10800,27 @@ "local" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-api" + }, + "b": { + "kind": "agent", + "id": "dashboard-scaffold" + }, + "score": 0.2211, + "shared_terms": [ + "api", + "client", + "dashboard", + "alpha", + "org", + "cloud", + "household", + "public" + ] + }, { "a": { "kind": "skill", @@ -10830,14 +10830,14 @@ "kind": "skill", "id": "policyengine-canada" }, - "score": 0.2213, + "score": 0.221, "shared_terms": [ "household", "income", "tax", "age", - "net", "microsimulation", + "net", "assert", "credit" ] @@ -10865,23 +10865,23 @@ }, { "a": { - "kind": "skill", - "id": "policyengine-api" + "kind": "agent", + "id": "dashboard-integrator" }, "b": { "kind": "agent", - "id": "dashboard-scaffold" + "id": "dashboard-plan-validator" }, - "score": 0.2209, + "score": 0.221, "shared_terms": [ "api", - "client", - "dashboard", - "alpha", - "org", - "cloud", - "household", - "public" + "components", + "plan", + "data", + "loading", + "component", + "lib", + "error" ] }, { @@ -11019,7 +11019,7 @@ "kind": "command", "id": "create-new-component" }, - "score": 0.2158, + "score": 0.2159, "shared_terms": [ "component", "components", @@ -11040,7 +11040,7 @@ "kind": "command", "id": "create-new-component" }, - "score": 0.2154, + "score": 0.2155, "shared_terms": [ "kit", "app", @@ -11073,6 +11073,27 @@ "public" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-api-access" + }, + "b": { + "kind": "agent", + "id": "dashboard-planner" + }, + "score": 0.2146, + "shared_terms": [ + "api", + "dashboard", + "public", + "server", + "pages", + "credential", + "answer", + "modal" + ] + }, { "a": { "kind": "agent", @@ -11115,27 +11136,6 @@ "scope" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-api-access" - }, - "b": { - "kind": "agent", - "id": "dashboard-planner" - }, - "score": 0.2144, - "shared_terms": [ - "api", - "dashboard", - "public", - "server", - "pages", - "credential", - "answer", - "modal" - ] - }, { "a": { "kind": "skill", @@ -11166,7 +11166,7 @@ "kind": "command", "id": "new-tool" }, - "score": 0.2135, + "score": 0.2136, "shared_terms": [ "kit", "app", @@ -11187,7 +11187,7 @@ "kind": "agent", "id": "dashboard-planner" }, - "score": 0.2122, + "score": 0.2123, "shared_terms": [ "plan", "dashboard", @@ -11229,7 +11229,7 @@ "kind": "agent", "id": "microsim-runner" }, - "score": 0.2118, + "score": 0.2116, "shared_terms": [ "api", "economy", @@ -11418,7 +11418,7 @@ "kind": "agent", "id": "model-worker" }, - "score": 0.2051, + "score": 0.205, "shared_terms": [ "test", "root", @@ -11439,7 +11439,7 @@ "kind": "command", "id": "audit-state-tax" }, - "score": 0.2044, + "score": 0.2045, "shared_terms": [ "pdf", "state", @@ -11544,7 +11544,7 @@ "kind": "agent", "id": "parameter-locator" }, - "score": 0.1996, + "score": 0.1995, "shared_terms": [ "gov", "parameter", @@ -11565,7 +11565,7 @@ "kind": "agent", "id": "report-logger" }, - "score": 0.1991, + "score": 0.1992, "shared_terms": [ "posts", "articles", @@ -11607,7 +11607,7 @@ "kind": "agent", "id": "structural-implementer" }, - "score": 0.1969, + "score": 0.197, "shared_terms": [ "changelog", "issue", @@ -11649,7 +11649,7 @@ "kind": "command", "id": "implement-structural" }, - "score": 0.1964, + "score": 0.1965, "shared_terms": [ "issue", "structural", @@ -11754,7 +11754,7 @@ "kind": "agent", "id": "edge-case-generator" }, - "score": 0.1937, + "score": 0.1938, "shared_terms": [ "tests", "test", @@ -11850,27 +11850,6 @@ "app" ] }, - { - "a": { - "kind": "agent", - "id": "dashboard-integrator" - }, - "b": { - "kind": "agent", - "id": "dashboard-planner" - }, - "score": 0.1923, - "shared_terms": [ - "api", - "data", - "dashboard", - "step", - "plan", - "backend", - "components", - "input" - ] - }, { "a": { "kind": "agent", @@ -12039,6 +12018,27 @@ "gov" ] }, + { + "a": { + "kind": "agent", + "id": "dashboard-integrator" + }, + "b": { + "kind": "agent", + "id": "dashboard-planner" + }, + "score": 0.1892, + "shared_terms": [ + "api", + "data", + "dashboard", + "step", + "plan", + "backend", + "components", + "input" + ] + }, { "a": { "kind": "agent", @@ -12165,27 +12165,6 @@ "model" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-api" - }, - "b": { - "kind": "command", - "id": "new-tool" - }, - "score": 0.1851, - "shared_terms": [ - "api", - "dashboard", - "public", - "client", - "org", - "calc", - "country", - "economy" - ] - }, { "a": { "kind": "skill", @@ -12216,7 +12195,7 @@ "kind": "command", "id": "create-dashboard" }, - "score": 0.1847, + "score": 0.1848, "shared_terms": [ "repo", "multi", @@ -12231,13 +12210,34 @@ { "a": { "kind": "skill", - "id": "policyengine-prior-scores" + "id": "policyengine-api" + }, + "b": { + "kind": "command", + "id": "new-tool" + }, + "score": 0.1846, + "shared_terms": [ + "api", + "dashboard", + "public", + "client", + "org", + "calc", + "country", + "economy" + ] + }, + { + "a": { + "kind": "skill", + "id": "policyengine-prior-scores" }, "b": { "kind": "command", "id": "household-calc" }, - "score": 0.1842, + "score": 0.1843, "shared_terms": [ "reform", "preset", @@ -12258,7 +12258,7 @@ "kind": "skill", "id": "policyengine-model-development" }, - "score": 0.1838, + "score": 0.1839, "shared_terms": [ "household", "age", @@ -12294,43 +12294,43 @@ { "a": { "kind": "command", - "id": "audit-seo" + "id": "encode-reform" }, "b": { "kind": "command", - "id": "audit-state-tax" + "id": "implement-structural" }, - "score": 0.1827, + "score": 0.1828, "shared_terms": [ - "audit", - "url", - "github", - "local", - "body", - "step", - "state", - "check" + "reform", + "contrib", + "implement", + "bill", + "gov", + "arguments", + "encode", + "phase" ] }, { "a": { "kind": "command", - "id": "encode-reform" + "id": "audit-seo" }, "b": { "kind": "command", - "id": "implement-structural" + "id": "audit-state-tax" }, "score": 0.1827, "shared_terms": [ - "reform", - "contrib", - "implement", - "bill", - "gov", - "arguments", - "encode", - "phase" + "audit", + "url", + "github", + "local", + "body", + "step", + "state", + "check" ] }, { @@ -12417,27 +12417,6 @@ "group" ] }, - { - "a": { - "kind": "agent", - "id": "rules-engineer" - }, - "b": { - "kind": "command", - "id": "backdate-program" - }, - "score": 0.1811, - "shared_terms": [ - "page", - "program", - "tanf", - "files", - "href", - "pdf", - "yaml", - "only" - ] - }, { "a": { "kind": "agent", @@ -12459,6 +12438,27 @@ "validator" ] }, + { + "a": { + "kind": "agent", + "id": "rules-engineer" + }, + "b": { + "kind": "command", + "id": "backdate-program" + }, + "score": 0.181, + "shared_terms": [ + "page", + "program", + "tanf", + "files", + "href", + "pdf", + "yaml", + "only" + ] + }, { "a": { "kind": "skill", @@ -12564,27 +12564,6 @@ "references" ] }, - { - "a": { - "kind": "agent", - "id": "dashboard-integrator" - }, - "b": { - "kind": "agent", - "id": "microsim-runner" - }, - "score": 0.1804, - "shared_terms": [ - "api", - "data", - "response", - "year", - "result", - "request", - "client", - "state" - ] - }, { "a": { "kind": "skill", @@ -12648,27 +12627,6 @@ "manifest" ] }, - { - "a": { - "kind": "agent", - "id": "dashboard-integrator" - }, - "b": { - "kind": "command", - "id": "new-tool" - }, - "score": 0.1788, - "shared_terms": [ - "api", - "client", - "dashboard", - "countryid", - "create", - "function", - "step", - "import" - ] - }, { "a": { "kind": "agent", @@ -12678,7 +12636,7 @@ "kind": "command", "id": "analyze-policy" }, - "score": 0.178, + "score": 0.1779, "shared_terms": [ "year", "microsim", @@ -12699,14 +12657,14 @@ "kind": "skill", "id": "policyengine-us" }, - "score": 0.1776, + "score": 0.1773, "shared_terms": [ "tax", "household", "income", "credit", - "net", "benefit", + "net", "child", "poverty" ] @@ -12762,7 +12720,7 @@ "kind": "agent", "id": "dashboard-planner" }, - "score": 0.1767, + "score": 0.1769, "shared_terms": [ "api", "dashboard", @@ -12804,7 +12762,7 @@ "kind": "command", "id": "encode-reform" }, - "score": 0.1762, + "score": 0.1763, "shared_terms": [ "pdf", "state", @@ -12837,6 +12795,48 @@ "path" ] }, + { + "a": { + "kind": "agent", + "id": "dashboard-integrator" + }, + "b": { + "kind": "agent", + "id": "frontend-builder" + }, + "score": 0.1756, + "shared_terms": [ + "components", + "builder", + "frontend", + "api", + "component", + "design", + "step", + "client" + ] + }, + { + "a": { + "kind": "agent", + "id": "dashboard-integrator" + }, + "b": { + "kind": "agent", + "id": "microsim-runner" + }, + "score": 0.1748, + "shared_terms": [ + "api", + "data", + "response", + "year", + "result", + "request", + "client", + "state" + ] + }, { "a": { "kind": "skill", @@ -12846,11 +12846,11 @@ "kind": "command", "id": "household-calc" }, - "score": 0.1752, + "score": 0.1741, "shared_terms": [ "household", - "net", "income", + "net", "reform", "benefits", "tax", @@ -12860,23 +12860,23 @@ }, { "a": { - "kind": "agent", - "id": "dashboard-integrator" + "kind": "skill", + "id": "policyengine-us" }, "b": { "kind": "agent", - "id": "frontend-builder" + "id": "dashboard-integrator" }, - "score": 0.1743, + "score": 0.1739, "shared_terms": [ - "components", - "frontend", - "api", - "builder", - "component", - "design", - "chart", - "step" + "household", + "unit", + "tax", + "year", + "income", + "spm", + "head", + "state" ] }, { @@ -12900,6 +12900,27 @@ "explicit" ] }, + { + "a": { + "kind": "agent", + "id": "dashboard-integrator" + }, + "b": { + "kind": "command", + "id": "new-tool" + }, + "score": 0.1732, + "shared_terms": [ + "api", + "client", + "dashboard", + "countryid", + "function", + "import", + "head", + "step" + ] + }, { "a": { "kind": "agent", @@ -13007,23 +13028,23 @@ }, { "a": { - "kind": "skill", - "id": "policyengine-us" + "kind": "agent", + "id": "policy-text-researcher" }, "b": { - "kind": "agent", - "id": "dashboard-integrator" + "kind": "command", + "id": "analyze-policy" }, - "score": 0.1712, + "score": 0.1705, "shared_terms": [ - "household", - "unit", - "tax", + "bill", "year", - "income", - "spm", - "head", - "state" + "arpa", + "federal", + "reform", + "ctc", + "text", + "number" ] }, { @@ -13035,7 +13056,7 @@ "kind": "command", "id": "household-calc" }, - "score": 0.1707, + "score": 0.1703, "shared_terms": [ "household", "api", @@ -13047,27 +13068,6 @@ "simulation" ] }, - { - "a": { - "kind": "agent", - "id": "policy-text-researcher" - }, - "b": { - "kind": "command", - "id": "analyze-policy" - }, - "score": 0.1705, - "shared_terms": [ - "bill", - "year", - "arpa", - "federal", - "reform", - "ctc", - "text", - "number" - ] - }, { "a": { "kind": "agent", @@ -13077,7 +13077,7 @@ "kind": "command", "id": "encode-reform" }, - "score": 0.1701, + "score": 0.1702, "shared_terms": [ "reform", "gov", @@ -13140,7 +13140,7 @@ "kind": "command", "id": "household-calc" }, - "score": 0.1685, + "score": 0.1684, "shared_terms": [ "reform", "household", @@ -13257,6 +13257,27 @@ "root" ] }, + { + "a": { + "kind": "command", + "id": "analyze-policy" + }, + "b": { + "kind": "command", + "id": "household-calc" + }, + "score": 0.1662, + "shared_terms": [ + "reform", + "year", + "yyyy", + "single", + "cost", + "analyze", + "microsim", + "baseline" + ] + }, { "a": { "kind": "skill", @@ -13278,27 +13299,6 @@ "colors" ] }, - { - "a": { - "kind": "command", - "id": "analyze-policy" - }, - "b": { - "kind": "command", - "id": "household-calc" - }, - "score": 0.1661, - "shared_terms": [ - "reform", - "year", - "yyyy", - "single", - "cost", - "analyze", - "microsim", - "baseline" - ] - }, { "a": { "kind": "agent", @@ -13308,7 +13308,7 @@ "kind": "command", "id": "household-calc" }, - "score": 0.1657, + "score": 0.1658, "shared_terms": [ "reform", "description", @@ -13383,6 +13383,27 @@ "multi" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-api-access" + }, + "b": { + "kind": "command", + "id": "create-dashboard" + }, + "score": 0.1648, + "shared_terms": [ + "dashboard", + "api", + "page", + "household", + "pages", + "ctc", + "analysis", + "json" + ] + }, { "a": { "kind": "agent", @@ -13392,7 +13413,7 @@ "kind": "agent", "id": "policy-text-researcher" }, - "score": 0.1646, + "score": 0.1645, "shared_terms": [ "enacted", "effective", @@ -13476,7 +13497,7 @@ "kind": "agent", "id": "test-creator" }, - "score": 0.1638, + "score": 0.1637, "shared_terms": [ "fix", "program", @@ -13540,36 +13561,15 @@ "id": "test-creator" }, "score": 0.1632, - "shared_terms": [ - "month", - "months", - "documentation", - "benefit", - "government", - "program", - "document", - "development" - ] - }, - { - "a": { - "kind": "skill", - "id": "policyengine-api" - }, - "b": { - "kind": "skill", - "id": "policyengine-app" - }, - "score": 0.1631, - "shared_terms": [ - "api", - "server", - "org", - "economy", - "client", - "calc", - "household", - "page" + "shared_terms": [ + "month", + "months", + "documentation", + "benefit", + "government", + "program", + "document", + "development" ] }, { @@ -13617,43 +13617,22 @@ { "a": { "kind": "skill", - "id": "policyengine-api-access" - }, - "b": { - "kind": "command", - "id": "create-dashboard" - }, - "score": 0.1629, - "shared_terms": [ - "dashboard", - "api", - "page", - "household", - "pages", - "ctc", - "analysis", - "json" - ] - }, - { - "a": { - "kind": "skill", - "id": "policyengine-canada" + "id": "policyengine-api" }, "b": { "kind": "skill", - "id": "policyengine-user-guide" + "id": "policyengine-app" }, - "score": 0.1629, + "score": 0.1627, "shared_terms": [ + "api", + "server", + "org", + "economy", + "client", "household", - "income", - "benefit", - "population", - "canada", - "tax", - "net", - "poverty" + "calc", + "page" ] }, { @@ -13677,6 +13656,27 @@ "step" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-canada" + }, + "b": { + "kind": "skill", + "id": "policyengine-user-guide" + }, + "score": 0.1626, + "shared_terms": [ + "household", + "income", + "benefit", + "population", + "canada", + "tax", + "net", + "poverty" + ] + }, { "a": { "kind": "skill", @@ -13761,6 +13761,27 @@ "custom" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-uk" + }, + "b": { + "kind": "agent", + "id": "dashboard-integrator" + }, + "score": 0.1599, + "shared_terms": [ + "household", + "income", + "unit", + "data", + "tax", + "year", + "age", + "person" + ] + }, { "a": { "kind": "agent", @@ -13770,7 +13791,7 @@ "kind": "agent", "id": "review-worker" }, - "score": 0.1597, + "score": 0.1596, "shared_terms": [ "test", "review", @@ -13812,7 +13833,7 @@ "kind": "agent", "id": "microsim-runner" }, - "score": 0.1594, + "score": 0.1595, "shared_terms": [ "result", "dataset", @@ -13848,22 +13869,22 @@ { "a": { "kind": "skill", - "id": "policyengine-uk" + "id": "policyengine" }, "b": { - "kind": "agent", - "id": "dashboard-integrator" + "kind": "skill", + "id": "policyengine-api-access" }, - "score": 0.1583, + "score": 0.1587, "shared_terms": [ "household", - "income", - "data", - "unit", - "tax", - "year", + "api", + "result", + "server", "age", - "person" + "income", + "analysis", + "country" ] }, { @@ -13875,7 +13896,7 @@ "kind": "agent", "id": "reference-validator" }, - "score": 0.1583, + "score": 0.1582, "shared_terms": [ "reference", "pdf", @@ -13992,6 +14013,27 @@ "development" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine" + }, + "b": { + "kind": "command", + "id": "audit-state-tax" + }, + "score": 0.1571, + "shared_terms": [ + "tax", + "state", + "income", + "year", + "result", + "revenue", + "gov", + "python" + ] + }, { "a": { "kind": "agent", @@ -14013,27 +14055,6 @@ "external" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine" - }, - "b": { - "kind": "command", - "id": "audit-state-tax" - }, - "score": 0.157, - "shared_terms": [ - "tax", - "state", - "income", - "year", - "result", - "revenue", - "gov", - "python" - ] - }, { "a": { "kind": "skill", @@ -14106,7 +14127,7 @@ "kind": "command", "id": "create-dashboard" }, - "score": 0.1558, + "score": 0.1559, "shared_terms": [ "household", "ctc", @@ -14181,27 +14202,6 @@ "workflow" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-data" - }, - "b": { - "kind": "skill", - "id": "policyengine-uk" - }, - "score": 0.1542, - "shared_terms": [ - "microcosm", - "data", - "person", - "entity", - "unit", - "household", - "see", - "national" - ] - }, { "a": { "kind": "skill", @@ -14211,7 +14211,7 @@ "kind": "agent", "id": "structural-implementer" }, - "score": 0.1542, + "score": 0.1545, "shared_terms": [ "draft", "changelog", @@ -14223,6 +14223,27 @@ "check" ] }, + { + "a": { + "kind": "skill", + "id": "policyengine-data" + }, + "b": { + "kind": "skill", + "id": "policyengine-uk" + }, + "score": 0.1543, + "shared_terms": [ + "microcosm", + "data", + "person", + "entity", + "unit", + "household", + "see", + "national" + ] + }, { "a": { "kind": "command", @@ -14253,7 +14274,7 @@ "kind": "agent", "id": "dashboard-plan-validator" }, - "score": 0.1534, + "score": 0.1535, "shared_terms": [ "component", "tsx", @@ -14274,7 +14295,7 @@ "kind": "command", "id": "audit-state-tax" }, - "score": 0.1529, + "score": 0.153, "shared_terms": [ "state", "number", @@ -14349,27 +14370,6 @@ "encode" ] }, - { - "a": { - "kind": "skill", - "id": "policyengine-model-development" - }, - "b": { - "kind": "agent", - "id": "structural-implementer" - }, - "score": 0.1513, - "shared_terms": [ - "tests", - "parameter", - "changelog", - "formula", - "encoding", - "bracket", - "contrib", - "model" - ] - }, { "a": { "kind": "skill", @@ -14393,23 +14393,23 @@ }, { "a": { - "kind": "agent", - "id": "dashboard-integrator" + "kind": "skill", + "id": "policyengine-model-development" }, "b": { "kind": "agent", - "id": "parameter-locator" + "id": "structural-implementer" }, - "score": 0.1511, + "score": 0.1512, "shared_terms": [ - "api", - "state", - "income", - "values", - "tax", - "states", - "step", - "household" + "tests", + "parameter", + "changelog", + "formula", + "encoding", + "bracket", + "contrib", + "model" ] }, { @@ -14463,7 +14463,7 @@ "kind": "agent", "id": "microsim-runner" }, - "score": 0.1506, + "score": 0.1507, "shared_terms": [ "data", "api", @@ -14498,23 +14498,23 @@ }, { "a": { - "kind": "skill", - "id": "policyengine" + "kind": "agent", + "id": "dashboard-integrator" }, "b": { - "kind": "skill", - "id": "policyengine-api-access" + "kind": "agent", + "id": "parameter-locator" }, - "score": 0.1502, + "score": 0.1501, "shared_terms": [ - "household", "api", - "result", - "server", - "age", - "analysis", - "country", - "python" + "state", + "income", + "values", + "tax", + "states", + "step", + "household" ] } ], diff --git a/skills/policyengine-api-access/SKILL.md b/skills/policyengine-api-access/SKILL.md index b069503..ffe3ab3 100644 --- a/skills/policyengine-api-access/SKILL.md +++ b/skills/policyengine-api-access/SKILL.md @@ -74,7 +74,7 @@ const household = await policyengine.calculateHousehold({ country: "us", household: { people: { you: { age: { 2026: 40 }, employment_income: { 2026: 50000 } } }, - households: { your_household: { members: ["you"] } }, + households: { your_household: { members: ["you"], household_net_income: { 2026: null } } }, }, policy: { "gov.irs.credits.ctc.amount.base[0].amount": { "2026-01-01.2100-12-31": 3000 } }, }); @@ -273,7 +273,7 @@ could be read), `message`, `body` and `retryAfterSeconds`. The dashboard API's o | Status | From | Meaning | What to do | |---|---|---|---| | 400 | Dashboard API | A missing or unknown field, or a malformed value | Fix the request; `message` names the field | -| 401 | Public API | `{"status":"error","message":"Authentication is required"}` with `WWW-Authenticate: Bearer`. Usually the server's own token: an invalid or expired token, a client not on the allow list, a client token from another tenant, two `Authorization` headers, or, once the requirement is on, no server credential. A user route answers the same when the server forwards no user credential, or a malformed `PolicyEngine-Unauthenticated-User` | Server: do not request another token, which would be refused too and counts against the tenant's monthly allowance. On a user route, check first that the request forwarded the user's credential; otherwise check that the client is listed in that environment and that its tenant and audience match, and report it. Page: the website's own credential failed; show an error, do not retry in a loop | +| 401 | Public API | `{"status":"error","message":"Authentication is required"}` with `WWW-Authenticate: Bearer`. Usually the server's own token: an invalid or expired token, a client not on the allow list, a client token from another tenant, two `Authorization` headers, or, once the requirement is on, no server credential. A user route answers the same when the server forwards no user credential | Server: do not request another token, which would be refused too and counts against the tenant's monthly allowance. On a user route, check first that the request forwarded the user's credential; otherwise check that the client is listed in that environment and that its tenant and audience match, and report it. Page: the website's own credential failed; show an error, do not retry in a loop | | 401 | Public API user routes | `WWW-Authenticate: Bearer error="invalid_token"` and "The bearer access token is invalid": the forwarded `PolicyEngine-User-Authorization` token is invalid or expired | Keep the server token; the user signs in again | | 403 | Dashboard API | "Pages on this origin may not call the dashboard API." The page's origin is not allowed | Serve the page from an allowed origin. A cross-origin page cannot read this answer: the browser reports a CORS error and the client throws with `status` `null` | | 403 | Public API user routes | A forwarded `PolicyEngine-User-Authorization` token is a machine-to-machine token, not a user's | Forward only a signed-in user's own token there | diff --git a/skills/policyengine-api-access/templates/public_api_token.py b/skills/policyengine-api-access/templates/public_api_token.py index f8fbe5e..f219629 100644 --- a/skills/policyengine-api-access/templates/public_api_token.py +++ b/skills/policyengine-api-access/templates/public_api_token.py @@ -45,7 +45,10 @@ def household(situation: dict) -> dict: A 401 is raised, never answered with a new token: it means the client is not on the Public API's allow list in this environment, or its tenant or audience is wrong, so a new token would be refused too and would only use up the tenant's -monthly allowance. +monthly allowance. So a token that Auth0 has revoked stays in use until it is +replaced, at most 24 hours later. To drop it sooner, delete its entry from the +shared store (the key is "public-api-token ") and +restart the instances. Requests never follow redirects: a followed redirect would send the client secret, or the token, to wherever it points. @@ -62,7 +65,7 @@ def household(situation: dict) -> dict: import urllib.request from collections.abc import Callable, Mapping from dataclasses import dataclass, field -from typing import Any, Protocol +from typing import Any, Protocol, TypeGuard LOGGER = logging.getLogger(__name__) @@ -91,7 +94,9 @@ def __setitem__(self, key: str, value: Any) -> None: ... class Opener(Protocol): """What the provider needs to send a request: urllib's OpenerDirector, or a fake in tests.""" - def open(self, request: urllib.request.Request, timeout: float) -> Any: ... + # The request by position and the timeout by keyword, as OpenerDirector.open + # (fullurl, data=None, timeout=...) accepts them. + def open(self, request: urllib.request.Request, /, *, timeout: float) -> Any: ... class PublicApiSettingsError(ValueError): @@ -103,7 +108,9 @@ class PublicApiTokenError(RuntimeError): class _RefuseRedirects(urllib.request.HTTPRedirectHandler): - def redirect_request(self, req, fp, code, msg, headers, newurl): # noqa: ANN001, ANN201 + def redirect_request( + self, req: urllib.request.Request, fp: Any, code: int, msg: str, headers: Any, newurl: str + ) -> None: return None # urllib then raises HTTPError with the 3xx status @@ -158,16 +165,17 @@ def __init__( def access_token(self) -> str: with self._lock: if self._is_usable(self._remembered): - return self._remembered["access_token"] + return str(self._remembered["access_token"]) shared_token = self._read_shared_token() if self._is_usable(shared_token): self._remembered = shared_token - return shared_token["access_token"] - self._remembered = self._request_token() - self._write_shared_token(self._remembered) - return self._remembered["access_token"] + return str(shared_token["access_token"]) + fresh_token = self._request_token() + self._remembered = fresh_token + self._write_shared_token(fresh_token) + return str(fresh_token["access_token"]) - def _is_usable(self, token: dict[str, Any] | None) -> bool: + def _is_usable(self, token: dict[str, Any] | None) -> TypeGuard[dict[str, Any]]: return ( isinstance(token, dict) and isinstance(token.get("access_token"), str) @@ -180,10 +188,11 @@ def _read_shared_token(self) -> dict[str, Any] | None: if self.shared_store is None: return None try: - return self.shared_store.get(self.cache_key) + stored = self.shared_store.get(self.cache_key) except Exception as error: # a store outage must not stop requests LOGGER.warning("Could not read the Public API token from the shared store: %s", error) return None + return stored if isinstance(stored, dict) else None def _write_shared_token(self, token: dict[str, Any]) -> None: if self.shared_store is None: diff --git a/targets/claude/agents/dashboard/backend-builder.md b/targets/claude/agents/dashboard/backend-builder.md index e89609a..db78c57 100644 --- a/targets/claude/agents/dashboard/backend-builder.md +++ b/targets/claude/agents/dashboard/backend-builder.md @@ -144,8 +144,28 @@ export type Household = { [groupEntities: string]: unknown; }; -/** The calculated household: the same shape, with the requested variables filled in */ -export type CalculatedHousehold = Household; +/** A calculated value: one value, or a list over the points when the household has axes */ +export type CalculatedValue = number | boolean | string | null | Array; + +/** The calculated household: the request's shape, with the requested variables filled in */ +export type CalculatedHousehold = Record; + +/** + * One variable from a calculated household, for example + * readVariable(result, 'households', 'household', 'household_net_income', '2026'). + * Null when the household did not ask for it. + */ +export function readVariable( + result: CalculatedHousehold, + entityGroup: string, + entity: string, + variable: string, + year: string, +): CalculatedValue { + const entities = result[entityGroup] as Record> | undefined; + const values = entities?.[entity]?.[variable] as Record | undefined; + return values?.[year] ?? null; +} // Add dashboard-specific types for the variables in the plan ``` diff --git a/targets/claude/agents/dashboard/dashboard-integrator.md b/targets/claude/agents/dashboard/dashboard-integrator.md index 42955e8..7e5fbdb 100644 --- a/targets/claude/agents/dashboard/dashboard-integrator.md +++ b/targets/claude/agents/dashboard/dashboard-integrator.md @@ -106,7 +106,7 @@ function buildHouseholdDict(values: FormValues): Record { } ``` -For `data_pattern: policyengine-api`, declare it so that `buildHouseholdDict` returns `Household` (from `lib/api/types`), with each output the plan needs named on its entity as `null` for the year, and pass it to the backend-builder's `useCalculation(countryId)` mutation: `@policyengine/api-client` takes the country and the household, not `buildHouseholdRequest`'s shape. The result is the calculated household in the same shape, so the transformers read `result.people.head.income_tax[year]` and `result.households.household.household_net_income[year]` rather than `HouseholdSimulationResult`'s `household[0]` and `person[0]`. +For `data_pattern: policyengine-api`, declare it so that `buildHouseholdDict` returns `Household` (from `lib/api/types`), with each output the plan needs named on its entity as `null` for the year, and pass it to the backend-builder's `useCalculation(countryId)` mutation: `@policyengine/api-client` takes the country and the household, not `buildHouseholdRequest`'s shape. The result is the calculated household in the same shape, so the transformers read it with backend-builder's `readVariable(result, 'people', 'head', 'income_tax', year)` and `readVariable(result, 'households', 'household', 'household_net_income', year)` rather than `HouseholdSimulationResult`'s `household[0]` and `person[0]`. With `axes`, each value is a list over the points. ### Step 3: Build Response Transformers @@ -141,7 +141,34 @@ export function buildChartData( ### Step 4: Wire React Query Hooks -Ensure the hooks in `useCalculation.ts` are correctly used by components: +For `data_pattern: policyengine-api`, calculate from debounced form values, so typing or dragging a slider sends one calculation when the user pauses, not one per keystroke: the dashboard API allows 30 household calculations a minute from one address. A query keyed on the debounced values also skips values it has already calculated: + +```typescript +import { useEffect, useState } from 'react'; +import { useQuery } from '@tanstack/react-query'; + +/** The value, once it has stopped changing for delayMilliseconds. */ +export function useDebouncedValue(value: Value, delayMilliseconds = 500): Value { + const [debounced, setDebounced] = useState(value); + const serialized = JSON.stringify(value); // compares by content, not object identity + useEffect(() => { + const timer = setTimeout(() => setDebounced(JSON.parse(serialized) as Value), delayMilliseconds); + return () => clearTimeout(timer); + }, [serialized, delayMilliseconds]); + return debounced; +} + +export function useHouseholdCalculation(values: FormValues, countryId: 'us' | 'uk') { + const debouncedValues = useDebouncedValue(values); + return useQuery({ + queryKey: ['household', countryId, debouncedValues], + queryFn: ({ signal }) => calculate(countryId, buildHouseholdDict(debouncedValues), signal), + retry: 1, + }); +} +``` + +For a custom backend, ensure the hooks in `useCalculation.ts` are correctly used by components: 1. Mutation hooks for on-demand calculations (user clicks "Calculate") 2. Query hooks for auto-fetching data (loads on mount or input change) @@ -200,16 +227,18 @@ For `data_pattern: policyengine-api`, send one calculation with `axes`, never on ```typescript export function useIncomeVariation(baseValues: FormValues, countryId: 'us' | 'uk') { + const debouncedValues = useDebouncedValue(baseValues); // Step 4 return useQuery({ - queryKey: ['income-variation', countryId, baseValues], + queryKey: ['income-variation', countryId, debouncedValues], queryFn: ({ signal }) => { - const year = String(baseValues.year); - const household = buildHouseholdDict(baseValues); + const year = String(debouncedValues.year); + const household = buildHouseholdDict(debouncedValues); household.people.head.employment_income = { [year]: null }; household.axes = [[{ name: 'employment_income', period: year, min: 0, max: 500000, count: 21 }]]; return calculate(countryId, household, signal); }, - enabled: !!baseValues.state, // Only run when required inputs are set + // Only run when required inputs are set; UK households have no state. + enabled: countryId === 'uk' || !!debouncedValues.state, retry: 1, staleTime: 30 * 60 * 1000, }); diff --git a/tests/test_public_api_browser_guidance.py b/tests/test_public_api_browser_guidance.py index 8cb4937..e660367 100644 --- a/tests/test_public_api_browser_guidance.py +++ b/tests/test_public_api_browser_guidance.py @@ -62,9 +62,10 @@ # VITE_AUTH0_CLIENT_ID, NEXT_PUBLIC_AUTH0_AUDIENCE) and other services' public # tokens named for their service (NEXT_PUBLIC_MAPBOX_ACCESS_TOKEN) are public by design. PUBLIC_PREFIX_CREDENTIAL = re.compile( - r"\b(?:NEXT_PUBLIC|VITE|REACT_APP)_(?=(?:API_|ACCESS_|BEARER_|AUTH_)?(?:TOKEN|KEY)\b" + r"\b(?:NEXT_PUBLIC|VITE|REACT_APP)_(?=(?:API_)?(?:ACCESS_|BEARER_|AUTH_)?(?:TOKEN|KEY)\b" r"|[A-Z0-9_]*(?:SECRET|PASSWORD|PRIVATE_KEY|CREDENTIAL" - r"|(?