Skip to content

Bench v2.0.0: Project-Scoped Ledgers and Fail-Closed Governance

Choose a tag to compare

@dburks-svg dburks-svg released this 24 Jul 21:29
· 207 commits to main since this release

Bench v2.0.0 governs each project into its own ledger and fails closed.

Two changes break existing installs. Read the migration notes before upgrading.

Breaking: governance now fails closed

A pipeline that cannot render a verdict now denies the change instead of
letting it through. API timeout, malformed judge response, unimportable
pipeline, unreadable constitution: all deny, with a pipeline_error VETO
recorded in the ledger.

The practical consequence: if your claude CLI is too old to recognize the
configured model IDs, every governed edit is blocked until you upgrade it. That
is intended. A broken or exploited judge must not be able to wave changes past
governance. Run claude update if edits start failing.

Recovery from a genuinely broken pipeline is an out-of-band human action,
editing files directly outside the governed tools, never an automatic pass.

Breaking: the ledger follows the project being governed

Previously every governed edit on the machine appended to Bench's own ledger,
wherever Bench happened to be installed. Now:

Condition Ledger
BENCH_LEDGER_PATH set that path
Working directory inside the Bench repo ledger/bench-ledger.json
Anything else <project>/.bench/bench-ledger.json

If you registered Bench's hook globally, receipts for your other projects will
start landing in those projects rather than in Bench's ledger. Set
BENCH_LEDGER_PATH if you want the old single-ledger behaviour.

This existed because a globally registered hook wrote every project's full
diffs into one ledger. If that ledger is committed to a public repository, it
publishes them. ledger-meta.json is now written alongside whichever ledger is
selected, so every chain carries its own anchor and verifies standalone.
python -m cli verify prints which ledger it read.

Also breaking

  • anthropic>=0.120.0 (was >=0.84). Run pip install -r requirements.txt.
  • Constitution is now version 4 (was 1). If you copied bench.json into
    your own project, yours is unaffected, but review C-004 and C-008 below before
    adopting the new one.

Out-of-project diffs are recorded without their bodies

A file governed from one project but belonging to another is still adjudicated
in full, but the ledger keeps only path, tool, and verdict. content,
old_string, new_string, edits, and formatted_diff are dropped and the
entry is marked redacted.

Judge prose may still quote a few lines of the change it reasons about. This
removes the systematic copy of file bodies, not every possible quotation.

Constitution changes

C-004 now tests for discarded precision rather than the token Any.
dict[str, Any] for parsed JSON is explicitly permitted; replacing a precise
annotation with a looser one, deleting a return annotation, or reaching for a
bare Any when the shape is knowable remain violations. Prefer object for
values only stored or passed through.

C-008 gains a bounded chain-retirement clause. Editing, reordering, or
removing an individual entry is still forbidden absolutely. A whole chain may be
retired only when it contains content that must not be published, and only with
a human decision, an archive verified by verify_chain before the original
moves, an anchor entry recording the retired chain's tip hash, genesis hash,
entry count, timestamps, verbatim archive path and reason, and indefinite
retention of that archive.

New

  • SECURITY.md with a disclosure policy scoped to Bench's actual threat
    model: governance bypass, fail-open regressions, ledger forgery that still
    passes cli verify, prompt injection through governed content, credential
    exposure. Model judgment quality is explicitly out of scope.
  • tests/test_ledger_hygiene.py, which fails if any ledger entry carries a
    diff body under a non-relative path.
  • cli verify prints the ledger it read; cli stats counts chain
    anchors separately so they do not skew pass rates.
  • Least-privilege CI permissions, Dependabot, and refreshed action pins.

Known boundary

Bench governs changes made through Claude Code's Write/Edit/MultiEdit tools. A
bot-authored dependency PR is edited on the forge, never reaches the hook, and
merges without a verdict or a ledger entry. Read those diffs before merging and
do not enable auto-merge. This is stated plainly in README.md, CLAUDE.md,
and SECURITY.md rather than left implied.

Upgrading

git pull
pip install -r requirements.txt
claude update          # fail-closed blocks edits on a stale CLI
python -m cli verify   # confirms which ledger you are on