dsh-preclaim
Pre-claim gate: a commit, push or tag claim like "tests pass" is checked against the session evidence ledger before it is written.
Install
dsh plugin --profile web add dsh-preclaim
Sandbox test
This plugin has not been tested yet. Submit a test →
README
dsh-preclaim
Repository name vs package name: the repo isdsh-evidence; the npm package isdsh-preclaim. They are the same plugin.
**A commit message that says "tests pass" is a claim. This checks it against what
the session actually ran — and stops the commit if the two disagree.**
A DeepSeek Harness plugin.
No model, no service, no network, no API key.
$ git commit -m "fix: parser handles empty input; tests pass" dsh-preclaim: this session has recorded no evidence at all, so this gate cannot tell "it did not happen" from "I did not see it" — asserted: CLAIM_TEST_PASSED [review] commit anyway, or run the tests first?
Whypreclaimand notevidence-gate? Because the obvious names are held by
other authors, some of them for plugins asking the same question:
dsh-evidence-gate(lory.top),dsh-evidence(tudamu),dsh-claim-gate,
dsh-attest. The project's design document checked the registry and picked the
free name that describes the right moment: before the claim is written down.
scripts/verify-artifacts.mjs fails the build if a later edit drifts back onto a
name somebody else owns.
Quick start
dsh plugin --profile web add dsh-preclaim@0.1.3
evidence_status / the pre-execute gate is now available; The gate records what ran in the session and checks a commit/push/README claim against that ledger before it is written.
Why this exists, and why it is not a model
The failure it targets is not a judgement call. "The message claims tests pass"
and "no test run is recorded in this session" are both facts, and whether they
agree is decidable. A model here would add a confidence interval to a yes/no
question, and would occasionally be wrong in a way nobody could reproduce.
So the whole plugin is deterministic:
tools/post-executerecords what ran into an in-memory ledger for the
session.
tools/pre-executereads that ledger before a gated action runs.
Three consequences follow from that split, and they are the design rather than
implementation details:
1. A claim cannot satisfy its own obligation. The action under review is never
consulted for evidence. A commit message saying "ran pytest; all tests pass"
contributes nothing to its own check.
2. A failed test run does not count as evidence that tests pass. test-run and
build-run require success. ci-check and file-read do not: observing a red
pipeline is still observing the pipeline, and reading a file is evidence of
reading it whatever the exit code.
3. Nothing is inferred from prose. The ledger holds what the host reported, and
nothing else. There is no transcript reading and no heuristic scanning.
Install
dsh plugin --profile <name> add dsh-preclaim@0.1.3
The bundled patch arms the gate on activation. Every key has a default, so it
works with no configuration at all.
What is gated
Shell calls running an asserting git verb — commit, push, tag. A commit
carries its message inline; a push asserts through the commits it carries, so the
command text is checked and the commit range is left to the human.
Read-only verbs (status, log, diff, show, branch, rev-parse, …) are
never gated, and neither are --dry-run, --help, -h or --version: none of
those makes a durable claim. git fetch && git commit -m x gates the commit and
not the fetch.
README-shaped writes — README, CHANGELOG, docs/**/*.md, **/README.md.
A README is where a project states what it does and whether it works. Ordinary
source writes are left alone; gating those would put a gate in front of every edit.
A write outside the working directory is not judged at all.
What counts as a claim
pattern · what it notices · answered by
CLAIM_TEST_PASSED · says tests pass · a recorded test run
CLAIM_VERIFIED · says something was verified · nothing observable → tool_unverified
CLAIM_RAN_CHECK · says a check was run · a recorded test run
CLAIM_BUILD_OK · says the build succeeds · a recorded build
CLAIM_CLI_ASSERTION · names a CLI invocation · a CI observation
CLAIM_DEPENDENCY · asserts a platform dependency · nothing observable → tool_unverified
CLAIM_LINE_REF · cites a line · a file read
CLAIM_COUNT · cites a count · nothing observable → tool_unverified
CLAIM_HASH_REF · cites a commit hash · nothing observable → tool_unverified
CLAIM_FILE_EXISTS · cites a file · a file read
The last column has a rule behind it: **evidence has to connect to the claim it
answers.** file-read answers a citation of a file or a line, because reading that
file is the connection. It does not answer "this was verified" — reading
some file is not verifying that claim. An earlier version treated it as if it
were, which made git commit -m "verified on Windows" pass as soon as anything at
all had been read.
The four kinds mapping to nothing are not an oversight. They are claims this gate
can observe but cannot adjudicate, so it says so and asks
(tool_unverified) rather than making an accusation it cannot support.
If no pattern matches, the action is allowed with no-claim-in-action. The patterns
are deliberately syntactic: a wider net means more false stops on honest work, and a
gate that cries wolf gets switched off — after which it checks nothing at all.
What happens on a miss
situation · verdict · why
not a watched action · allow · nothing to check
a watched action carrying no claim · allow · still nothing to check
every claim backed by recorded evidence · allow · the claim and the record agree
a claim with no evidence, ledger populated · review · the claim is not backed
the ledger is empty · review, and says so · cannot distinguish "it did not happen" from "I did not see it"
a claim no
…(truncated)
Rendered from the README published on npm. Formatted only, not edited.
Versions
Published on npm::5,最后更新 2026-10-20