Explaining Missing Simulink Coverage
Explain why coverage objectives are missing on a coverage result the user already
has, and what to do about each one — across all objective types (decision,
condition, MCDC, relational boundary, saturation/overflow, lookup-table execution).
Works from an existing cvdata / cvdatagroup, a .cvt file, a
Simulink.SimulationOutput with coverage on, or a Simulink Test result set.
It keeps two questions separate:
- Is this outcome reachable? — for decision/condition/MCDC objectives, answered by
formal proof (SLDV dead-logic detection) joined to the coverage result deterministically.
A provably-dead outcome is a fact.
- If reachable, why wasn't it tested — and if dead, was that intended? — answered by
the agent, reasoning over an input trace (Model Slicer) plus model structure. This is
judgment, always presented as a recommendation.
Requires: MATLAB R2023a+, Simulink Coverage, Simulink Design Verifier (dead-logic
detection), Simulink Check / Model Slicer (input tracing). The skill
never collects coverage — it reads a result that already exists. When SLDV or the Model
Slicer is unavailable, the affected step degrades honestly (see Guardrails), never
fabricating evidence.
When to Use
- User asks why an objective — of any metric — or a specific true/false outcome is
missing, unsatisfied, or uncovered.
- User asks whether uncovered logic is dead code (unreachable) or just untested.
- User asks how to close a coverage gap on a result they already collected — what test
to add, what to filter, or what to change.
- User needs audit-ready triage: provably-dead vs. still-to-test, each traced to its
inputs.
- User points at an existing coverage artifact and asks to explain it.
When NOT to Use
- Collecting coverage / simulating to measure coverage → this skill reads a result, it
does not collect one; tell the user to collect coverage first, then return here.
- Authoring or generating tests →
testing-simulink-models. This skill recommends a
scenario in words; it does not build a harness or generate vectors.
- Design-error detection / fixing runtime defects (divide-by-zero, overflow) →
resolve-design-errors.
- Model compliance against a standard (MISRA, MAB, JMAAB) →
checking-model-compliance.
- Requirement verification → not this skill (it only queries existing links, read-only).
Coverage Sources
All four sources resolve to the one object the analysis consumes — a cvdata /
cvdatagroup. resolveCoverageData normalizes them and makes no decisions; when a
source carries more than one unit, the agent asks which to explain.
| Source |
Holds |
Resolves via |
cvsim result |
cvdata / cvdatagroup |
pass through |
.cvt file |
path |
cvload (cell of cvdata) |
sim w/ coverage |
SimulationOutput |
embedded cvdata var, else cvresults(model) (per-run + cumulative) |
| Simulink Test |
ResultSet |
getCoverageResults (cvdata object array) |
Rules the agent applies: multiple units → always ask which to explain (never merge or
pick silently); cvresults per-run vs. cumulative → cumulative by default, mention the
single-run view exists.
Prerequisites
All script functions live in the skill's scripts/ directory. Call them with
evaluate_matlab_code and project_path set to that folder. Never addpath,
restoredefaultpath, or savepath — altering the session path breaks the coverage tooling.
Use these functions; do not hand-roll resolution, extraction, the SLDV run, the join, or the
trace. The Step-2 join in particular matches SLDV verdicts to outcomes on an exact key — the
agent must never do that matching itself.
| Function |
Inputs → Output |
Role |
resolveCoverageData(source) |
source → {cvdata,model,kind,label}[] |
Normalize sources to a list of units |
getCoverageSummary(cvd) |
one cvdata → covSummary |
Rollups + outcome detail + filter/reduced info |
detectDeadLogicObjectives(model, metrics) |
model + metrics → [dead, status] |
SLDV dead-logic (decision/condition/MCDC only) |
markSldvDeadLogic(covSummary, dead) |
covSummary + dead → covSummary |
Deterministic join — stamp dead, record unmatched/contradictions |
traceObjectiveInputs(model, blockPaths, maxDepth) |
model + paths → [traces, status] |
Slicer: controllable inputs + dependency chain |
The scripts return MATLAB structs. Their exact output contracts — field names, nesting,
what an absent field means — are documented in references/script-outputs.md; consume
the returns by that reference rather than probing fieldnames and guessing paths. Deeper
method detail lives in references (load on demand): SLDV recipe + join semantics in
references/dead-logic-analysis.md; classification + scenario composition in
references/explaining-and-resolving.md; filter authoring in
references/coverage-filter-api.md (load after filter approval, Step 3); read-only
requirement traceability in references/requirements-tracing.md (load when prioritizing
by requirement linkage, Step 3).
Workflow
Three steps. Step 1 is cheap and always safe; Steps 2–3 run the expensive engines and are
gated — do not run them for a plain "summarize" request.
1. Summarize coverage → resolveCoverageData + getCoverageSummary
2. Locate missing objectives → collect uncovered outcomes; if any decision/condition/MCDC
are uncovered, detectDeadLogicObjectives + markSldvDeadLogic
3. Explain and resolve → traceObjectiveInputs on the owning blocks; agent explains
Step 1 — Summarize coverage
cands = resolveCoverageData(source). The source's model must be loaded first — if it
isn't open or on the path, load_system it (not addpath). If numel(cands) > 1, ask
which unit(s) to explain. For a sim yielding per-run and cumulative, default to cumulative
and say so.
covSummary = getCoverageSummary(cands(k).cvdata).
- Render a summary: total satisfied / total, then a worst-first table of systems by
unsatisfied count (
kind == 'system' nodes — the model root and each subsystem/chart, not
subsystems only; omit fully-covered ones). Name the enabled metrics.
Gate. Stop here unless the user asked why coverage is missing or how to improve it.
Step 2 — Locate missing objectives
- Collect the uncovered Tier-2 outcomes (
covered == false). If none, STOP — report
full coverage on the enabled metrics.
- Run SLDV only if at least one uncovered outcome is decision / condition / MCDC (the
metrics SLDV dead-logic covers). Otherwise skip it and go to Step 3.
- If running it:
[dead, status] = detectDeadLogicObjectives(model, metrics); % dead-eligible metrics present
covSummary = markSldvDeadLogic(covSummary, dead); % exact-key join; do NOT match by hand
- Present the outcomes in their reachability states (detail in
references/dead-logic-analysis.md):
- Provably dead — SLDV
ran and the join stamped dead == true (fact).
- Reachable, stated cautiously — decision/condition/MCDC, SLDV
ran, not stamped
dead: "SLDV found no dead logic here, so it needs a test." Not a completeness proof.
- Deadness not established — SLDV
skipped_no_license / error, or a
non-SLDV-analyzable metric (relational / saturation / lookup-table). State the reason.
Step 3 — Explain and resolve
Trace the owning blocks of the uncovered outcomes in one batch, then reason over the
evidence (full method in references/explaining-and-resolving.md):
[traces, status] = traceObjectiveInputs(model, blockPaths);
- Judge intent from the traced evidence — the controllable inputs and what each block in
the chain computes. A control pinned by a
Constant/configuration, or a defensive guard
the trace shows can't be reached in this context (a range clamp, a divide-by-zero guard) →
likely intentional (recommend a coverage filter, Justify mode —
references/explaining-and-resolving.md, references/coverage-filter-api.md). A dead
branch tracing to controllable inputs → likely unintentional (recommend a design review).
When the trace leaves intent unclear, use model_read / model_overview for more context.
- Compose a test scenario for testable outcomes: invert the required condition from the
chain (Switch
y = (u2 >= 5) ? …, false uncovered → drive u2 < 5), stated in the
controllable inputs. Group outcomes sharing inputs — one test often closes several.
- When a trace is
method == "unavailable", fall back to model_read /
model_overview on that block; never fabricate inputs or a chain.
- When prioritizing which outcomes to test first — or whenever the user asks what to
address first — check requirement linkage (read-only,
references/requirements-tracing.md) if Requirements Toolbox is available: a
linked + uncovered outcome is "untested but required" (cite the requirement ID) and
outranks an unlinked one; an unlinked outcome is lower priority (a hint the logic may be
unrequired — surface it, do not conclude it). If Requirements Toolbox is unavailable, say
so and prioritize without it.
Writing a .cvf filter or editing the model is Ask First (Guardrails).
Guardrails
Always
- State the resolved unit (model, label, per-run vs. cumulative) and enabled metrics in the
summary header.
- Report covSummary counts verbatim; the two coverage tiers agree by construction — do not
recompute them.
- Separate fact from judgment in every finding ("SLDV proved this unreachable" vs.
"this appears intentional because the control is a constant").
- Signal honestly when an engine did not run:
status == "skipped_no_license" / "error"
and per-block method == "unavailable" mean not performed — say so.
- Group testable outcomes by shared inputs and note when one test closes several.
Ask First
- Which unit to explain, whenever the source resolves to more than one.
- Writing a coverage filter (
.cvf) — present the rule and rationale; write only on
explicit approval, using the engineer's rationale (never fabricated).
- Editing the model — present the change; apply only on explicit approval, never
silently to the original.
Never
- Never declare an outcome "dead code, safe to filter" as fact. SLDV proves
unreachability; whether dead logic is intentional and filterable is the engineer's
audit call. Present evidence + a recommendation.
- Never index-match SLDV verdicts to outcomes by hand —
markSldvDeadLogic owns the join.
- Never call a completed-SLDV "no dead logic" result a completeness proof — a timeout
(
status == -1) can hide deadness.
- Never modify the MATLAB path (
addpath / restoredefaultpath / savepath).
Common Mistakes
| Mistake |
Fix |
| Running SLDV / Slicer for a "summarize" request |
Step 1 only; gate on wanting the why |
| Running SLDV when no decision/condition/MCDC outcome is uncovered |
SLDV covers those three metrics only; skip otherwise |
| Reporting "provably dead" when SLDV was skipped/errored |
Nothing is provably dead without a completed SLDV run |
| Calling non-D/C/MCDC gaps "reachable" |
SLDV can't analyze them; state deadness as not established |
| Matching SLDV results to outcomes in the agent |
Call markSldvDeadLogic; consume dead_analysis |
| Classifying dead logic from block names |
Classify from the dependency chain + model_read |
Fabricating a chain when method == "unavailable" |
Fall back to model_read / model_overview |
| Silently picking one cvdata from many |
Ask which unit to explain |
Copyright 2026 The MathWorks, Inc.
1---2name: simulink-explain-missing-coverage3description: Use this skill when the user asks to summarize, or asks why Simulink Coverage objectives are missing, unsatisfied, or uncovered on a coverage result they already have — why specific decision, condition, MCDC, relational-boundary, or saturation/overflow outcomes weren't exercised, whether uncovered logic is dead code, or how to close the gap (a test, a coverage filter, or a design change). It reads an existing cvdata, .cvt file, sim-with-coverage output, or Simulink Test result; it never runs cvsim to collect coverage.4license: https://www.mathworks.com/content/dam/mathworks/license/pmrl/lic5---6
7# Explaining Missing Simulink Coverage
8
9Explain *why* coverage objectives are missing on a coverage result the user **already
10has**, and *what to do* about each one — across **all** objective types (decision,
11condition, MCDC, relational boundary, saturation/overflow, lookup-table execution).
12Works from an existing `cvdata` / `cvdatagroup`, a `.cvt` file, a
13`Simulink.SimulationOutput` with coverage on, or a Simulink Test result set.
14
15It keeps two questions separate:
16
17- **Is this outcome reachable?** — for decision/condition/MCDC objectives, answered by
18 formal proof (SLDV dead-logic detection) joined to the coverage result deterministically.
19 A provably-dead outcome is a *fact*.
20- **If reachable, why wasn't it tested — and if dead, was that intended?** — answered by
21 the agent, reasoning over an input trace (Model Slicer) plus model structure. This is
22 judgment, always presented as a recommendation.
23
24**Requires:** MATLAB R2023a+, Simulink Coverage, Simulink Design Verifier (dead-logic
25detection), Simulink Check / Model Slicer (input tracing). The skill
26**never collects coverage** — it reads a result that already exists. When SLDV or the Model
27Slicer is unavailable, the affected step degrades honestly (see Guardrails), never
28fabricating evidence.
29
30## When to Use
31
32- User asks **why** an objective — of any metric — or a specific true/false outcome is
33 missing, unsatisfied, or uncovered.
34- User asks whether uncovered logic is **dead code** (unreachable) or just **untested**.
35- User asks **how to close** a coverage gap on a result they already collected — what test
36 to add, what to filter, or what to change.
37- User needs **audit-ready triage**: provably-dead vs. still-to-test, each traced to its
38 inputs.
39- User points at an existing coverage artifact and asks to explain it.
40
41## When NOT to Use
42
43- **Collecting coverage / simulating to measure coverage** → this skill reads a result, it
44 does not collect one; tell the user to collect coverage first, then return here.
45- **Authoring or generating tests** → `testing-simulink-models`. This skill recommends a
46 scenario in words; it does not build a harness or generate vectors.
47- **Design-error detection / fixing runtime defects** (divide-by-zero, overflow) →
48 `resolve-design-errors`.
49- **Model compliance against a standard** (MISRA, MAB, JMAAB) → `checking-model-compliance`.
50- **Requirement verification** → not this skill (it only *queries* existing links, read-only).
51
52## Coverage Sources
53
54All four sources resolve to the one object the analysis consumes — a `cvdata` /
55`cvdatagroup`. `resolveCoverageData` normalizes them and makes **no** decisions; when a
56source carries more than one unit, the agent asks which to explain.
57
58| Source | Holds | Resolves via |
59|---|---|---|
60| `cvsim` result | `cvdata` / `cvdatagroup` | pass through |
61| `.cvt` file | path | `cvload` (cell of `cvdata`) |
62| `sim` w/ coverage | `SimulationOutput` | embedded cvdata var, else `cvresults(model)` (per-run + cumulative) |
63| Simulink Test | `ResultSet` | `getCoverageResults` (cvdata object array) |
64
65Rules the agent applies: **multiple units → always ask** which to explain (never merge or
66pick silently); **`cvresults` per-run vs. cumulative → cumulative by default**, mention the
67single-run view exists.
68
69## Prerequisites
70
71All script functions live in the skill's `scripts/` directory. Call them with
72`evaluate_matlab_code` and `project_path` set to that folder. **Never `addpath`,
73`restoredefaultpath`, or `savepath`** — altering the session path breaks the coverage tooling.
74
75Use these functions; do not hand-roll resolution, extraction, the SLDV run, the join, or the
76trace. The Step-2 join in particular matches SLDV verdicts to outcomes on an exact key — the
77agent must **never** do that matching itself.
78
79| Function | Inputs → Output | Role |
80|---|---|---|
81| `resolveCoverageData(source)` | source → `{cvdata,model,kind,label}[]` | Normalize sources to a list of units |
82| `getCoverageSummary(cvd)` | one `cvdata` → covSummary | Rollups + outcome detail + filter/reduced info |
83| `detectDeadLogicObjectives(model, metrics)` | model + metrics → `[dead, status]` | SLDV dead-logic (decision/condition/MCDC only) |
84| `markSldvDeadLogic(covSummary, dead)` | covSummary + dead → covSummary | **Deterministic join** — stamp `dead`, record unmatched/contradictions |
85| `traceObjectiveInputs(model, blockPaths, maxDepth)` | model + paths → `[traces, status]` | Slicer: controllable inputs + dependency chain |
86
87The scripts return MATLAB structs. Their exact output contracts — field names, nesting,
88what an absent field means — are documented in **`references/script-outputs.md`**; consume
89the returns by that reference rather than probing `fieldnames` and guessing paths. Deeper
90method detail lives in references (load on demand): SLDV recipe + join semantics in
91**`references/dead-logic-analysis.md`**; classification + scenario composition in
92**`references/explaining-and-resolving.md`**; filter authoring in
93**`references/coverage-filter-api.md`** (load after filter approval, Step 3); read-only
94requirement traceability in **`references/requirements-tracing.md`** (load when prioritizing
95by requirement linkage, Step 3).
96
97---
98
99## Workflow
100
101Three steps. Step 1 is cheap and always safe; Steps 2–3 run the expensive engines and are
102**gated** — do not run them for a plain "summarize" request.
103
104```
1051. Summarize coverage → resolveCoverageData + getCoverageSummary
1062. Locate missing objectives → collect uncovered outcomes; if any decision/condition/MCDC
107 are uncovered, detectDeadLogicObjectives + markSldvDeadLogic
1083. Explain and resolve → traceObjectiveInputs on the owning blocks; agent explains
109```
110
111### Step 1 — Summarize coverage
112
1131. `cands = resolveCoverageData(source)`. The source's model must be loaded first — if it
114 isn't open or on the path, `load_system` it (not `addpath`). If `numel(cands) > 1`, **ask**
115 which unit(s) to explain. For a `sim` yielding per-run and cumulative, default to cumulative
116 and say so.
1172. `covSummary = getCoverageSummary(cands(k).cvdata)`.
1183. Render a summary: total satisfied / total, then a **worst-first** table of systems by
119 unsatisfied count (`kind == 'system'` nodes — the model root and each subsystem/chart, not
120 subsystems only; omit fully-covered ones). Name the enabled metrics.
121
122**Gate.** Stop here unless the user asked *why* coverage is missing or *how* to improve it.
123
124### Step 2 — Locate missing objectives
125
1261. Collect the uncovered Tier-2 outcomes (`covered == false`). **If none, STOP** — report
127 full coverage on the enabled metrics.
1282. Run SLDV **only if** at least one uncovered outcome is decision / condition / MCDC (the
129 metrics SLDV dead-logic covers). Otherwise skip it and go to Step 3.
1303. If running it:
131 ```matlab
132 [dead, status] = detectDeadLogicObjectives(model, metrics); % dead-eligible metrics present
133 covSummary = markSldvDeadLogic(covSummary, dead); % exact-key join; do NOT match by hand
134 ```
1354. Present the outcomes in their reachability states (detail in
136 `references/dead-logic-analysis.md`):
137 - **Provably dead** — SLDV `ran` and the join stamped `dead == true` (fact).
138 - **Reachable, stated cautiously** — decision/condition/MCDC, SLDV `ran`, not stamped
139 dead: "SLDV found no dead logic here, so it needs a test." Not a completeness proof.
140 - **Deadness not established** — SLDV `skipped_no_license` / `error`, or a
141 non-SLDV-analyzable metric (relational / saturation / lookup-table). State the reason.
142
143### Step 3 — Explain and resolve
144
145Trace the owning blocks of the uncovered outcomes in one batch, then reason over the
146evidence (full method in `references/explaining-and-resolving.md`):
147```matlab
148[traces, status] = traceObjectiveInputs(model, blockPaths);
149```
150
151- **Judge intent from the traced evidence — the controllable inputs and what each block in
152 the chain computes.** A control pinned by a `Constant`/configuration, or a defensive guard
153 the trace shows can't be reached in this context (a range clamp, a divide-by-zero guard) →
154 likely *intentional* (recommend a coverage filter, Justify mode —
155 `references/explaining-and-resolving.md`, `references/coverage-filter-api.md`). A dead
156 branch tracing to controllable inputs → likely *unintentional* (recommend a design review).
157 When the trace leaves intent unclear, use `model_read` / `model_overview` for more context.
158- **Compose a test scenario** for testable outcomes: invert the required condition from the
159 chain (Switch `y = (u2 >= 5) ? …`, false uncovered → drive `u2 < 5`), stated in the
160 controllable inputs. **Group** outcomes sharing inputs — one test often closes several.
161- **When a trace is `method == "unavailable"`**, fall back to `model_read` /
162 `model_overview` on that block; never fabricate inputs or a chain.
163- **When prioritizing which outcomes to test first — or whenever the user asks what to
164 address first — check requirement linkage** (read-only,
165 `references/requirements-tracing.md`) if Requirements Toolbox is available: a
166 linked + uncovered outcome is "untested but required" (cite the requirement ID) and
167 outranks an unlinked one; an unlinked outcome is lower priority (a hint the logic may be
168 unrequired — surface it, do not conclude it). If Requirements Toolbox is unavailable, say
169 so and prioritize without it.
170
171Writing a `.cvf` filter or editing the model is **Ask First** (Guardrails).
172
173---
174
175## Guardrails
176
177### Always
178- State the resolved unit (model, label, per-run vs. cumulative) and enabled metrics in the
179 summary header.
180- Report covSummary counts verbatim; the two coverage tiers agree by construction — do not
181 recompute them.
182- Separate **fact** from **judgment** in every finding ("SLDV proved this unreachable" vs.
183 "this appears intentional because the control is a constant").
184- Signal honestly when an engine did not run: `status == "skipped_no_license"` / `"error"`
185 and per-block `method == "unavailable"` mean *not performed* — say so.
186- Group testable outcomes by shared inputs and note when one test closes several.
187
188### Ask First
189- **Which unit** to explain, whenever the source resolves to more than one.
190- **Writing a coverage filter** (`.cvf`) — present the rule and rationale; write only on
191 explicit approval, using the engineer's rationale (never fabricated).
192- **Editing the model** — present the change; apply only on explicit approval, never
193 silently to the original.
194
195### Never
196- **Never declare an outcome "dead code, safe to filter" as fact.** SLDV proves
197 unreachability; whether dead logic is intentional and filterable is the engineer's
198 audit call. Present evidence + a recommendation.
199- **Never index-match SLDV verdicts to outcomes by hand** — `markSldvDeadLogic` owns the join.
200- **Never call a completed-SLDV "no dead logic" result a completeness proof** — a timeout
201 (`status == -1`) can hide deadness.
202- **Never modify the MATLAB path** (`addpath` / `restoredefaultpath` / `savepath`).
203
204## Common Mistakes
205
206| Mistake | Fix |
207|---|---|
208| Running SLDV / Slicer for a "summarize" request | Step 1 only; gate on wanting the *why* |
209| Running SLDV when no decision/condition/MCDC outcome is uncovered | SLDV covers those three metrics only; skip otherwise |
210| Reporting "provably dead" when SLDV was skipped/errored | Nothing is provably dead without a completed SLDV run |
211| Calling non-D/C/MCDC gaps "reachable" | SLDV can't analyze them; state deadness as *not established* |
212| Matching SLDV results to outcomes in the agent | Call `markSldvDeadLogic`; consume `dead_analysis` |
213| Classifying dead logic from block names | Classify from the dependency chain + `model_read` |
214| Fabricating a chain when `method == "unavailable"` | Fall back to `model_read` / `model_overview` |
215| Silently picking one cvdata from many | Ask which unit to explain |
216
217----
218
219Copyright 2026 The MathWorks, Inc.
220
221----