Skip to content

Add tool output consumption rate trajectory grader - #57252

Open
pelikhan with Copilot wants to merge 4 commits into
mainfrom
copilot/trajectory-grader-implement-tool-output-consumptio
Open

Add tool output consumption rate trajectory grader#57252
pelikhan with Copilot wants to merge 4 commits into
mainfrom
copilot/trajectory-grader-implement-tool-output-consumptio

Conversation

Copilot AI commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

The built-in tool success rate does not reveal outputs fetched but never used. This adds a grader measuring consumed tool-originated observations over all tool-originated observations.

  • Grader contract

    • Higher-is-better ratio.
    • Matches observations[].sourceToolCallId against toolCalls[].id.
    • Treats non-empty consumedByActionIds as consumed.
  • Applicability

    • Returns passed: null when observations or matching tool provenance are absent.
    • Excludes non-tool and unmatched observations from the denominator.
    • Treats malformed consumption metadata as unconsumed.
  • Catalog

    • Marks Tier 2 rank 12 as implemented.
imports:
  - shared/graders/tool-output-consumption-rate.md

Copilot AI and others added 2 commits August 30, 2026 22:15
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 [WIP] Implement tool-output-consumption-rate for trajectory graders Add tool output consumption rate trajectory grader Aug 30, 2026
Copilot AI requested a review from pelikhan August 30, 2026 22:19
@pelikhan
pelikhan marked this pull request as ready for review August 30, 2026 22:21
Copilot AI balanced review requested due to automatic review settings August 30, 2026 22:21
@github-actions

github-actions Bot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

Test Quality Sentinel skipped because pre-fetch PR data was unavailable: unable to fetch test file diff

Warning

Firewall blocked 1 domain

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

  • github.com

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

network:
  allowed:
    - defaults
    - "github.com"

See Network Configuration for more information.

🧪 Test quality analysis by Test Quality Sentinel

@github-actions

github-actions Bot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

⚠️ Security scanning failed for Ponytail Reviewer. Review the logs for details.

Warning

Firewall blocked 1 domain

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

  • ab.chatgpt.com

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

network:
  allowed:
    - defaults
    - "ab.chatgpt.com"

See Network Configuration for more information.

Generated by Ponytail Reviewer for #57252

@github-actions

github-actions Bot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

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

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer

@github-actions

github-actions Bot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

Warning

Firewall blocked 3 domains

The following domains were blocked by the firewall during workflow execution:

  • codeload.github.com
  • github.com
  • registry.npmjs.org

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

network:
  allowed:
    - defaults
    - "codeload.github.com"
    - "github.com"
    - "registry.npmjs.org"

See Network Configuration for more information.

🔎 Code quality review by PR Code Quality Reviewer

@github-actions

github-actions Bot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ completed the design decision gate check. See the comment below for the result and any generated ADR draft.

No ADR enforcement needed: PR does not have the 'implementation' label and has ≤100 new lines of code in business logic directories.

🏗️ ADR gate enforced by Design Decision Gate 🏗️

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.

🟡 Changes recommended

Malformed array entries are incorrectly counted as valid consumption, inflating the reported rate.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds a trajectory grader that measures whether tool-originated observations are subsequently consumed.

Changes:

  • Implements the consumption-rate grader and applicability handling.
  • Adds grader tests.
  • Marks catalog rank 12 implemented.
File summaries
File Description
.github/workflows/shared/graders/tool-output-consumption-rate.md Defines the grader.
actions/setup/js/trace_graders.test.cjs Tests grader behavior.
.github/workflows/shared/graders/README.md Updates implementation status.
Review details
  • Files reviewed: 3/3 changed files
  • Comments generated: 1
  • Review effort level: Balanced

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +62 to +66
const consumed = toolObservations.filter(
observation => Array.isArray(observation.consumedByActionIds) && observation.consumedByActionIds.length > 0
);
const unconsumedIds = toolObservations
.filter(observation => !Array.isArray(observation.consumedByActionIds) || observation.consumedByActionIds.length === 0)

@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.

This one branch is more general than the current data model seems to need; trimming the fallback scaffolding would make the grader easier to read and maintain. net: -12 lines possible.

Warning

Firewall blocked 1 domain

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

  • ab.chatgpt.com

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

network:
  allowed:
    - defaults
    - "ab.chatgpt.com"

See Network Configuration for more information.

Generated by ✂️ Ponytail Reviewer for #57252 · codex · mai10 · 4.85 AIC · ⌖ 0.499 AIC · ⊞ 13.5K
Comment /ponytail to run again

max: 1.0
script: |
const isRecord = value => value !== null && typeof value === "object" && !Array.isArray(value);
const candidates = [

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.

L17-38: yagni: multi-branch trace-shape fallback chain for trajectoryIR, trajectoryIr, ir, and agentOutput variants. Collapse to the canonical trajectoryIR shape plus one nested agentOutput fallback.

@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 /tdd — commenting on test-coverage and extraction robustness. Overall a solid, well-tested addition; requesting minor changes.

📋 Key Themes & Highlights

Issues Found

  • Missing passed on success path — The grader's success-path return omits passed; both null-path returns set it explicitly. If the framework relies on it, this is a silent correctness gap.
  • Hardcoded slice(6) for YAML indent extraction — Brittle against reformatting; should derive indent dynamically.
  • Misleading it.each row label — "no tool calls" row actually tests the unmatched-call path already covered by the next row; the test intent is unclear.

Positive Highlights

  • ✅ Comprehensive test suite covers normal scoring, malformed metadata, nested IR structures, and all not-applicable conditions
  • ✅ Clear null-handling contract: returns passed: null rather than fabricating a value when provenance is absent
  • ✅ Multi-key IR candidate lookup (trajectoryIR, trajectoryIr, ir, nested under agentOutput) is thorough and defensive
  • ✅ Inline HTML comment provides excellent context for future maintainers

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · copilot · sonnet46 · 41.4 AIC · ⌖ 15.3 AIC · ⊞ 7.6K
Comment /matt to run again


return {
value: helpers.ratio(consumed.length, toolObservations.length),
unit: "ratio",

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.

[/tdd] The success-path return omits passed — if the grader framework expects it (even as null), this could silently yield an "unevaluated" result while both null-path returns explicitly set passed: null.

💡 Suggestion

Add a test that asserts the value of result.passed on the success path to lock in the contract:

it("scores the fraction of matching tool observations that were consumed", () => {
  const result = runToolOutputConsumptionRate({ ... });
  expect(result.value).toBeCloseTo(0.5);
  expect(result.passed).toBeNull(); // or true/false depending on framework threshold rules
  ...
});

If the framework derives passed from a threshold, add an explicit comment inside the grader's return stating that omission is intentional.

@copilot please address this.

throw new Error("unable to extract tool-output-consumption-rate grader script");
}
const toolOutputConsumptionRateScript = toolOutputConsumptionRateScriptMatch[1]
.split("\n")

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.

[/tdd] The script extraction regex uses slice(6) to strip indentation from the YAML block — this is a hardcoded assumption about the YAML indentation level (6 spaces). If the file is reformatted or the indentation changes, the extracted script will be silently corrupted.

💡 Suggestion

Derive the indent length dynamically instead:

const lines = toolOutputConsumptionRateScriptMatch[1].split("\n");
const indent = lines[0].match(/^(\s*)/)[1].length;
const toolOutputConsumptionRateScript = lines.map(line => line.slice(indent)).join("\n");

This makes the extractor robust to reformatting.

@copilot please address this.

expect(result.value).toBe(1);
});

it.each([

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.

[/tdd] The it.each table test for "no tool calls" sends observations with a sourceToolCallId that points to an unknown call — it ends up testing "no matching tool call" rather than the stated case. A true "no tool calls" case would have no toolCalls array at all and observations whose sourceToolCallId is also absent.

💡 Clarification

Current "no tool calls" fixture:

{ trajectoryIR: { observations: [{ id: "obs-1", sourceToolCallId: "tc-1", consumedByActionIds: ["act-1"] }] } }

This observation does have a sourceToolCallId — it just can't be matched because toolCalls is missing. That exercises the "unmatched" branch, which is already covered by the "no matching tool call" row below it. Consider either renaming the row or using an observation with no sourceToolCallId to truly test the "no tool-originated observations" path from a missing-sourceToolCallId angle.

@copilot please address this.

@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 grader logic and test coverage are solid overall, but there is one correctness issue.

Blocking: candidates is missing trace as the first entry — every peer grader (skill-constraint-coverage, exploration-error, etc.) probes the root trace object first. Omitting it means a trace where observations / toolCalls live at the top level of the trace (not nested under trajectoryIR) will always return passed: null instead of a real score. See inline comment.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · copilot · sonnet46 · 48.2 AIC · ⌖ 14.7 AIC · ⊞ 6.2K

trace.trajectoryIr,
trace.ir,
isRecord(trace.agentOutput) ? trace.agentOutput.trajectoryIR : null,
isRecord(trace.agentOutput) ? trace.agentOutput.trajectoryIr : null,

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 candidates array omits trace itself as the first probe. Every other grader in this repo (e.g. skill-constraint-coverage) starts with trace before the nested-path candidates. If a caller stores observations/toolCalls directly on the root trace object, the grader will silently return passed: null ("no observations") instead of computing a score.

Suggest:

const candidates = [
  trace,          // ← add this first, matching skill-constraint-coverage pattern
  trace.trajectoryIR,
  trace.trajectoryIr,
  trace.ir,
  ...
].filter(isRecord);

A test covering observations at the top-level trace shape would confirm the fix.

@copilot please address this.

@github-actions

Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Summary

Test Quality Score: 90/100 (Excellent)

File: actions/setup/js/trace_graders.test.cjs
Tests Added: 7 test cases (including parametrized variants)
Implementation Ratio: 14.3% (threshold: ≤30% ✅)


Quality Metrics

Metric Result Status
Design Tests 6/7 (85.7%) ✅ Excellent
Edge Case Coverage 6/7 (85.7%) ✅ Strong
Test Inflation Ratio 0.96:1 ✅ Healthy
Violations None ✅ Clean

Analysis

Test Breakdown

1. "scores the fraction of matching tool observations that were consumed"

  • Type: Behavioral contract (core scoring logic)
  • Assertions: 3 (value precision, stats details, unconsumed list)
  • Coverage: Main path with mixed observation states
  • Quality: ✅ HIGH

2. "treats malformed consumption metadata as unconsumed"

  • Type: Error handling (defensive robustness)
  • Assertions: 2 (zero value, details state)
  • Coverage: Malformed data edge case
  • Quality: ✅ HIGH

3. "reads a complete IR nested in agentOutput"

  • Type: Behavioral contract (data structure variant)
  • Assertions: 1 (full consumption detection)
  • Coverage: Alternative input structure
  • Quality: ✅ MEDIUM

4-6. "normalizes %s as unavailable" (parametrized 3×)

  • Type: Error handling (table-driven)
  • Scenarios: no observations | no tool calls | no matching tool call
  • Assertions: 4 per scenario (value, passed, status, message)
  • Coverage: All unavailability paths
  • Quality: ✅ HIGH
Strengths
  • ✅ Comprehensive design contract verification (ratio scoring, unavailability semantics)
  • ✅ Robust edge-case coverage (malformed data, missing fields)
  • ✅ Parametrized testing idiom for multiple scenarios
  • ✅ Descriptive assertions (checks both output values and details messages)
  • ✅ Healthy test inflation (0.96 lines test per line production, well below 2:1)
  • ✅ Clean test organization and naming
Violations Check
  • ✅ No mock library usage (pure JavaScript, no gomock/testify/mock)
  • ✅ No build tag violations (N/A for JavaScript)
  • ✅ No happy-path-only pattern (includes edge cases and error scenarios)
  • ✅ No assertion duplication beyond natural parametrization

Recommendation

APPROVE — Test Quality Sentinel approval.

  • Implementation tests within threshold: 1/7 = 14.3% (threshold: 30%)
  • No coding violations or red flags
  • Strong behavioral contract and edge-case coverage

Warning

Firewall blocked 1 domain

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

  • github.com

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

network:
  allowed:
    - defaults
    - "github.com"

See Network Configuration for more information.

🧪 Test quality analysis by Test Quality Sentinel · copilot · haiku45 · 24.6 AIC · ⌖ 13.6 AIC · ⊞ 8.3K ·
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: 90/100. 14.3% implementation tests (threshold: 30%). Excellent test coverage with strong edge-case handling and no violations.

@github-actions

Copy link
Copy Markdown
Contributor

Comment Memory

reviewed_at: 2026-08-30T22:24:59.798+00:00
review_event: REQUEST_CHANGES
top_themes:
  - malformed consumedByActionIds values are still counted as consumed
files_reviewed:
  - .github/workflows/shared/graders/README.md
  - .github/workflows/shared/graders/tool-output-consumption-rate.md
  - actions/setup/js/trace_graders.test.cjs
comment_count: 0

Note

This comment is managed by comment memory.

It stores persistent context for this thread in the code block at the top of this comment.
Edit only the text inside the backtick fences; workflow metadata and the footer are regenerated automatically.

Learn more about comment memory

Warning

Firewall blocked 3 domains

The following domains were blocked by the firewall during workflow execution:

  • codeload.github.com
  • github.com
  • registry.npmjs.org

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

network:
  allowed:
    - defaults
    - "codeload.github.com"
    - "github.com"
    - "registry.npmjs.org"

See Network Configuration for more information.

🔎 Code quality review by PR Code Quality Reviewer · copilot · gpt54 · 43.6 AIC · ⌖ 7.32 AIC · ⊞ 21.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.

Blocking issue

The new grader still overstates consumption because malformed consumedByActionIds entries are treated as valid as long as the array is non-empty.

Why this blocks

The grader contract in this PR says malformed consumption metadata must count as unconsumed. Right now values like [null] or [42] increase the numerator, so broken trajectory IR can look healthier than it is. That turns the metric into a false-positive generator instead of a reliability signal. The tests only cover the non-array case, so this regression would ship unnoticed.

Warning

Firewall blocked 3 domains

The following domains were blocked by the firewall during workflow execution:

  • codeload.github.com
  • github.com
  • registry.npmjs.org

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

network:
  allowed:
    - defaults
    - "codeload.github.com"
    - "github.com"
    - "registry.npmjs.org"

See Network Configuration for more information.

🔎 Code quality review by PR Code Quality Reviewer · copilot · gpt54 · 43.6 AIC · ⌖ 7.32 AIC · ⊞ 21.8K
Comment /review to run again

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot quick triage for this PR:

  • There are still requested/changes-needed review signals on the current head commit from Matt Pocock Skills Reviewer and Impeccable Skills Reviewer.
  • The latest code-quality note also calls out malformed consumedByActionIds array entries being counted as consumed.
  • After addressing the review feedback, please refresh the branch and run the pr-finisher skill.

Key review checkpoints:

  • Ensure malformed consumedByActionIds entries do not count as consumed.
  • Verify the grader can score traces where observations/toolCalls live on the root trace object.
  • Confirm the success path returns the expected passed field.

PR: #57252
Run: https://github.com/github/gh-aw/actions/runs/33339773357

Warning

Firewall blocked 1 domain

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

  • github.com

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

network:
  allowed:
    - defaults
    - "github.com"

See Network Configuration for more information.

Generated by 👨‍🍳 PR Sous Chef · pi · gpt54 · 14.3 AIC · ⌖ 8.62 AIC · ⊞ 9.2K ·
Comment /souschef to run again

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

Copilot AI commented Aug 30, 2026

Copy link
Copy Markdown
Contributor Author

@copilot quick triage for this PR:

  • There are still requested/changes-needed review signals on the current head commit from Matt Pocock Skills Reviewer and Impeccable Skills Reviewer....

Fixed in 3f4b8b0 (see subsequent push): consumedByActionIds arrays with only malformed entries (e.g. [null], [42]) are now treated as unconsumed — the check requires at least one non-empty string action ID. Also added trace itself as a candidate so observations/toolCalls living directly on the root trace object are scored. Added regression tests for both cases; all 116 tests in trace_graders.test.cjs pass.

Copilot AI requested a review from gh-aw-bot August 30, 2026 22:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[trajectory-grader] Implement tool-output-consumption-rate

4 participants