Add manual eval suite for /bills LLM features#25
Open
mikaalnaik wants to merge 2 commits into
Open
Conversation
Adds a token-conscious, manually-run eval suite for the two LLM touchpoints in /bills: summarizeBillText and socialIssueGrader. - Standalone tsx runner (`pnpm eval:bills`) with --refresh, --only, --grep, and --fallback flags; never wired into build/lint/CI. - Disk cache keyed by input + prompt hash so grader/fixture iteration costs no tokens; --refresh forces a re-call. - Structural checks on BillAnalysis (8 tenets, valid enums, exactly 3 QP questions, no speaker prefix, no self-reference) gate the run; judgment/social-issue accuracy and cross-consistency are reported. - 8 hand-labeled synthetic bill fixtures spanning the decision space, plus a fetch-fixture helper that bootstraps real bills via the existing fetchers + xmlToMarkdown. Minimal edits to existing code: export SOCIAL_ISSUE_GRADER_PROMPT for cache-keying, add eval:bills script, gitignore .cache/. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Migrates the /bills LLM eval suite from synthetic fixtures to real Parliament-45 bills, grounds the labels and prompt in Build Canada's documented positions, fixes two eval-runner bugs, and documents the Builder MP feature. Eval runner: - Load .env.local via tsx --env-file-if-exists in the eval:bills script, so a real OPENAI_API_KEY is actually picked up (tsx is not Next.js and does not auto-load env files). - Drop the steel-man-present structural check: steel_man is a human-editable editorial field, not produced by the analysis prompt, so the check failed on every live run. README updated to match. Real fixtures (replaces the 8 synthetic bills): - 10 committed real bills spanning the decision space: social/rights -> abstain (S-227, S-221, C-9), clear tenet alignment -> yes (C-5, C-266), clear conflict -> no (C-284, C-202, C-253), and two genuinely two-sided/ administrative bills left unlabeled for judgment (C-291, C-230). - Labels grounded in deep research on Build Canada's stances; C-5 (the One Canadian Economy Act) is their named flagship-alignment example. Prompt: - Sharpen tenets 3 and 4 to name internal free trade + labour mobility and domestic value-added processing (their strongest documented levers). - Add explicit align/conflict judgment signals so borderline calls stay consistent. Docs: - Add src/app/bills/README.md documenting the Builder MP feature (analysis model, tenets, data flow, auth, env, evals). Baseline eval (pre-sharpening) scored 8/8 judgment and 100% social-issue accuracy on the real fixtures; post-sharpening verification run pending. Co-Authored-By: Claude Opus 4.8 (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.
Context
The
/billsfeature has two LLM touchpoints, both calling OpenAIgpt-5via the Responses API, with no test or eval coverage today:summarizeBillText(services/billApi.ts) — summary, 8 tenet evaluations,final_judgment(yes|no|abstain), 3 Question Period questions.socialIssueGrader(services/social-issue-grader.ts) — binary "is this primarily a social issue" classifier.This adds a manually-run eval suite so prompt edits, model changes, and parsing changes can be validated before shipping. It is run explicitly (
pnpm eval:bills) and never wired intobuild,lint, or CI — LLM tokens are expensive.What it does
tsxrunner (pnpm eval:bills) with--refresh,--only=social|analysis,--grep, and--fallbackflags. No test-framework dependency added (tsxalready exists forseed:bills-admin)..cache/, gitignored). Editing a prompt invalidates its entries automatically; re-runs read from disk so iterating on checks/fixtures costs no tokens.--refreshforces a re-call.aligns|conflicts|neutral, validfinal_judgment, exactly 3 non-empty QP questions with no "Mr./Madam Speaker" prefix, noBuild Canada/we/ourself-reference.final_judgmentvs label, social-issue confusion matrix with precision/recall.summarizeBillTextabstains butsocialIssueGraderdisagrees — surfacing the known divergence that the two use separate prompts/criteria.fetch-fixture.tshelper that bootstraps real bills via the existing fetchers +xmlToMarkdown.Minimal edits to existing code:
export SOCIAL_ISSUE_GRADER_PROMPT(for cache-keying), add theeval:billsscript, gitignore.cache/.Running
```bash
export OPENAI_API_KEY=sk-...
pnpm eval:bills # all fixtures (cached where possible)
pnpm eval:bills --refresh # bypass cache, re-call the API
pnpm eval:bills --fallback # force no-key fallback path (0 tokens)
```
Verification
--fallback): harness runs end-to-end — imports resolve, fixtures load, checks execute, report prints + writesreport.json, exit code gates on structural failures.tsc --noEmitclean;eslintclean on the new files.🤖 Generated with Claude Code