Skip to content

Risk Coverage Matrix

github-actions[bot] edited this page Oct 21, 2026 · 1 revision

Risk Coverage Matrix — risk coverage, residual risk and release readiness (Refs #1951, parent #1066)

The coverage half of the Risk-Based Testing parent feature. The Risk Register (#1930) records what could go wrong; it is CRUD only and never says whether the risky area is actually covered by executed tests. This screen — backed by api/riskcoveragematrix/index.php — turns every risk of the project into a coverage line and ends in a release verdict.

Entry point

  • Screen: gui/templates/risk/riskCoverageMatrix.html (Dashio standalone HTML/JS/CSS)
  • BFF API: api/riskcoveragematrix/index.php
  • ASIDE menu: the Risk Register section (fas fa-exclamation-triangle) now holds two project-scoped items — Risk Register and Risk Coverage Matrix (fas fa-table-cells); shown whenever the user can read test cases (mgt_view_tc or mgt_modify_tc).
  • URL of the action: $actions->riskCoverageMatrix (lib/functions/common.php).
  • Server label: $TLS_title_risk_coverage_matrix in all 19 locale/*/strings.txt.
  • No legacy controller/template to retire — the module is net-new.

What the screen does

Area Behaviour
Verdict banner ready / at_risk / not_ready / no_data with the counts that produced it (avg coverage, avg mitigation, high-risk-low-coverage, failing tests)
Metric tiles Risks, High risk / low coverage, Avg coverage, Avg mitigation, Residual risk, Defects, Not linked
Scope Whole project or a single test plan (executions are restricted to the selected plan)
Filters Level (critical/high/medium/low), coverage state (covered/partial/uncovered/unlinked), Flagged only; explicit no-match empty state
Matrix table DataTable: Risk, Level, Score, Covered by, Coverage (bar), Mitigation (bar), Residual (red), Flags, Actions. Default sort by score desc
Details Read-only modal with the risk fields, the coverage/mitigation/state/residual, the execution breakdown (versions / executed / passed / failed / blocked / defects) and — when linked — the requirement coverage
Locale TLi18n locale switcher; every label/placeholder/message is a key
State cards rcmtx.noProject / rcmtx.noRight / rcmtx.errTitle machine-code states for 400/401/403/404

The model

  • Coverage — share of the linked test case versions actually executed.
  • Mitigation — share of them whose latest result is a pass. A failing test exposes a risk, it does not retire it, so mitigation ≠ coverage.
  • Residual risk — score × (100 − mitigation) / 100 (score = impact × likelihood).
  • High risk / low coverage flag — level ≥ high and coverage < 50 %.
  • Release verdict — ready when there are no flags, avg mitigation ≥ 80 % and no failing linked test; at_risk when avg mitigation ≥ 50 %; otherwise not_ready; no_data when the project has no risks.

Derived level (same scale as the registry): 1–4 low, 5–9 medium, 10–14 high, 15–25 critical.

BFF API — api/riskcoveragematrix/index.php

Session auth + same-origin CSRF guard (bffSameOriginGuard) + inactivity timeout (bffEnforceSession). Read only — there is no write verb at all. Rights are checked on the addressed test project before it is resolved (the #1697 lesson: no existence oracle — an unknown project and a forbidden project both fail closed).

Route Meaning
GET|HEAD ?action=init&tproject_id=N[&tplan_id=M] → {context, domains, stats, verdict, items} the report
GET|HEAD ?action=report&tproject_id=N[&tplan_id=M] alias of init
GET|HEAD ?action=projects {projects:[{id,name,prefix}]}
  • read = mgt_view_tc or mgt_modify_tc on the project.

Machine codes: not_authenticated (401), user_not_found (401), no_right (403), no_testproject (400), wrong_method (405, Allow: GET, HEAD), unknown_action (400), tproject_not_found (404), tplan_not_found (404).

stats counts distinct risks and deliberately separates the linked count from the no_link count (fixing a double-count found during verification). items[] carries the full per-risk breakdown used by the table and the modal.

Schema

The tc_risks table is created lazily via the shared helper api/_riskschema.php (also used by api/risk/index.php) so the DDL can never drift between the two risk endpoints.

i18n

90 rcmtx.* keys plus footers.riskCoverageMatrix in all 10 client bundles (gui/templates/i18n/*.json), plus $TLS_title_risk_coverage_matrix in all 19 server locales. ai/verify_i18n_coverage.sh passes (9231 keys, 9/9 bundles).

Verification

Suite Suite — Issue #1951 in tmp/TLU_Test_Cases.md (14/14 PASS). Verified in the browser as admin: render, verdict, plan scope, the three filters, the detail modal, and the 403 (right-less user) / 404 (unknown project) / empty-project states; console clean; Event Viewer shows only AUDIT rows, 0 new Error/Warning. BFF error paths exercised over curl (401/400/403/404/405). English and Romanian render fully translated. php -l clean on the BFF and the shared helper.

Bug fixed while modernizing this screen (#1952)

The shared lazy-schema helper returned the map of tlObjectWithDB::getDBTables() instead of the table name, so both risk BFFs interpolated the literal Array into their SQL: the DDL created a table named Array, the Risk Register and this matrix read and wrote THAT table instead of tc_risks (which stayed empty), and every screen load logged an E_WARNING Array to string conversion. The helper now returns $t['tc_risks']; the stray rows were migrated into tc_risks (INSERT IGNORE … SELECT, idempotent through uq_risk_project_name) and Array was dropped. Event Viewer 0 new Error/Warning afterwards.

Screenshots

Risk Coverage Matrix — verdict banner, KPI tiles, scope selector and the risk matrix (English) Risk Coverage Matrix — the same report in Romanian

Clone this wiki locally