Skill eval suite Phase 2: prose-register, choice-only gate, and CI - #67
Open
nonrational wants to merge 9 commits into
Open
nonrational wants to merge 9 commits into
nonrational wants to merge 9 commits into
Conversation
Record three decisions from Phase 1's keyed runs and CI planning: discrimination grades the choice deterministically and the stated rule with a soft llm-rubric judgment; every model call, judge included, runs through claude -p on one CLAUDE_CODE_OAUTH_TOKEN; the CI full-run job starts advisory until real runs tune its thresholds. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Seven tasks: verify subscription auth in a bare HOME, route the judge through claude -p, gate discrimination on the choice, grade prose-register's rank and structural cases, retire its runner, move the offline checks into preflight, and add the advisory PR workflow. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The judge now runs as a second claude -p provider with tools and skills off, outside the repo, so subject and judge share one subscription auth and no ANTHROPIC_API_KEY is needed. The spawn-and-parse logic both providers need moves to lib/claude-cli.mjs. lib/claude-cli.mjs also strips TMUX and TMUX_PANE from the spawned session's env, so a keyed run of dozens of sessions doesn't ring the developer's tmux bell through their Stop hook. The judge asks for a bare JSON reply, since claude -p sometimes wraps it in prose that promptfoo can't parse. Both subject conditions and the judge pass --no-session-persistence, so a keyed run leaves no transcript per case under ~/.claude/projects. evals/package.json scopes node --test to test/*.test.mjs so the executable echo stub under test/fixtures isn't picked up as a test itself. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Keyword overlap on the stated rule failed a different correct paraphrase each run. The choice stays a deterministic assert tagged metric "choice" and is the only one that gates; the rule moves to an llm-rubric judgment counted toward the pass-rate floor. check-gate now reads per-assert component results instead of case type, which also makes detection soft. make eval also sets PROMPTFOO_FAILED_TEST_EXIT_CODE=0, so check-gate, not promptfoo's exit code, decides pass/fail. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Structural cases grade as ordinary discrimination; rank cases grade the
full best-first ordering and judge the rule the worst version breaks.
Prompt framing moves into a per-skill table so prose cases read as text,
not code, and transformation rubrics list whatever criteria the case
defines (prose uses voice_match where code uses placement).
Prompts and rubric values are wrapped in {% raw %}, since promptfoo
renders vars and llm-rubric values as nunjucks and Hugo shortcodes in
prose-register's case text broke rendering; this applies to both
skills. The rank answer key passes as a comma-joined string because
promptfoo expands array vars into one test per element.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Every prose-register case type now grades through promptfoo, so its run-evals.mjs has no remaining job. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
eval-validate and the suite's unit tests cost no model calls, so they join preflight and block in the existing CI job. CI pins Node 24: the evals lockfile was written by npm 11, and npm ci on older npm (Node 22 ships npm 10) rejects it as out of sync. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
An advisory workflow diffs the PR, selects the evaluated skills it touches (every skill when the suite itself changes), links each skill into the runner's ~/.claude/skills, and runs make eval on the CLAUDE_CODE_OAUTH_TOKEN secret. Fork PRs and a missing secret skip with a notice. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
nonrational
force-pushed
the
skill-eval-phase2
branch
from
September 19, 2026 20:46
8daeda7 to
7683823
Compare
npm update within promptfoo's declared ranges (promptfoo itself stays pinned at 0.122.2) clears the transitive advisories Dependabot flagged in sharp, adm-zip, and smol-toml, plus fast-uri, qs, and fflate. The remaining extract-zip advisory has no upstream fix and arrives through @openai/codex-security, an optional promptfoo dependency the suite never calls. 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.
Problem
Phase 1 (#58) left the eval suite unfit to gate anything. A keyword-overlap check failed a different correct discrimination answer every run.
prose-register's rank and structural cases couldn't run at all. Nothing ran in CI, and the judge needed anANTHROPIC_API_KEYthat bills the API.Motivation
A flaky or never-run check teaches everyone to ignore it. Phase 2 makes the suite something CI can run on every skill PR. Real keyed runs, not just unit tests, drove the design: they turned up four promptfoo behaviors the offline tests couldn't see.
Proposed Solution
Spec revisions (decisions 5–9) and the plan are in
docs/superpowers/specs/2026-08-29-skill-eval-suite-design.mdanddocs/superpowers/plans/2026-09-19-skill-eval-suite-phase2.md. One commit per concern:claude -p. Subject and judge share one spawn helper and one subscription credential,CLAUDE_CODE_OAUTH_TOKEN. The judge runs with tools and skills off, outside the repo, and not in--baremode, which ignores OAuth. Spawned sessions dropTMUX/TMUX_PANEso they don't ring the developer's tmux bell through a Stop hook.metric: choice. The stated rule becomes a judgedllm-rubricthat sees the case's grading notes.check-gatereads per-assert results, so detection and judged checks count toward the 90% floor.make evalsetsPROMPTFOO_FAILED_TEST_EXIT_CODE=0so the gate actually runs after a failure.prose-registerfully supported. Rank and structural types, per-skill prompt framing, and rubric criteria read from each case. Prompts and rubrics are wrapped in{% raw %}, because promptfoo renders both as nunjucks and Hugo shortcodes broke that. The rank answer key is passed as a string, because promptfoo splits list-valued vars into one test per element. The oldrun-evals.mjsis deleted.preflight.eval-validateand the unit tests (60) block in the existing CI job.npm updatewithin promptfoo's ranges (promptfoo stays pinned at 0.122.2) clears the transitive advisories behind Dependabot's Bump sharp and @huggingface/transformers in /evals #64–Bump smol-toml and @openai/codex-security in /evals #66, plusfast-uri,qs, andfflate. What's left isextract-zip, which has no upstream fix and arrives through an optional promptfoo dependency the suite never calls. CI pins Node 24, because npm before 11.11 rejects this npm-11 lockfile as out of sync.evalsworkflow. It selects the evaluated skills a PR touches (every skill whenevals/changes), links each skill into the runner's~/.claude/skills(the repo has no root.claude/), runsmake eval, and uploads results. Fork PRs and a missing secret skip with a notice. It's hardened with read-only permissions,persist-credentials: falseand concurrency cancellation.Feedback
evals/, so its ownevalsrun tested token auth and skill discovery on a bare runner. Neither skill had any subject errors.code-comment-registerscored 15/16 and passed.prose-registeris red, on purpose. CI scored it 12/22. Local runs:code-comment-register16/16.prose-register15/22, with hard failures ondisc-09anddisc-11. Those two cases (plusdisc-04, which flipped once in four runs) have grading notes that call the alternative answers defensible. They stay hard until the cases are revised. Even then, prose sits below the 90% floor, because its detection cases are expected to fail. That's the main input for threshold tuning, recorded in the spec's After Phase 2.$HOMEdoesn't. The spec records this as a follow-up. CI's prose score (12/22, with extra hard failures ondisc-01anddisc-12) came in below the local 15/22, which fits that gap. One run isn't enough to tell.evals/bin/check-gate.mjs, and the judge's rule rubric inevals/lib/prompts.mjs.