Codecov Integration Plan

Status: Done

Confirmed live at https://app.codecov.io/github/grove/pg-trickle (March 2026).

The CODECOV_TOKEN secret has been added to the GitHub repository. The coverage workflow (coverage.yml) already collects lcov.info via cargo-llvm-cov and uploads it to Codecov. This plan captures scope decisions, configuration, and known limitations for the project record.


What Codecov covers in this project

This is a pgrx extension. Coverage instrumentation runs against the Rust test binary (cargo test --lib), not against the .so loaded by the PostgreSQL server process. This shapes what Codecov can and cannot measure.

Covered (meaningful signal)

Module Why it’s well-covered
src/dvm/parser.rs 910+ pure-Rust unit tests, no pgrx boundary
src/dvm/operators/ Exhaustive operator unit tests
src/dvm/diff.rs Delta SQL generation, fully unit-tested
src/dag.rs Graph logic, property tests
src/hash.rs Deterministic hashing, unit-tested
src/error.rs Enum variants, trivially covered
src/refresh.rs (pure logic only) classify_relkind, strip_view_definition_suffix

Not covered (structural limitation, not a gap)

Module Why it can’t be covered
src/api.rs #[pg_extern] functions — execute inside postgres process
src/cdc.rs Trigger-based CDC — runs as a PostgreSQL trigger callback
src/wal_decoder.rs WAL polling — runs inside postgres backend
src/scheduler.rs Background worker — separate postgres process
src/hooks.rs DDL event trigger planner hook
src/shmem.rs Shared memory init — postgres startup only

These modules are covered by the E2E test suite (384 tests in Docker) but that coverage is not instrumentable without a full PostgreSQL coverage build.


Codecov configuration (codecov.yml)

Placed at the repository root. Key decisions:

  1. Never fail the build on overall project coverage — the uninstrumentable pgrx modules structurally suppress the percentage below any reasonable gate.
  2. Enforce coverage on patch (PR diffs) for src/dvm/ — this is the pure-Rust differential engine where quality matters most and coverage is meaningful.
  3. Ignore uninstrumentable modules from all reporting to avoid noise.
# codecov.yml
coverage:
  status:
    project:
      default:
        informational: true        # never fail CI on overall %
    patch:
      dvm-engine:
        target: 70%
        paths:
          - "src/dvm/**"
          - "src/dag.rs"
          - "src/hash.rs"

ignore:
  - "src/api.rs"
  - "src/cdc.rs"
  - "src/wal_decoder.rs"
  - "src/scheduler.rs"
  - "src/hooks.rs"
  - "src/shmem.rs"
  - "src/bin/**"
  - "tests/**"
  - "benches/**"

Workflow (coverage.yml)

Current state

The workflow already: - Installs cargo-llvm-cov via taiki-e/install-action - Builds libpg_stub.so for LD_PRELOAD (provides NULL stubs for PG symbols) - Runs cargo llvm-cov --lib --features pg18 to produce lcov.info - Uploads to Codecov via codecov/codecov-action@v5 - Uploads lcov.info as a workflow artifact

Token placement

The CODECOV_TOKEN must be in with:, not env:, for codecov-action@v5:

- name: Upload coverage to Codecov
  uses: codecov/codecov-action@v5
  with:
    token: ${{ secrets.CODECOV_TOKEN }}
    files: coverage/lcov.info
    flags: unittests
    fail_ci_if_error: false

Triggers

Coverage runs on: - Push to main when src/**, Cargo.toml, or Cargo.lock change - Manual workflow_dispatch

It does NOT run on every PR (cost-saving decision — unit tests run on PR, coverage upload is post-merge).


Implementation checklist

  • [x] CODECOV_TOKEN secret added to GitHub repository
  • [x] coverage.yml workflow collects lcov.info via cargo-llvm-cov
  • [x] LD_PRELOAD stub (libpg_stub.so) enables linking on Linux
  • [ ] Move CODECOV_TOKEN from env: to with: in upload step
  • [ ] Create codecov.yml at repository root
  • [ ] Add Codecov badge to README.md
  • [ ] Verify first upload shows coverage on Codecov dashboard

Expected baseline numbers

Based on module analysis:

Scope Expected coverage
src/dvm/** ~75–85%
src/dag.rs ~80%
src/hash.rs ~90%
Overall project ~25–35% (structurally limited by pgrx)

The overall number will look low to outside observers. The Codecov badge should link to the src/dvm/ coverage view, or the README should note the structural limitation.


Future: E2E coverage (stretch goal)

To get meaningful coverage for api.rs, cdc.rs, etc., a PostgreSQL coverage build would be needed:

  1. Compile PostgreSQL itself with coverage instrumentation
  2. Build the extension .so with RUSTFLAGS="-C instrument-coverage"
  3. Run E2E tests against that PostgreSQL
  4. Merge LLVM profdata from the .so with the server’s gcov data

This is a significant engineering investment and is not planned for v1.0. Tracked as a potential post-1.0 improvement.