Skip to content

spec-coverage: WARN on high .openspec tag density unless an explicit coverage-rationale annotation is present #515

Description

@stevenobiajulu

Problem

A single test carrying many .openspec('[ID] …') tags is a tag-stuffing smell — one assertion claiming to discharge several distinct scenarios. But it is sometimes legitimate: the Lean bridge test in lean-spec-bridge.test.ts genuinely maps a cluster of [LEAN-RT-*]/[LEAN-FBA-*] scenarios to one property/fixture test by accepted convention. Today that legitimacy is invisible — a reviewer can't distinguish "deliberately maps a related cluster" from "stuffed N tags to hit the ratio".

This was a live failure mode in #513: [LEAN-RT-01..05] were initially piled onto one property test, and [LEAN-RT-05] in particular was on the wrong test (it requires a single-fixture case, not a 100-case property test).

Proposal

In validate_openspec_coverage.mjs (or a sibling lint), WARN when a single test(...) carries ≥3 .openspec tags, unless the test has an explicit adjacent annotation, e.g.:

// coverage-rationale: these five LEAN-RT scenarios are the round-trip lemma cluster;
// this is the one TS-side bridge test that exercises accept/reject round-trip on the live engine.
test
  .openspec('[LEAN-RT-01] …')
  .openspec('[LEAN-RT-02] …')
  ...
  • Make legitimate high-density mappings deliberate and greppable rather than silent.
  • A missing rationale → WARN (or FAIL under --strict, TBD). An empty / hand-wavy rationale is itself the smell a reviewer can scan for.
  • Threshold (≥3) and WARN-vs-FAIL severity are tunable; start at WARN to avoid churn, ratchet later.

Acceptance criteria

  • Density detector counts .openspec tags per test(...) call (AST-based).
  • Recognizes a // coverage-rationale: annotation (or equivalent JSDoc tag — note the repo convention that test narrative lives in JSDoc) to suppress the warning.
  • Existing legitimate high-density tests get rationale annotations added so main is clean.
  • Unit test: 3+ tags w/o rationale → WARN; with rationale → clean.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions