Checks an already-written risk matrix against what actually happened. Maps each row's likelihood rating to observed defect density, test failure rate and code churn, maps its impact rating to the severity mix and escape rate, then classifies each row as over-stated, under-stated, in-agreement, or not calibrated, using stated reporting thresholds so small differences are not treated as findings. Every proposed rating change carries the observation that produced it, and every proposal is handed to the matrix owner rather than applied. Also emits candidate new entries for areas that show up in defect data but have no row. Owns calibration only: choosing a scoring methodology, designing the matrix structure, picking risk categories, mapping risks to test types, FMEA scoring, review cadence and file storage are all out of scope. Use when a matrix has been driving test decisions for at least three releases and nobody has yet checked whether its ratings match the defects, escapes and incidents that followed.
75
94%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
A risk matrix records what a team believed, at authoring time, about how likely each area is to fail and how bad that failure would be. Risk-based testing is defined by ISTQB as "a test approach in which the management, selection, prioritization, and use of test activities and resources are based on corresponding risk types and risk levels" (https://glossary.istqb.org/en_US/term/risk-based-testing), so those ratings directly control where test effort goes. Lightweight risk assessment scores a row on two factors, likelihood and impact (https://en.wikipedia.org/wiki/Risk-based_testing).
Calibration asks one question: over the window that has since elapsed, did the things the matrix said were likely and severe actually turn out to be likely and severe? The output is a set of proposed rating changes, each attached to the observation that produced it, for the matrix owner to accept or reject.
This is the after-the-fact check, not the authoring pass. The axis is already-written ratings versus observed outcomes.
| In scope here | Out of scope here |
|---|---|
| Choosing which observed signal corresponds to each matrix dimension | Choosing lightweight versus heavyweight methodology |
| Turning observations into a comparable rating on the matrix's own scale | Designing the matrix columns, heatmap or banding |
| Deciding whether a difference is large enough to report | Picking the risk category taxonomy |
| Wording a proposed change so the owner can audit it | Deciding which test types a risk maps to |
| Surfacing areas absent from the matrix that the defect data insists on | FMEA severity / occurrence / detectability scoring |
| Naming the evidence gaps that leave a row uncalibratable | Review cadence, file layout, version control |
If the matrix does not yet exist, or its rows have no consistent feature
column and no consistent score format, there is nothing here to calibrate
against. Author or restructure it first. A skill named risk-matrix covers
that authoring work.
Calibration is also not prediction. It reports what was observed in a closed historical window. It does not forecast next quarter's defects, and it does not fit a model. That restraint is deliberate: only 19.9% of teams surveyed in the PractiTest State of Testing 2026 report use AI for risk identification, against 70% for test case creation (https://www.practitest.com/state-of-testing/), and unsourced predictive scoring at the decision layer is exactly what that gap is made of.
Observed defect data is a lagging and biased signal, and calibration is only as good as that signal. Read this section before running any of the steps below, because it changes what the numbers are allowed to conclude.
You only see defects in code that was tested and used. A row with zero defects in the window has at least three possible explanations:
No amount of defect data distinguishes these three. Absence of evidence in a defect tracker is not evidence of low likelihood. The practical rule that follows is in Step 3: a zero-defect row is never grounds for lowering a likelihood rating on its own. It is grounds for asking which of the three explanations applies, and reporting the answer.
Two further biases are worth naming explicitly:
State these limits in the report itself, not only here. A reader who does not know the data is biased will read a proposed downgrade as a fact.
Each of the two rating dimensions gets its own set of observed signals. Use more than one signal per dimension so that a single weak measurement cannot move a rating on its own.
| Matrix dimension | Primary observed signal | Corroborating signals |
|---|---|---|
| Likelihood | Defect density for the row's source paths, meaning "the number of defects per unit size of a work product" (https://glossary.istqb.org/en_US/term/defect-density) | Failure rate of the tests that cover the row over the window; code churn for the same paths |
| Impact | Severity mix of the row's defects, typically the share at the team's top two severity levels | Escape rate, meaning the share of the row's defects that were "not detected by a test activity that is supposed to find it" (https://glossary.istqb.org/en_US/term/escaped-defect); incident or SLO-breach correlation where the team records it |
The published results behind both rules (Nagappan and Ball; Zimmermann et al.), with their caveats, are in references/empirical-basis.md.
Produce an observed likelihood and an observed impact on the same 1 to 5 scale the matrix already uses. Do not invent a new scale, and do not normalise across teams: severity labels mean different things in different trackers, so a calibration is valid only inside the conventions of the tracker it read.
The team's own authoring rubric supplies the cut points. If the matrix says likelihood 4 means "expected to fail in most releases", express the observed density in those terms rather than in a generic band. Where the matrix has no written rubric, say so in the report and mark every proposed change as provisional, because without a rubric the comparison is between one person's judgement and another's.
Record, for each row, all of:
That last item is the honesty control. A row whose observed rating rests on two defects is a rating with a wide error bar, and the report should show the count so a reader can discount it.
Most rows will differ from their observations by a little. Reporting those differences buries the ones that matter and trains the owner to skim the report.
These are practitioner conventions, not standards. No published standard sets them. The reasoning for each cut is given so a team can move it with its eyes open.
| Threshold | Convention | Why this cut |
|---|---|---|
| Per-dimension difference | Report at 2 or more points on a 1 to 5 scale | One point is inside the spread two people produce scoring the same row independently, which is a known weakness of subjective scoring. Two points is the smallest gap that is unlikely to be scorer noise. |
| Combined score difference | Report at 4 or more points of likelihood times impact | Under a common 5x5 banding (low 1-4, medium 5-8, high 9-14, critical 15 and up) the narrowest band is four points wide, so a smaller change cannot by itself move a row out of its band, and a change that does not move the band does not change any decision. |
| Minimum window | At least 3 releases, or one quarter, whichever is longer | A single release usually yields a single-digit defect count per row, and single-digit counts move by 100% on one incident. Below this the observation has less authority than the authoring judgement it would overturn. |
| Minimum defect count per row | State the count; treat fewer than 5 defects as directional only | Below roughly five events, a rating change is being driven by individual incidents rather than by a rate. |
Rows that clear a threshold fall into one of three classifications.
The matrix rates the row higher than the observations support.
Report it as over-stated only after ruling out the three explanations in the biased-data section above. Specifically:
The matrix rates the row lower than the observations support. This is the finding calibration exists to produce, and it is the one least vulnerable to the absence-of-evidence problem: defects that happened, happened.
Strengthen it with corroboration. An under-stated finding is strongest when defect density, test failure rate and escape rate all point the same way, and weakest when only churn does.
An area that the defect data keeps naming has no row in the matrix at all, or has a row whose observations cannot be computed.
Two sub-cases, and they get different wording:
A rating change is a proposal for a human to accept, never an automatic edit. The matrix is a team artifact, usually version controlled and usually owned by a named person. Calibration produces a diff for review, and stops there.
The rule that makes review possible: every dimension of every proposed change names the observation behind it. Not a summary of the observation, a citation of it, precise enough that the owner can re-run the same query and see the same number.
A citation is adequate when it carries all four of:
A proposed change missing any of the four is not reportable. A reviewer who cannot check the number is being asked to trust a black box, and a black box that edits the team's risk ratings is worse than no calibration at all.
Areas absent from the matrix that the defect data insists on are output as candidates, listed with their supporting observations and a suggested starting rating. They are never added automatically. The matrix owner decides whether the area deserves its own row or belongs inside an existing one, and that decision is about how the team models its own system, not about the data.
Two entry conditions, both practitioner conventions and both self-calibrating to the team's own data rather than to an absolute number:
Self-calibrating conditions are preferred here because an absolute cut (say, "5 or more defects") means something different for a two-person project and a two-hundred-person one.
For each candidate, propose a starting likelihood and impact, and say plainly which half of the proposal is weaker. Impact is usually the weaker half: defect data shows what broke, not what the breakage cost the user, and that translation is a product judgement.
A full calibration report - summary, under-stated (R-12) and over-stated (R-03) findings with every dimension citing value / source / window / event count, not-calibrated rows, a candidate new entry, and the "what was not done" footer - is in references/worked-example.md.
| Anti-pattern | Why it fails | Fix |
|---|---|---|
| Treating "no defects in the window" as evidence for likelihood 1 | Could equally mean untested or unused. The data cannot distinguish the three. | Cross-check test executions and production usage first; if either is near zero, report a coverage or exposure gap instead (Step 3.1). |
| Ranking rows by raw defect count | Conflates a small busy area with a large stable one. | Normalise to defect density per the ISTQB definition (https://glossary.istqb.org/en_US/term/defect-density) and state the denominator. |
| Leading a rating change with churn | Churn is a correlate of where work happens, not a cause of defects, and only relative churn predicted anything in the published result. | Lead with defect density and severity mix; use churn to corroborate a direction only (Step 1). |
| Importing a published defect-prediction coefficient | Cross-project transfer fails even within the same domain and process (https://api.openalex.org/works/doi:10.1145/1595696.1595713). | Calibrate against the team's own history using the team's own rubric. |
| Reporting every difference | One-point differences are scorer noise; a full report of them buries the real findings. | Apply the Step 3 thresholds and say in the report that they are conventions. |
| Editing the matrix directly | The matrix is a team artifact with an owner; a silent edit destroys the record of who believed what and when. | Emit proposals; the owner applies them (Step 4). |
| A proposed change with a bare number and no source | The reviewer cannot re-derive it, so the ask is unauditable. | Every dimension carries value, source, window and event count (Step 4). |
| Auto-adding candidate entries | Whether an area deserves its own row is a modelling decision about the system, not a data question. | Surface candidates with observations and a suggested rating; the owner decides (Step 5). |
| Extending the report into a forecast | The window is closed history; projecting from it is a different technique with different error properties, and unsourced prediction is what erodes trust in the whole exercise. | Report observed divergence only. |
| Comparing severity across teams | Severity labels are local conventions; an S1 in one tracker is an S2 in another. | Calibrate within one tracker's conventions and say so. |