Skip to main content
Plumb

Plumb

Execution-grounded research-integrity verifier: re-runs a paper's own artifacts on your compute and returns a per-claim, reproducible verdict.

Point Plumb at a paper and the code behind it. It pins the code, builds an environment, re-runs the artifacts, re-derives the paper's quantitative claims from what the run actually produced, and renders an honest verdict per claim — REPRODUCED / WITHIN-TOLERANCE / DIVERGED / UNVERIFIED — decided by re-execution, never by a model's opinion of the paper.

Status License Python Built with uv One runtime dep Offline tests PRs welcome

Quickstart · How it works · The verdict · The number so far · Vision · Roadmap · Contributing


plumb verify --from-record fixtures/gate/rcai: a real replay of the Burtsev, arXiv:2609.00137 record — the notebook-computed paper. 31 claims, 30 bound through notebook_cell locators: 30 REPRODUCED, 1 UNVERIFIED (NO_BINDING), 0 DIVERGED; the replay is byte-identical to the committed verdicts.

The card is a real replay, not a mock. It shows the committed record of the first notebook-computed paper through the spine (fixtures/gate/rcai). The numbers the paper printed in its own notebook cells were re-derived by re-executing that notebook and bound through notebook_cell locators. C1 conformance on this paper is 0/31 — reported as conformance, never as coverage.


Why Plumb

Three kinds of tools sit near the literature. Text-mining tools extract numbers. LLM judges opine on them. Plumb is the third thing: the verifier. It answers the question none of the others do — "does the claim hold when you actually run it?" — by re-executing the paper's own artifacts and diffing the re-derived value against the reported one.

Why that question matters, and why a judge can't answer it:

  • Frontier models hit only ~6.1% precision / ~21.1% recall on real errata-worthy errors (SPOT, arXiv 2505.11855) — well below the bar for flagging a paper.
  • Only ~3.2% of published computational notebooks reproduce (widely cited) — a paper's numbers often cannot be rebuilt at all, which is itself the finding.
  • Free AI tools cannot reliably flag even retracted literature (JMIR 2026) — a guess about correctness is not verification of it.

Plumb's verdict is grounded in execution, not opinion — which means it gets better as base models improve (they write cleaner claims and better bindings), never redundant.

  • 🪢 The name. A plumb line is the oldest tool for testing whether something stands true — and "to plumb" is to investigate to the bottom. Plumb asks of a paper: does the claim hold when you actually run it?
  • 🔁 Re-derive, don't re-read. The value is re-derived from the paper's own run on your compute — never from a committed output, never from a stale file (a result that predates the run is UNVERIFIED, never parsed).
  • ⚖️ An honest verdict contract. REPRODUCED means the paper's number was re-derived within its written precision; DIVERGED means the artifact's own run contradicts the paper's claim — and UNVERIFIED is never dressed up as either. A discrepancy that could be our harness's fault resolves to UNVERIFIED, never DIVERGED.
  • 🧾 Signed, replayable bundles. Every finding ships with a hash-listed, ssh-keygen -Y-signed record — paper hash, tree hash, frozen environment, traces, verdicts — that a third party can replay byte-identical. A finding nobody can replay is an opinion.
  • 📈 A compounding discrepancy corpus. Every (claim, re-derived value, verdict) banks as a labeled, replay-validated case; plumb corpus report pools coverage / precision / recall with denominators and label-authority markers, measured against human labels.
  • 🔒 Runs on your compute. The paper, the repo, and the data never leave your machine; only hashes and the verdicts you choose to publish ever do.
  • 🧪 Test-first, deterministic. A 2,000+-test offline suite pins determinism byte-for-byte; no network is reachable from any test; one pinned runtime dependency (pypdf).

Honesty is the whole product. UNVERIFIED is never rendered as REPRODUCED, extraction conformance is never reported as coverage, and a DIVERGED that owner-review refutes (a run-to-run artifact, not a paper error) stays refuted — the corpus says so. Read The number so far before trusting any claim.


Quickstart

Install (PyPI plumb-verify):

uvx --from plumb-verify plumb --help   # run without installing
pipx install plumb-verify              # or put the `plumb` script on your PATH

