Regenerate the reviewer-feedback eval baseline against the shipped prompt - #212
Conversation
Its only entry point had no callers once the author-action binary shipped, so nothing in production rendered the prompt. Removing it leaves the batch runner reachable from the author-comment path alone, which lets its top_level and author_comment flags and the branch behind them go too.
…ompt The recorded baseline named a prompt that no longer exists, so it could not be reproduced and its labels described retired behavior.
Pull request dashboard statusMerged · refreshed 2026-08-04 13:35 UTC Status above doesn't look right?
|
There was a problem hiding this comment.
Pull request overview
Regenerates reviewer-feedback evaluation data against the shipped classifier while removing the retired classifier infrastructure.
Changes:
- Adds a cached baseline-regeneration utility.
- Refreshes 616 evaluation cases and adds five review summaries.
- Removes obsolete classifier code, scoring vocabulary, and tests.
Reviewed changes
Copilot reviewed 4 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
classification.py |
Removes the retired classifier path. |
test_top_level_actions.py |
Updates tests for the shipped classifier. |
eval/score_reviewer_feedback.py |
Removes obsolete scoring vocabulary. |
eval/regenerate_baseline.py |
Adds reproducible baseline generation. |
eval/reviewer_feedback_cases.json |
Records the refreshed baseline and new cases. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…rate-reviewer-feedback-baseline # Conflicts: # .github/scripts/pull-request-dashboard/classification.py # .github/scripts/pull-request-dashboard/eval/reviewer_feedback_cases.json
…line cache entries atomically
…seline cache on the rendered prompt
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 2 changed files in this pull request and generated 1 comment.
Suppressed comments (3)
.github/scripts/pull-request-dashboard/eval/regenerate_baseline.py:12
- The docstring says the cache is under
.cache/baseline/, but the code writes under.github/scripts/pull-request-dashboard/.cache/baseline(relative to repo root). Update the docstring to reflect the actual location (or clarify it’s relative to the dashboard script directory) so users can find/clean the cache confidently.
"""Re-measure the recorded baseline in reviewer_feedback_cases.json.
Drives from the cases already in the file rather than re-collecting them from
GitHub. Re-collecting would silently change the set, because the original
collection kept only pull requests that were open on the day it ran.
Raw responses are cached under .cache/baseline/, so a failed or interrupted run
resumes without paying for the calls it already made, and a change to how
answers are read costs nothing to apply.
Run manually; it makes several hundred model calls.
"""
.github/scripts/pull-request-dashboard/eval/regenerate_baseline.py:32
- The docstring says the cache is under
.cache/baseline/, but the code writes under.github/scripts/pull-request-dashboard/.cache/baseline(relative to repo root). Update the docstring to reflect the actual location (or clarify it’s relative to the dashboard script directory) so users can find/clean the cache confidently.
CACHE_DIR = Path(__file__).resolve().parent.parent / ".cache" / "baseline"
.github/scripts/pull-request-dashboard/eval/regenerate_baseline.py:141
- The script fans out model calls concurrently (default
--workers 12) without retry/backoff. If the underlying service throttles or has transient failures, batches will becomeunobserved, skewing stability counts and potentially forcing reruns. Consider (mandatory if throttling is realistic in your environment) adding a small retry policy for known transient failures and/or reducing the default concurrency (or making it opt-in) to improve baseline reproducibility.
with ThreadPoolExecutor(max_workers=workers) as pool:
results = list(pool.map(work, tasks))
…-positive --runs and --workers
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 2 changed files in this pull request and generated no new comments.
Suppressed comments (1)
.github/scripts/pull-request-dashboard/eval/regenerate_baseline.py:149
- The new baseline derivation is not covered by tests, even though this repository tests the adjacent scorer and validates the generated fixture. A regression here could silently relabel all 616 cases while the fixture-shape tests still pass. Please add focused unit tests for
rebuild(stable/flaky/partially unanswered trials and preservation of adjudication) and the duplicate/invalid-response handling inanswers.
def rebuild(payload: dict, trials: list[dict[str, str]], model: str) -> dict:
A failed call was written to the cache like any result, so every later run replayed it instead of retrying.
Cover rebuild (stable, flaky, unobserved, adjudication) and answers (unparseable, unknown verdict, unrequested and duplicated ids), plus run_batch caching only successful calls.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 3 changed files in this pull request and generated no new comments.
Suppressed comments (1)
.github/scripts/pull-request-dashboard/eval/regenerate_baseline.py:49
- This does not always reproduce the prompt sent by production.
derive_top_level_itemstruncates every top-level body to 1,200 characters before classification (dashboard.py:729,utils.py:7), but this path sends the recorded body verbatim. The newly addedpr-review-4660197614body in the fixture is several thousand characters and is not marked truncated, so its five recorded results were measured against input the dashboard never sends. Apply the same production truncation (or store the exact derived body) and regenerate the baseline.
"discussion_id": c["id"],
"requester": c["requester"],
"pr_author": c["pr_author"],
"body": c["body"],
}
One case was collected straight from the API, so it stored a body several thousand characters long while derive_top_level_items truncates to 1200 before classifying. Storing the derived body and re-measuring moves it and its batch sibling from stable noise to flaky, and a fixture test now keeps every body equal to what production would send.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 4 changed files in this pull request and generated no new comments.
Suppressed comments (1)
.github/scripts/pull-request-dashboard/eval/regenerate_baseline.py:173
batch_casespreserves list order, while production orders top-level items byroot_timestamp(dashboard.py:772). Sorting the regenerated fixture by the opaque string ID changes that order—especially by putting allpr-issue-comment-*entries beforepr-review-*entries—and can change prompt ordering and 10-item batch boundaries on the next regeneration. Preserve the recorded per-PR order (or record and sort by the production timestamp) instead of sorting by ID.
cases.sort(key=lambda c: (c["repo"], c["pull_request"], c["id"]))
The fixture was sorted by case id, which puts every issue comment ahead of every review, while the dashboard orders a pull request's items by root_timestamp. Because the scorer batches ten items at a time within a pull request, the recorded cases were being measured in batches production never sends. Each case now records its root_timestamp and the fixture is stored in that order, with a guard test that keeps it there. Depends on open-telemetry#215, which makes root_timestamp the time the feedback was posted rather than the time it was last edited.
…te-reviewer-feedback-baseline open-telemetry#187 renamed the fixture's fields, so the regenerated baseline is rewritten in that vocabulary: role/context replaces stability unobserved, recorded_label replaces baseline, run_actions and run_labels replace observed_actions and observed_runs, adjudicated_label replaces adjudicated, and the labels themselves are author_action and no_author_action. regenerate_baseline.py and its tests emit the same shape, and the retired prompt_note goes because this baseline is measured against the shipped prompt again. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: b6937855-e302-4419-adcf-d9340220ce5b
The recorded baseline in
eval/reviewer_feedback_cases.jsonnamedTOP_LEVEL_REVIEWER_FEEDBACK_BATCH_PROMPT_TEMPLATE, a prompt that #196 replaced and #210 deleted, so its labels described a classifier that no longer runs and a scored regression was as likely to be the old prompt showing through as a real one. This re-measures every case against the shippedREVIEWER_FEEDBACK_PROMPT_TEMPLATEatgpt-5.4-mini, five runs, batched one pull request at a time as the dashboard batches. Fifteen stable cases change label, eleven of them approvals carrying optional nits moving tono_author_action, which is the change #196 set out to make.eval/regenerate_baseline.pyis what produced the file, so the next prompt change can refresh it instead of retiring it. It drives from the cases already recorded rather than re-collecting from GitHub, because the original collection kept only pull requests that were open on the day it ran. It writes the field names #187 settled on, whereaction_labelsmaps the shipped binary's verdicts onto themselves because that binary already answers in the recorded labels.The cases also record the
root_timestampthe dashboard orders a pull request's items by and are stored in that order, and the one case holding an untruncated body now holds the truncated one, so the batches measured are the batches production sends.Also adds the five review summaries from open-telemetry/opentelemetry-java-instrumentation#19152, the thread that prompted this, and adjudicates the shortest of them,
AI-generated review, asno_author_action.