a73x

internal/server/api is the weakest package on both mutation axes

open   by a73x

Labels: backlog

[claude 2026-08-23] Falls out of the 2026-08-23 re-baseline (see the mutation baseline issue). `internal/server/api` is now the worst package in the tree on **both** axes at once — 38 surviving mutants and 41 unreached — and it holds that position without having got worse. Everything around it improved; it did not move.

That combination is what makes it worth a cycle. A package that is weak on efficacy has tests that execute the code without asserting on it. A package that is weak on coverage has code no test reaches. This package is both, and it is the HTTP surface: every authorization decision, every tenant-scoping check, and every refusal the control plane makes lives here.

Scale of the problem, for planning: 21 non-test files, ~3900 lines, with `api.go` alone at 1070.

## Not a rewrite

The tests here are not absent — the package has 27 test files. The deficit is what they assert, not whether they run. Treat this the way the comment audit was run: let the mutants name the specific claims nothing holds, fix those, and leave the rest alone. Do not refactor the package to make it testable; that trades a measured problem for an unmeasured one.

## Sequence

1. Get the per-mutant survivor list (`make mutate PKG=./internal/server/api`) and group survivors by file.
2. Split the security-relevant survivors — anything in `auth.go`, `principal.go`, `ratelimit.go`, `tokens.go`, `sshcert.go`, `usercas.go`, `trustedcas.go` — from the rest. An unasserted authorization branch is a different severity from an unasserted response field.
3. Kill the security group first, each with a test named for the claim it holds.
4. Judge the unreached 41 separately. Some will be genuinely dead code worth deleting rather than testing — that is a real outcome, not a failure to cover.

## Caveat on the numbers

38/41 come from a run made while the machine was under concurrent load, which inflated timeouts tree-wide. Timed-out mutants are unresolved rather than alive, so the true survivor count could be somewhat higher once they resolve. Re-measure on an idle box before treating any figure here as the target to drive to zero.