Skip to content

fix(ci): fix codecov PR coverage disparity with symmetric upload flags#626

Open
akunft wants to merge 2 commits intomainfrom
fix/codecov-carryforward-flags
Open

fix(ci): fix codecov PR coverage disparity with symmetric upload flags#626
akunft wants to merge 2 commits intomainfrom
fix/codecov-carryforward-flags

Conversation

@akunft
Copy link
Copy Markdown
Collaborator

@akunft akunft commented May 5, 2026

Summary

Fixes PRs falsely failing the `codecov/project` check (~65% vs ~76% on main).

Root Cause

Daily scheduled tests (staging + production) upload extra coverage for main's SHA, giving main 3 merged uploads → ~76%. PRs get 1 upload → ~65%, failing the 70% absolute target.

Correct Fix: Symmetric Uploads via Flags

Codecov's `default` project check only counts unflagged uploads when flags are present. Fix:

  • PR CI uploads stay unflagged → feed only the `default` check
  • Scheduled test uploads tagged `staging`/`production` → informational only, excluded from `default`

Both PR and main now have 1 unflagged upload each (~65%), making comparison symmetric.

Coverage Enforcement Unchanged

Enforcement is not relaxed — it is equally strict or stricter:

Check Before After
Project hard 70% floor `target: auto` — PR must not drop >2% below main's actual CI-only coverage
Patch 75% hard target 75% hard target (unchanged)
Scheduled env uploads polluted default check informational only, never block PRs

`target: auto` is stricter than a fixed floor: if main's CI-only coverage is 67%, a PR cannot drop below 65% — whereas the old 70% floor would have rejected the PR entirely for something main already accepts.

Why Not Carryforward

Carryforward is for monorepos that intentionally run a subset of tests per commit. It introduces stale data risk: if a PR touches code that scheduled tests cover, carried-forward data no longer reflects the PR's actual changes. The asymmetric upload count is the root cause Codecov's own docs identify for this failure mode.

Changes

File Change
`codecov.yml` `target: auto + threshold: 2%`, add `scheduled_environments` informational check, define `staging`/`production` flags (no carryforward)
`_test.yml` Remove `flags: ci` from CI upload (leave unflagged)
`_scheduled-test-daily.yml` Upload with `flags: staging` or `flags: production`

Test plan

  • After merging: next PR shows `target: auto` comparison ~65% vs ~65% → passes
  • Daily scheduled test shows coverage tagged `staging`/`production` in Codecov UI
  • PRs that genuinely drop coverage >2% still fail

Daily scheduled tests (staging + production) upload additional coverage
to codecov for main's SHA, but PR commits never receive these uploads.
This causes PRs to show ~65% coverage vs main's ~76%, failing the 70%
project target despite having equivalent code quality.

Fix: tag each upload type with a flag and use carryforward=true for
scheduled flags so that PR commits inherit the BASE commit's scheduled
test coverage when they don't have their own.

- ci flag: PR/push CI uploads (carryforward=false, fresh each run)
- scheduled_staging: daily staging uploads (carryforward=true)
- scheduled_production: daily production uploads (carryforward=true)

When a PR CI runs, codecov carries forward scheduled_* from BASE,
giving HEAD = ci(PR) ∪ scheduled_*(BASE) ≈ 76% → passes 70% target.
Copilot AI review requested due to automatic review settings May 5, 2026 20:40
@akunft akunft added the skip:test:long_running Skip long-running tests (≥5min) label May 5, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adjusts Codecov configuration and GitHub Actions uploads to use Codecov “flags” with carryforward enabled for scheduled daily coverage uploads, so PRs can inherit the scheduled coverage from the base commit and avoid an artificial PR-vs-main coverage disparity.

Changes:

  • Define Codecov flags for ci, scheduled_staging, and scheduled_production, enabling carryforward for scheduled flags.
  • Tag the standard CI Codecov upload with the ci flag.
  • Tag the daily scheduled workflow Codecov upload with scheduled_staging / scheduled_production based on the environment input.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
codecov.yml Adds flag definitions and enables carryforward for scheduled coverage flags.
.github/workflows/_test.yml Adds flags: ci to the Codecov upload step for regular CI runs.
.github/workflows/_scheduled-test-daily.yml Adds environment-derived scheduled_* flags to Codecov uploads for daily scheduled runs.

Root cause: daily scheduled tests (staging + production) upload additional
coverage to codecov for main's SHA, giving main 3 merged uploads (~76%)
while PRs only receive 1 upload (~65%), failing the 70% project target.

Carryforward would be wrong here — it propagates stale data into PRs and
is designed for monorepos with intentionally partial test runs, not for
the asymmetric-upload problem described in Codecov's own docs.

Correct fix: make PR vs main comparison symmetric by separating upload
types at the flag level.

- PR CI uploads with NO flag → feeds the "default" project check
- Scheduled daily tests upload with flags (staging/production) → informational
- Codecov's "default" check sees ONLY unflagged uploads on both sides:
  ~65% (PR CI) vs ~65% (main's CI upload) → symmetric → target: auto passes

target changed from absolute 70% to auto+threshold:2% because:
- The 70% was calibrated against 3-upload accumulated coverage, not 1-upload
- auto prevents coverage regression between commits
- threshold:2% allows small variance without blocking PRs
@akunft akunft changed the title fix(ci): use codecov carryforward flags to fix PR coverage disparity fix(ci): fix codecov PR coverage disparity with symmetric upload flags May 5, 2026
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented May 5, 2026

@codecov
Copy link
Copy Markdown

codecov Bot commented May 5, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ All tests successful. No failed tests found.

❗ There is a different number of reports uploaded between BASE (ef28b07) and HEAD (cc9847b). Click for more details.

HEAD has 2 uploads less than BASE
Flag BASE (ef28b07) HEAD (cc9847b)
3 1

see 22 files with indirect coverage changes

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

Labels

skip:test:long_running Skip long-running tests (≥5min)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants