Skip to content

refactor(capabilities): readiness_command_recommendation takes a stru… #1762

refactor(capabilities): readiness_command_recommendation takes a stru…

refactor(capabilities): readiness_command_recommendation takes a stru… #1762

Workflow file for this run

# Coverage Policy: See docs/COVERAGE_POLICY.md for full details
#
# Phased Threshold Schedule (br-2r76):
# Phase 1 (Current): 60% - Foundation
# Phase 2 (Q2 2026): 70% - Stability
# Phase 3 (Q3 2026): 80% - Confidence
# Phase 4 (Q4 2026): 90% - Excellence
#
# Update COVERAGE_THRESHOLD when advancing phases.
name: Coverage
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
env:
CARGO_TERM_COLOR: always
# NOTE: `-D warnings` intentionally NOT set here. The coverage job compiles
# sibling path-dep crates via `[patch]` in Cargo.toml, which makes them
# behave like workspace members and bypass cargo's default `--cap-lints
# allow` for dependencies. Upstream warnings (e.g. fsqlite-pager
# dead_code) must not fail the coverage run — lint enforcement lives in
# the Lint job (ci.yml).
# Phased coverage threshold - update per docs/COVERAGE_POLICY.md schedule
COVERAGE_THRESHOLD: 60
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
coverage:
name: Test Coverage
runs-on: ubuntu-latest
# llvm-cov instrumented tests take noticeably longer than plain `cargo
# test` (2-3x). Previously the job short-circuited at the compile step
# so 30 min sufficed; now it gets through compile + ~3500 tests, which
# can push past 30 min on a cold cache. Match CI's `test-rust` matrix
# timeout (45 min) for safety.
timeout-minutes: 45
steps:
- name: Checkout repository
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
- name: Clone sibling dependencies
shell: bash
run: |
git clone --depth 1 https://github.com/Dicklesworthstone/asupersync.git ../asupersync
git clone --depth 1 https://github.com/Dicklesworthstone/frankensqlite.git ../frankensqlite
git clone --depth 1 https://github.com/Dicklesworthstone/franken_agent_detection.git ../franken_agent_detection
git clone --depth 1 https://github.com/Dicklesworthstone/frankensearch.git ../frankensearch
- name: Install Rust nightly
uses: dtolnay/rust-toolchain@881ba7bf39a41cda34ac9e123fb41b44ed08232f # nightly
with:
components: llvm-tools-preview
- name: Install cargo-llvm-cov
uses: taiki-e/install-action@8db66d64862314dae6eb34821203eb85fcbc5055 # cargo-llvm-cov
- name: Cache cargo registry
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-coverage-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-coverage-
${{ runner.os }}-cargo-
- name: Generate coverage report
env:
# Deterministic test execution
RUST_TEST_THREADS: 1
PROPTEST_CASES: 32 # Fixed seed count for property tests
# llvm-cov instrumentation balloons stack frames enough to overflow
# the default 2 MiB thread stack inside clap derive parsers
# (pages_cli_flag_tests). Bump to 16 MiB to match what cargo test
# uses natively for deeply nested generated code.
RUST_MIN_STACK: "16777216"
run: |
# Run with deterministic options and skip known flaky tests
cargo llvm-cov --workspace --lib -j 1 \
--ignore-filename-regex "(tests/|benches/)" \
--codecov \
--output-path codecov.json \
-- --skip install_sh --skip install_ps1
- name: Upload to Codecov
uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4
with:
files: codecov.json
fail_ci_if_error: false
verbose: true
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
- name: Generate coverage summary (JSON)
run: |
# Generate JSON coverage report (reuses instrumented data from previous step)
cargo llvm-cov report \
--ignore-filename-regex "(tests/|benches/)" \
--json \
--output-path coverage.json
# Extract coverage percentage
COVERAGE=$(jq -r '.data[0].totals.lines.percent // 0' coverage.json)
echo "## Test Coverage: ${COVERAGE}%" >> $GITHUB_STEP_SUMMARY
# Phased threshold indicators (see docs/COVERAGE_POLICY.md)
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Phase Progress" >> $GITHUB_STEP_SUMMARY
if (( $(echo "$COVERAGE >= 90" | bc -l) )); then
echo ":trophy: **Phase 4 Complete** - Excellence (90%+)" >> $GITHUB_STEP_SUMMARY
elif (( $(echo "$COVERAGE >= 80" | bc -l) )); then
echo ":star: **Phase 3 Complete** - Confidence (80%+)" >> $GITHUB_STEP_SUMMARY
elif (( $(echo "$COVERAGE >= 70" | bc -l) )); then
echo ":white_check_mark: **Phase 2 Complete** - Stability (70%+)" >> $GITHUB_STEP_SUMMARY
elif (( $(echo "$COVERAGE >= 60" | bc -l) )); then
echo ":heavy_check_mark: **Phase 1 Complete** - Foundation (60%+)" >> $GITHUB_STEP_SUMMARY
else
echo ":x: **Below Phase 1** - Needs improvement (<60%)" >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
echo "_See [Coverage Policy](../docs/COVERAGE_POLICY.md) for targets_" >> $GITHUB_STEP_SUMMARY
- name: Generate gap report
run: |
COVERAGE_THRESHOLD=${{ env.COVERAGE_THRESHOLD }} \
./scripts/generate-gap-report.sh coverage.json gap-report.md
# Add top uncovered modules to job summary
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Top Coverage Gaps" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# Extract top 5 uncovered modules
jq -r '.data[0].files[] |
select(.filename | contains("/src/")) |
select(.summary.lines.count > 100) |
{
filename: (.filename | split("/src/") | last | "src/" + .),
uncovered: (.summary.lines.count - .summary.lines.covered),
percent: (if .summary.lines.count > 0 then (.summary.lines.covered * 100 / .summary.lines.count | floor) else 0 end)
} |
select(.uncovered > 200) |
"| \(.percent)% | \(.uncovered) | `\(.filename)` |"' coverage.json | \
sort -t'|' -k3 -nr | head -5 | {
echo "| Coverage | Uncovered Lines | Module |"
echo "|----------|-----------------|--------|"
cat
} >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "_See gap-report.md artifact for full analysis_" >> $GITHUB_STEP_SUMMARY
- name: Check coverage threshold
if: github.event_name == 'pull_request'
run: |
COVERAGE=$(jq -r '.data[0].totals.lines.percent // 0' coverage.json)
# Use environment variable for phased threshold (see docs/COVERAGE_POLICY.md)
THRESHOLD=${{ env.COVERAGE_THRESHOLD }}
echo "Coverage: ${COVERAGE}%"
echo "Threshold: ${THRESHOLD}% (Phase 1 - Foundation)"
echo "Policy: See docs/COVERAGE_POLICY.md for phased targets"
if (( $(echo "$COVERAGE < $THRESHOLD" | bc -l) )); then
echo "::error::Coverage ${COVERAGE}% is below ${THRESHOLD}% threshold"
echo "::error::Add tests for new code or see docs/COVERAGE_POLICY.md for exclusion process"
exit 1
fi
- name: Upload coverage artifacts
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: coverage-report
path: |
codecov.json
coverage.json
gap-report.md
retention-days: 14