agentsclimarketplace

Test coverage strategy

Skill jacob-balslev/skills/skills/quality-assurance/test-coverage-strategy

Public Agent Skills library exported from skill-graph. Install: npx skills add jacob-balslev/skills

Install
npx -y skills add jacob-balslev/skills --skill test-coverage-strategy

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Use when reasoning about code coverage as a strategic measurement rather than a quality target: structural reach versus behavioral verification (covered vs tested), the coverage-criterion hierarchy (function, line, branch, decision, condition, MC/DC, path) and matching the criterion to where a module's failure modes hide, Marick's floor-vs-ceiling distinction, Goodhart's Law applied to coverage and Goodhart-resistant policy (diagnostic use, diff/patch floors, risk-weighting, behavioral panels), denominator hygiene and cross-tool counter semantics, safety-critical MC/DC (DO-178C Level A required; ISO 26262 ASIL-D highly recommended) as requirements-based evidence, and interpreting coverage from AI-generated tests. Do NOT use for choosing test levels (use testing-strategy), mutation testing as a behavioral signal (use mutation-testing), test-double construction (use test-doubles-design), LLM eval iteration (use eval-driven-development), or specific coverage-tooling configuration (tool docs).

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

55.7 KB, ~9.2k tokens by cl100k_base, as published. Nobody here has run it

Test-Coverage Strategy

Concept of the skill

What it is: Test-coverage strategy is the discipline of using structural coverage reports to identify unexercised code and to choose an appropriate coverage criterion — without treating the percentage as proof of test-suite quality.

Mental model: Coverage is a reach map. The map gets more precise as the criterion gets stronger — functions, lines, branches, decisions, conditions, MC/DC independence, and paths each reveal a different kind of gap. The map still does not know whether a test asserted the right behavior. So coverage is a reliable floor (uncovered code is definitely untested) and an unreliable ceiling (covered code is not necessarily tested).

Why it exists: The coverage number is easy to produce and easy to gate on, and the moment it becomes the goal, tests degrade into reach-without-assertion padding. As of the LLM era that padding is now produced at scale by AI test generators, not just by humans gaming a gate. The skill keeps the strong floor signal and blocks the weak ceiling claim.

What it is NOT: It is not test-level selection, mutation testing, test-double construction, TDD, LLM eval design, production observability, or coverage-tool configuration.

Adjacent concepts: testing strategy, mutation testing, test doubles, TDD, requirements traceability, property/fuzz testing, contract/integration testing, and production observability.

One-line analogy: A green coverage map is like a green cell-phone coverage map — it shows where there is theoretical signal, not whether the call gets through. A 100% coverage map with a 30% call-completion rate is the same shape of problem as a 100%-line-coverage suite that misses bugs.

Common misconception: Higher coverage is not automatically better. A coverage report measures execution; only assertions, oracles, requirements, mutations, properties, contracts, or integration evidence tell you whether the reached behavior was verified.

Coverage

