Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .vale.ini
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,9 @@ Core.NoEmDash = NO
STE.Semicolons = NO
STE.Contractions = NO
Core.NoEmDash = NO

# Eval cases quote the prose a rune forbids, because a case shows the
# model the text to fix and a grader names the words to avoid. The suite
# README under evals/ stays linted.
[evals/*/*/**/*.md]
BasedOnStyles =
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ All notable changes to Rune Deck are documented here, following [Keep a Changelo

### Added

- Add `scripts/eval-rune` and `evals/`: each case runs with the rune and without it, and each run leaves a record and an optional GIF (runes-carry-eval-records).
- Add eval suites with records for twelve core and development runes, listed in `evals/` (runes-carry-eval-records).
- Add the FullSend skill in development: take one task to a merge-ready pull request while the owner reads nothing, then ask once, through the question tool, to merge.
- Add the PruneTests skill in development: delete tests that no plausible bug can fail, repair weak ones with a recorded mutation, and hand the pull request to FullSend.
- Add the PreferExistingTools, ProofsShowTheRealApp, AskBeforeMovingData, and AnswerBeforeEditing rules in core.
- Add the `provisioning` module shell: `PROVISION_ROOT` defaults, the `all` cast leaves it out, no executable file in it, and a two-model comparison record per rune (provisioning-joins-the-deck).
- Add the BrowserbaseToolkit skill in development: read a blocked page through a Browserbase cloud browser as clean markdown (automate-cloud-browsers-browserbase).
- Add the Dotfiles Scanner and Online Mentions routines with a deterministic detector the run takes from the deck object store, and retire GitHub Exposure (scanner-routines-from-deck).
Expand Down Expand Up @@ -97,12 +102,14 @@ All notable changes to Rune Deck are documented here, following [Keep a Changelo

### Removed

- Remove the Claude Code variant of SafetyFirst. Its load-time probe stopped the skill from loading where Bash was not granted, and the canon alone scores 0.44 against 0 (runes-carry-eval-records).
- Remove the BenchArtifact eval viewer, which no instruction used and which carried copied skill-creator code.
- Remove the legacy per-block review ledgers from BuildSkill and ReviewMarkers.
- Remove the dated markdown backlog.

### Fixed

- Fix VersionControl's directory advice: `gh -R` and `glab -R` take a remote `OWNER/REPO`, so a local directory needs its own `cd` call (runes-carry-eval-records).
- Fix the ReviewChange term links to point at the glossary pages by repository URL, so the bundle passes the source-layer check and the links survive deployment (skill-term-links-survive-deployment).
- Fix the Dotfiles Scanner to fetch the whole branch history and report a scan that stops at a shallow boundary as incomplete (scanner-routines-from-deck).
- Fix a Dotfiles notification bullet to point to the first file before a commit message (scanner-routines-from-deck).
Expand Down
81 changes: 81 additions & 0 deletions docs/changes/runes-carry-eval-records/design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Design

## Coverage table

The table has one row for each *[requirement][REQUIREMENT]* of this change. No hook runs an eval suite, so every behavior of a *[rune][RUNE]* is a *[missed requirement][MISSEDREQUIREMENT]* until a check reads its records. The Commands table below names the program behind each row.

| Capability | Requirement | Check or missed requirement |
|---|---|---|
| rune-cases-can-fail | Cases Run With And Without The Rune | missed requirement: the eval runner builds both runs, and no check proves that the run without the rune lacks the rune |
| rune-cases-can-fail | Every Case Can Fail | missed requirement: no check reads the newest record for a case whose score does not change without the rune |
| rune-cases-can-fail | Graders Give The Same Result | missed requirement: no check rejects a grader type outside the deterministic set |
| rune-cases-can-fail | Suites Pair A Direct Case With A Near Miss | missed requirement: review decides whether a case is a near miss, and no check reads the turn limit or the tool list |
| rune-cases-can-fail | Every Run Leaves A Record | missed requirement: the eval runner writes the record, and no check proves that a run never rewrites an old one |
| rune-cases-can-fail | Recorded Run Shows Both Answers | missed requirement: a reviewing model reads the recording, and no check reads the animated image |
| unattended-work-awaits-owner | Owner Gets Only Questions | missed requirement: the FullSend suite runs on demand, and no hook runs it |
| unattended-work-awaits-owner | Merge Waits For The Owner's Yes | missed requirement: the FullSend suite runs on demand, and only a real pull request shows the merge question |
| unattended-work-awaits-owner | Fix Is Reproduced And Proven | missed requirement: the FullSend suite runs on demand, and no hook runs it |
| unattended-work-awaits-owner | Confidence Rests On The Final Head | missed requirement: the FullSend suite runs on demand, and no check compares the evidence head with the live head |
| unattended-work-awaits-owner | Tests Earn Their Place | missed requirement: the PruneTests suite runs on demand, and no hook runs it |
| unattended-work-awaits-owner | Repairs Are Proven By Mutation | missed requirement: a read-only case cannot break production code, so only a real pull request shows the mutation |
| owner-lessons-become-rules | Existing Tools Come First | missed requirement: the rule has no eval suite yet |
| owner-lessons-become-rules | Proofs Show The Real App | missed requirement: a reviewing model judges each recording, and the rule has no eval suite yet |
| owner-lessons-become-rules | Bulk Copies Of Data Wait For A Yes | missed requirement: the rule has no eval suite yet, and no check scans an approved copy for secrets |
| owner-lessons-become-rules | Questions Get Answers Before Edits | missed requirement: the rule has no eval suite yet |

## Commands

A requirement names a role. This table names the program and flags behind each row. Every row runs on demand, outside the command sandbox, because a run starts full Claude Code sessions. A row that says "not built" is a task in `tasks.md`.

| Requirement | Role | Command and flags |
|---|---|---|
| Cases Run With And Without The Rune | *[assembler][ASSEMBLER]*, eval runner | `scripts/eval-rune <Rune>` copies the rune's domain to a temporary directory and runs `rune assemble --source <copy>`. It copies a skill instance into the plugin's `skills/`, or a rule into `rules/` beside `hooks/hooks.json`, whose `SessionStart` hook prints the rule. Then it runs `rune launch <profile>@claude --direct -- plugin eval <plugin> --runs <n> --no-publish --trust-plugin --keep-temp --model <id> --json <result>` with `CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=0` |
| Every Case Can Fail | *[validator][VALIDATOR]* | the record's `cases[].delta`. A check over the newest record of each suite: not built |
| Graders Give The Same Result | validator | the `type` key of each `evals/<Rune>/<case>/graders/*.md`: `regex`, `tool_used`, `tool_order`, or `file_exists`. A check that rejects any other type: not built |
| Suites Pair A Direct Case With A Near Miss | review | `max_turns` and `allowed_tools` in the frontmatter of each `evals/<Rune>/<case>/prompt.md` |
| Every Run Leaves A Record | eval runner | `scripts/eval-rune <Rune> [--profile <name>] [--model <id>] [--runs <n>]` writes `evals/<Rune>/records/<UTC stamp>-<model>.json`. The defaults are profile `main`, model `claude-haiku-4-5-20251001`, and one run. The record also keeps the profile, the passed and total case counts, the cost, and the duration |
| Recorded Run Shows Both Answers | eval runner | `scripts/eval-rune <Rune> --record docs/proofs/runes-carry-eval-records` runs `asciinema rec --headless --window-size 100x30 --idle-time-limit 2 --overwrite --return <dir>/<Rune>.cast`, then `agg --theme github-dark --font-size 18 --last-frame-duration 4 <cast> <gif>`. Inside the recording, `scripts/eval-rune --show <result.json>` prints each case's scores and the first twelve lines of each answer |
| Owner Gets Only Questions, Merge Waits For The Owner's Yes, Fix Is Reproduced And Proven, Confidence Rests On The Final Head | eval runner | `scripts/eval-rune FullSend`. On Claude Code the question tool is `AskUserQuestion`, from the variant `runes/development/skills/FullSend/claude/SKILL.md` |
| Tests Earn Their Place, Repairs Are Proven By Mutation | eval runner | `scripts/eval-rune PruneTests` |
| Existing Tools Come First, Proofs Show The Real App, Bulk Copies Of Data Wait For A Yes, Questions Get Answers Before Edits | eval runner | `scripts/eval-rune <Rule>` after the rule has a suite under `evals/<Rule>/`: not built |

## Proposed terms

The ontology has no entry for these words. The specifications describe each one in plain words. The owner approves or rejects each term before the *[fixer][FIXER]* adds it.

| Term | Definition | Related term |
|---|---|---|
| eval case | One task for a *[model][MODEL]*, with graders that score the answer, run once with a rune and once without it. | *[scenario][SCENARIO]*, because both state a situation and the expected result, and *[fixture][FIXTURE]* |
| eval suite | The eval cases kept for one rune and run together against its *[instance][INSTANCE]*. | [rune][RUNE] |
| eval record | The stored result of one suite run: the instance digest, the model, and each case's score with and without the rune. | *[verdict][VERDICT]*, the judgment a bench draws from such scores |
| eval runner | The role that runs a rune's suite against its instance and writes the eval record. | *[tool role][TOOLROLE]* and *[proof runner][PROOFRUNNER]* |

## Decisions

- The runner wraps the assembled instance in a throwaway plugin. A case then tests what Claude Code loads, and not the *[canon][CANON]*. Each run assembles a private copy of the domain, so parallel runs never share one build directory.
- A plugin cannot hold a rule file. A session-start hook prints the rule instead. Only the run with the plugin gets the hook, and Claude Code's plugin eval makes the run without it by its default with-and-without comparison.
- Graders are deterministic only, because the model judge cannot sign in from the eval's child sessions on this machine. An eval record is therefore not a verdict in the sense of DECK-0003. It holds grader scores with and without the rune, and no assertion on meaning or blind preference.
- The runner launches Claude Code through a rune launch profile, so the profile supplies the model route and its credential. The runner turns off the session's environment scrub, so the child sessions keep that credential.
- A run in which any case fails in the harness writes no record and exits with an error. A broken run never reads as a score.
- Records only accumulate. The file name is the UTC time stamp and the model, so two runs never share a name.
- A *[variant][VARIANT]* earns its place when its record beats the canon's record on the same cases and the same model, as Companions Earn Their Place requires. The runner assembles with the variant. The record for the canon alone needs a run with the variant removed from the private copy. FullSend's Claude Code variant is the first to need it.
- PruneTests gives its pull request to FullSend, so the pull-request loop has one home.
- The rules PreferExistingTools, ProofsShowTheRealApp, and AskBeforeMovingData take their substance from the workshop drafts and their wording from the deck's plain register. AnswerBeforeEditing is new.
- The draft WhenTheUserSignals stays out, because PlainSpokenLanguage already tells a model to stop and explain when the owner does not understand.
- The eval runner is not one of the roles that the record CORE-0023 assigns to rune. The specifications describe it in plain words until the owner decides on the term.

[REQUIREMENT]: ../../specs/glossary/requirement.md
[RUNE]: ../../specs/glossary/rune.md
[MISSEDREQUIREMENT]: ../../specs/glossary/missed-requirement.md
[ASSEMBLER]: ../../specs/glossary/assembler.md
[VALIDATOR]: ../../specs/glossary/validator.md
[FIXER]: ../../specs/glossary/fixer.md
[MODEL]: ../../specs/glossary/model.md
[SCENARIO]: ../../specs/glossary/scenario.md
[FIXTURE]: ../../specs/glossary/fixture.md
[INSTANCE]: ../../specs/glossary/instance.md
[VERDICT]: ../../specs/glossary/verdict.md
[TOOLROLE]: ../../specs/glossary/tool-role.md
[PROOFRUNNER]: ../../specs/glossary/proof-runner.md
[CANON]: ../../specs/glossary/canon.md
[VARIANT]: ../../specs/glossary/variant.md
85 changes: 85 additions & 0 deletions docs/changes/runes-carry-eval-records/proposal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
---
adr: "docs/decisions/DECK-0001 Artifact Benchmarking Skill.md"
status: proposed
---

# Runes carry eval records

## Why

The foundations decide what stays in an *[instruction][INSTRUCTION]*: a *[requirement][REQUIREMENT]* states a check that can fail, and the shortest instruction that passes the check wins. These are *[falsifiability][FALSIFIABILITY]* and *[Occam's razor][OCCAMSRAZOR]*, and the foundations cite an evaluation score as the measure ([foundations][FOUNDATIONS]). The foundations also say that a *[variant][VARIANT]* for one *[harness][HARNESS]* or *[model][MODEL]* must beat the *[canon][CANON]* alone on an evaluation, or the author removes it. That is the requirement Companions Earn Their Place ([vendor-neutral instructions][NEUTRAL]).

Until now no *[rune][RUNE]* in the *[deck][DECK]* had a case that could fail inside the *[repository][REPOSITORY]*. The *[coverage][COVERAGE]* table of the foundations lists Companions Earn Their Place as a *[missed requirement][MISSEDREQUIREMENT]* for that reason. The record DECK-0001 already asks for the same evidence for a skill, a rule, and an agent alike: behavior with the rune against behavior without it ([DECK-0001][DECK0001]).

An evaluation case, an eval case for short, gives a model one task. Checks called graders score the answer, and each grader gives the same result every time for the same answer. The case runs twice, once with the rune loaded and once without it. The difference between the two scores is what the rune does. When both runs pass a case, the case shows nothing about the rune, and the author rewrites it or drops it.

Two more needs come with this change. The owner asks for a task taken to a merge-ready pull request while nobody reads the output, with one question at the end. And lessons the owner gave sit as drafts in the owner's workshop under machine-made names, outside the deck where no check reads them.

## What Changes

- A runner for one rune's eval suite. It builds the rune's Claude Code *[instance][INSTANCE]* through the *[assembler][ASSEMBLER]* and wraps it in a throwaway plugin. A *[rule][RULE]* loads through a session-start hook, because a plugin cannot hold a rule file. The runner runs the cases with the rune and without it through Claude Code's own plugin eval command, launched through a rune launch profile. Each run writes a JSON record beside the suite. With a record directory, the runner also records the run and renders an animated image that shows both answers of every case.
- The graders are deterministic only. The model judge cannot sign in from the eval's child sessions on this machine ([evals guide][EVALS]).
- Eval suites for the *[skills][SKILL]* VersionControl, SafetyFirst, SimplifiedTechnicalEnglish, BuildSkill, FullSend, and PruneTests, and for the rules RemoteWrites, PreferTrash, OnePurpose, PlainSpokenLanguage, Deslop, and VerifyClaims. The recordings go into the *[proof][PROOF]* directory of this change.
- When a rune fails its own case, this change fixes the rune or the case and says which.
- FullSend, a new skill in the development domain. It takes one task to a merge-ready pull request while the owner reads nothing, then asks once to merge. It never merges without the owner's yes.
- PruneTests, a new skill in the development domain. It deletes tests that no plausible bug can fail and repairs weak ones. A recorded mutation proves each repair, and FullSend takes the pull request from there.
- The core rules PreferExistingTools, ProofsShowTheRealApp, and AskBeforeMovingData, which this change rewrites from the workshop drafts.
- The core rule AnswerBeforeEditing, new, from a lesson the owner gave.
- This change drops the draft WhenTheUserSignals, because PlainSpokenLanguage already says it.

## Capabilities

### New Capabilities

- `rune-cases-can-fail`: a rune's eval cases run with the rune and without it on the same model and instance. Every case can fail, and a grader gives one result for one answer. Every run leaves a record, and a new run never rewrites an old one.
- `unattended-work-awaits-owner`: FullSend asks the owner only through the question tool and proves the fix on the final head. It never merges before the owner's yes. PruneTests deletes tests no plausible bug can fail and proves each repair with a mutation.
- `owner-lessons-become-rules`: an existing tool comes before a custom script, and a proof records the real app. A bulk copy of data waits for the owner's yes. A question gets an answer before any edit.

## Impact

- `scripts/eval-rune` and the suite guide `evals/README.md`.
- One directory per rune under `evals/`, each with its cases and a `records/` directory that runs fill.
- The recordings under `docs/proofs/runes-carry-eval-records/`.
- `runes/development/skills/FullSend/` with a Claude Code variant, and `runes/development/skills/PruneTests/`.
- The new rule files under `runes/core/rules/`.
- Changelog entries under Unreleased.
- A run starts full Claude Code sessions on the launch profile's credential. It runs outside the command sandbox and uses model calls for each case and each run.

## Risks

- A record speaks for one model and one harness. The runner defaults to a small model ([runner][RUNNER]), and a rune that a larger model does not need can still score on it.
- A pattern grader reads the words of an answer. It never sees the result on disk, and a right answer in an unexpected form fails a required pattern. The records hold grader scores only. A three-metric verdict in the sense of DECK-0003 also needs assertions on meaning and blind preference ([DECK-0003][DECK0003]).
- Cases use read-only tools and four turns or fewer ([evals guide][EVALS]). A case shows what a model says and plans. It cannot show FullSend open a real pull request or PruneTests break production code. The recordings prove the runner and the answers, and a real pull request must prove those two skills.
- The new rules PreferExistingTools, ProofsShowTheRealApp, AskBeforeMovingData, and AnswerBeforeEditing have no eval suite yet. They have not shown that they can fail. FullSend's Claude Code variant has no record against the canon alone.
- The runner turns off the session's environment scrub. The eval's child sessions then get the profile's credential.

## Sources

- [The foundations][FOUNDATIONS], the change `plain-text-first-principles`
- [DECK-0001 Artifact Benchmarking Skill][DECK0001] and [DECK-0003 Three-Metric Verdict and Cross-Vendor Judging][DECK0003]
- [The evals guide][EVALS] and [the runner][RUNNER]

[FOUNDATIONS]: ../plain-text-first-principles/proposal.md
[NEUTRAL]: ../plain-text-first-principles/specs/instructions-stay-vendor-neutral/spec.md
[DECK0001]: ../../decisions/DECK-0001%20Artifact%20Benchmarking%20Skill.md
[DECK0003]: ../../decisions/DECK-0003%20Three-Metric%20Verdict%20and%20Cross-Vendor%20Judging.md
[EVALS]: ../../../evals/README.md
[RUNNER]: ../../../scripts/eval-rune
[INSTRUCTION]: ../../specs/glossary/instruction.md
[REQUIREMENT]: ../../specs/glossary/requirement.md
[FALSIFIABILITY]: ../../specs/glossary/falsifiability.md
[OCCAMSRAZOR]: ../../specs/glossary/occams-razor.md
[VARIANT]: ../../specs/glossary/variant.md
[HARNESS]: ../../specs/glossary/harness.md
[MODEL]: ../../specs/glossary/model.md
[CANON]: ../../specs/glossary/canon.md
[RUNE]: ../../specs/glossary/rune.md
[DECK]: ../../specs/glossary/deck.md
[REPOSITORY]: ../../specs/glossary/repository.md
[COVERAGE]: ../../specs/glossary/coverage.md
[MISSEDREQUIREMENT]: ../../specs/glossary/missed-requirement.md
[INSTANCE]: ../../specs/glossary/instance.md
[ASSEMBLER]: ../../specs/glossary/assembler.md
[RULE]: ../../specs/glossary/rule.md
[SKILL]: ../../specs/glossary/skill.md
[PROOF]: ../../specs/glossary/proof.md
Loading
Loading