feat(benchmark): add the evaluator the README already points at - #131
feat(benchmark): add the evaluator the README already points at#131Kairose-master wants to merge 2 commits into
Conversation
The README says "Benchmark assets, logs, evaluator, and generated projects live in examples/agent-comparison/" — but no evaluator is there, so the score table (95/73/62/59) cannot currently be re-derived from anything in the repo. This adds a deterministic scorer for the published rubric so anyone can re-run the comparison on any agent's output and get the same numbers. What it scores and how honestly it does it: - Structure (20), Hygiene (20), Git (15): recomputed from the project directory, one evidence line per check. A disputed score becomes an argument about a file listing or a git log, not about taste. - Functional (30): actually runs npm install + npm test, opt-in via --run-tests because it executes the project's code. - Quality (15): never auto-scored. It is a judgment call, so the script reports the inputs to that judgment (README, package metadata, custom error types) and assigns no points. A deterministic scorer that pretended to measure "quality" would just be an opinion with extra steps. - Unscorable is never zero: the vendored artifacts had .git stripped when they were copied in, so the Git dimension reports UNSCORABLE on them and drops out of the denominator instead of silently failing. Stdlib-only, no new dependencies. tests/test_benchmark_scorer.py covers the full-marks fixture, each defect docking exactly its own check, the unscorable-vs-zero distinction, and a smoke run against the vendored claude-code-sonnet artifact (8 tests, pass under the CI env guard).
AbirAbbas
left a comment
There was a problem hiding this comment.
Thanks — this fills a real gap (the README does point at an evaluator that doesn't exist), the --run-tests gating is correctly implemented (verified: the default path never invokes npm), it's genuinely stdlib-only with no network access, and all 8 tests pass under the CI env. Requesting a small set of changes:
_list_filesprunes only.gitandnode_modules(score.py:86) whileJUNK_DIRSalso namescoverage. A checked-incoverage/lcov-report/is simultaneously counted as project source modules (inflating Structure) and penalized as junk (docking Hygiene) — the scorer contradicts itself about one directory, and it's already firing on the vendored artifacts (e.g. claude-code-sonnet reports "6 source modules"; it has 2). Prune everything inJUNK_DIRS.- Uncaught exceptions crash the run:
subprocess.run(["npm", ...])raisesFileNotFoundErrorwhen npm isn't installed, and thetimeout=on the npm/git calls (score.py:93, 212, 218) can raiseTimeoutExpired. A scorer whose thesis is "unscorable is never zero" should record these aspassed=None/Falsewith evidence, not traceback out. - Cheap hardening, optional but free:
--ignore-scriptson thenpm installstep (test-running is the opt-in, lifecycle scripts don't need to be), andgit -c core.fsmonitor= ...in_gitsincegit status/logon an untrusted repo can execute config-supplied commands on the default path. - Nit:
"node_modules" in gitignore.read_text()is a substring match — a commented-out line earns the 5 points.
One larger point I'm flagging for a maintainer decision rather than asking you to resolve: running the scorer against the five vendored artifacts doesn't reproduce the README's published table (e.g. Structure gives Codex and CC-Haiku 20/20 where the README says 10, and several published values like Structure=10 aren't reachable under the 7/7/6 check split). Whether the answer is tuning the checks or documenting the published table as human-scored under a finer rubric is a call for the repo owners — please hold off reworking the rubric until that's settled; the four items above are worth doing regardless.
…, harden subprocess calls, parse .gitignore lines Review items from Agent-Field#131, each pinned by a test: - _list_files prunes everything JUNK_DIRS names: a checked-in coverage/ no longer counts as project modules for Structure while Hygiene docks it as junk — one directory, one verdict. - FileNotFoundError/TimeoutExpired can't crash the scorer. Missing npm is UNSCORABLE (the scorer's toolchain gap is not the project's failure); a hung npm test is a failure with evidence (a suite that never finishes is a property of the project). Missing/hung git routes every git-backed check to UNSCORABLE — including hygiene's clean-status, whose empty stdout would otherwise read as "clean". - npm install runs with --ignore-scripts (running the suite is the opt-in; lifecycle scripts are not part of that deal) and every git call clears core.fsmonitor. - .gitignore coverage is parsed per line: comments excluded, and node_modules / /node_modules / node_modules/ / **/node_modules all count. A commented-out line no longer earns the 5 points.
Thanks for the careful review — all four items were real. Fixed in 5b9a1be, each pinned by a test: |
The README says "Benchmark assets, logs, evaluator, and generated projects live in examples/agent-comparison/" — but no evaluator is there, so the score table (95/73/62/59) cannot currently be re-derived from anything in the repo. This adds a deterministic scorer for the published rubric so anyone can re-run the comparison on any agent's output and get the same numbers.
What it scores and how honestly it does it:
Stdlib-only, no new dependencies. tests/test_benchmark_scorer.py covers the full-marks fixture, each defect docking exactly its own check, the unscorable-vs-zero distinction, and a smoke run against the vendored claude-code-sonnet artifact (8 tests, pass under the CI env guard).
Summary
Validation
make checkBehavior Impact
Notes
Any rollout notes, migration notes, or follow-ups.