Repository navigation
Risk Coverage Matrix
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.
- 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_tcormgt_modify_tc). - URL of the action:
$actions->riskCoverageMatrix(lib/functions/common.php). - Server label:
$TLS_title_risk_coverage_matrixin all 19locale/*/strings.txt. - No legacy controller/template to retire — the module is net-new.
| 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 |
- 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 ≥ highandcoverage < 50 %. -
Release verdict —
readywhen there are no flags, avg mitigation ≥ 80 % and no failing linked test;at_riskwhen avg mitigation ≥ 50 %; otherwisenot_ready;no_datawhen the project has no risks.
Derived level (same scale as the registry): 1–4 low, 5–9 medium, 10–14 high, 15–25 critical.
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_tcormgt_modify_tcon 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.
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.
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).
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.
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.
