Skip to content

feat: resolve eval question text for metrics referencing evals in experiments analyze#45834

Merged
pelikhan merged 5 commits into
mainfrom
copilot/update-experiments-command
Jul 16, 2026
Merged

feat: resolve eval question text for metrics referencing evals in experiments analyze#45834
pelikhan merged 5 commits into
mainfrom
copilot/update-experiments-command

Conversation

Copilot AI commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

The experiments analyze command loaded ExperimentConfig.Metric from workflow frontmatter but never surfaced it — silently dropping eval references like metric: "evals.builds" that point to declared eval question IDs.

Changes

pkg/workflow/

  • Export ParseExperimentMetricEvalReference (was package-private)
  • Add ParseEvalsFromFrontmatter — public wrapper to extract EvalsConfig without a compiler instance

pkg/cli/experiments_command.go

  • Introduce experimentFrontmatterResult struct carrying both ExperimentConfigs and EvalsConfig
  • Update loadLocalExperimentConfigs / loadRemoteExperimentConfigs to also parse and return evals (best-effort; logged, non-fatal)
  • Plumb EvalsConfig through to computeExperimentAnalyses

pkg/cli/experiments_analyze_statistics.go

  • Add metric and metric_question fields to ExperimentAnalysis
  • Resolve eval references in computeExperimentAnalysis: evals.builds → question text from declared evals
  • Display resolved metric in human output:
    Metric     : evals.builds — Does the generated code compile?
    

Tests

  • Updated all existing call sites for the new evals parameter
  • 5 new cases: plain metric, evals. resolution, eval: resolution, unknown ID, nil evals

Copilot AI and others added 2 commits July 15, 2026 21:47
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title feat: resolve evals values referenced in experiment metrics feat: resolve eval question text for metrics referencing evals in experiments analyze Jul 15, 2026
Copilot AI requested a review from pelikhan July 15, 2026 21:59
@pelikhan
pelikhan marked this pull request as ready for review July 15, 2026 22:05
Copilot AI review requested due to automatic review settings July 15, 2026 22:05
@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ completed the design decision gate check.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds eval-backed metric question resolution to experiment analysis output.

Changes:

  • Exposes workflow helpers for parsing eval references and configurations.
  • Propagates eval definitions through local and remote analysis.
  • Adds metric fields, rendering, and resolution tests.
Show a summary per file
File Description
pkg/workflow/evals_config.go Exposes eval frontmatter parsing.
pkg/workflow/compiler_experiments.go Exports metric-reference parsing.
pkg/workflow/compiler_experiments_test.go Updates parser tests.
pkg/cli/experiments_command.go Loads and propagates eval configuration.
pkg/cli/experiments_analyze_statistics.go Resolves and displays metric questions.
pkg/cli/experiments_analyze_statistics_test.go Adds metric-resolution coverage.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 6/6 changed files
  • Comments generated: 1
  • Review effort level: Medium

Comment on lines +140 to +144
// Populate metric and resolve any eval reference to its question text.
if cfg.Metric != "" {
a.Metric = cfg.Metric
evalID, isEval := workflow.ParseExperimentMetricEvalReference(cfg.Metric)
if isEval && evalID != "" && evals != nil {

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes are clean and well-structured. The refactoring correctly threads *workflow.EvalsConfig through the call chain, the new experimentFrontmatterResult struct is a clean bundling, and the test coverage for all edge cases (nil evals, unknown ID, plain metric, both prefix forms) is thorough. No blocking issues found.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · 25 AIC · ⌖ 7.35 AIC · ⊞ 5K

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 82/100 — Excellent

Analyzed 5 test(s): 5 design, 0 implementation, 0 violation(s).

📊 Metrics (5 tests)
Metric Value
Analyzed 5 (Go: 5, JS: 0)
✅ Design 5 (100%)
⚠️ Implementation 0 (0%)
Edge/error coverage 5 (100%)
Duplicate clusters 0
Inflation Yes (but refactoring-driven)
🚨 Violations 0
Test File Classification Edge Cases
metric from config (plain) experiments_analyze_statistics_test.go:331 design_test Plain metric (no eval)
metric resolves eval question when evals provided experiments_analyze_statistics_test.go:346 design_test Happy-path resolution
metric eval reference with eval: prefix resolves question experiments_analyze_statistics_test.go:367 design_test Alternative prefix format
eval reference with unknown id leaves MetricQuestion empty experiments_analyze_statistics_test.go:387 design_test Missing eval ID gracefully
eval reference with nil evals leaves MetricQuestion empty experiments_analyze_statistics_test.go:407 design_test Nil evals gracefully
✅ Analysis

Strengths:

  • All 5 new subtests are well-structured behavioral contracts
  • Each test has descriptive names and clear assertion messages
  • Comprehensive edge-case coverage: plain metrics, happy path, missing IDs, nil values
  • Tests directly verify the new metric resolution feature
  • No mock library violations (using testify/assert only)
  • All existing test calls updated correctly to pass new evals parameter

Test Inflation Note:
The 115 new test lines include ~91 lines of signature updates (adding nil parameter to existing calls) to accommodate the production API change. The 5 new subtests themselves represent high-quality behavioral coverage.

Verdict

Passed. 0% implementation tests (threshold: 30%). Quality: 82/100 (Excellent).

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • awmgmcpg

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "awmgmcpg"

See Network Configuration for more information.

🧪 Test quality analysis by Test Quality Sentinel · 23.3 AIC · ⌖ 8.7 AIC · ⊞ 6.8K ·
Comment /review to run again

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Test Quality Sentinel: 82/100. 0% implementation tests (threshold: 30%). All 5 new subtests are well-structured behavioral contracts with comprehensive edge-case coverage.

@github-actions

Copy link
Copy Markdown
Contributor

Design Decision Gate — ADR Required

This PR makes significant changes to core business logic (209 new lines in pkg/) but does not have a linked Architecture Decision Record (ADR).

Draft ADR committed: docs/adr/45834-surface-metric-and-resolve-eval-references-in-experiments-analyze.md — review and complete it before merging.

This PR cannot merge until an ADR is linked in the PR body.

What to do next
  1. Review the draft ADR committed to your branch — it was generated from the PR diff
  2. Complete the missing sections — add context the AI could not infer, refine the decision rationale, and list real alternatives you considered
  3. Commit the finalized ADR to docs/adr/ on your branch
  4. Reference the ADR in this PR body by adding a line such as:
    ADR: [ADR-45834: Surface Metric and Resolve Eval References in experiments analyze](docs/adr/45834-surface-metric-and-resolve-eval-references-in-experiments-analyze.md)

Once an ADR is linked in the PR body, this gate will re-run and verify the implementation matches the decision.

Why ADRs Matter

ADRs create a searchable, permanent record of why the codebase looks the way it does. Future contributors (and your future self) will thank you.

Michael Nygard ADR Format Reference

An ADR must contain these four sections to be considered complete:

  • Context — What is the problem? What forces are at play?
  • Decision — What did you decide? Why?
  • Alternatives Considered — What else could have been done?
  • Consequences — What are the trade-offs (positive and negative)?

All ADRs are stored in docs/adr/ as Markdown files numbered by PR number.

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · 63.4 AIC · ⌖ 11.5 AIC · ⊞ 8.5K ·
Comment /review to run again

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-blocking observations only — the core feature logic (eval question resolution, struct plumbing, test coverage) is correct and well-tested.

Review themes

Asymmetry between local and remote frontmatter loaders

loadLocalExperimentConfigs always parses evals after a successful frontmatter parse; loadRemoteExperimentConfigs gates evals parsing inside if len(cfg.ExperimentConfigs) > 0. Today this is harmless because the two always co-exist, but the structural divergence is a latent correctness issue and a maintainability trap.

Zero-value Compiler receiver in ParseEvalsFromFrontmatter

Using var c Compiler to call a method on a ~30-field struct is fragile. The method works now but there's no guard against future extensions accessing Compiler fields. The function should either be a standalone free function or document the constraint explicitly.

🔎 Code quality review by PR Code Quality Reviewer · 71.9 AIC · ⌖ 4.67 AIC · ⊞ 5.6K
Comment /review to run again

Comments that could not be inline-anchored

pkg/cli/experiments_command.go:425

Evals silently dropped when remote workflow has no experiment configs: the guard if len(cfg.ExperimentConfigs) &gt; 0 means evals are only parsed for the candidate that also carries experiment configs. If a workflow file declares evals: but cfg.ExperimentConfigs is empty (unexpected parse result, future structural change, etc.), evals are silently discarded with no log message. This diverges from loadLocalExperimentConfigs, which always parses evals after a successful frontmatter parse…

pkg/workflow/evals_config.go:602

ParseEvalsFromFrontmatter relies on a zero-value Compiler receiver: the implementation constructs var c Compiler and delegates to the method receiver. This works today because parseEvalsFromFrontmatter doesn't access any Compiler fields, but there is no compiler-level contract enforcing that. The Compiler struct has ~30 fields; if parseEvalsFromFrontmatter is ever extended to consult any of them (e.g. c.verbose, c.ctx), this wrapper will silently use zero-values, producing…

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skills-Based Review 🧠

Applied /codebase-design — one actionable finding; otherwise clean implementation.

📋 Key Themes & Highlights

Finding

  • Asymmetric evals parsing in remote path: loadRemoteExperimentConfigs only calls ParseEvalsFromFrontmatter inside the if len(cfg.ExperimentConfigs) > 0 guard, while loadLocalExperimentConfigs always parses evals. This means a remote workflow that declares evals without experiment configs will silently lose its evals data.

Positive Highlights

  • ✅ 5 well-named, well-structured test cases covering all branches (plain metric, evals prefix, eval: prefix, unknown ID, nil evals)
  • experimentFrontmatterResult struct cleanly encapsulates the new coupling between experiment configs and evals
  • ✅ All error paths in evals parsing are logged and non-fatal — keeps the command resilient
  • ParseEvalsFromFrontmatter public wrapper is minimal and idiomatic; zero-value Compiler is safe to use
  • Metric/MetricQuestion JSON fields use omitempty — no schema breakage for existing consumers

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · 32.6 AIC · ⌖ 4.51 AIC · ⊞ 6.7K
Comment /matt to run again

@@ -396,12 +414,20 @@ func loadRemoteExperimentConfigs(repoOverride, experimentName string) map[string

if len(cfg.ExperimentConfigs) > 0 {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/codebase-design] loadRemoteExperimentConfigs only parses evals when len(cfg.ExperimentConfigs) > 0, while loadLocalExperimentConfigs always parses evals — a silent asymmetry. If a workflow declares evals without any experimentConfigs, the remote path silently drops the evals.

💡 Suggested fix

Parse evals unconditionally before the guard, mirroring the local path:

evals, evalsErr := workflow.ParseEvalsFromFrontmatter(result.Frontmatter)
if evalsErr != nil {
    experimentsLog.Printf("Failed to parse evals config from %s: %v", apiPath, evalsErr)
}
if len(cfg.ExperimentConfigs) > 0 {
    experimentsLog.Printf("Loaded remote configs from %s", apiPath)
    return experimentFrontmatterResult{
        ExperimentConfigs: cfg.ExperimentConfigs,
        Evals:             evals,
    }
}

This keeps both code paths symmetric and avoids a surprising gap.

@copilot please address this.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, address the ADR gate by completing and linking the draft ADR in your PR body, review the latest workflow feedback, and rerun checks once any required updates are pushed.

Generated by 👨‍🍳 PR Sous Chef · 8.83 AIC · ⌖ 6 AIC · ⊞ 7.5K ·
Comment /souschef to run again

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>

Copilot AI commented Jul 15, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please run the pr-finisher skill, address the ADR gate by completing and linking the draft ADR in your PR body, review the latest workflow feedback, and rerun checks once any required updat...

Addressed in 5b58112: experiment analysis now preserves metric metadata for single-variant state, remote frontmatter parsing now reads evals unconditionally, and the draft ADR is completed at /home/runner/work/gh-aw/gh-aw/docs/adr/45834-surface-metric-and-resolve-eval-references-in-experiments-analyze.md. Local make fmt, make lint, make test-unit, make test, make agent-report-progress, and parallel validation all passed. I could not update the PR body from this environment because the available GitHub APIs here are read-only and direct gh api writes are blocked by the DNS proxy, so the ADR link still needs to be added to the PR body manually. CI on this pushed HEAD also still needs a maintainer re-trigger.

Copilot AI requested a review from gh-aw-bot July 15, 2026 22:41
@github-actions

Copy link
Copy Markdown
Contributor

🤖 PR Triage

Field Value
Category feature
Risk medium
Score 68 / 100
Action fast_track

Score breakdown: Impact 35 + Urgency 18 + Quality 15

Exports ParseExperimentMetricEvalReference and wires up eval question text in experiments analyze. Behavioral change in the experiments command path; tests included. CI status unknown — awaiting checks.

Run §29462479491

Generated by 🔧 PR Triage Agent · 189.6 AIC · ⌖ 5.52 AIC · ⊞ 5.6K ·

@github-actions

Copy link
Copy Markdown
Contributor

Hey @copilot-swe-agent 👋 — great work surfacing the metric and metric_question fields in experiments analyze! Silently dropping eval references like metric: "evals.builds" was a real usability gap, and this fix is well-scoped.

The PR is focused, includes tests in both pkg/cli and pkg/workflow, has a clear description with an ADR, and introduces no new dependencies. It looks ready for review. 🎉

Generated by ✅ Contribution Check · 124.7 AIC · ⌖ 9.92 AIC · ⊞ 6.2K ·

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, address any unresolved review feedback, and rerun checks once the branch is up to date.

Generated by 👨‍🍳 PR Sous Chef · 9.13 AIC · ⌖ 6.02 AIC · ⊞ 5.1K ·
Comment /souschef to run again

…ments-command

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>

Copilot AI commented Jul 16, 2026

Copy link
Copy Markdown
Contributor Author

@copilot please run the pr-finisher skill, address any unresolved review feedback, and rerun checks once the branch is up to date.

...

Addressed on 719613d: the branch is now up to date with origin/main, and the remaining in-scope review feedback was already satisfied by the earlier experiments analyze fixes (5b58112) plus the single-variant metric metadata coverage in /home/runner/work/gh-aw/gh-aw/pkg/cli/experiments_analyze_statistics_test.go. I re-ran make fmt, make recompile, make lint, make test-unit, make test, and make agent-report-progress; all passed locally, and secret scanning was clean. I can’t re-trigger PR CI from this environment, so checks on the new HEAD still need a maintainer re-run.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

\n@copilot please run the skill, address the unresolved review feedback (newest first: github-actions: #45834 (comment); copilot-pull-request-reviewer: #45834 (comment)), and rerun checks once the branch is up to date.\n\n> Generated by \ud83c\udf73 PR Sous Chef

Generated by 👨‍🍳 PR Sous Chef · 4.65 AIC · ⌖ 9.69 AIC · ⊞ 7.5K ·
Comment /souschef to run again

@pelikhan
pelikhan merged commit 2e430b3 into main Jul 16, 2026
29 checks passed
@pelikhan
pelikhan deleted the copilot/update-experiments-command branch July 16, 2026 04:23
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.82.10

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants