feat(skills): the expense-reporter skill and its eval cases - #30
Merged
Merged
Conversation
Replaces the placeholder body with real guidance: whether to chart at all, which of the two types, how to shape the query, and how to read the result back. The restraint half matters most — nothing in code stops the agent charting a single figure, and a skill that encourages charts without saying when to stop would make answers worse. Adds eval/cases/skills.cases.mts, a defect class the suite did not cover: a capability the agent must choose to consult, and choose not to overuse. Four cases — activation, order, chart-type selection, and the over-triggering guard, which is the one that keeps the rest honest. The fixture already supports this: the seeding formula spreads expenses across nine months with varying totals, so the trend case needed no new seed data and no second source of truth for expected figures. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The skills section said "when a task matches a skill" without defining what matching means, so a weaker model fell back to lexical overlap: claude-haiku-4-5 loaded the expense-reporter skill for "show me a chart" but never for "chart my spending" — 0/5, deterministic, same trajectory every time. Sonnet loaded it either way, so the instruction was carrying the difference. Now states the principle — judge the KIND of work, not the vocabulary — and blocks the easy-task escape, since the agent charted correctly without the skill and had no reason to consult it. Deliberately no example phrasings: listing the synonyms would have made the eval pass by feeding it the answer, which tests the hint rather than the reframe. Activation went 0/5 -> ~6/8 on haiku with no vocabulary shared between the prompt and the case. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Case order was load-bearing and silent. Only `approval` and `config` cases reset, so an approved log_expense left a $4.20 row behind and the next case asserting a Dining TOTAL read fixture + leftovers — $2,737.20 against an expected $2,733.00, identically across all three runs. Three existing cases assert that same total and passed only because they run before the approval cases in the barrel. The bug predates them being noticed; a new case simply landed downstream of the mutation. Also fixes no-double-prompt-on-mutation, whose premise went stale when the currency feature shipped: it claims "nothing legitimate to ask for", but with no currency established the agent correctly asks before writing, so the case failed for the inverse of its own reason. Pre-seeding the currency makes the premise true again. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Slices C1 and C2 of v3 phase 2 — the real skill, and the evals that grade it. Completes the phase: the loader (#26), the renderer (#28), the tool (#29), and now the instructions plus their guard.
The skill
Replaces the placeholder with four steps: whether to chart at all → which type → how to shape the query → how to read it back, plus what each of
render_chart's refusals means.The restraint half is the part that matters. Nothing in code stops the agent charting a single figure, and a skill that only encourages charts would make answers worse — so the skill says a single number is a sentence and a short ranking is a table.
The eval cases
eval/cases/skills.cases.mts— a defect class the suite did not cover: a capability the agent must choose to consult, and choose not to overuse. A unit test provesload_skillreturns the body; only a model can show whether the agent reaches for it, reads it before acting, or leaves it alone.chart-request-loads-skillskill-read-before-chartingtoolCalledBefore(load_skill, render_chart)trend-question-picks-linesingle-figure-needs-no-chartThe fixture needed no changes: the seeding formula already spreads expenses across nine months with varying totals, so the trend case has real shape and no second source of truth for expected figures.
What the evals found
A prompt defect. The skills section said "when a task matches a skill" without defining matching, and haiku fell back to lexical overlap — loading the skill for "show me a chart" but never for "chart my spending": 0/5, deterministic, identical trajectory every run. Sonnet loaded it either way, so the instruction was carrying the difference, not the model.
The fix states the principle (judge the KIND of work, not the vocabulary) and blocks the easy-task escape. Deliberately no example phrasings — listing synonyms would have made the eval pass by feeding it the answer. Activation went 0/5 → ~6/8 on haiku with no vocabulary shared between the prompt and the case.
A harness bug, older than this work. Only
approvalandconfigcases reset the fixture, so an approvedlog_expenseleft a $4.20 row behind and the next case asserting a Dining total read $2,737.20 against an expected $2,733.00. Three existing cases assert that same total and passed only because they run before the approval cases. Case order was load-bearing and silent.A stale case.
no-double-prompt-on-mutationclaims "nothing legitimate to ask for", but the currency feature made that false — with no currency established the agent correctly asks before writing, so the case failed for the inverse of its own reason. Pre-seeding the currency makes the premise true again.Verified
18/18 eval cases on
claude-haiku-4-5(2 legacy scripted twins still skipped), 185 unit tests,tscandtypecheck:evalclean.🤖 Generated with Claude Code