e1d73bdf

Redundant-test detection for mutation testing

## What

Adds redundant-test detection to sydtest mutation testing, produced **by the mutation `run` itself** (no separate command). After a full run, alongside `report.json`/`report.txt`, the driver writes `redundancy.json`/`redundancy.txt` describing which tests are redundant w.r.t. the mutations they *kill*.

The analysis (`analyzeRedundancy`, pure, in `sydtest-mutation-runtime`) reports three lenses plus extras:
- **Equivalence classes** — tests with identical killsets (keep one).
- **Dominated tests** — every mutation a test kills is also killed by another test.
- **Suggested minimal suite** — greedy min-set-cover + the removable remainder.
- **Load-bearing (sole-killer)** tests, and the dual **redundant-mutant** grouping.

## How (kill basis, no extra processes)

The mutation child already runs each mutation's covering set. When `--mutation-kill-row-output` is given it runs that set with within-set fail-fast **off** and writes a `TestKillRow` (`Map TestId Bool`) derived from the **structured `ResultForest`** (not text). One pass yields both the killed/survived verdict and the kill-matrix row. The parent aggregates the rows and runs `analyzeRedundancy`.

Per-test ids are aligned by canonical source order (full-forest flatten <-> result leaves; randomisation disabled), and `buildKillRow` returns `Left` rather than crashing on a mismatch — so the optional analysis can never flip a mutation's verdict.

## Toggle

Opt-out via `--redundancy`/`--no-redundancy` (default on) and `mutationCheck { redundancy = false; }`. Cost: each *killed* mutant runs its whole covering set instead of stopping at the first killer (no extra processes; survived/uncovered mutants are unaffected).

## Notable fix included

Found and fixed a latent bug: the mutation child writes its kill row *after* `printOutputSpecForest`, which in a C/POSIX-locale build sandbox **crashed encoding the checkmark marker** and made the child exit non-zero — silently mis-scoring **every survivor as killed**. Forcing UTF-8 on the child's stdout/stderr fixes it, and unmasked 9 genuine `sydtest-mutation-example` survivors, now killed by exhaustive `majorityOf5` tests.

Also: all on-disk JSON in the mutation pipeline (and the rerun cache) now uses `aeson-pretty` for diff/debug-friendliness.

## Tests / CI

- `sydtest-mutation-driver-gen`: `analyzeRedundancy`/`buildKillRelations`/`buildKillRow` unit tests, `genValidSpec` + `jsonSpec` roundtrips, golden renders (76 pass).
- Nix checks green: `release`, `mutation-sydtest-mutation-example` (redundancy populates; 35 sole-killers), `mutation-manifest-example`, `pre-commit`.