Skip to content

Add an evaluation harness for file selection and content generation #14

Description

@AshwinUgale

The problem

I had a few ideas for improving precision/recall on file selection . None of them are worth proposing yet, because there isn't a way to tell whether a change actually helps. The existing tests cover plumbing — parsing, path validation, truncation, git ops — but nothing measures what gets selected or what the LLM produces. So today every quality change is evaluated by eyeballing a few PRs.

I'd like to try landing an eval harness first so any future quality PR can be backed by numbers.

Method I'm thinking of

Two evaluators, one per pipeline stage.

File selection

A "case" is a folder containing diff.patch, a minimal docs/ tree, and an expected.json listing the files the pipeline should have selected. The runner builds a throwaway git repo in tmp_path, materializes the docs tree, applies the diff against a base commit, points env at a real model, and calls find_relevant_files_optimized(diff). The returned set is compared against the expected set to compute precision (of files selected, how many were right), recall (of files we should have caught, how many we did), and F1, per case and aggregate.

The two code paths inside find_relevant_files_optimized — the index-based fast path and the full-scan fallback — get scored separately by running each case twice, once with .doc-index/ populated and once with it removed. Otherwise a regression on one path can be hidden by improvement on the other.

Content generation

The case folder adds assertions.json with concrete claims about each file's output:
{
"docs/cli/reference.md": {
"must_mention": ["--verbose"],
"must_not_mention": ["--debug"],
"must_not_add_sections": true,
"max_new_lines": 20
}
}

must_mention catches missing updates, must_not_mention catches a specific class of hallucination (naming things the diff didn't introduce), must_not_add_sections enforces the "be conservative" instruction by comparing heading counts, max_new_lines bounds scope creep.

Global assertions run on every case regardless of contract: the output parses cleanly under the format declared by extension, code fences balance, and the first non-blank line isn't ``` (the prompts in ask_ai_for_updated_content forbid wrapping the file in a fence, but the LLM still does it sometimes).

The runner calls ask_ai_for_updated_content per case, runs per-case assertions for that file, then global assertions. Each is a pass/fail. Aggregate is the fraction of assertions passing across the corpus, broken out by assertion type so regressions on one specific kind are visible.

Frozen baseline + CI

After the first run, the aggregated numbers (F1 per path, per-assertion-type pass rates) get written to baseline.json and committed. Every subsequent CI run computes new numbers, diffs against baseline, posts the delta on the PR. Drops beyond a configurable tolerance fail the job. Baseline bumps are explicit commits when an intentional improvement lands.

Honest caveat

Whether this is the right method, I genuinely don't know yet. Assertions are cheap and deterministic but they're an indirect proxy for "is this update actually good," and the only way to find out how much of the real failure surface they catch is to write some cases and look at what gets through. I'd rather try it on a small corpus, see whether the scores correlate with good output by eye, and then decide whether to keep this approach or switch to something else. If the first ~10-15 cases show the harness missing obvious failures, I'll write up what didn't work and move to an LLM-as-judge approach against gold updates.

Does this direction make sense before I start? And if so — is there a docs repo that's been an active code-to-docs target? Mining merged docs-PRs from it would give much higher-signal cases than synthetic ones.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions