Skip to content

Commit aff03b0

Browse files
fix: enforce trustworthy quality snapshots (#505)
## Summary Turn PET performance and coverage snapshots into trustworthy, enforceable quality gates instead of advisory comments. - compare against artifacts for the exact PR base commit - fail malformed/missing snapshots, inventory mismatches, and platform-budget regressions - evaluate P50, P95, time-to-first-environment, line coverage, and function coverage - centralize tested cross-platform comparison/report logic - preserve one buffered JSON-RPC stdout reader and continuously drain bounded stderr - document budgets, local validation, and the macOS tail-latency follow-up ## Validation - `python -B -m unittest discover -s scripts/tests -p 'test_*.py' -v` - parsed all changed workflows with existing PyYAML - validated all platform comparators against real baseline artifacts - `cargo test --all` - `./scripts/rust-precommit.ps1` Fixes #503 --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 13542c1 commit aff03b0

8 files changed

Lines changed: 911 additions & 552 deletions

File tree

‎.github/workflows/coverage-baseline.yml‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ on:
44
push:
55
branches:
66
- main
7+
- release*
8+
- release/*
9+
- release-*
10+
workflow_dispatch:
711

812
permissions:
913
contents: read
@@ -29,6 +33,10 @@ jobs:
2933
with:
3034
python-version: "3.12"
3135

36+
- name: Validate Snapshot Comparator
37+
run: python -m unittest discover -s scripts/tests -p 'test_*.py' -v
38+
shell: bash
39+
3240
- name: Add Conda to PATH (Windows)
3341
if: startsWith(matrix.os, 'windows')
3442
run: |
@@ -175,6 +183,16 @@ jobs:
175183
RUST_LOG: trace
176184
shell: bash
177185

186+
- name: Validate Coverage Baseline
187+
run: >-
188+
python scripts/quality_snapshot.py coverage
189+
--current lcov.info
190+
--baseline lcov.info
191+
--platform "${{ matrix.os }} baseline"
192+
--report coverage-baseline-report.md
193+
--summary "$GITHUB_STEP_SUMMARY"
194+
shell: bash
195+
178196
- name: Upload Coverage Artifact
179197
uses: actions/upload-artifact@v4
180198
with:

‎.github/workflows/coverage.yml‎

Lines changed: 35 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -23,41 +23,36 @@ jobs:
2323
include:
2424
- os: ubuntu-latest
2525
target: x86_64-unknown-linux-musl
26+
platform: Linux
27+
comment_header: coverage-linux
2628
- os: windows-latest
2729
target: x86_64-pc-windows-msvc
30+
platform: Windows
31+
comment_header: coverage-windows
2832
steps:
2933
- name: Checkout
3034
uses: actions/checkout@v4
3135

32-
- name: Post Coverage Started Comment (Linux)
33-
if: startsWith(matrix.os, 'ubuntu')
36+
- name: Post Coverage Started Comment
3437
uses: marocchino/sticky-pull-request-comment@v2
3538
with:
36-
header: coverage-linux
39+
header: ${{ matrix.comment_header }}
3740
message: |
38-
## Test Coverage Report (Linux)
41+
## Test Coverage Report (${{ matrix.platform }})
3942
4043
:hourglass_flowing_sand: **Coverage analysis in progress...**
4144
42-
This comment will be updated with results when the analysis completes.
43-
44-
- name: Post Coverage Started Comment (Windows)
45-
if: startsWith(matrix.os, 'windows')
46-
uses: marocchino/sticky-pull-request-comment@v2
47-
with:
48-
header: coverage-windows
49-
message: |
50-
## Test Coverage Report (Windows)
51-
52-
:hourglass_flowing_sand: **Coverage analysis in progress...**
53-
54-
This comment will be updated with results when the analysis completes.
45+
Comparing against exact base `${{ github.event.pull_request.base.sha }}`.
5546
5647
- name: Set Python to PATH
5748
uses: actions/setup-python@v5
5849
with:
5950
python-version: "3.12"
6051

52+
- name: Validate Snapshot Comparator
53+
run: python -m unittest discover -s scripts/tests -p 'test_*.py' -v
54+
shell: bash
55+
6156
- name: Add Conda to PATH (Windows)
6257
if: startsWith(matrix.os, 'windows')
6358
run: |
@@ -198,167 +193,47 @@ jobs:
198193
shell: bash
199194

200195
- name: Run Tests with Coverage
196+
id: coverage
201197
run: cargo llvm-cov --features ci --lcov --output-path lcov.info -- --nocapture --test-threads=1
202198
env:
203199
RUST_BACKTRACE: 1
204200
RUST_LOG: trace
205201
shell: bash
206202

207203
- name: Upload PR Coverage Artifact
204+
if: always()
208205
uses: actions/upload-artifact@v4
209206
with:
210207
name: coverage-pr-${{ matrix.os }}
211208
path: lcov.info
209+
if-no-files-found: ignore
212210

213-
- name: Download Baseline Coverage
211+
- name: Download Exact PR Base Coverage
212+
if: always()
214213
uses: dawidd6/action-download-artifact@v6
215-
id: download-baseline
216-
continue-on-error: true
217214
with:
218215
workflow: coverage-baseline.yml
219-
branch: main
216+
commit: ${{ github.event.pull_request.base.sha }}
217+
workflow_conclusion: success
220218
name: coverage-baseline-${{ matrix.os }}
221219
path: baseline-coverage
222-
223-
- name: Install lcov (Linux)
224-
if: startsWith(matrix.os, 'ubuntu')
225-
run: sudo apt-get update && sudo apt-get install -y lcov
226-
227-
- name: Install lcov (Windows)
228-
if: startsWith(matrix.os, 'windows')
229-
run: choco install lcov -y
220+
check_artifacts: true
221+
search_artifacts: true
222+
223+
- name: Compare Coverage Snapshot
224+
if: always()
225+
run: >-
226+
python scripts/quality_snapshot.py coverage
227+
--current lcov.info
228+
--baseline baseline-coverage/lcov.info
229+
--platform "${{ matrix.platform }}"
230+
--report coverage-report.md
231+
--summary "$GITHUB_STEP_SUMMARY"
230232
shell: bash
231233

232-
- name: Generate Coverage Report (Linux)
233-
if: startsWith(matrix.os, 'ubuntu')
234-
id: coverage-linux
235-
run: |
236-
# Extract PR coverage
237-
PR_LINES=$(lcov --summary lcov.info 2>&1 | grep "lines" | sed 's/.*: //' | sed 's/%.*//' | tr -d ' ')
238-
PR_FUNCTIONS=$(lcov --summary lcov.info 2>&1 | grep "functions" | sed 's/.*: //' | sed 's/%.*//' | tr -d ' ')
239-
240-
# Extract baseline coverage (default to 0 if not available)
241-
if [ -f baseline-coverage/lcov.info ]; then
242-
BASELINE_LINES=$(lcov --summary baseline-coverage/lcov.info 2>&1 | grep "lines" | sed 's/.*: //' | sed 's/%.*//' | tr -d ' ')
243-
BASELINE_FUNCTIONS=$(lcov --summary baseline-coverage/lcov.info 2>&1 | grep "functions" | sed 's/.*: //' | sed 's/%.*//' | tr -d ' ')
244-
else
245-
BASELINE_LINES="0"
246-
BASELINE_FUNCTIONS="0"
247-
fi
248-
249-
# Calculate diff
250-
LINE_DIFF=$(echo "$PR_LINES - $BASELINE_LINES" | bc)
251-
FUNC_DIFF=$(echo "$PR_FUNCTIONS - $BASELINE_FUNCTIONS" | bc)
252-
253-
# Determine delta indicator
254-
if (( $(echo "$LINE_DIFF > 0" | bc -l) )); then
255-
DELTA_INDICATOR=":white_check_mark:"
256-
elif (( $(echo "$LINE_DIFF < 0" | bc -l) )); then
257-
DELTA_INDICATOR=":x:"
258-
else
259-
DELTA_INDICATOR=":heavy_minus_sign:"
260-
fi
261-
262-
# Set outputs
263-
echo "pr_lines=$PR_LINES" >> $GITHUB_OUTPUT
264-
echo "baseline_lines=$BASELINE_LINES" >> $GITHUB_OUTPUT
265-
echo "line_diff=$LINE_DIFF" >> $GITHUB_OUTPUT
266-
echo "delta_indicator=$DELTA_INDICATOR" >> $GITHUB_OUTPUT
267-
268-
# Write step summary
269-
echo "## Test Coverage Report (${{ matrix.os }})" >> $GITHUB_STEP_SUMMARY
270-
echo "" >> $GITHUB_STEP_SUMMARY
271-
echo "| Metric | Value |" >> $GITHUB_STEP_SUMMARY
272-
echo "|--------|-------|" >> $GITHUB_STEP_SUMMARY
273-
echo "| Current Coverage | ${PR_LINES}% |" >> $GITHUB_STEP_SUMMARY
274-
echo "| Base Branch Coverage | ${BASELINE_LINES}% |" >> $GITHUB_STEP_SUMMARY
275-
echo "| Delta | ${LINE_DIFF}% ${DELTA_INDICATOR} |" >> $GITHUB_STEP_SUMMARY
276-
shell: bash
277-
278-
- name: Generate Coverage Report (Windows)
279-
if: startsWith(matrix.os, 'windows')
280-
id: coverage-windows
281-
run: |
282-
# Extract PR coverage
283-
$prContent = Get-Content -Path "lcov.info" -Raw
284-
$prLinesFound = ($prContent | Select-String -Pattern "LF:(\d+)" -AllMatches).Matches | ForEach-Object { [int]$_.Groups[1].Value } | Measure-Object -Sum | Select-Object -ExpandProperty Sum
285-
$prLinesHit = ($prContent | Select-String -Pattern "LH:(\d+)" -AllMatches).Matches | ForEach-Object { [int]$_.Groups[1].Value } | Measure-Object -Sum | Select-Object -ExpandProperty Sum
286-
if ($prLinesFound -gt 0) {
287-
$prPct = [math]::Round(($prLinesHit / $prLinesFound) * 100, 2)
288-
} else {
289-
$prPct = 0
290-
}
291-
292-
# Extract baseline coverage (default to 0 if not available)
293-
if (Test-Path "baseline-coverage/lcov.info") {
294-
$baselineContent = Get-Content -Path "baseline-coverage/lcov.info" -Raw
295-
$baselineLinesFound = ($baselineContent | Select-String -Pattern "LF:(\d+)" -AllMatches).Matches | ForEach-Object { [int]$_.Groups[1].Value } | Measure-Object -Sum | Select-Object -ExpandProperty Sum
296-
$baselineLinesHit = ($baselineContent | Select-String -Pattern "LH:(\d+)" -AllMatches).Matches | ForEach-Object { [int]$_.Groups[1].Value } | Measure-Object -Sum | Select-Object -ExpandProperty Sum
297-
if ($baselineLinesFound -gt 0) {
298-
$baselinePct = [math]::Round(($baselineLinesHit / $baselineLinesFound) * 100, 2)
299-
} else {
300-
$baselinePct = 0
301-
}
302-
} else {
303-
$baselinePct = 0
304-
}
305-
306-
$diff = [math]::Round($prPct - $baselinePct, 2)
307-
308-
if ($diff -gt 0) {
309-
$deltaIndicator = ":white_check_mark:"
310-
} elseif ($diff -lt 0) {
311-
$deltaIndicator = ":x:"
312-
} else {
313-
$deltaIndicator = ":heavy_minus_sign:"
314-
}
315-
316-
# Set outputs
317-
echo "pr_lines=$prPct" >> $env:GITHUB_OUTPUT
318-
echo "baseline_lines=$baselinePct" >> $env:GITHUB_OUTPUT
319-
echo "line_diff=$diff" >> $env:GITHUB_OUTPUT
320-
echo "delta_indicator=$deltaIndicator" >> $env:GITHUB_OUTPUT
321-
322-
# Write step summary
323-
echo "## Test Coverage Report (${{ matrix.os }})" >> $env:GITHUB_STEP_SUMMARY
324-
echo "" >> $env:GITHUB_STEP_SUMMARY
325-
echo "| Metric | Value |" >> $env:GITHUB_STEP_SUMMARY
326-
echo "|--------|-------|" >> $env:GITHUB_STEP_SUMMARY
327-
echo "| Current Coverage | ${prPct}% |" >> $env:GITHUB_STEP_SUMMARY
328-
echo "| Base Branch Coverage | ${baselinePct}% |" >> $env:GITHUB_STEP_SUMMARY
329-
echo "| Delta | ${diff}% ${deltaIndicator} |" >> $env:GITHUB_STEP_SUMMARY
330-
shell: pwsh
331-
332-
- name: Post Coverage Comment (Linux)
333-
if: startsWith(matrix.os, 'ubuntu')
234+
- name: Post Coverage Comment
235+
if: always()
334236
uses: marocchino/sticky-pull-request-comment@v2
335237
with:
336-
header: coverage-linux
337-
message: |
338-
## Test Coverage Report (Linux)
339-
340-
| Metric | Value |
341-
|--------|-------|
342-
| Current Coverage | ${{ steps.coverage-linux.outputs.pr_lines }}% |
343-
| Base Branch Coverage | ${{ steps.coverage-linux.outputs.baseline_lines }}% |
344-
| Delta | ${{ steps.coverage-linux.outputs.line_diff }}% ${{ steps.coverage-linux.outputs.delta_indicator }} |
345-
346-
---
347-
${{ steps.coverage-linux.outputs.line_diff > 0 && 'Coverage increased! Great work!' || (steps.coverage-linux.outputs.line_diff < 0 && 'Coverage decreased. Please add tests for new code.' || 'Coverage unchanged.') }}
348-
349-
- name: Post Coverage Comment (Windows)
350-
if: startsWith(matrix.os, 'windows')
351-
uses: marocchino/sticky-pull-request-comment@v2
352-
with:
353-
header: coverage-windows
354-
message: |
355-
## Test Coverage Report (Windows)
356-
357-
| Metric | Value |
358-
|--------|-------|
359-
| Current Coverage | ${{ steps.coverage-windows.outputs.pr_lines }}% |
360-
| Base Branch Coverage | ${{ steps.coverage-windows.outputs.baseline_lines }}% |
361-
| Delta | ${{ steps.coverage-windows.outputs.line_diff }}% ${{ steps.coverage-windows.outputs.delta_indicator }} |
362-
363-
---
364-
${{ steps.coverage-windows.outputs.line_diff > 0 && 'Coverage increased! Great work!' || (steps.coverage-windows.outputs.line_diff < 0 && 'Coverage decreased. Please add tests for new code.' || 'Coverage unchanged.') }}
238+
header: ${{ matrix.comment_header }}
239+
path: coverage-report.md

‎.github/workflows/perf-baseline.yml‎

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ on:
44
push:
55
branches:
66
- main
7+
- release*
8+
- release/*
9+
- release-*
10+
workflow_dispatch:
711

812
permissions:
913
contents: read
@@ -31,6 +35,10 @@ jobs:
3135
with:
3236
python-version: "3.12"
3337

38+
- name: Validate Snapshot Comparator
39+
run: python -m unittest discover -s scripts/tests -p 'test_*.py' -v
40+
shell: bash
41+
3442
- name: Add Conda to PATH (Windows)
3543
if: startsWith(matrix.os, 'windows')
3644
run: |
@@ -73,26 +81,33 @@ jobs:
7381
shell: bash
7482

7583
- name: Run Performance Tests
76-
continue-on-error: true
77-
run: cargo test --release --features ci-perf --target ${{ matrix.target }} --test e2e_performance test_performance_summary -- --nocapture 2>&1 | tee perf-output.txt
84+
run: |
85+
set -o pipefail
86+
cargo test --release --features ci-perf --target ${{ matrix.target }} --test e2e_performance test_performance_summary -- --nocapture 2>&1 | tee perf-output.txt
7887
env:
7988
RUST_BACKTRACE: 1
8089
RUST_LOG: warn
8190
shell: bash
8291

8392
- name: Extract Performance Metrics
84-
id: metrics
8593
run: |
86-
# Extract JSON metrics from test output
87-
if grep -q "JSON metrics:" perf-output.txt; then
88-
# Extract lines after "JSON metrics:" until the closing brace
89-
sed -n '/JSON metrics:/,/^}/p' perf-output.txt | tail -n +2 > metrics.json
90-
echo "Metrics extracted:"
91-
cat metrics.json
92-
else
93-
echo '{"server_startup_ms": 0, "full_refresh_ms": 0, "environments_count": 0}' > metrics.json
94-
echo "No metrics found, created empty metrics"
94+
if ! grep -q "JSON metrics:" perf-output.txt; then
95+
echo "Performance baseline produced no JSON metrics" >&2
96+
exit 1
9597
fi
98+
sed -n '/JSON metrics:/,/^}/p' perf-output.txt | tail -n +2 > metrics.json
99+
python -m json.tool metrics.json > /dev/null
100+
cat metrics.json
101+
shell: bash
102+
103+
- name: Validate Performance Baseline
104+
run: >-
105+
python scripts/quality_snapshot.py performance
106+
--current metrics.json
107+
--baseline metrics.json
108+
--platform "${{ matrix.os }} baseline"
109+
--report performance-baseline-report.md
110+
--summary "$GITHUB_STEP_SUMMARY"
96111
shell: bash
97112

98113
- name: Upload Performance Baseline Artifact

0 commit comments

Comments
 (0)