Fix audit comparison turns delta for cached summaries#43501
Conversation
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Fixes an audit comparison bug where cached-summary rendering could incorrectly treat Run.Turns as 0 (stale) even when the cached Metrics.Turns was non-zero, leading to incorrect turns_decrease classifications.
Changes:
- Backfill
ProcessedRun.Run.TurnsfromRunSummary.Metrics.TurnswhenRun.Turnsis0and metrics turns are available. - Add regression tests covering both the backfill behavior and the “do not overwrite non-zero turns” behavior.
Show a summary per file
| File | Description |
|---|---|
| pkg/cli/audit.go | Backfills processedRun.Run.Turns from cached summary metrics when the cached run metadata is missing turns. |
| pkg/cli/audit_test.go | Adds unit tests to prevent regressions in cached-summary turns handling. |
Review details
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Files reviewed: 2/2 changed files
- Comments generated: 0
- Review effort level: Low
|
🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅ |
|
✅ PR Code Quality Reviewer completed the code quality review. |
|
✅ Test Quality Sentinel completed test quality analysis. |
|
✅ Design Decision Gate 🏗️ completed the design decision gate check. No ADR enforcement needed: PR #43501 does not have the 'implementation' label and has only 26 new lines of code in business logic directories (threshold: >100). |
There was a problem hiding this comment.
Review: Fix audit comparison turns delta for cached summaries
The fix is correct, well-scoped, and well-tested.
Root cause: processedRunFromSummary copies summary.Run into processedRun.Run, but Run.Turns can be zero when the summary was cached before that field was populated — while summary.Metrics.Turns is always authoritative (computed from logs). The backfill guard (Run.Turns == 0 && Metrics.Turns > 0) is the right condition and correctly preserves any pre-existing non-zero value.
What was reviewed:
processedRunFromSummaryfix inpkg/cli/audit.go— minimal, correct, placed before theLogsPathassignment- Two regression tests in
pkg/cli/audit_test.go— cover the backfill path and preserve-existing-turns path with clear assertions - Downstream in
audit_comparison.go—delta.Turns.Afternow gets the correct non-zero value, fixing the falseturns_decreaseclassification
No issues found. LGTM.
Warning
Firewall blocked 1 domain
The following domain was blocked by the firewall during workflow execution:
proxy.golang.org
To allow these domains, add them to the
network.allowedlist in your workflow frontmatter:
network:
allowed:
- defaults
- "proxy.golang.org"See Network Configuration for more information.
🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · 31.1 AIC · ⌖ 4.99 AIC · ⊞ 4.8K
🧪 Test Quality Sentinel Report✅ Test Quality Score: 90/100 — Excellent
📊 Metrics (2 tests)
Verdict
Warning Firewall blocked 1 domainThe following domain was blocked by the firewall during workflow execution:
network:
allowed:
- defaults
- "awmgmcpg"See Network Configuration for more information.
|
Skills-Based Review 🧠Applied 📋 Key Themes & HighlightsSuggestions
Positive Highlights
@copilot please address the review comments above.
|
There was a problem hiding this comment.
🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · 45.6 AIC · ⌖ 5.51 AIC · ⊞ 6.6K
Comment /matt to run again
| GitHubRateLimitUsage: summary.GitHubRateLimitUsage, | ||
| JobDetails: summary.JobDetails, | ||
| } | ||
| if processedRun.Run.Turns == 0 && summary.Metrics.Turns > 0 { |
There was a problem hiding this comment.
[/diagnosing-bugs] The fix is correct, but the why is missing — future readers will not know that Run.Turns can be stale/zero specifically in the cached-summary rendering path.
💡 Suggested comment
// Run.Turns may be zero on cached-summary paths where the RunSummary was
// serialised before the run completed. Metrics.Turns is populated from log
// parsing and is authoritative; backfill here so that audit comparison deltas
// are computed from an accurate value.
if processedRun.Run.Turns == 0 && summary.Metrics.Turns > 0 {
processedRun.Run.Turns = summary.Metrics.Turns
}Without this context, the next developer may remove it as apparently defensive dead code.
@copilot please address this.
There was a problem hiding this comment.
Added the explanatory comment in 3d0db57.
| } | ||
| } | ||
|
|
||
| func TestProcessedRunFromSummaryBackfillsTurnsFromMetrics(t *testing.T) { |
There was a problem hiding this comment.
[/tdd] Consider also testing the edge case where both Run.Turns and Metrics.Turns are zero — the current fix silently leaves turns as 0 in that scenario, which would still produce a false turns_decrease in comparison. A dedicated test makes the invariant explicit.
💡 Suggested test
func TestProcessedRunFromSummaryBothTurnsZero(t *testing.T) {
summary := &RunSummary{
Run: WorkflowRun{DatabaseID: 789, Turns: 0},
Metrics: LogMetrics{Turns: 0},
}
processed := processedRunFromSummary(summary, "/tmp/run-output")
// Both are zero — no backfill occurs, and turns should remain 0.
assert.Equal(t, 0, processed.Run.Turns, "turns should remain zero when neither Run.Turns nor Metrics.Turns is available")
}Documents the known limitation: if a run genuinely has zero turns and Metrics.Turns is also zero, the delta will still reflect 0.
@copilot please address this.
There was a problem hiding this comment.
Added TestProcessedRunFromSummaryBothTurnsZero in 3d0db57.
There was a problem hiding this comment.
REQUEST_CHANGES — incomplete fix scope
The processedRunFromSummary backfill is correct, but the same staleness bug exists in computeRunMetricsDiff (audit_diff.go) which reads summary.Run.Turns directly and is not patched by this PR. Old cached summaries will still produce zero turns in audit diff output. See inline comments for details and suggested fixes.
Review summary
High: computeRunMetricsDiff reads summary{1,2}.Run.Turns directly without the backfill — audit diff remains broken for old cached summaries.
Medium: Test suite is missing the edge case where both Run.Turns == 0 and Metrics.Turns == 0, leaving the Metrics.Turns > 0 guard untested.
🔎 Code quality review by PR Code Quality Reviewer · 112.3 AIC · ⌖ 6.55 AIC · ⊞ 5.4K
Comment /review to run again
| Metrics: LogMetrics{Turns: 34}, | ||
| } | ||
|
|
||
| processed := processedRunFromSummary(summary, "/tmp/run-output") |
There was a problem hiding this comment.
Missing test for the both-zeros edge case (Run.Turns == 0, Metrics.Turns == 0). The two new tests cover backfill (zero→non-zero) and preservation (non-zero→non-zero). Neither exercises the path where Metrics.Turns == 0 too — meaning the guard summary.Metrics.Turns > 0 is never exercised as false. A future regression that drops the > 0 check and unconditionally writes summary.Metrics.Turns back to processedRun.Run.Turns would not be caught by the current suite.
💡 Suggested test
func TestProcessedRunFromSummaryBothTurnsZero(t *testing.T) {
summary := &RunSummary{
Run: WorkflowRun{DatabaseID: 789, Turns: 0},
Metrics: LogMetrics{Turns: 0},
}
processed := processedRunFromSummary(summary, "/tmp/run-output")
// Neither field has data; turns should remain 0, not be set to Metrics.Turns.
assert.Equal(t, 0, processed.Run.Turns, "run turns should remain 0 when both Run.Turns and Metrics.Turns are 0")
}There was a problem hiding this comment.
Added TestProcessedRunFromSummaryBothTurnsZero and also applied the same Run.Turns backfill from Metrics.Turns inside computeRunMetricsDiff (audit_diff.go) so audit diff is fixed for old cached summaries too — see 3d0db57.
|
@copilot please run the
|
…backfill, add both-zeros test Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
auditcomparison could reportcomparison.delta.turns.after = 0even when the run had non-zero turns, causing falseturns_decreaseclassifications. The bug occurred on cached-summary rendering paths whereRun.Turnscould be stale/zero whileMetrics.Turnswas correct.Current-run snapshot backfill in cached path
processedRunFromSummaryto backfillprocessedRun.Run.Turnsfromsummary.Metrics.Turnsonly whenRun.Turnsis zero.Run.Turnsvalues.Regression coverage