Skip to content

coverage-crap: replace staleness detectors with a coverage run stamp #3468

Closed

Description

@thymikee

Purpose

The blocking touched-function check (#3426, PRs #3460 → #3454) uses four problem kinds to tell when coverage/ wasn't written by this checkout's own run: map_partial, unscored_touched, unmeasured_touched and enumeration_missing.

lcov and the json map come from the same Vitest coverage map, so in a fresh run they can't disagree. The real question is just "is this coverage/ stale?" Four detectors is more machinery than that needs, and they still miss two cases: new files, and estimates below the threshold.

Proposal

  • Have test:coverage (or a small Vitest reporter) stamp HEAD and a tree hash into coverage/.
  • Have scripts/coverage-crap/model.ts refuse with "no trustworthy verdict" when the stamp doesn't match the checkout.
  • Replace the four staleness kinds with that one check.
  • Keep corrupt_touched, plus a declared "uninstrumented" set read from coverage.exclude.

Completion

  • A stale coverage/ always fails PR mode, including when the diff adds new files.
  • The four staleness kinds and their tests are deleted.
  • CONTRIBUTING.md and docs/agents/testing.md describe the single rule.

Suggested by the maintainer's review of #3460. Part of #3414's follow-ups. Blocked by #3460 and #3454.

Activity

  1. thymikee commented on Oct 12, 2026

    @thymikee
    MemberAuthor

    Scope additions from a read-only review of the merged #3460 and #3454. Neither can happen in CI, where coverage runs fresh on the same checkout with src/** included, but both are reachable locally. The stamp proposed above fixes both:

    1. Freshness against source. Matching file lists and function locations can produce a clean verdict from old counters if a function body is replaced in place. Record source hashes (or the HEAD + tree-hash stamp) with the coverage, and reject a mismatch before scoring.
    2. Eligibility from config, not absence. A file that is missing from both reports is treated as outside coverage scope. For example, a src/new.ts added after the coverage run is reported as non-blocking at an estimated CRAP 42, and reports from another checkout pass the same way. Derive eligibility from the resolved Vitest coverage config, refuse eligible files that are missing, and reject paths outside the analyzed checkout.
  2. thymikee commented on Oct 12, 2026

    @thymikee
    MemberAuthor

    Two more inputs from an audit of the merged gate:

    • Use fallow's own map check. The health JSON's summary.istanbul_files_matched / istanbul_files_total read 1724/1724 on a fresh map and 1722/1724 on a stale one. Refusing when matched < total catches a map from the wrong root, where every finding falls back to an estimate and --all would print "no function(s)". It also catches files deleted since the coverage run. It could replace the lcov cross-check and the parseLcov import.
    • Known defects to clear while replacing the detectors:
      • A sanitizer-dropped file stays in mapPaths (scripts/coverage-crap/model.ts:~318). Its complex functions then come back as unmeasured_touched, with the wrong fix advice. The "named once" test passes no estimates, so it doesn't catch this.
      • A function inside c8 ignore (for example conformance-harness.ts) would block forever with "run again".
      • In CI, coverage/ is wiped and both reports come from one process, so the staleness kinds can only fire locally. The stamp should be designed for the local case.
  3. added 8 commits that reference this issue on Oct 14, 2026
    1ca5932
    2b981be
    29d90bd
    67ce8ff
    d75b694
    e396830
    6e58546
    bea411c
  4. added a commit that references this issue on Oct 14, 2026
    334970a
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