Skip to content

Coverage gate passes when its include globs stop matching: guard the measured file set #2709

Closed

Description

@cliffhall

Problem

The per-file ≥90 coverage gate only checks the files that end up in the coverage report. Nothing checks that the report covers the files it should, so if the include globs stop matching, coverage gating silently shrinks and local:gate (and CI) stay green.

This actually happened during the #2557 dependency refresh (analysis). Under vitest 5, which fixed "coverage include/exclude globs too eager", clients/web's include patterns (src/components/**/*.{ts,tsx}, the absolute core/… paths) stopped matching. Only clients/web/server/** still matched:

client files in coverage/coverage-summary.json
web (vitest 4) 418
web (vitest 5) 11

Every test passed, every remaining file cleared 90, and the gate went green. It was caught only because someone compared the summary file counts by hand. The vitest 5 bump was deferred for this reason, and this guard should land before it is attempted again.

This is the same failure class as #1301 (core/ files silently dropping out of the per-file gate), arrived at from a tooling upgrade rather than a path change.

Expected

A coverage run whose measured file set has collapsed or shrunk unexpectedly fails, naming the client and the files that went missing.

Suggested shape (implementer's call)

  • Preferred: compare against an independent expansion. For each client, expand that client's own coverage include/exclude against the file system, using a glob library rather than vitest, and assert every expanded file appears in coverage-summary.json. That checks the scope against its own declaration with no number to maintain, and it would have reported ~400 missing web files by name. Any intended differences, such as files vitest legitimately omits, would need to be stated explicitly in the guard.
  • Fallback: a floor. Record a per-client minimum file count and fail when a run falls below it. Simpler, but it needs bumping as files are added and only catches large drops.
  • Wire it into the coverage step of local:gate and the CI coverage job, since it reads the coverage output (verify:* naming, alongside verify:format-coverage / verify:typecheck-coverage).
  • Cover all five gated clients (web, cli, tui, launcher, mcpdo). Counts on v2/main as of chore(deps): monthly dependency refresh #2557: web 419, cli 20, tui 41, mcpdo 31, launcher 1.

Acceptance

Activity

  1. added this to the v2.12.0 milestone on Oct 13, 2026
  2. added
    v2Issues and PRs for v2
    choreMaintenance: deps, build tooling, CI, cleanup — no user-facing behavior change
    on Oct 13, 2026
  3. cliffhall commented on Oct 13, 2026

    @cliffhall
    MemberAuthor

    Triage: Priority Medium (total 6)

    • Severity 3 — a real safeguard (the per-file coverage gate) can silently stop enforcing; nothing user-facing breaks
    • Urgency 2 — wanted eventually; becomes a prerequisite before the deferred vitest 5 bump is retried
    • Bonuses: +1 milestone (filed into v2.12.0)

    Board: #28, Status Todo, milestone v2.12.0.

  4. modified the milestones: v2.12.0, v2.11.0 on Oct 13, 2026
  5. self-assigned this
    on Oct 13, 2026
  6. added 2 commits that reference this issue on Oct 13, 2026
  7. cliffhall commented on Oct 13, 2026

    @cliffhall
    MemberAuthor

    Shipped in #2711.

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

Metadata

Metadata

Assignees

Labels

choreMaintenance: deps, build tooling, CI, cleanup — no user-facing behavior changev2Issues and PRs for v2

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions