mirror of
https://github.com/magnus919/agent-skills.git
synced 2026-09-12 20:16:29 +03:00
92299e1238
Add a schema-valid eval manifest (6 cases: fine-tuning plan review, eval-set design, quantization decision, deployment plan, regression triage, training-run reproducibility), three fillable templates (training-run record, eval regression table, quantization decision record), a stdlib eval-set overlap/leakage checker with a unittest suite, routing to the llama-cpp tool skill, and a README Quick Start documenting the script. Closes #240. Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
204 lines
7.7 KiB
Python
204 lines
7.7 KiB
Python
"""Tests for check-eval-overlap.py.
|
|
|
|
Covers: clean corpora (exit 0), exact-duplicate eval files (exit 1), partial
|
|
overlap above and below the threshold, JSON report shape, directory recursion,
|
|
token n-gram mode, the --shingle-size flag, missing-path errors, an empty eval
|
|
file, a training corpus too short to shingle, and --help.
|
|
|
|
Discoverable by both pytest and unittest (unittest.TestCase classes).
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
import unittest
|
|
|
|
SCRIPTS_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
CHECKER = os.path.join(SCRIPTS_DIR, "check-eval-overlap.py")
|
|
|
|
TRAIN_PARAGRAPH = (
|
|
"The quick brown fox jumps over the lazy dog near the riverbank while the "
|
|
"sun sets behind the mountains and the evening train crosses the old bridge."
|
|
)
|
|
EVAL_SENTENCE = (
|
|
"The quick brown fox jumps over the lazy dog near the riverbank"
|
|
)
|
|
UNIQUE_FILLER = (
|
|
"blueberry pancakes with maple syrup served at the corner cafe on tuesday "
|
|
"morning while the radio played classical music and the barista practiced "
|
|
"latte art with carefully steamed milk and a gentle hand."
|
|
)
|
|
|
|
|
|
def run_checker(args):
|
|
proc = subprocess.run(
|
|
[sys.executable, CHECKER, *args],
|
|
capture_output=True,
|
|
text=True,
|
|
timeout=30,
|
|
)
|
|
return proc.returncode, proc.stdout, proc.stderr
|
|
|
|
|
|
class TempCorpora(unittest.TestCase):
|
|
"""Per-test temporary train/ and eval/ directories."""
|
|
|
|
def setUp(self):
|
|
self._tmp = tempfile.TemporaryDirectory()
|
|
self.root = self._tmp.name
|
|
self.train = os.path.join(self.root, "train")
|
|
self.eval_dir = os.path.join(self.root, "eval")
|
|
os.makedirs(self.train)
|
|
os.makedirs(self.eval_dir)
|
|
|
|
def tearDown(self):
|
|
self._tmp.cleanup()
|
|
|
|
def write_train(self, name, content):
|
|
path = os.path.join(self.train, name)
|
|
with open(path, "w", encoding="utf-8") as handle:
|
|
handle.write(content)
|
|
return path
|
|
|
|
def write_eval(self, name, content):
|
|
path = os.path.join(self.eval_dir, name)
|
|
with open(path, "w", encoding="utf-8") as handle:
|
|
handle.write(content)
|
|
return path
|
|
|
|
|
|
class TestOverlapDetection(TempCorpora):
|
|
def test_help_exits_zero(self):
|
|
rc, stdout, _ = run_checker(["--help"])
|
|
self.assertEqual(rc, 0)
|
|
self.assertIn("overlap", stdout)
|
|
|
|
def test_clean_corpora_exit_zero(self):
|
|
self.write_train("train.txt", TRAIN_PARAGRAPH)
|
|
self.write_eval("eval.txt", UNIQUE_FILLER)
|
|
rc, stdout, _ = run_checker(["--train", self.train, "--eval", self.eval_dir])
|
|
self.assertEqual(rc, 0)
|
|
self.assertIn("No leakage", stdout)
|
|
self.assertIn("ok", stdout)
|
|
|
|
def test_exact_duplicate_flags_leak(self):
|
|
self.write_train("train.txt", TRAIN_PARAGRAPH)
|
|
self.write_eval("eval.txt", TRAIN_PARAGRAPH)
|
|
rc, stdout, _ = run_checker(["--train", self.train, "--eval", self.eval_dir])
|
|
self.assertEqual(rc, 1)
|
|
self.assertIn("LEAK", stdout)
|
|
self.assertIn("Leakage detected in 1", stdout)
|
|
|
|
def test_partial_overlap_above_threshold_flags_leak(self):
|
|
# Eval reuses the whole train sentence (53 shingles) plus ~210 chars of
|
|
# unique filler, so overlap is roughly 20% and must be flagged.
|
|
self.write_train("train.txt", TRAIN_PARAGRAPH)
|
|
self.write_eval("eval.txt", EVAL_SENTENCE + " " + UNIQUE_FILLER[:210])
|
|
rc, stdout, _ = run_checker(["--train", self.train, "--eval", self.eval_dir])
|
|
self.assertEqual(rc, 1)
|
|
self.assertIn("LEAK", stdout)
|
|
|
|
def test_overlap_below_threshold_clean(self):
|
|
# Eval reuses one sentence (~54 shingles) plus unique filler (~210
|
|
# shingles), for roughly 20-25% overlap. A raised threshold must accept
|
|
# it; the default threshold flags the same input (see the partial-overlap
|
|
# test above).
|
|
self.write_train("train.txt", TRAIN_PARAGRAPH)
|
|
self.write_eval("eval.txt", EVAL_SENTENCE + " " + UNIQUE_FILLER)
|
|
rc, stdout, _ = run_checker(
|
|
["--train", self.train, "--eval", self.eval_dir, "--max-overlap-fraction", "0.30"]
|
|
)
|
|
self.assertEqual(rc, 0)
|
|
self.assertIn("No leakage", stdout)
|
|
|
|
|
|
class TestOverlapCli(TempCorpora):
|
|
def test_json_report_shape(self):
|
|
self.write_train("train.txt", TRAIN_PARAGRAPH)
|
|
self.write_eval("eval.txt", TRAIN_PARAGRAPH)
|
|
rc, stdout, _ = run_checker(
|
|
["--train", self.train, "--eval", self.eval_dir, "--json"]
|
|
)
|
|
self.assertEqual(rc, 1)
|
|
report = json.loads(stdout)
|
|
self.assertEqual(report["tool"], "check-eval-overlap.py")
|
|
self.assertEqual(report["train_files"], 1)
|
|
self.assertEqual(report["eval_files"], 1)
|
|
self.assertEqual(len(report["leaked"]), 1)
|
|
entry = report["files"][0]
|
|
self.assertEqual(entry["verdict"], "LEAK")
|
|
self.assertAlmostEqual(entry["fraction"], 1.0, places=4)
|
|
self.assertGreater(entry["shared"], 0)
|
|
|
|
def test_directory_recursion(self):
|
|
nested = os.path.join(self.train, "nested")
|
|
os.makedirs(nested)
|
|
with open(os.path.join(nested, "corpus.txt"), "w", encoding="utf-8") as handle:
|
|
handle.write(TRAIN_PARAGRAPH)
|
|
self.write_eval("eval.txt", TRAIN_PARAGRAPH)
|
|
rc, _, _ = run_checker(["--train", self.train, "--eval", self.eval_dir])
|
|
self.assertEqual(rc, 1)
|
|
|
|
def test_multiple_eval_files_partial_leak(self):
|
|
self.write_train("train.txt", TRAIN_PARAGRAPH)
|
|
self.write_eval("clean.txt", UNIQUE_FILLER)
|
|
self.write_eval("duplicate.txt", TRAIN_PARAGRAPH)
|
|
rc, stdout, _ = run_checker(["--train", self.train, "--eval", self.eval_dir])
|
|
self.assertEqual(rc, 1)
|
|
self.assertIn("Leakage detected in 1 of 2", stdout)
|
|
|
|
def test_token_ngram_mode(self):
|
|
tokens = "alpha beta gamma delta epsilon"
|
|
self.write_train("train.txt", tokens)
|
|
self.write_eval("eval.txt", tokens)
|
|
rc, stdout, _ = run_checker(
|
|
["--train", self.train, "--eval", self.eval_dir, "--token-ngram", "3"]
|
|
)
|
|
self.assertEqual(rc, 1)
|
|
self.assertIn("token-3", stdout)
|
|
|
|
def test_shingle_size_flag(self):
|
|
# A short shared word is invisible at size 8 but flagged at size 4.
|
|
self.write_train("train.txt", "zebra crossing")
|
|
self.write_eval("eval.txt", "zebra")
|
|
rc_default, _, _ = run_checker(["--train", self.train, "--eval", self.eval_dir])
|
|
rc_small, stdout, _ = run_checker(
|
|
["--train", self.train, "--eval", self.eval_dir, "--shingle-size", "4"]
|
|
)
|
|
self.assertEqual(rc_default, 0)
|
|
self.assertEqual(rc_small, 1)
|
|
self.assertIn("LEAK", stdout)
|
|
|
|
|
|
class TestOverlapErrors(TempCorpora):
|
|
def test_missing_path_exit_two(self):
|
|
self.write_train("train.txt", TRAIN_PARAGRAPH)
|
|
rc, _, stderr = run_checker(
|
|
["--train", self.train, "--eval", os.path.join(self.root, "nope")]
|
|
)
|
|
self.assertEqual(rc, 2)
|
|
self.assertIn("ERROR", stderr)
|
|
|
|
def test_empty_eval_file_handled(self):
|
|
self.write_train("train.txt", TRAIN_PARAGRAPH)
|
|
self.write_eval("empty.txt", "")
|
|
rc, _, _ = run_checker(["--train", self.train, "--eval", self.eval_dir])
|
|
self.assertEqual(rc, 0)
|
|
|
|
def test_train_corpus_too_short_exit_two(self):
|
|
self.write_train("tiny.txt", "hi")
|
|
self.write_eval("eval.txt", TRAIN_PARAGRAPH)
|
|
rc, _, stderr = run_checker(["--train", self.train, "--eval", self.eval_dir])
|
|
self.assertEqual(rc, 2)
|
|
self.assertIn("no shingles", stderr)
|
|
|
|
def test_missing_train_required_flag(self):
|
|
rc, _, _ = run_checker(["--eval", self.eval_dir])
|
|
self.assertEqual(rc, 2)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|