Releases: driftproofhq/driftproof
Release list
v0.11.3
Receipts written by 0.11.3 are receipt spec v0.9. Every earlier receipt still validates against its own version.
What changed
- Fewer false passes. A suite with two cases of the same id is refused before any call. A receipt with two rows for one case and arm is refused by
validate,badge,exportanddecide. The Action fails a job whose receipts give two answers for one model, naming the files. Each Action invocation now writes and uploads its own receipts, so one job can run it more than once. The artifact is no longer nameddriftproof-receipt: its name is the step outputartifact_name. - Import Anthropic's eval results.
driftproof import --from claude-plugin-evalreads theaggregate-result.jsonthatclaude plugin evalwrites.--from skill-creatorreads skill-creator'sbenchmark.json, which skill-up also writes. The receipts are DECLARED. They record the harness, the source document and its sha256, and whether the skill fired, beside the score and never inside it. - Regrade.
driftproof regrade <receipt> --skill <dir> --answers <file> --judge-model <id>grades a receipt's saved answers again with another judge, without generating them again. Because a normal run does not keep the answers yet, it works today only where the answers were kept beside the receipt, as they were for Report 011's Amendment 1. - What's stale.
driftproof stale receipts/*.jsoncompares what each receipt recorded (model, harness, skill, suite, judge, grading template, rubrics) with what would run today. For each arm it says whether the result still stands, needs a rerun, or needs only a regrade, and prints the command to run next. Anything a receipt does not record is reported unknown, never current. A patch release of the harness is an advisory. A rubric edit reruns both arms, because receipts do not yet record a hash per case prompt. Exit 0 current, 1 stale, 3 unknown or advisory, 2 error;--strictturns 3 into 1.--jsonprintsdriftproof.stale/1, whose schema is served at/spec/stale.v1.schema.json.driftproof runnow records the harness and its version in each receipt. - Import redaction. Local paths in text an import copies are redacted whole: quoted paths with spaces, paths across line breaks, and names with an apostrophe, though the part of a quoted path after an apostrophe followed by a space can still appear, while the home folder and user name are always redacted. An import that would still name a home folder anywhere in a path (
/var/home,/mnt/c/Users, a network share) is refused and writes nothing. - Model registry.
claude-opus-5-5is registered (released 2026-09-22, US$4 and US$20 per million input and output tokens), so a run on it is priced as itself, not at the most expensive tier.claude-opus-5andclaude-opus-4-8gain their release dates. - Receipt spec v0.8 and v0.9. v0.8: a count the source did not record stays absent, never 1; generation and judge-sample counts are kept apart; a re-judge records when it ran. v0.9: an imported receipt says what produced it. Both only add fields.
- The interop page names receipt spec v0.9 and all four import formats.
- Report 011, Amendment 1 (the site). Report 011's answers were graded again with Claude Opus 5.5 as the judge. No verdict changed, and 50 of 51 answers stayed on the same side of the pass line. One crossed: Claude Opus 5's baseline on
code-review-and-quality, 0.827 to 0.633. The report above the amendment is unchanged.
What you must do
- If a workflow downloads the Action's artifact by the name
driftproof-receipt, read the name from the step outputartifact_nameinstead. - If a suite has two cases with the same id, give them distinct ids. 0.11.3 refuses the suite before any call.
v0.11.2
The ajv floor moves to ^8.18.0, closing the v0.7.0 known-open row "AJV >= 8.18". No installed byte moves; the lowest ajv a consumer's install may resolve moves from 8.17.1 to 8.18.0, and every committed receipt validates under 8.18.0 and 8.20.0 as it does under 8.17.1. spec/RECEIPT.md's coexistence rule now names v0.7, the version a producer emits (it read v0.6). No verdict, receipt field or published figure changes; the receipt spec stays at v0.7. The site gains Report 009 Amendment 1, Report 010 Amendment 1 and the interop page's corrected schema line. Full notes: RELEASES.md.
v0.11.1
package.json reads 0.11.1, and config.js's RUNNER_VERSION is held equal to it. The Action pins in README.md and docs/index.html are @v0.11.1, the plugin's pin in plugin/driftproof/.claude-plugin/plugin.json is 0.11.1, and so is the minimum in plugin/driftproof/version-guard.json. package-lock.json moves with them, and tests/fixtures/export-summary.snapshot.json's receipt_hash is re-cut because runner_version is inside the canonical receipt that hash is taken over.
No verdict, receipt field or published figure changes. The receipt spec stays at v0.7. The one file the npm package carries that differs from 0.11.0 is lib/hygiene.js (below). Everything else in this release is the site, or the repository's own gates.
What this release contains
- The site's visual pass (spec 038). The site keeps its words and changes how it looks. Pages are set on a paper ground with a faint texture, records sit on receipt stock, and the verdict stamp is tilted slightly, with no animation. Headings are set in Newsreader, body text in Alegreya Sans and code in Courier Prime, all self-hosted. The band plot is drawn in ink, with a graticule, tabular numerals and each arm's mean printed on its band. The plots on the homepage receipt card, every receipt page, the report cards and the methodology page's floor figure are inlined into the page instead of loaded as images, so they take the page's fonts. Each one is the generated file's own bytes and keeps the accessible name its image had. The playground draws the same plot, and the share cards follow the new palette. No copy changes, no script is added, and the sitemap's URL set is unchanged. It was approved with findings on
9a11045, and the two findings on its own gate were closed ondevunder A-038-8. - Two site fixes from spec 025 (A-025-21). The homepage hero's Range row prints each value to three decimals, matching the delta display, so it stays on one line.
stats.jsonkeeps the receipt's full precision. The render check now clicks the playground's own "point" toggle to read the point outline, rather than relying on the default view's data to draw one. - The hygiene scan reads a PNG's text, not its pixels (spec 038 A-038-5, A-038-7).
lib/hygiene.jsscans a PNG as every chunk exceptIDAT, and reads compressed text chunks in the encoding they carry text in. It fails closed on bytes afterIENDand on a truncated file. A pattern that appears only in compressed pixel data no longer reads as a disclosure. A name rendered into a screenshot is pixels, and no byte scan sees that, before or after this change. The repository gate andscripts/merge-check.jsboth call it. - The repository's scope checks read a merged spec on
dev(spec 037 A-037-7). A shared helper resolves a spec's range from the merge that brought its Tip in. Specs 034, 036, 037 and 038 read their NFR-1 through it. This is repository process, and the published tree does not carry it. - Report 009's draft (spec 034 A-034-7). The draft page is re-rendered from its renderer and picks up spec 038's
<head>. Its body did not change. The draft is not published. - The v0.11.0 record. The v0.11.0 entry's Published section and the Pages deployment it records, written after that publish, are part of this tree.
Published
driftproof@0.11.1 is on npm, published 2026-09-18 from the public clone at the v0.11.1 tag, latest. The public repository's v0.11.1 tag points at 8f5879a, built from source commit 4ef3ad3f. GitHub Pages deployed that commit: pages-build-deployment run #39 on 8f5879a reached success, and the live site serves the redesign. The post-publish checks (npm gitHead against the public commit, the clean-runner gate on a depth-1 clone of the tag, spec 028 NFR-7 and spec 031 AC-1 and AC-2 against the published package) are recorded in RELEASES.md once they have run.
Known open
- Three sibling gates were red at the release commit for reasons that predate this release, all gate-side: spec 030 (its fixture predates the 0.11.0 verdict change), spec 026 AC-16 (archived verdicts moved under specs 035 and 036), and spec 033 (it still measures from its 0.10.2 base). None touches shipped code; the shipped package differs from 0.11.0 in
lib/hygiene.jsonly. Recorded inDECISIONS.mdon 2026-09-18 as a deliberate deviation; each is owed as its own fix loop. - Everything the findings page lists as open, carried from v0.11.0.
v0.11.0
package.json reads 0.11.0, and config.js's RUNNER_VERSION is held equal to it. The Action pins in README.md and docs/index.html are @v0.11.0, the plugin's pin in plugin/driftproof/.claude-plugin/plugin.json is 0.11.0, and so is the minimum in plugin/driftproof/version-guard.json. package-lock.json moves with them, and tests/fixtures/export-summary.snapshot.json's receipt_hash is re-cut because runner_version is inside the canonical receipt that hash is taken over.
The UNDERPOWERED verdict (spec 035). A receipt that could not have resolved the effect floor at the draws it took now says so, instead of saying NO_EFFECT, which reads as a measured absence. The rule is R-1 to R-6 with a new named constant POWER_Z (2) in config.js, and the receipt spec bumps to v0.7, which adds no field: readers derive the verdict, and v0.6 is frozen rather than widened.
Behaviour changes, read these before upgrading
- A job that used to fail can now pass (the fail-open direction).
decisionStateno longer reads the aggregate delta. Before this release,delta <= -0.05was aregressionand failed the job. Now the state comes from the receipt verdict, so a receipt whose aggregate delta clears the floor downward with no case separated readsno detected effect, orunderpoweredwhere the rule finds it so, and the job no longer fails. If your gate relied on the aggregate delta alone to catch a regression, it no longer does. No archived receipt moves out ofREGRESSEDby this, so the exposure is to receipts generated from here on. - A job that used to pass can now fail to report success (the tightening direction). A workflow that passed on an aggregate lift with no case separated now reads
UNDERPOWERED, which is inNEVER_SUCCESSand never renders as success. - All 120 receipts archived before this release now badge
NOT_MEASURED. The verdict rule refuses a receipt whoseanswered_byblock is absent, not only one stating a kind other thanmodel. This is the fail-safe reading and is word for word whatdecisionStatehas applied since spec 030, so the badge and the Action stop answering differently about one receipt. The site's old example receipt (2026-07-27) rendersnot measured on claude-haiku-4-5, lightgrey, where it renderedpassing, brightgreen, so the site no longer uses it as the example (below). - Published report figures do not move. The differ's per-case verdict values are unchanged and the new state rides beside them, so Reports 006 to 008 rebuild byte-identical.
What else this release contains
- The badge and the receipt page (spec 036). An
UNDERPOWEREDorNOT_MEASUREDbadge prints the draws taken against the draws needed, not a lift. The receipt page says which refusal fired, and a receipt with no readable case readsNOT_MEASURED, neverNO_EFFECT. - The homepage and How this is built (spec 037). The homepage opens on the question a skill's own tests leave open, whether the gap it makes is real or noise and whether it held on the last model release. The Claude Code plugin is the first install path, and
npxand the GitHub Action sit under a CI heading. The first screen links the findings page and a receipt page, and the receipt card's verdict is read from that receipt. A new How this is built page in the Docs menu describes the method, with counts taken at a named commit. The hero plot's accessible title carries the verdict word only, and the receipt page carries the sentence under it (A-037-4). - A fresh example receipt, and the site artefacts that were stale now agree with it.
receipts/commit-message-conventions-claude-haiku-4-5-20251001-2026-09-17.jsonwas run on this release after the bump:runner_version0.11.0,claude-clithrough the isolated eval user,answered_by.kindmodel,TESTED, receipt schema 0.7, 462 calls, lift +0.389 ± 0.217, verdictPASSED. The README badge, the homepage card, its plot,docs/data/stats.jsonand the CI badge's alt text all read from it. Re-cut from this receipt, the badge JSON is byte-identical (passing on claude-haiku-4-5, brightgreen), so the site's accent token does not move and no design decision was needed. A pre-build run of the same suite on 2026-09-16, before the bump, recordedrunner_version0.10.2 and also readPASSED(+0.441 ± 0.183); it stays in the archive. This clears the stale-artefacts item that was open on this entry (spec 035 F-3).
Published
driftproof@0.11.0 is on npm, published 2026-09-17, built from source commit d8ed3646684d79a96519f435ef3cfe6cfaf802ef; the published repository's v0.11.0 tag points at 2c6a747ab39f35dd92dbe443832fe7797c785980. The post-publish gate figures are recorded in RELEASES.md once read.
Known open
- Everything the findings page lists as open, carried from v0.10.2.
- The sibling spec gates and their re-freezes were deferred to a post-release loop, recorded in
DECISIONS.mdat the release commit.
v0.10.2
A fix release for the badge, the judge and the differ's wording. If you render a Driftproof badge, or pin the Action or the plugin at 0.10.1, update. Plugin users get the badge fixes only after claude plugin update.
Two external audits of 0.10.1, an end-to-end retest and a reliability audit, found the badge and judge defects; the site's findings page (docs/findings/) records both audits, what this release fixes, and what it does not. The receipt spec is unchanged at v0.6.
What this release contains
- The badge rechecks retained judge output. On 0.10.1
/driftproof:badgerechecked each retained generation text against its receipt and nothing else, so a receipt whose retained judge output had been edited still rendered a passing badge. It now refuses a receipt when any retained judge text no longer digests to thejudge_sample_hashesthe receipt carries (spec 031). - The badge says what it checked. Its statement no longer says judge text is not retained when the transcripts beside the receipt hold it (spec 031).
- The comparison caveat prints only when it is true.
driftproof diffprinted that a comparison was not like for like whenever either receipt's band carried a source label. It now prints only when the two receipts' band sources differ (spec 031). - The band wording. A band is the mean plus or minus one standard deviation, a descriptive spread and not a confidence interval.
driftproof diff, the README and the site now state a separation as detected under the rule and a non-separation as none detected at the sample size used. The verdict values underneath, and every machine-facing token, are unchanged. Twelve published records carry a versioned amendment for the old wording (spec 031). - A judge score that is not a number is refused. On 0.10.1 a judge reply that parsed with a score of
null,false,""or[]was measured as 0, andtrueas 1. Such a reply is now refused the way an unparseable reply is, and no score is recorded from it (spec 032). - The badge reads transcripts only from inside the transcripts directory. It refuses an
index.jsonentry, or anindex.json, that resolves outside it (spec 032). - The site gains the findings page, a platform statement on the homepage and in the README, and a scope sentence on the judge policy: the fixed judge governs the reports Driftproof publishes, and a receipt records its own judge in
run.judge(spec 033).
Known open
Everything the findings page lists as open: the statistical results of the reliability audit, the single-receipt badge's use of the effect floor alone, TESTED on a receipt with attested false or an incomplete run, the --trusted-skill flag, and Windows, which is untested. The underpowered-verdict rule is decided and is the next spec.
v0.10.1
A fix release for the Claude Code plugin. If you installed the plugin at 0.10.0, update it. No version published before this one carries either fix.
Both defects were found by an external audit of the published v0.10.0 plugin, received 2026-09-13. Nothing else in the runner, the receipt or the Action changed: since the v0.10.0 tag, the three plugin command files are the only shipped files that changed, apart from the version strings this release moves and docs/sitemap.xml, whose homepage lastmod moved from 2026-09-12 to 2026-09-13. package.json reads 0.10.1, and config.js's RUNNER_VERSION is held equal to it. The Action pins in README.md and docs/index.html are @v0.10.1, and the plugin's pin in plugin/driftproof/.claude-plugin/plugin.json is 0.10.1. So is the minimum in plugin/driftproof/version-guard.json, whose resolved_by names the commit that set it. tests/fixtures/export-summary.snapshot.json's receipt_hash is re-cut, because runner_version is inside the canonical receipt that hash is taken over. The receipt spec is unchanged at v0.6.
What this release contains
- The plugin's commands now find their own script reliably. On 0.10.0 each command told Claude to run the door script at a literal
<plugin-root>placeholder, and to fill in the plugin's location itself. Claude Code does not substitute that placeholder, so the path a command ran from was whatever the model wrote there. Each command now names the script through${CLAUDE_PLUGIN_ROOT}, the path variable Claude Code substitutes into a command's text before the model reads it. The line the model runs already carries the plugin's real directory. - Claude no longer fires a Driftproof command on its own judgement. On 0.10.0 none of the three commands set
disable-model-invocation, so Claude could invoke any of them when a request looked like a match for its description./driftproof:runspends your Claude Code subscription. All three now carrydisable-model-invocation: true, and each runs only when you type it. That includes/driftproof:init, which writes a new directory, and/driftproof:badge. Both fetch and run the pinned CLI from npm, the same asrun.
Spec 028's gate now holds both properties in every command file (A-028-37), with standing arms that go red against the command files as they shipped in 0.10.0.
Provenance
- Published commit:
378bac8378e2c536f17a05875d6a55a2c1b59d9f - Tag:
v0.10.1, annotated tag object1c99e8157ced130514153165e759e77f4a93a698 - Tracked files: 725
- Clean-runner gate:
node tests/gate.js --scan-root .on a depth-1 clone of the publishedv0.10.1tag, run with no network: 611/611 passed, 0 failed, 1 not applicable; the one row not applicable because this checkout carries no refs/heads/main (a shallow or tag-only clone), so the merge range this rule is about does not exist here; results file sha25691bae7c84f437a0d3d8e0393d02becf30f7b3a94e5dee81397f5c354f3712859 - Built from source commit:
db6aed47698192b246ae69ce4d21638086473e85
v0.10.0
Multi-model runs enforced on a single receipt. On v0.9.0 and earlier,
a run given more than one model in inputs.models produced one receipt per
model and then decided the job from exactly one of them - the one whose
filename sorted first, which is a property of the model id and not of the run.
A skill that regressed on a model that did not sort first was reported as
a pass: a green check, and a brightgreen "passing" badge naming the other
model. The failure message, when it did fire, named every model that had been
requested rather than the ones that actually regressed. A run that measured
nothing at all (NOT_MEASURED) also exited 0, indistinguishable from a pass.
Fixed in this release: the decision is taken over every receipt a run
produced, a receipt count below the requested model count fails closed, the
badge renders the worst decision and names the model it came from, and the job
summary carries one row per model. inconclusive and not measured never
render as success on the badge, the summary or the check title.
If you pin this action, move your pin. If a Driftproof check has been
green on a multi-model run, that result was only ever about one of your
models; re-run it on this version before relying on it.
Also fixed: a receipt edited after it was sealed was rendered and enforced as
though it verified. driftproof badge has refused a receipt whose
receipt_hash does not verify since v0.9.0 (spec 026); the multi-model
decision path added in this release went through a new command that did not,
so a hand-edited receipt could produce a green check and a passing badge.
driftproof decide now verifies every receipt in the set before any decision
is taken and before anything is written, naming the file it refused.
This path was added in this release, and no published version carried the defect.
Also fixed: npm run gate on a clean clone of the published tag died with an
unhandled ENOENT instead of reporting a verdict, because the publish step
silently dropped force-added files from the commit. The build now refuses to
publish a tree that does not carry what it copied.
Also in this release: the plugin self-test workflow that ships in this repository runs the published tree's own gate, node tests/gate.js --scan-root ., rather than a self-test file that exists only outside the published tree, so CI on this repository checks the same files you install the plugin from (spec 028, A-028-34).
The four checks that keep governance files, state/, reports/pending-publish.md and internal reports out of the published tree now decide from what the tree actually contains rather than from a command-line flag, so a published tree carrying any of those files fails its own gate however the gate is invoked (spec 028, A-028-35 and A-028-36).
Provenance
- Published commit:
607303240896708b502ee1ef0a754c6033bc37bd - Tag:
v0.10.0, annotated tag object4eb98b8a3ef574095f9d74751fe53a5fb7af4006 - Tracked files: 725
- Published-tree gate:
npm run gateon a depth-1 clone of the publishedv0.10.0tag, run with no network: 621/621 passed, 0 failed, 1 not applicable; the one row not applicable because this checkout carries no refs/heads/main (a shallow or tag-only clone), so the merge range this rule is about does not exist here - Built from source commit:
d133cfc7fe938ed1704ffe7969c02f92c422bf36
v0.9.0 - four merged loops: receipt integrity, the site, and two quiet ones
Carries four merged loops: specs 021, 025, 026 and 027. The v0.9.0 entry in RELEASES.md is the record, and it carries the Known open list this does not.
Four changes can break a caller's script
- A budget or cap flag that is not a number is refused, at exit 2, naming the input and the value.
- A model id the registry does not carry is refused before the first call, at exit 2, naming the id and the absolute path of the registry it consulted (
DRIFTPROOF_REGISTRYwhen set, otherwise the packagedconfig/models.json). - A run that measured nothing no longer reads as a run.
- The receipt schema is v0.6, and
badge,diffandexportverifyreceipt_hashbefore they read a receipt rather than warning and proceeding.
v0.5 of the receipt spec stays readable at spec/receipt.v0.5.schema.json.
And the rest
- Spec 025 - the site, measured in a browser instead of read out of a stylesheet.
- Spec 021 - the carry list, and six controls that were lying about their scope.
- Spec 027 - the confidentiality scan classifies before it scans.
v0.8.1
Spec 023, Action input hardening. The change that earns a patch version is action.yml: it hardens a surface published on the Marketplace, so the tag adopters are told to use moves to a commit that carries the fix. What driftproof run measures is unchanged: bin/, every measurement module in lib/, the receipt schema and the model registry are byte-identical to v0.8.0; a receipt from 0.8.1 differs from one from 0.8.0 in the version stamp, and therefore its hash, and in nothing else.
What shipped
- The Action's inputs are data, not shell. Every
${{ inputs.* }}moved out of inlinerun:scripts into the step'senv:block; step bodies live in action/run.sh and action/enforce.sh and reference those variables double-quoted only. Norun:line in action.yml or the self-test workflow contains an expression. (Audit finding A1, High.) - The refusal is proved on a real GitHub runner, in public (spec 024). The self-test workflow passes a value carrying a double quote, a semicolon,
$(...), a backtick and a newline through each of the five inputs of the real action.yml and fails the job unless every one is refused before anything ran. A control step pastes the same payload the way v0.8.0 did and requires the markers to appear first, so the mechanism is shown live before it is relied on. Run: https://github.com/driftproofhq/driftproof/actions/runs/33775114997 - Inputs are validated before use:
modelsover[A-Za-z0-9._-],max-usda positive decimal,max-callsa positive integer,fail-on-regressionexactlytrueorfalse,skill-diran existing directory with no control character. Anything else fails the step with::error title=Driftproofbefore a directory is created or a model call is projected. $GITHUB_OUTPUTentries are heredocs with a random delimiter, and a value carrying a line break is refused before anything is written. (A6, High when chained with A1.)- Full-SHA pins on actions/checkout, actions/setup-node and actions/upload-artifact, and
npm cino longer falls back tonpm install. (A9, Low.) - RUNNER_VERSION 0.8.1, stamped into every receipt from here on.
Known open
The other audit groups: judge prompt injection (A4), budget validation (A3), S3 to S9, and the spec-021 carry list. The honest scope of this release is the Action input surface and the local-agent boundary; judge integrity and budget enforcement are the next loop.
Full notes in RELEASES.md.
Action usage: uses: driftproofhq/driftproof@v0.8.1
v0.8.0
Spec 019b plus the Report 008 promotion. The change that earns a minor version is config/models.json, which ships inside the package.
What shipped
- claude-fable-5-1 registered, with its price bound to a dated snapshot (input 10, output 50) that the spec gate asserts field by field. The registration moves no projection; DEFAULT_PRICE already priced an unregistered id at the same values. Receipts now stamp registry: "registered" instead of falling back. claude-fable-5 retained, annotated lifecycle: "legacy".
- Report 008, release drift, claude-fable-5-1 against claude-fable-5. Two cells, 14 cases, release-axis tally 0 improved, 0 regressed, 14 within noise, 0 not measured. Skill content_hash and suite_hash asserted identical on both sides before the first call, and both sides are generation-sampled receipts, so the delta is attributable to the model rather than the instrument.
- Report 007 v1.1, an economics amendment: 28 inserted lines, zero deleted. The table re-priced on the fresh-input basis and one mechanism sentence retracted. No published figure above the block is edited.
- RUNNER_VERSION 0.8.0, stamped into every receipt from here on.
What the promotion changed, which was supposed to change nothing
Three places asserted that promoting the draft was a rename that re-checked nothing. All three were wrong: the head tags key on the published path, so the draft was reviewed without the structured data it now ships; the draft rendered verdicts as bare text; and the derived tally summed two axes into one. All corrected at promotion and recorded.
Gates
Spec 019b 8/8. Repo gate 566/566. Site gate 163/168, the five failures being spec-020 migration guards evaluated as evergreen invariants (AC-21, AC-30, AC-31, AC-35, NFR-5), dispositioned and carried to spec-021.
Full notes in RELEASES.md.
Action usage: uses: driftproofhq/driftproof@v0.8.0