From 118100e58d3d16764ef1d64a3225ce30e7014a51 Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 14 May 2026 08:54:59 +0200 Subject: [PATCH 1/2] =?UTF-8?q?chore(coverage):=20drop=20client=20branches?= =?UTF-8?q?=20threshold=2080=E2=86=9275,=20add=20ADR-013?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Branches gate was blocking CI at 75% measured coverage. The 80% floor suffers Istanbul parent/child denominator coupling (long-tail grind, per #496) that makes the remaining gap disproportionately costly to close. Drop branches to 75 to match current state; leave lines/functions/ statements at 80. ADR-013 documents the rationale and the ratchet rule for raising the gate back incrementally. Closes #556 Co-Authored-By: Claude Sonnet 4.6 --- .../013-client-branches-coverage-threshold.md | 92 +++++++++++++++++++ frontend/vitest.client-coverage.config.ts | 3 +- 2 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 docs/adr/013-client-branches-coverage-threshold.md diff --git a/docs/adr/013-client-branches-coverage-threshold.md b/docs/adr/013-client-branches-coverage-threshold.md new file mode 100644 index 00000000..a4058fa5 --- /dev/null +++ b/docs/adr/013-client-branches-coverage-threshold.md @@ -0,0 +1,92 @@ +# ADR 013 — Client-Project Branch Coverage Threshold + +**Status:** Accepted +**Date:** 2026-05-14 +**Issues:** [#556 — threshold drop](https://git.raddatz.cloud/marcel/familienarchiv/issues/556) · [#496 — long-tail-grind tracking](https://git.raddatz.cloud/marcel/familienarchiv/issues/496) + +--- + +## Context + +The browser-mode component test suite (`vitest.client-coverage.config.ts`) enforces Istanbul coverage thresholds across `lines`, `functions`, `branches`, and `statements`. The `branches` metric was set to 80%, but the codebase sits at approximately **75%** — below the gate — causing every CI run of `unit-tests` and `coverage-flake-probe` to fail on this check alone, even when all tests are green. + +**Measured baseline (2026-05-14, branch `feat/issue-553-birpc-async-mock-factory`, head `2e6cc346`):** + +``` +branches: ~75% (below the 80% gate — reason for this ADR) +lines: ≥ 80% +functions: ≥ 80% +statements: ≥ 80% +``` + +Reproducer: + +```bash +cd frontend && npm ci && npx vitest run -c vitest.client-coverage.config.ts --coverage +``` + +### The long-tail-grind problem + +In Istanbul's branch accounting, when a child component gains test coverage its branches are added to the parent's denominator. A child moving from 40% → 80% coverage can drag a parent from 78% → 72% because more branches in the call graph become reachable and must be covered. This is not a bug — it is how branch accounting works — but it means that on a large SvelteKit application the denominator grows with every coverage improvement, making an arbitrary 80% ceiling a constant grind. Per #496, the expected cost to reach 80% branches from 75% is 30–100+ commits with no guarantee of stability. + +### Why this layer is different + +The 80% branch floor used for backend unit/integration tests is appropriate for Java service code and permission logic. Browser-mode component coverage measures Svelte template branches: conditional class bindings, `{#if}` blocks, empty/loaded/error state guards. These branches have a fundamentally different accounting model and a higher inherent denominator. This ADR **only** lowers the browser-mode component gate; the backend test coverage gates are unaffected. + +### Security-relevant uncovered components + +The following auth/permission-boundary components currently have low or zero branch coverage. When ratchet-up work begins (see below), these are the highest-priority targets: + +- `src/routes/login/+page.svelte` +- `src/routes/forgot-password/+page.svelte` +- `src/routes/reset-password/+page.svelte` +- `src/routes/register/+page.svelte` + +Note: the 75% figure already reflects the absence of coverage on these files. Lowering the gate does not create this gap — it makes the existing state legible. + +--- + +## Decision + +Drop the `branches` threshold from `80` → `75` in `frontend/vitest.client-coverage.config.ts`. Leave `lines`, `functions`, and `statements` at `80`. + +The 75% figure matches the measured current state, allowing CI to pass while deliberate coverage improvement work (tracked in #496) continues without blocking other PRs. The asymmetry in the thresholds block is intentional and documented with an inline comment pointing here. + +--- + +## Ratchet Rule + +The branches threshold ratchets **up by 3 percentage points** when the rolling 3-PR-average client-project branches figure on `main` stays at or above `threshold + 3pp` for ≥ 30 consecutive days. Direction is **up-only** — never lower the floor below 75 without a new ADR superseding this one. Manual today (verify before any `vitest.client-coverage.config.ts` edit); a future automation issue may codify the check. + +Concretely: +- When `main` sustains ≥ 78% branches across 3 consecutive PRs for 30 days → raise gate to 78% +- When `main` sustains ≥ 81% branches across 3 consecutive PRs for 30 days → raise gate back to 80% + +--- + +## Non-goals + +- **Not** raising actual branch coverage — that is #496's job, tracked separately. +- **Not** touching the server-project coverage configuration (`vitest.config.ts`) — only the client project hits the long-tail-grind pattern. +- **Not** removing or relaxing any existing test files, `skipIf` guards, or axe-playwright accessibility runs. + +--- + +## Consequences + +**Easier:** +- CI unblocked — `unit-tests` and `coverage-flake-probe` jobs pass when all tests are green +- The ratchet rule creates a concrete, observable path back to 80% + +**Harder:** +- The gate now has near-zero headroom — any branch regression that drops below 75% will fail CI immediately +- The 75% floor must not be treated as a permanent ceiling; the ratchet discipline requires active attention + +--- + +## References + +- [#496 — Branch coverage long-tail grind](https://git.raddatz.cloud/marcel/familienarchiv/issues/496) +- [#556 — This threshold drop](https://git.raddatz.cloud/marcel/familienarchiv/issues/556) +- [ADR 012 — Browser-Mode Test Mocking Strategy](./012-browser-test-mocking-strategy.md) +- `frontend/vitest.client-coverage.config.ts` — thresholds block (lines 44–51) diff --git a/frontend/vitest.client-coverage.config.ts b/frontend/vitest.client-coverage.config.ts index d6ada2f5..6aa1614a 100644 --- a/frontend/vitest.client-coverage.config.ts +++ b/frontend/vitest.client-coverage.config.ts @@ -44,7 +44,8 @@ export default defineConfig({ thresholds: { lines: 80, functions: 80, - branches: 80, + // branches at 75 — long-tail parent/child accounting grind; see docs/adr/013-client-branches-coverage-threshold.md and #496 + branches: 75, statements: 80 } } -- 2.49.1 From 582191d01463fa1979c7153c192449d27f9c0fcc Mon Sep 17 00:00:00 2001 From: Marcel Date: Thu, 14 May 2026 09:03:45 +0200 Subject: [PATCH 2/2] docs(adr-013): set exact baseline to 75% (confirmed in CI) Co-Authored-By: Claude Sonnet 4.6 --- docs/adr/013-client-branches-coverage-threshold.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/adr/013-client-branches-coverage-threshold.md b/docs/adr/013-client-branches-coverage-threshold.md index a4058fa5..7086a0e1 100644 --- a/docs/adr/013-client-branches-coverage-threshold.md +++ b/docs/adr/013-client-branches-coverage-threshold.md @@ -8,12 +8,12 @@ ## Context -The browser-mode component test suite (`vitest.client-coverage.config.ts`) enforces Istanbul coverage thresholds across `lines`, `functions`, `branches`, and `statements`. The `branches` metric was set to 80%, but the codebase sits at approximately **75%** — below the gate — causing every CI run of `unit-tests` and `coverage-flake-probe` to fail on this check alone, even when all tests are green. +The browser-mode component test suite (`vitest.client-coverage.config.ts`) enforces Istanbul coverage thresholds across `lines`, `functions`, `branches`, and `statements`. The `branches` metric was set to 80%, but the codebase sits at **75%** — below the gate — causing every CI run of `unit-tests` and `coverage-flake-probe` to fail on this check alone, even when all tests are green. **Measured baseline (2026-05-14, branch `feat/issue-553-birpc-async-mock-factory`, head `2e6cc346`):** ``` -branches: ~75% (below the 80% gate — reason for this ADR) +branches: 75% (below the 80% gate — reason for this ADR) lines: ≥ 80% functions: ≥ 80% statements: ≥ 80% -- 2.49.1