Skip to content
Back to skills

Principles

ASecurity

Metric literacy for what this plugin reports: what each measure means, where each reference value comes from, and what none of them can tell a reader. Use when: 'what does cyclomatic complexity mean', 'is CRAP a real metric', 'why is the cyclomatic reference 20', 'what is a good coverage number', 'which metric should I look at', 'code metrics principles'. The numbers themselves: the /code-metrics:audit-* skills.

  • 13 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 12, 2026
ai-agentstypescriptpythongobashexpresstestinggit

Security analysis

A100/100

Pro scans all 6 files and shows the line behind each finding

Scanned October 4, 2026

npx -y skills add melodic-software/claude-code-plugins --skill principles --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Principles?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Principles
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/melodic-software-principles-a6b951e9/badge)](https://www.skillsdirectory.com/skills/melodic-software-principles-a6b951e9)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
description: "Metric literacy for what this plugin reports: what each measure means, where each reference value comes from, and what none of them can tell a reader. Use when: 'what does cyclomatic complexity mean', 'is CRAP a real metric', 'why is the cyclomatic reference 20', 'what is a good coverage number', 'which metric should I look at', 'code metrics principles'. The numbers themselves: the /code-metrics:audit-* skills."
argument-hint: "[question or concept]"
user-invocable: true
disable-model-invocation: false
metadata:
  workflow-stage: anytime
  summary: What each code measure can and cannot tell you
---

# Code metrics knowledge base

The five `audit-*` skills in this plugin print numbers with their provenance and stop. This skill
says what each number means, where its reference value came from, and where reading it as a verdict
goes wrong. It renders no verdict of its own, and neither does the plugin: a reference is a value to
count against, never a bar, and no skill here emits a finding, a severity, or an exit-code gate,
because a finding needs a measured corpus sweep behind it and none has been run. Reference files in
`reference/` are source-attributed; the sections below answer the common questions without a load.

## Routing table

| Query about... | Load |
|---|---|
| What a measure is, its formula, per-lane collector behavior, coverage artifact formats | [measures.md](reference/measures.md) |
| Where a reference value came from, which popular numbers have no source, how to set your own | [thresholds.md](reference/thresholds.md) |
| The CRAP formula, its two authorial names, the coverage join, what it does not predict | [crap.md](reference/crap.md) |
| Who published what, what a paper claims and does not claim, confidence per source | [literature.md](reference/literature.md) |
| The report vocabulary (`cov_source`, `not-applicable`, `partial`) and the JSON document shape | `${CLAUDE_PLUGIN_ROOT}/reference/report-schema.md` |

Load the one file the question lands in. Load a second only when the first leaves the question open.

## Quick decision guide (no file load needed)

- **"Which measure should I look at?"**. Start from the question, not from the report. How much
  testing a function needs is cyclomatic complexity: McCabe 1976 defines it as the size of a basis
  set of paths, and NIST SP 500-235 makes that the number of tests a module needs. How hard a
  function is to read is cognitive complexity: Campbell's measure penalizes nesting and charges a
  `switch` and all its cases once. Whether a diff is too large or copied is lines per file and
  duplication over the changed files, the two measures ISO/IEC 5055 files as weaknesses (CWE-1080
  and CWE-1041). Whether the suite would catch a fault is not a coverage question: coverage records
  which lines executed, the primary literature disagrees on how well that predicts fault detection,
  and the owner of that question is behind the mutation-testing gate below. No measure here ranks
  changes by risk.
- **"Is 22 the cyclomatic threshold?"**. No source this plugin cites attributes 22 to anyone. The
  bundled reference is 20, from ISO/IEC 5055:2021 §8.2.117, with 10 (McCabe 1976) and 15 (NIST SP
  500-235) as the cited alternatives you can select.
- **"What is a good coverage number?"**. No standard sets one, so this plugin ships no coverage
  reference. A percentage counts executed lines; it says nothing about whether anything was checked.
- **"Is 8% duplication bad?"**. No duplication reference ships, so the report counts nothing as
  over. The percentage moves with `duplication.min_tokens`, so two runs compare only at the same
  floor, and replication the repository declares in a registry is excluded rather than suppressed.
- **"Is CRAP a real metric?"**. It is real and authored (Savoia and Evans, 2007), and it is not a
  validated change-risk predictor. See [crap.md](reference/crap.md) before quoting a CRAP number.
- **"Is this file too long at 1200 lines?"**. The report tells you it is at or above the reference
  of 1000, which is this plugin's own number. ISO/IEC 5055's normative clause for the same weakness
  is a percentage on a function, not a line count on a file.
- **"Cyclomatic or cognitive?"**. Cyclomatic counts independent paths through a function, which is
  what makes it a testing measure. Cognitive weights nesting and forgives a flat `switch`, which is
  what makes it a readability measure. They disagree on the same function by design.
- **"Halstead difficulty rose when I split the file. Why?"**. Difficulty is `(n1/2) * (N2/n2)`,
  operator variety times operand reuse, with no explicit length term, so it does not track size. A
  split changes each half's operator count and reuse ratio, so per-file difficulty legitimately
  moves on a split, in either direction. Check which collector produced the row: `multimetric`
  reports Halstead per file and `radon` per function.
- **"Type coverage is 96%. Is that good?"**. No standard and no CWE anchors the measure, so there is
  no external answer. The percentage also counts `unknown` as typed, so an `any`-to-`unknown` sweep
  raises it without adding type information.

## Cross-metric caveats

The whole plugin carries these once, here; the `audit-*` skills point at this section rather than
repeating it. Every one of them is a way a true number supports a false conclusion.

- **Coverage responds to tests that assert nothing.** A line is counted as covered when it executed,
  and a test that calls a function without an assertion executes it. Raising a coverage percentage is
  therefore always possible without improving the suite, which is why no coverage reference ships and
  why the number is reported beside the code rather than as a score.
- **A complexity refactor usually moves complexity rather than removing it.** Splitting a function of
  cyclomatic 30 into six functions leaves roughly the same number of paths in the file and turns one
  measured row into six smaller ones. Per-function complexity falls, the file's total does not, and
  the reader who compares only the maximum sees an improvement that the sum of the rows denies.
- **Duplication drops the moment you extract a helper, whether or not that helped.** The measure
  counts repeated token runs and has no view of whether the two copies change for the same reason,
  and the extraction leaves both call sites depending on the new helper. Some replication is
  deliberate, which is why a declared registry excludes a cluster rather than suppressing it, and
  whether the coupling that replaces it is an improvement is a question this plugin cannot measure.
- **Type coverage counts identifiers whose type is not `any`.** `unknown`, a widened supertype, and a
  falsely narrow annotation all count as typed. The TypeScript percentage and the Python
  Any-expression figures are different measures over different populations and never compare.
- **The measures interact, and none of them composes.** Coverage and complexity combine in CRAP, and
  that is the only combination this plugin computes. A function at 100% coverage and complexity 40
  still has CRAP 40; a small function with three untested branches can outrank a large tested one.
  There is no supported way to add or average these numbers into a quality score, and doing it is
  the mistake this section exists to prevent.

## Owners of the other measures

This plugin does not measure these. Each one has an owner, and each pointer is gated:

- **Surviving mutants and mutation score.** Invoke `/mutation-testing:principles` for what a
  surviving mutant means, and `/mutation-testing:audit` to run one, when the `mutation-testing` plugin is installed;
  otherwise the concern is out of this plugin's scope and nothing here substitutes for it. Coverage
  cannot answer it: a covered line can still be unchecked.
- **Tautological and assertion-free tests.** Invoke `/testing:audit` when the `testing` plugin is installed;
  otherwise the concern is out of this plugin's scope and nothing here substitutes for it.
- **Dead code.** Invoke `/code-tidying:audit-dead-code` when the `code-tidying` plugin is installed;
  otherwise the concern is out of this plugin's scope and nothing here substitutes for it. ISO/IEC
  5055 files dead code as its own weakness (7.1.5, CWE-561), separate from every measure here.
- **Coupling and fan-in.** Invoke `/coupling:reduce` when the `coupling` plugin is installed;
  otherwise the concern is out of this plugin's scope and nothing here substitutes for it.
- **Lint rules and style violations.** Invoke `/toolchain:lint` when the `toolchain` plugin is installed;
  otherwise the concern is out of this plugin's scope and nothing here substitutes for it. A lint
  rule fires a finding; the measures here do not.
- **Comparing two reports.** Feed an audit skill's `--json` document to `/verification:measure metrics` when the `verification` plugin is installed,
  treating a report whose `status` is `empty` on either side as INCONCLUSIVE; otherwise keep the
  JSON beside your notes and compare by hand.

## Sources

- **McCabe**: T. J. McCabe, "A Complexity Measure", IEEE Transactions on Software Engineering
  SE-2(4), December 1976, pp. 308-320.
- **Watson and McCabe**: NIST Special Publication 500-235, *Structured Testing*, September 1996.
- **Halstead**: Maurice H. Halstead, *Elements of Software Science*, Elsevier North-Holland, 1977.
- **Campbell**: G. Ann Campbell, SonarSource, *Cognitive Complexity: a new way of measuring
  understandability*, white paper version 1.7, 29 August 2023.
- **Savoia and Evans**: Alberto Savoia with Bob Evans, Agitar Labs, the CRAP score, July 2007, and
  the Crap4j project FAQ.
- **Lewis et al.**: "Does Bug Prediction Support Human Developers? Findings from a Google Case
  Study", ICSE 2013.
- **Coverage and test effectiveness**: Inozemtseva and Holmes, ICSE 2014; Gopinath, Jensen and
  Groce, ICSE 2014; Kochhar, Thung and Lo, SANER 2015; Jia and Harman, IEEE TSE 2011; Petrovic and
  Ivankovic, ICSE-SEIP 2018; Petrovic, Ivankovic, Fraser and Just, IEEE TSE 2022.
- **ISO/IEC 5055:2021** (the ISO publication of OMG ASCQM v1.0; OMG's current release is v1.1) and
  **ISO/IEC 25023:2016**, cited by clause and version, never by page number.

Per-source annotation, including what each does not claim and the confidence behind it, is in
[literature.md](reference/literature.md).

## Scope boundary

This skill is **knowledge**, not **workflow**. It measures nothing, runs no collector, and reads no
repository. The `audit-*` skills in this plugin produce the numbers; this one explains them, and
deciding what to do about a number is the reader's call.

## Spoke paths

The `reference/` files write the plugin's root directory as `<plugin-root>`, which is
`${CLAUDE_PLUGIN_ROOT}`. Put that path in place of the placeholder before running a command or
writing it into a brief. Those files arrive through the Read tool as plain bytes, so a `${…}` token
in them would reach the Bash tool unsubstituted, and the Bash tool's environment has no
`CLAUDE_PLUGIN_ROOT` to expand it from. Basis: the plugins reference,
<https://code.claude.com/docs/en/plugins-reference#where-each-variable-resolves>, verified
2026-09-30; recheck when that table adds supporting files to where a `${…}` reference resolves.

## Next

- The number in question still has to be measured: `/code-metrics:audit-complexity`, or the
  `audit-*` skill for that measure.
- The bundled reference values are not the ones your codebase can defend: `/code-metrics:setup`.

## Gotchas

- Provenance strength varies inside one report. The cyclomatic reference is normative in a
  standard; the file-line reference is this plugin's own number; cognitive, Halstead, CRAP, coverage,
  and type debt ship `null` because nothing authoritative sets a value. Treating the four as one
  tier is the error [thresholds.md](reference/thresholds.md) exists to prevent.
- A citation for a threshold's existence is not evidence that the threshold predicts defects. The
  empirical literature does not support a fixed default that transfers across projects, and
  [literature.md](reference/literature.md) records which studies say so.
- Two collectors for one measure can disagree on the same function; they implement the same
  definition with different parsers and different variants. The report names the collector per row
  so the number is traceable, and comparing rows from different collectors is not supported.
- CRAP has two authorial expansions and one of them still appears on the authors' own homepage.
  Quoting one as canonical overstates the record; [crap.md](reference/crap.md) carries both.

Files in this skill

  • SKILL.md12.3 KB
  • evals/evals.json3.9 KB
  • reference/crap.md8.2 KB
  • reference/literature.md13.7 KB
  • reference/measures.md11.1 KB
  • reference/thresholds.md8.8 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…