This repository contains the Quarto / Reveal.js talk deck and reproducible analysis for the MOVA talk Why Vulnerability MTTR Alone Misleads.
The central claim is simple: MTTR can rise while backlog age falls. MTTR reflects the age of work that got closed. MOVA (Mean Open Vulnerability Age) measures backlog age: the age of the work still open today. When a team finally closes older backlog, the age of closed work goes up, so MTTR can look worse even while the remaining backlog gets healthier.
The talk is grounded in a real operational pattern, but the repo stays vendor-neutral and reproducible. The examples use deterministic synthetic data, and the metric definitions, charts, and tables all live in code rather than dashboard screenshots or hidden platform logic.
- MTTR reflects flow: the age of work that got closed.
- MOVA measures backlog age: the age of work still open today.
- MTTR alone can reward closing recent work while older backlog remains.
- Open count and a threshold like
180+ days openhelp show whether the aging tail is actually shrinking. - The point is not to replace MTTR. It is to stop using MTTR alone.
index.qmd: the talk deck sourcescripts/01_generate_data.py: builds the deterministic synthetic backlog and arrivalsscripts/02_simulate_metrics.py: simulates monthly metrics foroldest_firstandnewest_firstscripts/03_build_outputs.py: writes the end-state comparison used in the deck_quarto.ymlandstyles.css: deck configuration and presentation stylingpyproject.tomlanduv.lock: Python dependencies for the analysis pipeline
Generated artifacts are created during render under data/ and _output/.
The deck uses a small reproducible simulation to isolate prioritization:
- same starting backlog
- same deterministic arrival pattern (with realistic variability)
- same deterministic capacity pattern (shared across strategies)
- same 24-month horizon
- only the work order changes:
newest_firstvs.oldest_first
Both strategies operate on the exact same arrivals and capacity each month. Only prioritization changes.
Small deterministic variability is introduced to avoid perfectly smooth charts while keeping the comparison fair.
That makes the tradeoff explicit:
- Newest-First keeps MTTR lower by closing newer findings first.
- Oldest-First raises MTTR while lowering MOVA and shrinking the
180+ daystail. - If you look only at MTTR, you pick the wrong winner.
The published materials use this structure:
- Landing page: https://typeerror.com/mova
- Talk deck: https://typeerror.com/mova/slides/
- BSides Charm listing: https://pretalx.com/bsidescharm2026/talk/MMNUPD/
In the published output, docs/index.html is the landing page and docs/slides/index.html is the talk.
uv sync
uv run quarto renderuv run quarto render runs the pre-render scripts in _quarto.yml, regenerates the synthetic data and comparison outputs, and writes the local deck to _output/index.html.
For live preview while editing:
uv run quarto previewTo render the published deck into docs/slides for GitHub Pages:
quarto render index.qmd --output-dir docs/slidesThis keeps local development output in _output/ and published output in docs/slides/.
- Quarto keeps the deck, narrative, and rendered outputs in one reproducible workflow.
- Positron is a convenient place to inspect the data and iterate on the analysis before rendering, though the workflow does not depend on any particular IDE.
- Shiny for Python is useful for lightweight interactive checks when testing metric definitions and backlog slices.
- Polars implements the metric logic.
- Plotnine and Great Tables keep charts and tables in code so the analysis stays inspectable and rerunnable.
- Python Polars: The Definitive Guide by Jeroen Janssens and Thijs Nieuwdorp
- Effective Vulnerability Management: Managing Risk in the Vulnerable Digital Ecosystem by Chris Hughes and Nikki Robinson
MIT License