Coverage¶
Measured on 11 October 2026 against v2026.10.2, the release in
production (main at 7117914), in the working checkout on acc at
c51ec0a — a tree identical to 7117914 — after npm run deps:check
reported "Dependencies are ready.", on Node 22.23.3, the version
.nvmrc names. Each package was measured serially, one workspace at a
time: the backend by npx jest --coverage --runInBand, the Jest command its
test:serial runs, and the four Vitest packages by their own
npm run test:serial. All five collect coverage, as their npm test
counterparts do. Every figure on this page is read from the
coverage/coverage-final.json each of those runs wrote, and checked against
the run's own totals.
Read the backend from coverage-final.json, not from a stale summary
None of the five runner configs asks for istanbul's json-summary
reporter, so no ordinary run writes coverage/coverage-summary.json.
A copy left in packages/backend/coverage/ by an earlier run that did
ask for it — the one in this checkout dates from 30 September — is not
overwritten, and reads 98.90 / 95.14 / 97.98 / 99.20: the 30 September
figures, not today's. The 11 October backend figures below come from
the coverage-final.json and lcov.info that run wrote. To get a
summary file, ask for it, as
Running the tests does with
--coverageReporters=json-summary.
| Package | Statements | Branches | Functions | Lines | Δ branches since v2026.08.36 |
|---|---|---|---|---|---|
| Backend | 98.78% | 94.95% | 97.95% | 99.10% | +4.94 |
| Frontend | 95.35% | 93.18% | 91.48% | 95.85% | +12.85 |
| pa-cockpit | 92.61% | 93.89% | 89.57% | 93.13% | +18.34 |
| pa-demo | 93.47% | 95.65% | 85.00% | 92.85% | +8.70 |
| Public site | 96.68% | 97.41% | 95.09% | 97.23% | +27.02 |
Against the 9 October reading of v2026.10.1, pa-cockpit, pa-demo and the
public site reproduced all four figures to the decimal, on packages
v2026.10.2 did not touch. The backend moved on two measures, by a
hundredth or two — statements 98.77 → 98.78, branches 94.97 → 94.95,
functions and lines unchanged — all of it in services/operaton.service.ts,
which now picks the decision document of the path a case took and reads
98.41 / 92.78 / 96.93 / 98.80. The frontend fell by three to eight
hundredths on all four — 95.42 → 95.35, 93.21 → 93.18, 91.54 → 91.48,
95.93 → 95.85 — on code whose only change was the changelog data, and in
one area row only, CaseworkerDashboardV2: run-to-run noise, set out in the
last two decimals warning below.
History, 9 October: against the 3 October reading of v2026.10.0, the two
packages v2026.10.1 changed moved in opposite directions. The frontend rose on all four —
95.23 → 95.42, 93.02 → 93.21, 91.21 → 91.54, 95.76 → 95.93 — on new code
that arrived well covered and on the DVTP sections leaving. The backend
fell by a tenth or two on three — statements 98.91 → 98.77, branches
95.21 → 94.97, lines 99.18 → 99.10, functions up 97.92 → 97.95 — on the
eDOCS-as-a-person work: services/edocs.service.ts took on most of the new
branches and reads 92.95% of them, and the new auth/entra-token.service.ts
arrived at 91.48%. pa-demo reproduced all four figures to the decimal,
and pa-cockpit and the public site all four but one hundredth each —
pa-cockpit functions 89.56 → 89.57, public-site branches 97.40 → 97.41 — on
packages v2026.10.1 did not touch: git diff 0625d48 ebec288 --
packages/pa-cockpit packages/public-site packages/pa-demo is empty. That
hundredth is the noise the last two decimals warning below describes.
The repository-wide figure, and why it is not an average of that column
Across all five workspaces together: 96.54% statements · 94.13% branches · 93.03% functions · 97.01% lines.
Those come from summing the covered and total counts across the five
workspaces' coverage reports and dividing once — 14744/15271 statements,
9514/10107 branches, 3417/3673 functions, 13329/13739 lines — not from
averaging the five percentages in the table. Averaging the column would
weight pa-demo's 92 statements exactly as heavily as the backend's 6889 and
give a repository-wide branch figure of 95.02% instead of 94.13%: nearly a
point of pure arithmetic error, in the flattering direction. The
denominators differ by two orders of magnitude here, so the distinction is
not academic. On 11 October the counts were summed from each workspace's
coverage/coverage-final.json, which every one of the five runs writes —
each file's timestamp matching that day's run; each workspace's own total
reproduces the table row above exactly, the four Vitest totals match the
covered/total counts in the run's own Coverage summary block, and the
backend's match the lcov.info its run wrote.
Against the 9 October measurement of v2026.10.1 every repository-wide figure fell by two or three hundredths — 96.57 → 96.54, 94.15 → 94.13, 93.05 → 93.03, 97.04 → 97.01 — on a body of code that grew by 10 statements and 8 branches. Most of the fall is the frontend's noise, which took one to four off each of its covered counts; the backend's new code is 10 statements, all covered, and 8 branches, 7 of them covered.
History: against the 3 October measurement of v2026.10.0 the repository-wide figures held or rose in the second decimal — statements 96.51 → 96.57, branches 94.13 → 94.15, functions 92.83 → 93.05, lines 96.97 → 97.04 — on a body of code that grew by 544 statements and 331 branches. That is the shape of a feature release: new code arriving roughly as well covered as the old.
Which frontend run the aggregate uses — like for like since 3 October
Every pass from 24 to 30 September took the frontend's figures from its
default parallel run, the one CI makes. The 3 and 9 October passes
ran every workspace with test:serial, the frontend included, and so
did the 11 October pass, so the frontend row comes from a serial run and
the 3 → 9 → 11 October comparison is like for like. (11 October also
made a default parallel run of the four Vitest workspaces, to collect
per-file test counts; none of this page's figures is taken from it.) Serial and parallel runs of the same code do
not report identical v8 coverage.
The size of that effect is on record. On 28 September, when the parallel run carried one contention-only failure, the green serial run of the same suite reported slightly lower frontend coverage — 93.16 / 89.88 / 87.84 / 93.98 against 93.24 / 89.91 / 87.98 / 94.07, four statements and two functions out of 4971 and 1423. That is v8 worker-attribution noise, the same phenomenon the last two decimals warning below describes. So part of the frontend's tenth-of-a-point fall on 3 October was the change of run, not the code, and a frontend difference of that size against 30 September should not be read as a regression. The backend's figures have a sensitivity of their own — see that warning.
Every package moved, and branches moved most
v2026.09.2 extended the backend-only coverage campaign to all five workspaces with a test runner, against a per-file 80% branch floor: 53 files were below it, none are now. That is why the branch column moved furthest and why public-site — which started lowest at 70.39% — moved most.
That was unusual and worth noting as a check that the run was sound: the pass before it had three packages reproducing their figures to the decimal, while in the campaign pass every package gained on every measure — which is what a campaign targeting all of them should look like. The table above is several releases further on. It moved only in decimals until v2026.09.14, then by whole points again on the margin work, and in v2026.10.0, v2026.10.1 and v2026.10.2 by decimals once more; what changed is set out below.
The floor is a gate, and it is per file
It used to be a convention held by review, with no threshold configured anywhere. v2026.09.6 configured it in all five runner configs, and the two runners express the same rule differently:
| Workspace | Config | How the per-file floor is written |
|---|---|---|
backend |
jest.config.js |
coverageThreshold: { './src/**/*.ts': { branches: 80 } } |
frontend |
vite.config.ts |
coverage.thresholds: { branches: 80, perFile: true } |
pa-cockpit |
vitest.config.ts |
coverage.thresholds: { branches: 80, perFile: true } |
pa-demo |
vite.config.ts |
coverage.thresholds: { branches: 80, perFile: true } |
public-site |
vite.config.ts |
coverage.thresholds: { branches: 80, perFile: true } |
The Jest form is a glob key rather than global: Jest applies a glob
threshold to each matching file individually, which is what makes it a
per-file floor and not a package average. Vitest needs perFile: true
alongside the number to say the same thing. Get either detail wrong and the
threshold silently becomes an average, which is the one thing it exists not
to be.
A file below the line exits the run non-zero and names that file, locally
and in CI alike — npm test already collects coverage in every workspace,
so nothing needed a separate coverage job. The five thresholds are
unchanged at c51ec0a — the frontend's vite.config.ts changed in
v2026.10.1, but only to add the tenant-pages build plugin, and no runner
config changed in v2026.10.2 — and no file was named in any of the five
runs of this pass; reading every file entry in the five workspaces'
coverage reports on 11 October confirms it independently:
zero of 337 files below 80% branches — 105 in backend, 134 in
frontend, 38 in pa-cockpit, 16 in pa-demo and 44 in public-site. (Since
3 October the backend gained four source files: auth/citizen-services.ts
and services/edocs-author.ts at 100 on all four measures,
routes/edocs.access.ts at 98.52 / 89.28 / 100 / 100 and
auth/entra-token.service.ts at 95.87 / 91.48 / 92.85 / 96.77. The
frontend gained eight and lost two: LoginChoice/AccessDeniedDialog.tsx
(95.45% branches) and SingleBoardLanding.tsx (100% branches, 91.66%
functions), services/board-request.ts (91.66% branches) and
services/landing.ts, login-choice/landing-login.ts and
single-board.copy.ts, and pages/citizen/citizenServiceUi.ts and
heusdenpasTestCases.ts — the last five at 100 on all four, three of them
data with no branches at all — while
CaseworkerDashboard/DvtpStartSection.tsx and DvtpTakenSection.tsx
went. vite-plugin-tenant-pages.ts, new at the frontend's package root,
is tested but outside src/, so outside the coverage report. For the
3 October additions, see the history below.)
Zero below the line — but since v2026.10.0, two frontend files within five points of it
On 30 September every file in the repository cleared 85% branches. On 3 October two did not, both new or rewritten in v2026.10.0 and both in the frontend — and restated from the 11 October coverage reports, the same two are still the only files below 85 in any workspace, at the same figures. Neither v2026.10.1 nor v2026.10.2 touched either:
| File | Branches | |
|---|---|---|
components/CaseworkerDashboard/BesluitOverzichtSection.tsx |
80.43 (37/46) | New: the Lopende and Afgeronde besluiten list. One more uncovered branch fails the gate |
components/process/phaseSet.ts |
83.33 (10/12) | New in place of awbStepper.ts: the phase set a process declares, or the Awb set |
85 is a margin, not a floor, and v2026.10.0 was the first release
since the margin was reached to arrive below it; v2026.10.1 and
v2026.10.2 added nothing below it. The two are the obvious next targets;
BesluitOverzichtSection.tsx is the urgent one, because the next
uncovered edge added to it fails a required check. Of the files
v2026.10.1 changed or added, the nearest to the margin are
components/signing/SigningPanel.tsx at 85.93%, and in the backend
routes/edocs.access.ts at 89.28% and routes/brp.routes.ts at
89.47%. v2026.10.2's one changed source file under coverage,
services/operaton.service.ts, reads 92.78% (270/291).
History. On 28 September the margin was thinner than the headline sounded:
three files sat at exactly 80.00% branches —
backend/src/media-aggregator/sanitize.ts,
frontend/src/components/CaseworkerDashboardV2/NoAccessPanel.tsx and
pa-cockpit/src/components/PADashboardV2/dossierbeheer/DossierRow.tsx —
so one uncovered edge added to any of them would have failed a required
check. Two commits closed that:
391b1a8(#256, v2026.09.14) covered the remaining arms of all three, taking each to 100%. Its missing-kompas test exposed a latent crash inDossierRow, fixed in the same commit.73a6764(v2026.09.15) brought 32 files that sat between 80.00 and 85 — 11 in the backend, 13 in the frontend, 6 in pa-cockpit, 2 in public-site — to 85 or above, most well past 90.services/edocs.service.ts, which that commit records at exactly 80.00% before it, read 98.67% on 30 September — and 92.95% on 9 October, after v2026.10.1 more than doubled its branch surface. It needed one production change: public-site'slib/api.tsnow readsimport.meta.envdirectly, sovi.stubEnvcan reach it, and went from 83.78% branches to 97.29% (96.55% on 3 October, after v2026.10.0 taught it to read a problem'sdetail). The arms left there cannot occur in Node and are tracked in #294.
Measured on 11 October, the lowest file in each workspace — the same five as on 3 and 9 October, at the same figures:
| Workspace | Lowest file by branches | Branches |
|---|---|---|
| backend | src/pa-monitoring/pa-cache.ts and src/services/llm/OpenAILlmProvider.ts |
86.36 (19/22 each) |
| frontend | src/components/CaseworkerDashboard/BesluitOverzichtSection.tsx |
80.43 (37/46) |
| pa-cockpit | src/services/dossierbeheer.api.ts |
85.10 (40/47) |
| pa-demo | src/demo/changelog/DemoChangelogPanel.tsx |
87.50 (⅞) |
| public-site | src/lib/useQueryState.ts and src/pages/herkomst/HerkomstTrace.tsx |
87.50 (14/16 each) |
Four of the five are as on 30 September. IouFeedbackSection.tsx,
which then sat exactly on the 85 line at 51 of 60 branches, has read
86.21% — 50 of 58 — since a change in v2026.10.0 that came with a
test.
Per file is the whole point: against a package average, one file falling to
40% barely moves 95%, and the regression the floor exists to catch would
pass. Branches only is equally deliberate. Measured the same way on
11 October, a functions floor at 80 would fail 23 files — frontend 8,
pa-cockpit 7, pa-demo 5, public-site 3, backend 0 — so the symmetry is a
trap for whoever adds functions: 80 on the assumption that it is free.
public-site/src/components/TopBar.tsx is the example the configs
themselves reach for, and it still holds: 100% branches, 66.66%
functions. The two metrics are not interchangeable, and a file can be
exemplary on one while failing the other — though note that TopBar.tsx
has no branches at all, so its 100% is the reporter's default for an empty
denominator rather than anything a test achieved.
See Coverage Floor.
The configs' own comments say 26 — corrected on 28 September, and three high on 11 October
Through v2026.09.13 all five runner configs claimed a functions floor would
fail 31 files, a figure the reports had contradicted on 20, 24, 26 and
28 September, which each measured 26. 391b1a8 (v2026.09.14) corrected the
comments to 26 and dated the measurement 28 September; they are
unchanged at c51ec0a. Measured since, the figure was 23 on
30 September, 24 on 3 October, 23 on 9 October and is 23 on
11 October:
| Workspace | Comment until v2026.09.13 | Comment since 391b1a8 |
Measured, 30 Sep | Measured, 3 Oct | Measured, 9 Oct | Measured, 11 Oct |
|---|---|---|---|---|---|---|
frontend |
11 | 10 | 8 | 9 | 8 | 8 |
pa-cockpit |
10 | 8 | 7 | 7 | 7 | 7 |
pa-demo |
7 | 5 | 5 | 5 | 5 | 5 |
public-site |
3 | 3 | 3 | 3 | 3 | 3 |
backend |
0 | 0 | 0 | 0 | 0 | 0 |
| Total | 31 | 26 | 23 | 24 | 23 | 23 |
The comments are not wrong so much as dated: each says when it was
measured, which is the fix that matters, since a count like this moves
with every release that touches a container — v2026.10.0 added one,
BesluitStartSection.tsx at 2 of 3 functions, and v2026.10.1 removed one
when it deleted DvtpTakenSection.tsx. Where the two disagree, re-run the
suites rather than trusting either.
The 23 are concentrated where the largest containers live: in the
frontend, the four board page containers (CaseworkerDashboardV2,
Dashboard, InfraBoardDashboard, WooDashboard), three
CaseworkerDashboard sections — BesluitStartSection,
IouFeedbackSection and IouGebruiksscenarioSection — and
RegelSimulatie at 54%; in pa-cockpit,
PADashboardV2, Dossierbeheer, MdEditor, Vandaag, pa.data,
CuratieSpecSection and ZoekcriteriaSection; in pa-demo, App.tsx and
four shims, two of which — the dock stand-in and the session-expiry
warning — render null by design; and in public-site,
TopBar, Herkomst and Results. The backend has none.
The frontend row is not comparable to v2026.08.23
The Public Affairs cockpit was extracted into packages/pa-cockpit in this
window, taking 41 test files and 368 tests with it. The frontend percentage
is therefore measured over a different, smaller body of code than the
87.47% recorded last time — it did not simply improve. Read the frontend and
pa-cockpit rows together.
pa-demo's jump is the vendored fork leaving, not a testing campaign. Its
figures previously spanned a byte-identical copy of the cockpit with
src/vendor/** excluded by hand; the fork was deleted in v2026.08.28 and the
package is now a thin host adapter over @ronl/pa-cockpit. There is nothing
left to exclude — see pa-demo by area below.
What moved in v2026.10.2 — measured 11 October, against the 9 October
reading of v2026.10.1. git diff --name-status ebec288 c51ec0a --
'packages/*/src/**' is the whole window: services/operaton.service.ts and
its test, bpmn-swimlane.test.ts and seven of its fixtures in the backend,
and pages/changelog-data.ts in the frontend.
- Backend: no new file, +5 tests, 2633 → 2638. Package figures:
statements 98.77 → 98.78, branches 94.97 → 94.95, functions
97.95 and lines 99.10 unchanged. All of it is
operaton.service.ts, whosegetDecisionDocumentnow reads the instance's completed user tasks to pick the document of the path taken; the file reads 98.41 / 92.78 / 96.93 / 98.80, and theservicesrow is the only area row that moved. See Backend by area. - Frontend: no test change, 1540. Package figures 95.42 → 95.35,
93.21 → 93.18, 91.54 → 91.48, 95.93 → 95.85, both runs serial,
on source whose only change is the changelog data. Every area row
reproduced to the decimal but
CaseworkerDashboardV2, in which no file has changed since 14 September — see Frontend by area and the last two decimals warning below. - pa-cockpit, pa-demo and the public site: no source and no test change, and every package figure and every area row reproduced to the decimal against 9 October — pa-demo for the tenth release running.
What moved in v2026.10.1 — measured 9 October, against the 3 October
reading of v2026.10.0. git diff --name-status 0625d48 ebec288 --
'packages/*/src/**' is the whole window, plus the frontend's
vite-plugin-tenant-pages.ts at its package root.
- Backend: +5 files, +176 tests, 2457 → 2633, and four new source files.
Package figures: statements 98.91 → 98.77, branches 95.21 →
94.97, functions 97.92 → 97.95, lines 99.18 → 99.10. The new
code is the eDOCS connection acting as the person:
auth/grew from two files to four and from 100 on all four measures to 98.21 / 96.07 / 97.72 / 98.56, onentra-token.service.ts;routes/gainededocs.access.ts; andservices/edocs.service.tswent from 98.67% branches on 30 September to 92.95% (132 of 142).citizen-services.tsandedocs-author.tsarrived at 100 on all four. See Backend by area. - Frontend: +6 files (eight new, two removed), +162 tests, 1378 → 1540.
Package figures: 95.23 → 95.42, 93.02 → 93.21, 91.21 → 91.54,
95.76 → 95.93, both runs serial. The organisation landing pages and the
citizen services arrived well covered —
components/LoginChoiceat 97.82% branches over four files,pages/login-choiceand the newpages/citizenat 100 — andsrc/pagesrose on all four, functions 78.68 → 81.2, on the citizenDashboardandLoginChoice. The one row that fell isCaseworkerDashboardV2, functions 84.24 → 82.92. - pa-cockpit, pa-demo and the public site: no source and no test change.
pa-demo reproduced every figure to the decimal, for the ninth release
running; pa-cockpit and the public site moved by one hundredth in one
package figure each, and pa-cockpit's one-file
src/pagesrow by more — see pa-cockpit by area.
What moved in v2026.10.0 — measured 3 October, against the 30 September
reading of v2026.09.15. git diff --name-status ae06c9e 0625d48 --
'packages/*/src/**' is the whole window.
- Backend: +3 files, +87 tests, 2370 → 2457. Package figures:
statements 98.90 → 98.91, branches 95.14 → 95.21, functions
97.98 → 97.92, lines 99.20 → 99.18. The three new source files —
middleware/error.middleware.ts,utils/problem.tsandroutes/besluitvorming.routes.ts— arrived at 100 on all four measures;operaton.service.ts,validsignCompletion.service.ts,validsign.routes.ts,m2m.routes.tsandbpmn-swimlane.tseach rose a little. The one file that fell isroutes/public.routes.ts, from 100% functions to 96.66% and 98.59 → 98.14 statements, after the problem-details change. See Backend by area. - Frontend: +4 files, +60 tests, 1318 → 1378, and four new source files.
Package figures: 95.36 → 95.23, 93.09 → 93.02, 91.41 → 91.21,
95.89 → 95.76 — measured serially this time; see Which frontend run
the aggregate uses above. The new code is uneven:
utils/problem.tsanduseTaskSignature.tsat 100,BesluitStartSection.tsxat 66.66% functions, andBesluitOverzichtSection.tsxat 80.43% branches.components/process/fell from 91.96 to 91.18 branches on the declared-phases work, withProcessWhere.tsx91.66 → 85.71 and the newphaseSet.tsat 83.33; andTakenInbox.tsx, which now hosts the signing panel, went from 96.02 to 94.9 statements while its branches rose, 93.24 → 94.11. - Public site: +1 file, +10 tests, 265 → 275 —
lib/problem.test.ts(9) and one more case inlib/api.test.ts. Package figures: 96.60 → 96.68, 97.34 → 97.40, 95.07 → 95.09, 97.17 → 97.23, all of the movement insrc/lib. - pa-cockpit and pa-demo reproduced all four package figures and every per-area row to the decimal, on source that did not change — pa-demo for the eighth release running.
What moved in v2026.09.14 and v2026.09.15 — measured 30 September, against
the 28 September reading of v2026.09.13; v2026.09.14 was not measured on its
own. git diff --name-status 963fe24 ae06c9e -- 'packages/*/src/**' is the
whole window.
- Backend: +1 file, +168 tests, 2202 → 2370. Package figures: statements
98.49 → 98.90, branches 92.57 → 95.14, functions 97.51 → 97.98,
lines 98.89 → 99.20. The new file is the conformance helper's own test;
the branch gain is mostly the margin work in
routes/,services/,auth/andmcp-servers/lde— see Backend by area. - Frontend: +10 files, +196 tests, 1122 → 1318, and twelve new source
files, nine of them the caseworker's process view. Package figures:
93.24 → 95.36, 89.91 → 93.09, 87.98 → 91.41,
94.07 → 95.89. The new code arrived well covered —
components/process/at 99.56% statements and 91.96% branches — and73a6764liftedCaseworkerDashboard/andsrc/pagesby several points each. - pa-cockpit: no new file, +39 tests, 476 → 515, all from the two margin commits. Package figures: 90.07 → 92.61, 88.52 → 93.89, 86.39 → 89.56, 91.33 → 93.13 — the largest branch gain of the five.
- Public site: +1 file, +30 tests, 235 → 265 — the new
indexHtml.test.tsfor the link-preview tags (23) and the rest inprerender.test.ts,lib/api.test.tsandFooter.test.tsx. Package figures: 95.92 → 96.60, 96.31 → 97.34, functions unchanged at 95.07, 96.41 → 97.17, all of the movement insrc/lib. - pa-demo reproduced all four package figures and every per-area row to the decimal, for the seventh release running.
What moved in v2026.09.13, measured 28 September against the 26 September
reading of v2026.09.12, for the record: the backend +4 tests in existing
files, the frontend +5 and one new source file, pa-demo and the public site
unchanged to the decimal, and pa-cockpit moving in the second decimal on
statements and functions with no src/ change and no test change at all —
the nondeterminism this page warns about below, caught in the cleanest
possible conditions.
Two windows further back, for the record: 24 → 26 September was the backend
alone, 89 → 96 files and 2072 → 2198 tests, the seven new files covering six new
source modules all at 100 on all four measures. 20 → 24 September took the
backend 86 → 89 files and 2028 → 2072 tests on root.routes, build-info and
cors-origin; the public site gained four tests in Detail.test.tsx, the
frontend three in infra-board.data.test.ts.
The last two decimals are noise
Frontend coverage is not deterministic. Six runs at the same commit, with no source change between them, produced 87.34% twice and 87.47% four times — the same 6789-statement denominator, nine statements apart. Clearing the Vite cache changed nothing. Treat a mismatch in the second decimal as expected rather than as something to chase; a difference of a whole point is worth investigating.
The backend has a different sensitivity: its figures depend on the
invocation. Through 30 September they came from
npm test --workspace=@ronl/backend; the 3, 9 and 11 October figures
come from the same Jest command with --runInBand, so a second-decimal
difference against earlier passes may be the invocation rather than the
code.
9 October caught it again on unchanged packages. pa-cockpit's
one-file src/pages row read 86.87% statements and 79.03% functions on
3 October and 86.95% and 79.36% on 9 October, on byte-identical source — enough to move the
package's functions figure by one hundredth, 89.56 → 89.57. The public
site's branches did the same, 97.40 → 97.41.
11 October caught it in the frontend, and larger. Between 9 and
11 October no file under components/CaseworkerDashboardV2/ changed —
none has since 14 September — yet its row went from 91.98 / 93.22 /
82.92 / 92.35 to 91.22 / 92.97 / 82.31 / 91.46, serial run against
serial run. RegelSimulatie.tsx is in it: 54% functions (27 of 50),
where 9 October recorded 56% (28 of 50) and 3 October 60%. That one row
moved the package by three to eight hundredths on every measure. A move
that size, on code nobody touched, is noise to note rather than a
regression to chase; a fall of a whole point would not be. pa-cockpit's
and the public site's rows, by contrast, reproduced their 9 October
readings exactly.
All five configure collectCoverageFrom / coverage.include to span the whole
src tree rather than only the files a test happens to import, so an untested
file shows as 0% instead of silently disappearing from the report. pa-demo no
longer needs a src/vendor/** exclusion, because there is no vendored tree left
to exclude — see pa-demo by area.
What the headline numbers mean here. Backend, frontend and public site have been through a dedicated coverage campaign that closed breadth gaps deliberately — every backend feature area, every frontend component and page, and every public-site module now has at least a test file. What remains there is depth. pa-cockpit inherits the frontend's profile, since it is the code that used to be measured there. pa-demo is the outlier in the other direction (see pa-demo by area):
| Package | Statements → branches | Gap | Was, v2026.08.36 |
|---|---|---|---|
| Backend | 98.78 → 94.95 | 3.8 | 7.5 |
| Frontend | 95.35 → 93.18 | 2.2 | 8.0 |
| pa-cockpit | 92.61 → 93.89 | −1.3 | 10.6 |
| pa-demo | 93.47 → 95.65 | −2.2 | 4.4 |
| Public site | 96.68 → 97.41 | −0.7 | 16.4 |
Every gap narrowed, and three have gone negative — branches now sit above
statements, pa-cockpit joining pa-demo and the public site on 30 September,
and all three still there on 11 October. The backend's gap widened by a tenth
in v2026.10.1, on the new eDOCS branches.
That is what a campaign aimed at branch edges produces once it reaches the
guards inside files whose plain statements nobody had a reason to execute. The
public site, whose 16.4-point gap was the widest in the repository at
v2026.08.36, is one of the three. pa-demo's position is a property of what it
became rather than of effort spent: a thin host adapter over a package that
carries its own tests. What is left elsewhere is the same kind of thing:
defensive if (!req.user) guards behind real middleware, ?? null fallbacks,
catch blocks unreachable through a legal input, and deliberately-scoped
"critical interactions only" passes on the largest components — documented
per-file rather than silently absent.
Backend by area¶
Sub-directories report separately rather than rolling up into their parent, and
istanbul truncates to two decimals rather than rounding. Match these against
npm test --workspace=@ronl/backend -- --coverageReporters=text.
Re-derived on 11 October 2026 from the run's own
coverage/coverage-final.json, grouped per directory the way istanbul's text
reporter groups them and truncated to two decimals the same way. The rows
reconcile to the package total in the table at the top of this page, and that
total to the lcov.info the same run wrote, which is the check that they are
current.
| Area | Files | Statements | Branches | Functions | Lines |
|---|---|---|---|---|---|
mcp-servers/edocs |
1 | 100 | 100 | 100 | 100 |
openapi |
1 | 100 | 100 | 100 | 100 |
openapi/testing |
2 | 100 | 100 | 100 | 100 |
services/document |
4 | 100 | 100 | 100 | 100 |
rip-swimlane |
2 | 100 | 99.26 | 100 | 100 |
middleware |
4 | 100 | 96.66 | 94.11 | 100 |
mcp-servers/triplydb |
1 | 100 | 90.9 | 100 | 100 |
routes |
20 | 99.16 | 97.41 | 99.42 | 99.25 |
services/llm |
4 | 99.02 | 92.3 | 100 | 98.95 |
utils |
13 | 98.96 | 98.95 | 100 | 98.84 |
pa-monitoring |
10 | 98.95 | 89.35 | 95.93 | 98.99 |
services |
16 | 98.71 | 94.98 | 98.69 | 99.09 |
auth |
4 | 98.21 | 96.07 | 97.72 | 98.56 |
pa-monitoring/sources |
6 | 98.13 | 93.05 | 94.52 | 99.13 |
mcp-servers/lde |
1 | 98.03 | 100 | 100 | 97.95 |
media-aggregator |
10 | 97.58 | 93.37 | 100 | 98.61 |
services/mcp |
6 | 96.35 | 100 | 93.9 | 97.86 |
One row moved in v2026.10.2, and sixteen are unchanged to the decimal.
services went 98.7 → 98.71 statements, 95.05 → 94.98 branches and
98.68 → 98.69 functions, lines unchanged, on operaton.service.ts at
98.41 / 92.78 / 96.93 / 98.80 (558/567, 270/291, 95/98, 495/501): the
decision-document path brought 10 statements and 8 branches, and the
five new tests reach all the statements and 7 of the branches.
History: five rows moved in v2026.10.1, and twelve were unchanged to the decimal —
mcp-servers/edocs among them, still at 100 on all four although its server
now refuses a person's call in Dutch when their eDOCS session cannot be
used. auth moved most: two new files, citizen-services.ts at 100 and
entra-token.service.ts at 95.87 / 91.48 / 92.85 / 96.77, took the row from
100 on all four to 98.21 / 96.07 / 97.72 / 98.56. routes gained
edocs.access.ts (89.28% branches) and fell on branches, 98.3 →
97.41, while its functions rose, 99.39 → 99.42. services
gained edocs-author.ts at 100, and fell on branches, 95.54 → 95.05,
almost all of it edocs.service.ts at 92.95%. utils rose a tenth on
config.ts — 96.29% statements and 98.52% branches, up from 95.12 and
98.31, on the Entra settings it now validates — and services/mcp by
two hundredths on EdocsMcpProvider.ts.
History: seven rows moved in v2026.10.0, and ten were unchanged to the
decimal.
Three gained a file at 100 on all four — middleware
(error.middleware.ts; branches 95.83 → 96.66, functions 92.85 →
94.11), utils (problem.ts; 98.82 → 98.89 statements) and
routes (besluitvorming.routes.ts). routes is also the one row that
fell on a measure: functions 100 → 99.39, every bit of it
public.routes.ts at 96.66%. rip-swimlane rose to 99.26 branches with
the declared-phases parser, services moved in the second decimal
(operaton.service.ts and validsignCompletion.service.ts up, branches
95.61 → 95.54 on the larger denominator), and pa-monitoring lost a
little on lines, 99.16 → 98.99, in pa.routes.ts and
pa-dossiers.routes.ts after their errors became problems.
media-aggregator moved by one hundredth on statements.
History: nine rows moved between v2026.09.13 and v2026.09.15, and eight were unchanged
to the decimal. The biggest moves are the margin work: auth from
90.74 / 88.63 / 90.9 / 91.91 to 100 on all four, jwt.middleware.ts
reaching 100 alongside tenant-access.ts; mcp-servers/lde from 82.14%
branches to 100; routes 94.6 → 98.26 branches; services
91.79 → 95.61 branches, edocs.service.ts, lde.service.ts and
search.service.ts above all. rip-swimlane reached 100 statements,
functions and lines, and 99.12 branches, while its parser grew to read any
laned process. openapi/testing gained conformance.ts at 100 on all
four. pa-monitoring, pa-monitoring/sources and media-aggregator each
moved by about a point on branches. media-aggregator/sanitize.ts, one of
the three files at exactly 80.00% on 28 September, is at 100% branches.
The v2026.09.13 window, before that: two rows moved in the second decimal —
rip-swimlane on bpmn-swimlane.ts reading a list of document references
instead of one, and services/ on operaton.service.ts, where three caches
keyed by process-definition key became one keyed by definition id.
The v2026.09.12 window, which this table also absorbed: openapi and
openapi/testing — document.ts and routeOperations.ts — arrived at 100
across the board; auth/ gained tenant-access.ts at 100 and rose on every
measure; middleware/ gained version.middleware.ts at 100, its branch and
function figures moving a fraction (95.91 → 95.83, 92.3 → 92.85) on the larger
denominator; routes/ gained openapi.routes.ts and registry.ts, both at
100.
utils/ is no longer the exception
Through v2026.08.20 this table's lowest row by a wide margin was utils/
at 43.47% statements and 6.54% branches, documented as an accepted
artifact: config.ts sat at 0% because it self-runs dotenv and
validateConfig on import, and logger.ts was mocked in every test that
touched it.
Both are closed. Of the thirteen source files in utils/ on 11 October,
twelve report 100 / 100 / 100 / 100 — altcha, build-info,
client-ip, cors-origin, dutch-datetime, env, errors, logger,
operaton-variables, problem (new in v2026.10.0), slug,
tls-bootstrap. The thirteenth is config.ts at
96.29% statements and 98.52% branches, which is what pulls the area row
off 100 and is comfortably the largest branch surface in the area.
tls-bootstrap.ts was also at 0% and is now fully covered. The area that
was the standing excuse is now the joint-best large area in the package, and
the one that grew most in v2026.09.11.
auth/ was the lowest row on statements, functions and lines through the
28 September pass. Through v2026.09.11 it was jwt.middleware.ts alone, at
88.23% statements and 82.75% branches; v2026.09.12 added tenant-access.ts
at 100 on all four, lifting the row to 90.74% statements and 88.63% branches;
and 73a6764 took jwt.middleware.ts itself to 100, so the row read
100 on all four from 30 September to 3 October, until v2026.10.1's
entra-token.service.ts arrived. The lowest rows on 11 October, as on
9 October, are
services/mcp on statements, functions and lines (96.35%, 93.9% and
97.86%) — middleware, lowest on functions through 30 September, rose past
it with error.middleware.ts — and pa-monitoring on branches at
89.35%, more than nine points clear of the floor. At file level the
closest are pa-monitoring/pa-cache.ts and services/llm/OpenAILlmProvider.ts,
both at 86.36% branches.
Frontend by area¶
Re-derived on 11 October 2026, from the serial run, for the reason
given in Which frontend run the aggregate uses at the top of this page.
The rows reconcile to the 95.35 / 93.18 / 91.48 / 95.85 package total above.
Vitest's text table omits fully covered files, so the rows are grouped from
the run's coverage-final.json.
In v2026.10.2 one row moved, on unchanged code, and twenty-one reproduced
to the decimal. CaseworkerDashboardV2 went 91.98 → 91.22 statements,
93.22 → 92.97 branches, 82.92 → 82.31 functions and 92.35 →
91.46 lines, although no file in it has changed since 14 September;
RegelSimulatie.tsx reads 54% functions (27 of 50), against 56% on
9 October. That is run-to-run noise — see the last two decimals warning.
src/pages, where the changelog data did change, reproduced to the decimal.
History: in v2026.10.1 six rows moved, one was new and fifteen reproduced
to the decimal. src/pages/citizen is new, at 100 — citizenServiceUi.ts and
heusdenpasTestCases.ts, both data. src/components/LoginChoice went from
two files at 100 to four (98.38 / 97.82 / 96 / 98.21), with
AccessDeniedDialog.tsx and SingleBoardLanding.tsx;
src/pages/login-choice from one file to three, still at 100, with
landing-login.ts and single-board.copy.ts; and src/services from eight
to ten (96.9 → 97.25 statements, 91.07 → 91.69 branches) with
board-request.ts and landing.ts, tenant.ts reading 97.72% branches.
CaseworkerDashboard lost the two DVTP sections (28 → 26 files) and
rose a little on every measure; src/pages rose on all four, functions
78.68 → 81.2; and CaseworkerDashboardV2 fell on statements, functions
and lines — functions 84.24 → 82.92 — not only in the files v2026.10.1
changed: RegelSimulatie.tsx, untouched, reads 56% functions (28 of 50)
where 3 October recorded 60%.
History: in v2026.10.0 five rows moved, one was new and fifteen reproduced
to the decimal —
src/utils among them, at 100 with one more file.
src/components/signing is new — SigningPanel.tsx and resolveSigningUrl.ts
moved in from InfraBoardDashboard, which drops from 12 files to 10, and
useTaskSignature.ts is new. CaseworkerDashboard gains
BesluitOverzichtSection.tsx and BesluitStartSection.tsx (26 → 28) and
src/utils gains problem.ts at 100 (2 → 3). The moves are small and
mostly downward on new or reworked code: CaseworkerDashboard 94.93 →
94.45 branches, components/process 91.96 → 91.18 branches,
CaseworkerDashboardV2 84.66 → 84.24 functions, and src/services
97.81 → 96.9 statements and 97.32 → 95.65 functions on the new
response interceptor in api.ts. InfraBoardDashboard rose on branches,
89.37 → 89.91, once the signing panel left it.
| Area | Files | Statements | Branches | Functions | Lines |
|---|---|---|---|---|---|
src/ (root files) |
1 | 100 | 100 | 100 | 100 |
src/components/…/regelsimulatie/__helpers__ |
1 | 100 | 100 | 100 | 100 |
src/components/PADashboardV2 |
2 | 100 | 100 | 100 | 100 |
src/hooks |
1 | 100 | 100 | 100 | 100 |
src/pages/caseworker-v2 |
1 | 100 | 100 | 100 | 100 |
src/pages/citizen |
2 | 100 | 100 | 100 | 100 |
src/pages/login-choice |
3 | 100 | 100 | 100 | 100 |
src/types |
1 | 100 | 100 | 100 | 100 |
src/utils |
3 | 100 | 100 | 100 | 100 |
src/pages/infra-board |
6 | 100 | 98.47 | 100 | 100 |
src/components/process |
10 | 99.16 | 91.18 | 100 | 99.74 |
src/pages/woo |
2 | 99.13 | 100 | 100 | 99 |
src/components/LoginChoice |
4 | 98.38 | 97.82 | 96 | 98.21 |
src/components/…/regelsimulatie |
8 | 98.33 | 88.59 | 96.38 | 98.89 |
src/components/WooDashboard |
12 | 98.26 | 94.78 | 98.52 | 98.57 |
src/components |
7 | 97.65 | 93.47 | 98.3 | 100 |
src/services |
10 | 97.25 | 91.69 | 95.93 | 97.33 |
src/components/InfraBoardDashboard |
10 | 95.34 | 89.91 | 92.59 | 95.85 |
src/components/CaseworkerDashboard |
26 | 94.2 | 94.51 | 90.43 | 95.12 |
src/components/signing |
3 | 93.1 | 88.75 | 95.65 | 96.11 |
src/components/CaseworkerDashboardV2 |
10 | 91.22 | 92.97 | 82.31 | 91.46 |
src/pages |
11 | 89.03 | 95.73 | 81.2 | 88.97 |
This table no longer carries the cockpit's rows
Earlier versions listed src/pages/public-affairs-v2,
src/components/PADashboardV2/dossierbeheer and a large
src/components/PADashboardV2 here. Those directories live in
packages/pa-cockpit since the extraction and are measured by that
package's own suite — see pa-cockpit by area below.
The two-file src/components/PADashboardV2 that remains in the frontend is
what stayed behind, and it is at 100.
The other reason the shape changed: several areas that were middling are
now at 100, and the old src/utils row of 66.66% statements / 50% branches
is gone entirely. Nothing in the frontend is below the 80% branch floor,
though since v2026.10.0 two files are below 85 — see the floor note at the
top of this page.
src/pages is the lowest of the top-level areas because it is where the
largest containers live — and at 81.2% functions it holds four of the eight
frontend files that a functions floor would fail. Its branches, at 95.73%, are
well clear of the floor; this is a functions gap, not a branch gap. Per-board detail is on the board
pages: Caseworker,
PA cockpit,
Infra-board,
Woo-dashboard.
pa-cockpit by area¶
Re-derived on 11 October 2026, on a package none of v2026.10.0,
v2026.10.1 and v2026.10.2 touched. These rows reconcile to the 92.61 /
93.89 / 89.57 / 93.13 package total above, and all seven are identical to
9 October. Six of them are also identical to 30 September and 3 October;
the seventh, the one-file src/pages row, moved on identical code between
3 and 9 October — 86.87 → 86.95 statements, 79.03 → 79.36 functions,
86.76 → 86.86 lines — the run-to-run noise the last two decimals
warning describes, enough to move the package's functions figure by one
hundredth, and has held there since. The account below is of the
28 → 30 September window. The package's only changes in it were tests —
391b1a8's four in DossierRow.test.tsx and 73a6764's 35 across six files — plus the small DossierRow.tsx fix the
first of them exposed, so nearly everything that moved below moved on new
assertions against unchanged code.
| Area | Files | Statements | Branches | Functions | Lines |
|---|---|---|---|---|---|
src/ (root files) |
2 | 100 | 100 | 100 | 100 |
src/services |
3 | 95.97 | 93.99 | 98.19 | 95.28 |
src/modes |
1 | 95.65 | 100 | 100 | 95 |
src/pages/public-affairs-v2 |
13 | 94.73 | 95.04 | 92.55 | 95.53 |
src/components/PADashboardV2 |
10 | 92.12 | 91.78 | 86.98 | 93.73 |
src/pages |
1 | 86.95 | 95.57 | 79.36 | 86.86 |
src/components/PADashboardV2/dossierbeheer |
8 | 85.47 | 92.88 | 81.35 | 86.29 |
In the 28 → 30 September window four rows moved and three were identical
to 28 September.
src/pages/public-affairs-v2 moved most — 88.2 → 95.04 branches, 86.4 →
92.55 functions — on the 16 new Monitoring.test.tsx cases; src/services
84.98 → 93.99 branches on 13 new cases in pa.api.test.ts;
dossierbeheer 89.12 → 92.88 branches, DossierRow.tsx now at 100; and
src/components/PADashboardV2 89.44 → 91.78. The 28 September reading had
the second-decimal wobble this page warns about — statements and functions
alternating on identical code — which is why a move that small would not be
worth a sentence, and why these are.
dossierbeheer is still the lowest area on statements and functions, but at
92.88% branches it clears the floor by nearly thirteen points — the same
pattern as the frontend's src/pages. This package holds 7 of the 23 files
that an 80% functions floor would fail.
Public site by area¶
Re-derived on 11 October 2026, on a package neither v2026.10.1 nor
v2026.10.2 touched. These rows reconcile to the 96.68 / 97.41 / 95.09 /
97.23 package total above, and all six are identical to 9 October. Five of
them are also identical to 3 October; the sixth, src/pages, read 97.29%
branches then and 97.31% on 9 and 11 October, on identical code — the
same run-to-run noise as pa-cockpit's. On 3 October src/lib was the row that
moved, on v2026.10.0's problem details: lib/problem.ts is new, at 100 on
all four, and lib/api.ts now reads a problem's detail through it.
| Area | Files | Statements | Branches | Functions | Lines |
|---|---|---|---|---|---|
src/ (root files) |
1 | 100 | 100 | 100 | 100 |
src/i18n |
3 | 100 | 100 | 100 | 100 |
src/pages/herkomst |
8 | 100 | 97.05 | 100 | 100 |
src/components |
13 | 97.14 | 100 | 96.29 | 97.05 |
src/lib |
9 | 96.8 | 97.05 | 97.43 | 98.03 |
src/pages |
10 | 95.45 | 97.31 | 92 | 95.83 |
src/lib went 96.49 → 96.8 statements, 96.66 → 97.05 branches,
97.36 → 97.43 functions and 97.87 → 98.03 lines. Before that, the
v2026.09.15 window took it from 93.85 / 91.11 to 96.49 / 96.66, on the one
production change 73a6764 made anywhere: lib/api.ts reads
import.meta.env directly, so its base-URL fallbacks can be tested with
vi.stubEnv. lib/api.ts itself went from 83.78% branches — the lowest file
in the package from v2026.09.11 to v2026.09.13 — to 97.29% then, and has read
96.55% since 3 October; the arms left cannot occur in Node and are tracked in
#294. The lowest files by branches are lib/useQueryState.ts and
pages/herkomst/HerkomstTrace.tsx, both at 87.50%.
The new src/indexHtml.test.ts adds no row: it tests index.html's
link-preview tags, filled from each mode's .env file, and index.html is
not a source file under coverage.
The pre-campaign rows are gone, and the difference is the point
This table used to carry three rows derived on 22 August 2026 —
src/components 96.77, src/lib 84.9 / 73.17 branches, src/pages 82 /
61.51 branches — which sat visibly below a package total of 96.41% and
carried a warning saying so. They are now re-measured: src/lib branches
have gone 73.17 → 97.05, and src/pages branches 61.51 → 97.31.
Nothing in the package is below the 80% branch floor, and src/components
is at 100% branches outright.
The whole-tree src/pages row covers the ten files directly in that
directory; the eight-file herkomst/ provenance explorer reports as its own
row, at 100% statements.
See Public site suite for what these files are and what is deliberately not covered.
pa-demo by area¶
Re-derived on 11 October 2026, and every row below reconciles to the
All files row rather than predating it. All five rows reproduced to the
decimal against 24, 26, 28 and 30 September and 3 and 9 October, on a package whose
src/ tree has not changed since v2026.09.5.
| Area | Files | Statements | Branches | Functions | Lines |
|---|---|---|---|---|---|
| All files | 16 | 93.47 | 95.65 | 85.00 | 92.85 |
src/demo |
8 | 100 | 100 | 100 | 100 |
src/demo/changelog |
2 | 100 | 87.50 | 100 | 100 |
src/ (root) |
2 | 75.00 | 100 | 50.00 | 75.00 |
src/demo/shims |
4 | 75.00 | 100 | 44.44 | 75.00 |
src/demo reached 100 across the board
The rows that used to sit here were derived on 30 August and did not sum to
the total — v2026.09.2's campaign had added tests across the package after
they were taken. Re-measured, src/demo is at 100 / 100 / 100 / 100
where it previously read 95.91 / 84.61, and the package's remaining gaps are
entirely in the two rows at 75%, both of which are at 100% branches.
This package contributes 5 of the 23 files an 80% functions floor would
fail, and none at all to a branch floor.
The src/vendor/** exclusion is gone, because the vendored tree is. Until
v2026.08.28 this package held a byte-identical copy of the cockpit — 39 files
kept honest by a manifest, a sync script and a drift checker — which had to be
excluded from these figures to avoid double-counting code the frontend suite
already exercised. The extraction into
@ronl/pa-cockpit deleted the fork and all of that
machinery, so every figure above is now pa-demo's own demo-owned surface and
nothing else. That is the whole reason the package total jumped from 73.94% to
91.30% without a single test being written for that purpose.
What remains uncovered is almost entirely shims that deliberately return
nothing: the dock stand-in and the session-expiry warning both render null
by design, because the real components pull in chat machinery and session
handling that a public, unauthenticated page must not have. They depress the
function percentage without representing a gap.
Two more files are excluded from coverage entirely, by config rather than by
this table's rounding: src/main.tsx (it calls createRoot; its one
meaningful line, forceMockMode(), is tested separately via the extracted,
fully-covered src/main-helpers.ts) and src/vite-env.d.ts (a type-only
ambient declaration file, nothing to execute). The src/ row above is just
these two remaining root files, App.tsx and main-helpers.ts — 100% on
main-helpers.ts (3/3 statements) pulled down by 0% on App.tsx (0/1) gives
the row's 75%. App.tsx is the lowest-covered file in the package — its one
statement, the route shell itself, has no test rendering it.