Skip to content

Add a Coverage column, read from CI artifacts - #24

Merged
tschm merged 1 commit into
mainfrom
feat/coverage-column
Aug 30, 2026
Merged

Add a Coverage column, read from CI artifacts#24
tschm merged 1 commit into
mainfrom
feat/coverage-column

Conversation

@tschm

@tschm tschm commented Aug 30, 2026

Copy link
Copy Markdown
Member

Adds Coverage to Size and cadence, sourced from the coverage-report artifact your CI already uploads — so the number is tied to a commit and a branch.

Two sources I rejected first

  • The .coverage files in the checkouts. 18 of 24 repos have one, aged 1 to 16 days. It records whenever someone last ran pytest in that directory — possibly a subset of tests, possibly on a feature branch. A column that looks like a fact about the repo and is actually a fact about a shell history.
  • test LOC / code LOC. Cheap, complete, and not coverage. Fine as a ratio, dishonest under that heading.

The branch filter is load-bearing

Artifacts come back newest-first across every ref, and in a repo that tags releases the newest is usually a tag build — rhiza's most recent coverage artifact is from v1.7.1, not main. Taking the latest would report a release build's coverage as the repo's, measured at a different commit. Pinned by a test.

Cost, measured rather than estimated

Artifact listing (every refresh, so new reports are picked up) +25 calls, ~150/hour
Zip download (only when the artifact id changes) 19 cold, 0 on the next refresh

That measurement also caught a documentation bug: the API-budget page claimed 119 calls/refresh and ~1430/hour. Counting requests through a full refresh gives 370 and ~2220/hour. Corrected, with a note saying it was understated.

Two metrics, not one

jq_ci_coverage_percent is the figure. jq_ci_coverage_lines is what CI actually measured — and the percentage is not interpretable without it. The denominator is not jq_local_code_lines: CI measures whatever it pointed --cov at, so rhiza reads 100% of 176 lines while the LOC column counts 1477. Both are right; they answer different questions.

Absent, never zero, when a repo publishes no report — six of yours don't. The column reads no report, because "nobody publishes coverage here" is not the finding "nothing is covered".

What you'll actually see

All 19 reporting repos are at 100.0%. I verified that's real (lines-covered == lines-valid in every report), not a parsing artifact. So this column is a regression tripwire, not a differentiator — the varying, informative number is the line count, from 49 to 4,652. Worth knowing before you judge the column: if you'd rather see the denominator on the board too, say so and I'll add it as a second column.

Checks

74 tests (15 new, incl. the branch trap, the download cache, malformed/oversized archives), ruff, check-dashboard.py, mkdocs build --strict, compose parses. Verified live against all 25 repos.

Coverage comes from the `coverage-report` artifact CI already uploads, so the
number is tied to a commit and a branch. Two sources were rejected first:

  * The .coverage files lying in the checkouts. 18 of 24 repos have one, aged
    1 to 16 days. It records whenever someone last ran pytest in that
    directory - possibly a subset of tests, possibly on a feature branch. It
    would be a column that looks like a fact about the repo and is actually a
    fact about a shell history.
  * test LOC / code LOC. Cheap, complete, and not coverage. Fine as a ratio,
    dishonest under that heading.

The branch filter is the load-bearing part. Artifacts come back newest-first
across every ref, and in a repo that tags releases the newest is usually a tag
build - rhiza's most recent coverage artifact is from v1.7.1, not main. Taking
the latest would report a release build's coverage as the repo's, measured at
a different commit. There is a test for exactly this.

Cost, measured rather than estimated

  * Listing artifacts is one call per repo and always happens, so a report
    published between refreshes is picked up: +25 calls, ~150/hour.
  * The zip is downloaded only when the artifact id changes: 19 downloads on a
    cold pass, 0 on the next.

That measurement also showed the documented API budget was wrong - the page
claimed 119 calls per refresh and ~1430/hour for a fleet of 32. Counting
requests through a full refresh gives 370 and ~2220/hour for a fleet of 25.
Corrected, with a note saying so.

Two metrics, not one. jq_ci_coverage_percent is the figure; jq_ci_coverage_lines
is what CI actually measured, and the percentage is not interpretable without
it. The denominator is NOT jq_local_code_lines: CI measures whatever it pointed
--cov at, so rhiza reads 100% of 176 lines while LOC counts 1477. Both are
right and they answer different questions.

Absent, never zero, when a repo publishes no report - six of this fleet do not,
and "nobody publishes coverage here" is not the finding "nothing is covered".
The column reads `no report`.

A malformed or oversized artifact is logged and skipped rather than failing a
refresh that has already gathered everything else, with guards on both the
download and the unpacked size.
@tschm
tschm merged commit 1f08513 into main Aug 30, 2026
6 checks passed
@tschm
tschm deleted the feat/coverage-column branch August 30, 2026 15:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant