30.0 / 30
What changed in the harness
Selection accuracy 91→93, token cost up 1%, unconfirmed writes 100%→100%.
Category breakdown
Where the score comes from.
Earned points across the four signals Gradable measures. Safety and Legibility are scored out of 30; Economics and Discoverability are scored out of 20.
01Safety
02Legibility
25.6 / 30
03Economics
18.9 / 20
04Discoverability
11.8 / 20
Highest-impact fix
Estimated gain +8 pointsMake target tools discoverable on the first call
Clarify tool names, decision boundaries, and required argument schemas so an agent can choose and construct the target call without exploratory steps.
Description evidence
Defects and rewrites.
4 defects found across the exposed tool descriptions. Suggested rewrites make purpose, inputs, boundaries, and returns easier for an agent to understand.
| Tool | Defect types | Suggested rewrite |
|---|---|---|
get_campaign |
params_unexplained |
Get one campaign and its up-to-date details by campaign_id, with budget fields converted to USD. Get the id from get_campaigns, or use find_entity to resolve a campaign name to its id. |
get_ad_group |
params_unexplained |
Get one ad group and its up-to-date details by ad_group_id, with budget and bid fields in USD. Its budget, bid, and targeting are what update_budget, update_bid, and update_targeting change, so read it before and after those calls to confirm a change landed. Get the id from get_ad_groups or find_entity. |
get_ad |
params_unexplained |
Get one ad and its details by ad_id: its status, ad group, and click-through URL, but not the creative copy. Get the id from get_ads or find_entity; use get_ad_creative for the headline, body, and media. |
get_ad_creative |
params_unexplained |
Read the creative behind an ad by ad_id: its headline, body text, media, thumbnail, and post URL. The creative lives on the ad's promoted post and is immutable via the API, so changing copy means creating a new ad. Use get_ad for the ad's status and click-through URL instead; get the id from get_ads or find_entity. |
Selection evidence
Confusable tool pairs.
9 pairs where similar names or overlapping descriptions may send an agent toward the wrong tool.
| Tool A | Tool B | Confidence | Why they collide |
|---|---|---|---|
get_ad_groups |
get_ad_group |
medium | Near-identical names differing only by plurality; a task like 'show me the ad group for campaign X' or 'get my ad group' without an explicit id can route an agent to the list tool when the single-id tool was meant, or vice versa. |
get_campaigns |
get_campaign |
medium | Same singular/plural list-vs-one trap; 'get the campaign' vs 'show me my campaigns' is easy to misroute unless the user quotes an id, and ids like a2_... are opaque strings users rarely provide. |
get_ad |
get_ad_creative |
medium | Both take the same ad_id and describe 'details of an ad'; a task like 'show me this ad' or 'what does ad 123 contain' likely wants headline/body (creative) but may route to get_ad, which returns only status, ad group, and URL. |
get_performance_report |
get_daily_performance |
medium | Both report account performance over a window in USD; 'get me performance for the last week' is ambiguous between window totals and a per-day breakdown, and get_performance_report even accepts a date breakdown that overlaps get_daily_performance. |
compare_periods |
compare_ads |
medium | 'Compare my ads' performance' is ambiguous between account-level period-over-period totals (compare_periods) and per-ad ranking within one ad group (compare_ads); the phrase 'compare ads' maps by name to compare_ads even when a period comparison was intended. |
get_accounts |
get_account_overview |
low | 'Give me an overview of my accounts' could route to get_accounts (the list) or get_account_overview (health counts plus spend comparison); the word 'overview' pulls toward the latter even when the user just wanted the account list. |
get_ad_group |
get_ad |
low | Users freely conflate ads and ad groups; 'what's the budget/bid on this ad' should use get_ad_group, but an agent may pick get_ad, which only returns status, ad group id, and click-through URL. |
get_ad_groups |
get_ads |
low | 'Show me the ads in campaign X' is a plausible trap: get_ads is named for 'ads' but has no campaign filter, while get_ad_groups accepts campaign_id yet returns ad groups, so the correct multi-step path is easy to get wrong. |
get_account_overview |
get_campaigns |
low | 'Give me an overview of my campaigns' could pull get_account_overview (campaign/ad-group/ad counts and spend comparison) when the user actually wants the campaign list, or vice versa for 'how are my campaigns doing'. |
Compare the field