0.1.0 is packaged and release-ready but not published yet — the first tag is the owner step in docs/LAUNCH.md. Until then, install from a checkout below.

The import package and the console script are both plumb; the distribution is plumb-verify because the PyPI name plumb belongs to an unrelated, older library.

From a checkout:

uv sync && uv run pytest        # 2,077 tests, no network, one runtime dep (pypdf)

Verify a paper live:

uv run plumb verify <paper> <repo> [--rev REV] [--bindings bindings.json]
#   <paper>  a local PDF/Markdown — the claims are extracted and selected by rule
#   <repo>   a local dir, git URL (with --rev), or archive — pinned checkout + env
#   --bindings   your user-written bindings: which captured value each claim is checked against

Replay a committed record, byte-identical:

uv run plumb verify --from-record fixtures/gate/rcai --json
uv run plumb verify --from-record fixtures/gate/rcai --bank   # fold into the discrepancy corpus

Exit contract: 0 iff every claim is decided; 1 on any UNVERIFIED or named cause; 2 on usage. Never a traceback; a harness failure is never a DIVERGED.


How it works

The spine: intake → run → re-derive → verdict → bundle (plumb verify runs it end to end).

paper (text/PDF)                      repo/data (path | git URL --rev | archive)
       │                                        │
       ▼                                        ▼
 C1  extract & select claims   ──┐      C2  pinned checkout + frozen environment
       │   (typed Claim records) │          │
       │                         │          ▼
       │                         │  C3  run the repo's own entry point
       │                         │      (script | [project.scripts] | root main.py
       │                         │       | notebook via nbconvert — freshness-guarded,
       │                         │        content-addressed outputs)
       │                         │          │
       └──────────────┬──────────┘          ▼
                      ▼                re-derived values
                 C4  bind each claim to a value via a locator
                     (JSON pointer · stdout regex · CSV cell ·
                      notebook cell output · notebook HTML table cell)
                     → compare within the paper's written precision or a declared tolerance
                     → REPRODUCED / WITHIN-TOLERANCE / DIVERGED / UNVERIFIED
                      │
                      ├────────────►  C5  discrepancy corpus (bank every case)
                      ▼
                 C6  signed, replayable bundle (paper hash + tree hash + env + traces + verdicts)
  • The claim is the unit of work. C1 emits typed, self-describing Claim records — reported value (verbatim), units, metric, paper location — through a deterministic admission gate; a candidate the paper didn't make is recorded as a non-claim with a named cause, never a silent drop. An optional BYOK LLM proposer may suggest candidates; every proposal is re-grounded against the paper text before admission and never assigns a verdict.
  • Reproduce what ran, not what was committed. C3 executes the repo's own entry point in a working copy under the run area and captures stdout / JSON / CSV / notebook cells into a per-run object store keyed by SHA-256. An output whose mtime predates the run start is STALE_ARTIFACT — its bytes are never read.
  • Notebooks are first-class. A root *.ipynb is the fallback entry point (jupyter nbconvert --execute); each output-bearing cell becomes a content-addressed artifact, and a claim binds into it — including <td> cells inside pandas Styler HTML, the way notebooks actually render tables.
  • The verdict is decided by code, in pinned Decimal. No float reaches a comparison; run causes govern every claim first; every DIVERGED carries review_required.

The verdict

Verdict Meaning May be emitted when
REPRODUCED The paper's value was re-derived from its own run, within tolerance The artifact ran, the value bound, and it matches
WITHIN-TOLERANCE Matches within a stated numeric tolerance, not exactly Same, with a non-zero delta inside the tolerance band
DIVERGED The re-derived value contradicts the paper's claim The artifact ran and its own output contradicts the paper — never on a harness-side failure
UNVERIFIED We could not decide Repo won't run, claim won't bind, result is stale, tolerance can't be set — the honest default

A model may extract a claim or propose a binding; execution assigns the verdict.


The number so far

