Skip to content

The 100% coverage gate rounds, and judges in awk #49

Open

Description

@tannevaled

The coverage gate rounds, and it does its judging in awk.

.github/workflows/ci.yml asserts exact 100% statement coverage like this:

go tool cover -func=coverage.out | tail -n +1 > /tmp/cov.txt
below=$(go tool cover -func=coverage.out | awk '$3 != "100.0%"')

Two separate defects, found while replaying this gate locally to check #48 rather than approximating it.

⛔⛔ -func prints one decimal, so the gate cannot see the last 0.05%

go tool cover -func formats each percentage to one decimal place. A function at 99.96% prints 100.0%, matches $3 != "100.0%" as equal, and passes. The gate therefore asserts "every function rounds to 100.0%", which is not what its own step name claims ("Assert exact 100% statement coverage") and not what this repo wants.

This is a gate that can pass for the wrong reason, which is the failure mode the gate exists to prevent. It has not yet done so here — covblocks reports 0 uncovered blocks and 0 uncovered statements of 1815 and 2484 on the current head — so this is a hole, not an outage. A hole in a gate is worth closing while it is still cheap to prove it was never exercised.

covblocks counts blocks and statements exactly and takes a --max:

covblocks --max 0 coverage.out

1815 block(s), 2484 statement(s); 0 block(s) uncovered, 0 statement(s) uncovered

It exits non-zero above the maximum, so the verdict is the tool's exit status rather than a string comparison on rounded output.

⛔ And the verdict is computed in awk, inside a repository whose rule forbids exactly that

awk '$3 != "100.0%"' is the judging step: a filter deciding pass or fail. A pipeline cannot distinguish "no answer" from "zero failures" — if go tool cover fails, writes nothing, or changes its column order, below is empty and the gate reports success. covblocks fails loudly instead, because an unreadable profile is an error and not an empty set.

The first line is dead too: | tail -n +1 > /tmp/cov.txt copies the output unchanged and nothing reads the file afterwards.

Proposed change

Replace both lines with one covblocks --max 0 coverage.out step, after installing covblocks the way the qpdf judge is installed in the same workflow. The step name then describes what the step does.

⛔ Not folded into #48: that PR is a linearization refusal and this is CI. Separating them keeps the question "did the gate change, or did the code?" answerable from the history.

🤖 Generated with Claude Code

Prior art: priorart "coverage gate rounds awk cover -func" at 2026-11-15 10:42 CET reported prior art; checked: priorart's 28 hits match on the words 'gate' and 'coverage' only: #45 installed the qpdf judge and added REQUIRE_QPDF but never touched the coverage step; #27 added the macOS and Windows lanes; #29 is a go-version bump; #40, #42, #43, #44, #48 are linearization work whose 'gate' is a refusal in the checker, not a CI step. Searches for 'covblocks' and 'awk' over the tracker return zero. Nothing covers the -func rounding hole or the awk verdict.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions