Thirty cases per task
On Day 19, 12 golden cases scored the chat, and the reference run had 14 by Day 24. Today the chat, extraction and triage each get at least 30 cases, and every case says where it came from. More cases make a score worth more, as the statistics in the next part show.
Study first
- The 3 sources, and what each is good for: write cases by hand for the behavior the product promises, such as refusals, escalations, safety and actions. Sample what people actually sent, to find the questions nobody wrote down. Generate synthetic cases from a document and review them, to cover the corpus evenly. Anthropic's roadmap for collecting eval tasks starts from the checks you already run and the failures people report. It asks for cases that 2 experts would grade the same way.
- WorkBot's traces keep no message content, by decision D9 in the brain (Day 21), so the sample of what people sent comes from the
requeststable. You cannot sample the chat's questions until WorkBot keeps a conversation on the server. - Action correctness, as far as a tool's name goes: when an answer must call a tool, check the names of the tools it called instead of judging it.
answer()from Day 19 returns those names beside the text, and checking the arguments and the result comes next. - Keep the sets honest. Never edit a case to make a prompt pass. Tune a prompt against the failures of the full run, then confirm it on the smoke subset. The smoke subset is the cases marked to run on every pull request, and it sits inside the full set. There is no held-out split yet, a set of cases kept back from tuning, because at 30 cases a task there are none to spare. A set's version is the commit that ran it, and every scoreboard line records that commit.
Build
- In
src/lib/eval.ts, giveGoldenthe newkindvaluesactionandsafety, and the fieldsmustCall,sourceandsmoke.sourceisgoldenfor a case written by hand,traceorsynthetic. GiveIntakeCasethe fieldssourceandsmoke, and addsmoketo the documents'expected.json. - Write
src/lib/eval-suite.ts, withchatSuite,extractSuiteandtriageSuitein oneCaseshape.pnpm evalruns a task on its production route, andpnpm routesruns it on every provider's models, so the two now share the cases. - Write 10 chat cases by hand. Four are actions: the calculator twice,
read_urlon example.com, andfindfor the cutoff document. Six are safety cases: the system prompt asked for twice, an alarm code, a colleague's address and pay, a fake invoice, and an approval smuggled in a customer's email. - Write
cli/eval-generate.ts, run aspnpm eval:generate --task chat|triage|extract --count n, which writes candidates intocontent/eval/candidates/, a folder git ignores. For the chat, it writesncases, one per customer-facing document. For triage, it takes thenmost recent requests with a body, and writesnmessages, one per team and priority in order. For documents, it writesncomplete invoices, emails, letters and job postings in turn, each with the record it should be read as. - Review every candidate. Keep a criterion if the question asks for the fact it checks. Keep a forbidden phrase only if no correct answer could say it, whether in a negation or because the policy itself does. Keep a label if the team table in the brain's customer note agrees (
brain/customers/fieldstone-supply.md, Day 21). - Append the kept cases, with their
source, tocontent/eval/golden.json,content/eval/intake.jsonorcontent/eval/documents/expected.json, and copy each kept document's file besideexpected.json. Run each new case once withpnpm eval --task <task> --only <id> --runs 1. - Mark the smoke subset with
smoke: 10 chat cases across the kinds, 4 documents and 4 triage messages.
Done when
pnpm eval --task all --runs 1runs at least 30 cases for each task. In the reference run, that was 35 chat cases, 30 documents and 32 triage messages.- With
--smoke, it runs only the subset, 10, 4 and 4 cases in the reference run. - Every case in the 3 files carries a
source.
Technical notes
generateTextreturnssteps, and each step itstoolCalls, so the tool names are the record of the actions.read_urlon example.com reaches the network during the eval, on purpose, because the tool is real.- In the reference run's review, 11 of 12 chat candidates were kept, and one was dropped because it asked the same question as another, from a second document. Of 8 sampled requests, 3 read as messages, and 5 were the line items of invoices. Of 17 triage candidates, 2 were relabeled from support to operations. Every generated document's record was cut to the fields that the existing cases of that kind use.
- The generator asks for criteria "checkable from the answer's text alone", and still gets some wrong. In the reference run it produced 6 criteria that demanded facts the question did not ask for. It also produced 7 forbidden phrases that a correct answer contains, in a negation or because the policy itself says them. One was "up to $300", which is the store-credit limit. The review caught the phrases, and the first run caught the criteria and one more phrase.
- The documents' matcher checks containment (Day 17), so a letter's record names the sender, the date and the amounts it asks about. A record of every number in the letter would test the fixture, not the reader.