plumb corpus report: 3 banked cases — Perrin (16 claims: 2 REPRODUCED, 14 DIVERGED, all refuted on review), AgroDesign (86 claims: 85 REPRODUCED, 1 DIVERGED, confirmed), Burtsev rcai (31 claims: 30 REPRODUCED, 1 UNVERIFIED). Totals: 133 claims, 132 bound, 117 REPRODUCED, 15 DIVERGED, 1 UNVERIFIED, precision 1/15, recall 1/15 (owner labels).

Three real papers are banked — each record replays byte-identical and every labeled verdict is owner-reviewed:

  • AgroDesign (arXiv:2603.09041) — 86 rule-defined claims, 85 REPRODUCED, 1 DIVERGED: a Shapiro-Wilk p reported as 0.034 that its own code computes as 0.03455, confirmed genuine on review and unchanged in a paper-era environment. C1 recovered 86/86 of its claims (conformance to the curated rule; fixtures/gate/agrodesign/README.md).
  • Perrin (arXiv:2401.11842) — 16 claims, 2 REPRODUCED, 14 DIVERGED … refuted on review: the artifact is not run-to-run reproducible at the paper's written precision (unseeded worker RNG; noise ~0.005–0.010 vs written precision 0.001; four verdict flips across three runs). A reproducibility finding about the artifact, not a paper error — recorded as refuted, never published as a discrepancy.
  • Burtsev (arXiv:2609.00137) — the first notebook-computed paper through the spine: 31 claims, 30 REPRODUCED through notebook_cell locators, 1 UNVERIFIED (NO_BINDING), 0 DIVERGED; 70 s wall; a second full run changes zero verdicts (fixtures/gate/rcai/README.md).

Totals: 133 claims, 132 bound, 117 REPRODUCED, 15 DIVERGED (14 refuted, 1 confirmed), 1 UNVERIFIED — precision/recall 1/15 against owner labels. The 1/15 is the honest number: one republishable discrepancy out of fifteen flagged, because fourteen were the artifact's own run-to-run noise. The runnable-paper space is thin (consistent with ~3.2% notebook reproduction), and growing the panel is blocked by named engine gaps — figure-with-data locators and the fact that most papers ship no code at all (the C7 no-code path). The C2 poetry env policy gap is now closed (src/plumb/intake/env.py: a poetry-locked checkout is classified "poetry" and built via uv pip install, and a build that installs nothing is a named failure, never a silent empty venv; fixtures/gate/perrin/README.md, probe note 2026-10-17).


Docs

Contributing

Test-first is the house rule: every capability lands with its failing test written first, the suite runs offline, no network is reachable from any test, and a verdict is never assigned by a model. See CLAUDE.md before opening an issue.

Support the project

If this project is useful to you, you can chip in with a crypto donation:

Crypto donation button by NOWPayments

Lineage

Plumb generalizes a "reproduce & verify published work" capability out of genomics and points it at the literature at large — the deterministic spine (intake → run → re-derive → verdict → bundle) plus a compounding discrepancy corpus that gets sharper as base models improve.

Metadata

Release files for plumb-verify 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for plumb-verify 0.1.0
File Size Uploaded Provenance
plumb_verify-0.1.0.tar.gz 170.0 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for plumb-verify 0.1.0
File Interpreter ABI Platform
plumb_verify-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 377.4 kB

Release files / plumb_verify-0.1.0.tar.gz

Download URL plumb_verify-0.1.0.tar.gz
Size 170.0 kB
Tags Source
SHA-256 checksum
How to use checksums
863d58d69f8cbefab5ff0811038ef2253d56aa462370b5f3dd02f26b545e4ae7
BLAKE2b-256 checksum
How to use checksums
fdb32b41f9726b812f00fc18852a303e2dedea39f9dff4f5ecc69acbd530c569
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.

Transparency log

Release files / plumb_verify-0.1.0-py3-none-any.whl

Download URL plumb_verify-0.1.0-py3-none-any.whl
Size 207.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
370e5212d18ce01444216eb61572d547cac1744234322910b8efc0121249a800
BLAKE2b-256 checksum
How to use checksums
eb0f88b3910d79e7ad66609eeae9d21f20fc9ecaffc6c5524b3e31722846d8e4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.

Transparency log

Security for plumb-verify 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for plumb_verify-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page