Thanks for looking. This project has one job — be right about what a diff hides — so the bar for a new rule is evidence, not cleverness.
git clone https://github.com/YKLovePython/cheatcheck
cd cheatcheck
npm install
npm test
node dist/cli.js --diff examples/agent-cheat.diffNo runtime dependencies. TypeScript compiles to CommonJS in dist/, which is committed so the GitHub
Action and npx github:YKLovePython/cheatcheck work without a build step.
src/
diff.ts unified diff parser (no dependencies)
files.ts path classification: is this a test file? a snapshot? a lockfile?
rules.ts all 18 rules, one object each
score.ts per-rule aggregation, trust score, verdict
report.ts terminal / JSON / Markdown / GitHub annotations
cli.ts argument parsing, git invocation, exit codes
examples/ diffs used by tests and the demo image
docs/rules.md human-readable rule reference
scripts/ demo image generator, real-repo precision check
A rule is an object with metadata and a run(files, config) function that returns findings.
const noSleepInTests: RuleMeta = {
id: "sleep-in-tests",
severity: "medium",
weight: 8,
name: { en: "sleep in tests", zh: "测试里用 sleep" },
why: {
en: "A fixed sleep is a race condition with better manners.",
zh: "固定 sleep 是带着礼貌的竞态条件。",
},
run(files) {
const out: RawFinding[] = [];
for (const f of files) {
if (!isTestFile(f.path)) continue;
const hits = f.added.filter((l) => /\bsleep\s*\(/.test(l.text));
if (hits.length === 0) continue;
out.push({
file: f.path,
line: hits[0].line,
evidence: hits.slice(0, 3).map((l) => l.text.trim()),
message: { en: `${hits.length} fixed sleeps`, zh: `${hits.length} 处固定 sleep` },
count: hits.length,
});
}
return out;
},
};Then register it in RULES and document it in docs/rules.md.
- A positive test. A minimal diff that must fire.
- A negative test. A near-miss that must not fire. If you cannot think of one, the rule probably is not precise enough.
- Bilingual copy.
name,whyandmessageall needenandzh. - A documented false-positive guard, if the rule needs one (see
classifyDisableinrules.ts).
Rules must be pure: no filesystem, no subprocesses, no network, no clock.
We optimize for precision over recall. A rule that fires on clean, well-written code will be reverted, even if it also catches real cheats. When in doubt, raise the evidence threshold.
Two mechanisms exist for this:
trimEvidencecaps evidence at three lines so reports stay readable.- Aggregation in
score.tscharges each rule once per diff, so one pattern in five files is one finding, not five.
Before opening a pull request that changes a rule, run:
npm run verify:reposIt fetches the latest commit of seven real repositories and fails if any scores below 100. If the
command cannot reach GitHub from your network, run it with node --use-system-ca scripts/verify-real-repos.js.
feat(rules): catch fixed sleeps in tests
fix(cli): do not crash on a diff without a header
docs(zh): clarify the trust score table
Rebuild dist/ before committing if you touched src/:
npm run buildThe Chinese README is not a translation of the English one — it is the same product written for a
different reader. Keep it natural. lang is threaded through every user-facing string; new strings need
both languages.
npm version patch
npm run build
npm test
npm publish
git push --follow-tags