The strategic use of code-coverage measurement as a diagnostic signal about test-suite gaps, without falling into the Goodhart-Law trap of treating the coverage number as the target. This skill covers:

  • Coverage as a structural measurement — execution reach, not behavioral verification (the covered-vs-tested distinction, kept precise in policy and review language).
  • The coverage-criterion hierarchy — function → statement/line → basic-block/instruction → branch → decision → condition → condition/decision → MC/DC → multiple-condition → path, and choosing the weakest criterion that still reveals the failure modes that matter for a given module.
  • Marick's floor-vs-ceiling distinction — uncovered code is definitely untested (reliable); covered code is not necessarily tested (unreliable).
  • Goodhart-resistant coverage policy — diagnostic use, changed-code (diff/patch) floors, risk-weighted thresholds, reviewable exceptions, and pairing coverage with behavioral signals.
  • Denominator hygiene — what population of code the percentage is a fraction of: included roots, exclusions, the all-files-vs-loaded-only trap, and holding the denominator stable when reading a trend.
  • Tool-counter semantics — how "line," "branch," "condition," and "MC/DC" differ across JaCoCo, coverage.py, Istanbul/nyc, gcov, llvm-cov, and Codecov, so a percentage is read with its definition attached.
  • The two empirical anchors — advisory-at-scale (Google's voluntary, code-review-surfaced, changelist-level coverage) and mandated-for-safety (DO-178C / ISO 26262 MC/DC) — as the empirical counterpoints to "set a high gate."
  • Safety-critical structural coverage — MC/DC as requirements-based evidence inside a certification process, including unique-cause vs masking MC/DC, object-code coverage, and tool qualification — not a standalone correctness proof.
  • AI-generated-test coverage inflation — the now-dominant practical instance of covered-but-not-tested, and the review discipline that contains it.

Philosophy of the skill

Coverage measures execution, not verification. A test that calls every function but asserts nothing has 100% line coverage and zero testing value; a test with rich assertions but missing some branches has lower coverage and may have much higher testing value. The metric's strategic value is in the floor direction: uncovered code is definitely untested. The reverse direction — covered code is necessarily tested — is not reliable.

The discipline of coverage strategy is using the metric where it is informative (gap detection, regression signaling, test-effort allocation, audit compliance) and refusing to use it where it is misleading (as a quality target, as a substitute for behavioral verification, as a ceiling claim about test thoroughness). The risk is large because coverage numbers are easy to produce, easy to gate on, and easy to optimize for in ways that degrade the test suite.

Coverage policy is measurement design. A real policy must name the criterion, the denominator, the threshold posture, the exception rules, the paired behavioral signals, and the review workflow. "80%" or "100%" by itself is not a policy; it is an ungrounded number. Most working test suites should aim for coverage that is high enough to reveal gaps without becoming the goal. Where the certification environment mandates a specific criterion (MC/DC for safety-critical), the discipline shifts: the criterion is given; the work is meeting it without coverage-padding.

The Criterion Hierarchy

CriterionWhat it requires (proves structurally)Test count for A && B && CTypical use / what it misses
FunctionEach function called once1Detects entirely-untested functions; misses lines, branches, assertions
Statement / LineEach line executed once1Default in most tools; misses untaken branches and weak assertions
Basic block / InstructionEach compiled block or bytecode instruction ranLow-level / JVM / compiled-language reports; abstracts away source intent
BranchEach branch (true/false) taken once2Catches missed-else-branch bugs; tool-specific branch definition, exception paths sometimes uncounted
DecisionEach decision evaluated both ways2Often conflated with branch in tooling; conditions inside a compound decision may not independently matter
ConditionEach Boolean sub-expression both true and false2Catches short-circuit-evaluation bugs; the overall decision may still not vary
Condition / decisionCondition and decision criteria both met2+Middle ground for compound Boolean expressions; independent effect may still be unshown
MC/DCEach condition independently affects the decision4 (N+1 for N independent conditions)Required at DO-178C Level A; highly recommended at ISO 26262 ASIL-D; coupled/repeated conditions may need masking forms
Multiple conditionAll 2^N combinations exercised8 (2^N)Combinatorial; rarely required; infeasible for many operands
PathEvery execution path through the functionInfeasible for loopsTheoretical; loops create unbounded paths

The "test count" column is an idealized minimum for the three-operand expression A && B && C, not a guarantee. The real count depends on the language and tool's short-circuit semantics (whether && is short-circuiting, whether the tool instruments each operand separately), on how decision vs condition vs branch are defined by the specific instrumenter, and — for MC/DC — on which flavor the certification interpretation accepts:

  • Unique-cause MC/DC shows a condition's independent effect with a pair of tests where only the condition of interest and the decision outcome change; all other conditions stay fixed (the strict reading). It generally needs more cases.
  • Masking MC/DC allows other conditions to change only when Boolean masking means they cannot affect the decision outcome in that pair. It is accepted by DO-178C for expressions with coupled/strongly-coupled conditions and is often the practical answer there — but the report must name the form, and the reviewer must understand which independence argument the tool is making.

N+1 is the floor for independent conditions; coupled conditions can require more. Treat the numbers as orders of magnitude, not as a tool-agnostic contract. Higher criteria do not make tests better by themselves; they reveal more structural gaps. Upgrade the criterion when the lower one cannot see the failure mode.

Coverage Criterion Selection

The right criterion depends on where the code's failure modes hide.

Code characterRecommended criterionWhy
Straight-line procedural; few branchesLineThe main risk is unexecuted code; adequate and cheap
Branchy business logicBranch / decisionLine coverage can execute an if without exercising both outcomes
Compound Boolean guardsCondition/decision or MC/DCBranch coverage can miss short-circuit and independence failures
Security, authorization, rate limits, financial gatesCondition/decision plus mutation or property testsThe failure risk is often a missing operand, boundary, or negated condition
Error, exception, and defensive pathsBranch (or accept the gap) plus explicit exception-path reviewMany suites skip failure paths; some tools do not count exceptions as branches
Algorithmic / mathematical codeBranch plus property-based tests and mutationCoverage finds structural holes; properties/mutations check behavior
Legacy system with weak testsFunction/line first, then branch on changed or risky modulesA low-friction floor beats a 100% target nobody can meet honestly
Safety-critical (aviation, automotive, medical)Standard-required criterion, often MC/DC for highest criticalityCertification evidence requires the named criterion and traceability
High-traffic, incident-prone, or business-critical pathsStart with the structural criterion the code implies, then prioritize gaps by production usage / incident dataRuntime impact ranks which dark areas matter first; it is not itself test coverage
Generated, vendor, or framework glueExclude or separate with explicit policyA denominator full of irrelevant code makes the percentage meaningless

Covered vs Tested

AspectCoveredTested
What it measuresTest reached the codeTest verified the code's behavior
Detected byCoverage toolAssertion/oracle presence + correctness
100% achievable cheaply byFunction/line traversal with no assertionsReal behavioral assertions (not cheaply fakeable if the oracle is real)
Signal directionFloor (uncovered = untested) reliableCeiling (covered = tested) unreliable
Typical companionDiff coverage, branch gaps, per-test contextsMutation tests, properties, contracts, integration tests, requirements traceability
Strategic valueGap detectionQuality assurance

Use the words precisely. "This line is covered" means a test executed it. "This behavior is tested" means a test would fail if the behavior were wrong. Mixing the terms is how false confidence enters policy discussions. A test that calls processOrder() but asserts nothing covers processOrder and tests nothing in it; the coverage report cannot distinguish this from a test with full behavioral assertions. The discipline is to read coverage as one part of a picture that includes assertion review, mutation testing (see mutation-testing), and integration test coverage.

Mutation testing is the layer that makes the covered/tested gap visible: a coverage tool reports a line green whether or not an assertion would notice it changing, whereas a mutant on that line survives precisely when no assertion catches the change. This is why coverage is the substrate mutation testing runs on — Google's mutation system generates one mutant per covered line (uncovered lines have nothing to mutate against), so coverage is the precondition and mutation score is the behavioral confirmation on top of it. The pairing is not free: Google reports that ~85% of naively-generated mutants are unproductive (equivalent or not-worth-a-test), which is why behavioral signal must itself be curated rather than turned on blindly.

Denominator Hygiene — what the number is a fraction of

A coverage percentage is a ratio, and the number is only as meaningful as its denominator. The strategic failure here is not picking the wrong criterion but measuring against the wrong population of code — a 95% that silently excludes the risky modules is worse than an honest 70%. This is a strategy concern, not a tool-config concern: it governs what the metric means, independent of which tool produces it.

Denominator issueRiskPolicy
Only loaded files countedA module with zero tests is never imported, so it never enters the denominator — the least-tested code is invisible and the percentage looks highUse all-source / all-files inclusion when the tool supports it (so adding an untested module lowers the number), or separately list never-loaded files. This is the single most common way a coverage number lies.
Generated / vendor / framework code includedPercentage drops for code the team should not test directlyExclude with a named category and rationale
Generated / vendor / framework code excluded silentlyThe team hides real ownership behind ignore-globs to lift the numberKeep exclusions versioned and reviewable in the config, not buried
Dead code includedTeams write tests for code that should be deletedDelete it or mark the gap as dead-code debt
Defensive / logging / debug code includedTeams pad tests around low-value pathsAllow justified exceptions, reviewed periodically
Tool / compiler upgrade changes countersCoverage trend moves without any test changingRe-baseline after major tool/compiler changes; a delta is only interpretable if the denominator did not move underneath it
Source maps / synthetic code distort line mappingCoverage measured on transpiled/minified output (TS→JS, bundled code) attributes lines wronglyMap back to source before acting; inspect the tool's counter definitions

State the denominator explicitly — which roots are instrumented, which exclusions apply (and why), all-files vs loaded-only, and which tool's counter — and treat any unexplained jump as a denominator change until proven otherwise. None of this requires choosing a specific tool; it requires knowing what your chosen tool counts.

Tool-Counter Semantics

Do not assume two tools mean the same thing by the same label. A "90%" from one tool is not comparable to a "90%" from another.

  • JaCoCo (JVM). Counts six distinct countersinstructions (single Java bytecode instructions, its smallest and most reliable unit), branches (the two outcomes of each if/switch; exception handling is not counted as a branch), lines (when debug info exists), complexity (cyclomatic), methods, and classes. Because it instruments bytecode, a source line maps to many instructions and source-line numbers are approximate; the headline percentage depends on which counter the report surfaces, and synthetic compiler-generated code can create surprising source mappings.
  • coverage.py (Python). Defaults to line coverage, optionally measures branch coverage, and supports contexts — tagging which test or dynamic context covered each line — so the same raw run can be sliced into per-test or per-feature coverage rather than one global number. Emits HTML/XML/LCOV/JSON.
  • Istanbul / nyc (JS/TS). Reports four separate percentages — statements, branches, functions, lines — so a suite can sit at 95% lines but far lower branches; quoting "Istanbul coverage" without saying which of the four is ambiguous. By default it reports only files visited by tests; --all changes the denominator by including unvisited files. Threshold checks exist, but they do not decide whether the threshold is strategically wise.
  • gcov / GCC. GCC 14 added explicit condition coverage (-fcondition-coverage, gcov --conditions), distinct from its older line/branch counters — so the same compiler reports different granularities depending on the flag.
  • Clang / LLVM source-based coverage. Counts region, line, and branch execution with precise AST/preprocessor-based mapping, and offers MC/DC instrumentation (-fcoverage-mcdc, llvm-cov show -show-mcdc) — so an LLVM "coverage %" must state whether it is region, line, branch, or MC/DC before it means anything.
  • Codecov (aggregator). Re-rolls whatever the underlying tool emitted and reports three different numbers teams routinely conflate: project coverage (whole codebase), patch coverage (only the lines changed in the PR — the diff-gating number), and change/delta (indirect coverage shifts in untouched files). A PR can be green on patch and red on project, or vice-versa.

Tooling can make the structural signal sharper. It does not solve the oracle problem.

Goodhart-Resistant Strategy

Patterns that use coverage strategically without producing Goodhart-pressure:

  1. Use coverage to ask questions, not award grades — and default to diagnostic. The safe default is to report coverage on PRs rather than fail the build on an aggregate number; reviewers read the report and the team adjusts allocation. This is not an absolute prohibition on gates. Google's own Code Coverage Best Practices (2020) is explicit that coverage targets can be useful when set per-team/per-workflow, risk-weighted to the code's criticality, scoped to the change rather than the whole codebase, and paired with human review — and equally explicit that a single global percentage gate imposed top-down is an anti-pattern that drives coverage-padding. The discriminator is how the gate is set, not whether one exists.
  2. Prefer changed-code floors over whole-project trophies. New/changed lines must be covered above (e.g.) 70%, not the codebase as a whole. Lower aggregate target, higher meaningfulness of each test; keeps new gaps from entering unnoticed without forcing legacy cleanup into every PR.
  3. Risk-weight thresholds. Security, financial, data-loss, safety, and high-change modules deserve stronger criteria and higher floors than generated glue or stable boilerplate.
  4. Pair coverage with behavioral signals. Mutation score, survived-mutant review, property tests, fuzzing, assertion review, contract tests, integration breadth, and requirements traceability answer questions coverage cannot. No single metric is the target.
  5. Review uncovered lines in context. A specific uncovered authorization branch matters more than a percentage delta.
  6. Keep exclusions explicit. Every ignored file or pragma has a reason: generated, vendor, dead, impossible, defensive, or covered at another level.
  7. Treat 100% as suspicious outside regulated contexts. It can be legitimate for small pure modules or mandated safety evidence; as a broad management target it usually creates padding.
  8. Prioritize gap-closing by production exposure. Where available, pair coverage with runtime telemetry (OpenTelemetry traces, RUM, or impact-analysis tooling that maps coverage to executed-in-production paths) so the team tests the code users actually exercise first. Hot, uncovered paths are the highest-value test debt; cold, uncovered paths may be acceptable gaps.
  9. Audit agent-generated tests. Coding agents can quickly raise coverage; require oracle review, boundary cases, and double/real-boundary checks before accepting the coverage gain (see § Coverage in the age of AI-generated tests).

The two empirical anchors: advisory at scale, mandated for safety

The most consequential real-world coverage programs sit at opposite ends of the gating spectrum, and both vindicate the patterns above rather than the "set a high gate" instinct.

  • Advisory at scale (Google). Google runs coverage for the large majority of its projects (~90% adoption by Q1 2018), yet coverage is voluntary and advisory, not a merge gate. Its primary delivery is changelist-level (diff) coverage surfaced inside code review — the reviewer sees which new/changed lines are green, orange (uncovered), or uninstrumented, which is exactly pattern #1 (diagnostic) plus pattern #2 (diff-based) at planetary scale. Project coverage is a slow health signal that can identify modules needing investment but can also hide a risky uncovered component under a healthy aggregate; changelist coverage is the changed-code floor. The researchers' own framing is that coverage is worth computing even when it is not a direct human quality signal, and that it should not be treated as a standalone success measure — an industrial confirmation of the floor-not-ceiling, panel-not-target doctrine. Mutation-at-review complements coverage-at-review: Google's mutation work presents a small number of actionable mutants on changed code, giving developers concrete behavioral test goals where coverage alone would only say code was reached. Runtime-impact prioritization is prioritization, not proof — production usage, incidents, and business impact rank which uncovered gaps to inspect first; that data belongs to observability and product-risk review, and coverage strategy only uses it to order the work.
  • Mandated for safety (DO-178C / ISO 26262). At the other end, certification narrows the choice: the criterion is fixed at MC/DC — required for DO-178C Level A, and highly recommended (++) for ISO 26262 ASIL-D, where deviating is permitted only with a documented rationale and supplementary verification. This is the case where a hard coverage requirement is correct — precisely because the requirement is on the criterion's granularity, backed by certification audit, not on a raw line-coverage percentage chosen by a team. Note the asymmetry: even at ASIL D the standard allows a reasoned deviation, so "MC/DC is the law" overstates ISO 26262 — it is the strongly-expected default, not an absolute. See § Safety-Critical and MC/DC Discipline for the object-code and tool-qualification nuances.

The takeaway: a default repo should look more like the Google end (advisory, diff-scoped, reviewer-read) than like a blanket "fail the build under 90% line coverage" gate, and the hard-gate end is reserved for environments where a certification standard dictates the criterion.

Coverage in the age of AI-generated tests

LLM test generators and coding agents have made the covered-vs-tested gap the dominant practical failure mode, not a 1999 abstraction. Current agents can find low-coverage modules, generate candidate tests, run suites, and iterate on failures — this accelerates the mechanics of closing structural gaps; it does not displace coverage strategy. The new failure mode is faster Goodharting: an agent can generate many tests that traverse code while providing little independent behavioral evidence. The mechanisms are specific and worth naming so a reviewer recognizes them:

  • Assertion-free or assertion-weak tests. Generated tests reliably execute the target lines (coverage climbs) while asserting little or nothing of consequence — the classic "covered, not tested" shape, now produced in bulk.
  • Bug-documenting tests. A generator that writes assertions against the current output of the code under test pins whatever the code does today, including its bugs, as "expected." The test is green, coverage is up, and the defect is now protected by a regression test that asserts the wrong thing.
  • Implementation-shaped assertions. The test mirrors a private helper's behavior or an exact incidental data-structure shape, so a benign refactor fails while the real behavior remains correct.
  • Over-mocked boundaries. The test replaces the collaborator, network, database, filesystem, or framework behavior that actually carries the risk, so coverage rises over code whose real integration point is never exercised.
  • Trivial-target / happy-path padding. Generators favor easy targets — getters, setters, constructors, happy paths — which have near-zero defect probability but lift the percentage, while skipping the subtle edge cases (race conditions, timezone and Unicode boundaries, integer overflow) where real bugs live.
  • Scattershot volume on unfamiliar logic. When the code diverges from patterns the model recognizes, generators tend to brute-force many shallow tests rather than engage the altered control flow — inflating both coverage and test count without exercising the new behavior.
  • Denominator manipulation. The coverage gain came from exclusions, generated-file changes, or loaded-file behavior rather than from better tests.

The empirical tell is the gap between the two metrics: a generated suite can post high line coverage while its mutation score (the share of injected defects the suite actually catches) stays far lower — meaning most injected defects would survive despite the green coverage number. Treat any specific figure here as illustrative, not as a settled benchmark: a single vendor-adjacent blog has reported LLM-generated suites near ~20% mutation score on complex functions, but that is one practitioner data point, not peer-reviewed measurement, and rigorous published study of LLM-test mutation scores is still emerging. The 2026 MSR empirical studies on coding-agent test generation are checkable evidence that agents modify tests, add mocks, and can produce coverage gains — they do not prove that every AI-authored test is weak, so treat their findings as a reason for review discipline, not an automatic rejection rule. So the load-bearing claim is the direction and shape of the gap (coverage high, behavioral catch-rate low), not a precise percentage.

Review AI-generated coverage with stricter questions before reading a coverage rise as a quality improvement:

  • What behavior would make this generated test fail?
  • Does the test assert an intended contract, or just the implementation's current return value?
  • Did the agent mock away the boundary that actually matters?
  • Did it cover edge cases and failure paths, or only happy-path line traversal?
  • Would a mutation, property, or contract violation survive?
  • Did coverage rise because tests improved, or because the denominator/exclusions changed?

The strategic response is the same panel this skill already prescribes — never accept a coverage rise from generated tests as evidence of quality without a behavioral check (mutation score, assertion review, or running the suite against a known-buggy variant). A coverage gate alone actively rewards the generator for producing exactly these tests. Agentic test generation is a source of candidate tests, not an upstream replacement for coverage interpretation.

Interpreting Coverage Changes

A coverage delta is only interpretable alongside the commit, denominator, criterion, and test oracle. A trend without that context is measurement noise.

ChangePossible good interpretationPossible bad interpretationWhat to inspect
Coverage dropsDead code removed from denominator; riskier code added honestlyNew code lacks tests; tests deleted; tool now includes more filesDiff, denominator, changed files, test deletions
Coverage risesMeaningful tests added for important gapsTraversal tests with weak assertions; exclusions hid code; generated tests locked current behaviorNew assertions, failure cases, excluded paths, mutation/property signal
Patch coverage passesChanged lines were exercisedImportant behavior changed outside the diff; tests only smoke-called codeBehavior target, assertions, integration/contract boundary
Project coverage passesOverall suite did not regress structurallyA risky module remains uncovered under a healthy aggregatePer-module and per-risk slice view
Branch coverage is highControl-flow outcomes were reachedCompound conditions still lack independence; exception paths not counted by toolCondition/decision or MC/DC details, tool branch definition
MC/DC is highConditions independently affected decisionsRequirements may be wrong or untested; tool may not match the standard's definitionRequirements traceability, qualified-tool evidence, decision tables

Safety-Critical and MC/DC Discipline

Safety-critical coverage is not "100% coverage, but stricter." It is structural evidence inside a broader requirements-based verification process.

  • For DO-178C / ED-12C Level A avionics work, MC/DC is the canonical structural criterion for the highest software level. The discipline is not merely producing an MC/DC number; it is proving that requirements-based tests exercised the code structure, and investigating gaps as missing requirements, missing tests, dead code, deactivated code, or unintended functionality.
  • Source-level coverage is not the full object-code story at Level A. DO-178C requires that structural coverage be analyzed at the source level and that the gap between source and object code be addressed. When the compiler introduces branching not directly traceable to source (e.g. a short-circuit Boolean lowered to extra object-code branches, or compiler-generated array-bounds/initialization checks), Level A requires additional verification of that object code — so MC/DC measured purely on source is necessary but not automatically sufficient. This is why safety-critical toolchains pair a qualified coverage tool with object-code coverage analysis rather than trusting a source-level percentage alone.
  • NASA's MC/DC tutorial is valuable because it explains how to assess MC/DC claims without blindly trusting a tool — when a tool's definition, short-circuit behavior, masking form, or source/object-code mapping is under certification scrutiny.
  • For ISO 26262 automotive work, describe MC/DC as ASIL-dependent structural-coverage evidence, commonly highly recommended (++) or required by project safety policy for the highest ASILs. Do not state a blanket "ISO mandates MC/DC for all ASIL-D code" unless the safety plan and the specific standard table being applied make that exact claim; a deviation is permitted with documented rationale and additional verification.
  • In safety contexts, the coverage tool itself may need DO-330 / ED-215 qualification or explicit project validation when its output is used to automate, replace, or substantiate a certification verification activity. A convenient report from a general-purpose tool is not automatically acceptable certification evidence.

Coverage Policy Template

Use this shape when setting a project policy. If a policy cannot fill this table, it is not ready to fail builds.

Policy partDecision
PurposeDiagnostic, changed-code floor, safety evidence, legacy cleanup, or release gate
CriterionLine, branch, condition/decision, MC/DC, or tool-specific equivalent
DenominatorIncluded roots, excluded categories, unloaded-file behavior
Threshold postureWarn, PR comment, soft gate, hard gate, or safety-case requirement
Risk differentiationWhich modules get stricter criteria or thresholds
ExceptionsAllowed reasons and review cadence
Behavioral companionsMutation, property/fuzz, assertion review, contract/integration, requirements traceability
Impact prioritizationProduction usage, incident history, customer-facing criticality — used only to rank gaps
Review workflowWho inspects gaps and what constitutes closure
Tool semanticsTool name/version and any non-obvious counter definitions

Verification

After applying this skill, verify:

  • The coverage question is stated as a diagnostic question, not a quality grade.
  • The team's coverage criterion is appropriate to the code's failure modes (line for procedural, branch for branchy, condition/decision or MC/DC for compound Boolean logic, the standard-mandated criterion for safety work). The default criterion is not assumed correct without checking what it measures.
  • Coverage is read as a floor signal (gaps point to untested code), not a ceiling signal (high coverage proves tests are good). "Covered" and "tested" are kept separate in conversation, policy, and review comments.
  • Coverage gates, if used, are tied to risk and a review workflow and set at a level achievable by real behavioral testing — not copied as a universal number that forces coverage-padding.
  • Project-level and change-level coverage are interpreted separately: aggregate health does not hide risky changed-code gaps, and diff/patch coverage is read as a changed-code floor, not proof the behavior is verified.
  • The denominator is explicit and defensible: which source roots are instrumented, which exclusions are applied (and why), whether the tool counts all source files or only those loaded during the run, and the tool/version. Any unexplained jump is treated as a denominator change until proven a real test change. Coverage measured on transpiled/bundled output is mapped back to source.
  • Coverage is paired with at least one behavioral / oracle-oriented signal in any quality claim: mutation testing, property/fuzz tests, assertion review, contract/integration evidence, or requirements traceability.
  • Any coverage rise driven by AI-generated or agent-authored tests is confirmed behaviorally (mutation score, assertion review, or a known-buggy variant the suite must fail) and reviewed for assertion-free reach, bug-documenting assertions, over-mocking, implementation-locking, and boundary/failure-path gaps before it is read as a quality improvement.
  • Coverage of dead code is excluded or noted. A coverage drop is interpreted before being judged (dead-code removal, denominator change, tool upgrade, test deletion, or new untested code), not treated as automatically bad.
  • Production usage or incident data, if used, only prioritizes uncovered gaps; it is not described as test coverage. Production observability is treated as a separate verification dimension — coverage tells you what tests exercised; observability tells you what production exercises.
  • For safety-critical work, the applicable standard, DAL/ASIL or equivalent criticality level, coverage criterion, requirements-traceability evidence, object-code-coverage handling, and tool-qualification/validation status are named, and the tool's reported number actually matches the standard's definition.
  • The team can explain every important uncovered gap as accepted risk, off-scope code, dead code to remove, behavior tested at another level, or real test debt. Unexplained gaps are test debt.

Do NOT Use When

Instead of this skillUseWhy
Deciding which test levels (unit/integration/e2e) to invest intesting-strategytesting-strategy owns the level/scope and behavior-target question; this skill owns the measurement of structural reach
Measuring whether tests would catch deliberately-introduced defectsmutation-testingmutation owns the behavioral defect-detection signal; this skill owns the structural signal
Constructing mocks, stubs, fakes, spies, or doublestest-doubles-designdoubles can affect coverage quality, but their design is a separate skill
Practicing red-green-refactor or choosing a TDD schooltest-driven-developmentTDD is a design rhythm; coverage may be a side effect, never the target
Iterating on LLM behavior via an eval suiteeval-driven-developmentLLM evals are stochastic pass-rate measurements, not deterministic code-structure coverage
Configuring Istanbul, Jest, nyc, JaCoCo, coverage.py, gcov, llvm-cov, Coverlet, or Codecovtool documentationtool API choice and flag syntax are tactical detail below this skill's scope
Monitoring what production actually exercisesObservability / error-tracking skillsproduction telemetry is runtime evidence, complementary to test coverage

Key Sources

Foundational and empirical

  • Marick, B. (1999). "How to Misuse Code Coverage". The canonical practitioner essay on coverage as a strategic signal vs target; defines the floor/ceiling distinction.
  • Cornett, S. "Code Coverage Analysis". Long-form reference defining the coverage-criterion hierarchy and the practical differences between branch, decision, MC/DC, path, and extended criteria.
  • Inozemtseva, L., & Holmes, R. (2014). "Coverage Is Not Strongly Correlated with Test Suite Effectiveness". ICSE 2014. Empirical study showing coverage and test-suite effectiveness are weakly correlated; the peer-reviewed backbone of the floor-not-ceiling reading.
  • Namin, A. S., & Andrews, J. H. (2009). "The influence of size and coverage on test suite effectiveness". ISSTA 2009. Earlier empirical study; size and coverage both matter and the relationship is not linear. DOI: 10.1145/1572272.1572280.
  • Goodhart, C. (1975). "Problems of Monetary Management: The U.K. Experience." The origin of Goodhart's Law as commonly cited; applies sharply to coverage-as-target.

Industrial scale (Google)

  • Ivanković, M., Petrović, G., Just, R., & Fraser, G. (2019). "Code Coverage at Google". ESEC/FSE 2019. Describes Google's industrial program — voluntary/advisory adoption (~90% by Q1 2018), changelist-level coverage surfaced in code review; the empirical case that coverage works best as a diagnostic, not a gate.
  • Arguelles, C., Ivanković, M., & Bender, A. (2020). "Code Coverage Best Practices". Google Testing Blog. Source for the calibrated gating stance: targets can be useful when set per-team/per-workflow, risk-weighted, change-scoped, and review-paired — and a single global top-down percentage gate is an anti-pattern. The discriminator is how the gate is set, not whether one exists.
  • Petrović, G., Ivanković, M., Fraser, G., & Just, R. (2021). "Does mutation testing improve testing practices?". ICSE 2021. Evidence that mutation findings drive higher-quality tests, making mutation a strong companion signal to coverage.
  • Petrović, G., Fraser, G., Ivanković, M., & Just, R. (2021/2022). "Practical Mutation Testing at Scale: A View from Google". Generates one mutant per covered line surfaced during code review; ~85% of naive mutants are unproductive, motivating context-based mutant selection — evidence that coverage is the substrate mutation builds on and that behavioral signal must itself be curated.

Safety-critical standards

  • RTCA. DO-178C: Software Considerations in Airborne Systems and Equipment Certification (2011). The aviation certification standard requiring MC/DC for Level A software. Industry benchmark for what coverage criterion safety-critical software requires.
  • FAA. "AC 20-115D: Airborne Software Development Assurance Using EUROCAE ED-12( ) and RTCA DO-178( )". FAA recognition of DO-178C/ED-12C and DO-330/ED-215 (tool qualification) as acceptable airborne-software guidance.
  • FAA/AVS. "DO-178B/C Differences Tool". Public FAA guide noting DO-178C structural-coverage changes, object-code traceability, and DO-330 tool-qualification context.
  • ISO. ISO 26262: Road vehicles — Functional safety (2018). The automotive safety standard. Part 6 Table 12 rates MC/DC as highly recommended (++) for ASIL-D software — a strong default rather than an absolute mandate: a deviation is permitted with documented rationale and additional verification. Parallel benchmark to DO-178C, with the weaker normative force noted.
  • Hayhurst, K. J., Veerhusen, D. S., Chilenski, J. J., & Rierson, L. K. (2001). "A Practical Tutorial on Modified Condition/Decision Coverage". NASA technical memorandum; the practical reference on MC/DC, including unique-cause vs masking MC/DC, coupled-condition handling, and the tool-qualification and structural-coverage pitfalls that make a fixed per-expression test count tool- and interpretation-dependent.

Tooling references (counter semantics)

Coverage and AI-generated tests

  • Hora, A., & Robbes, R. (2026). "Are Coding Agents Generating Over-Mocked Tests? An Empirical Study". MSR 2026. Evidence that coding-agent commits often touch tests and mocks, supporting explicit over-mocking review. (Model-researched external source; central to the over-mocking failure mode.)
  • Yoshimoto, S., Fujita, S., Horikawa, K., Feitosa, D., Kashiwa, Y., & Iida, H. (2026). "Testing with AI Agents: An Empirical Study of Test Generation Frequency, Quality, and Coverage". MSR 2026. Study of AI-authored test additions and their coverage effects. (Model-researched external source.)
  • KeelCode. (2025). "When AI tests pass but your code still breaks". Practitioner account of the LLM-test "safety illusion": coverage rises while defect detection falls, reporting LLM-generated suites near ~20% mutation score on complex functions. Vendor-adjacent blog, NOT an empirical anchor — cited only for the failure-mode framing and the order-of-magnitude direction of the coverage-vs-mutation gap; the ~20% figure is a single practitioner data point, not peer-reviewed measurement. Do not cite the number as a benchmark. The peer-reviewed backbone for "coverage ≠ effectiveness" remains Inozemtseva & Holmes (2014) and Namin & Andrews (2009).

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.