538e9c18

A rule that sees every package at once, and the build that feeds it

Replaces #8, which GitHub will not let me reopen: I merged it by mistake and
then took it back off master.

Stacked on #11, and the last of the five. Review that first; this diff is
against it.

Adds `TestGenValidSpecPerGenValid` from `testing.md`, the flagship: for every
`GenValid` instance, a `genValidSpec` call in the matching gen package's test
suite. An obligation made and an obligation met are different facts, found in
different packages, so the check between them is a left join and a null check.

128 files, 6,326 lines. 350 tests.

## Two things this rule needs that nothing before it did

**The compiler.** A `GenValid` instance a splice produced appears in no source,
and a `genValidSpec` call a splice produced appears in no source either, so each
unmet obligation is put to the artifacts before it is reported. Reading them is
its own package, because the `ghc` library and `ghc-lib-parser` both expose
modules under `GHC.` and one component cannot import both.

The artifacts are not optional. Given any `.hie` directories, every module read
must have both a `.hie` and a `.hi` or the run fails naming the module, because
a tree missing one module is indistinguishable at the point of use from no tree
at all: both say nothing.

**Every package at once**, which is what the process boundary is for. Facts
cross it; source does not. A package is read once into a SQLite store and the
project layer answers from those stores alone, so the Nix side is one derivation
per package plus one for the repository, and changing one package rebuilds
three derivations rather than all of them. That the two paths agree is a
property in the suite, per project rule, so a fact a project rule reads out of
memory and extraction never serialises fails the tests rather than the build.

## What the second process can find wrong

`StoreProblem`, six constructors, every one of them an obligation that would
otherwise be quietly satisfied: a package whose facts never arrived, facts from
another build of the tool, a module a cabal file declares and the facts do not
cover, a module that did not parse, a suppression naming a rule this half does
not run, and a module a build was held to covering and did not. All six are about
names rather than about paths on this machine, so all six are typed and the
renderer is the only place any of them becomes a sentence. What a package output
directory can be wrong about is one constructor carrying text, because what it is
about is an absolute store path.

The two readers in `hopinion-hie` take a `Path Abs File` and fail with an
`ArtifactUnreadable` rather than a bare `Text`, and the source path a `.hie` file
records is parsed into a `Maybe (Path Rel File)` at that boundary: GHC records
what it was handed, and a build that hands it absolute paths is one whose two
`Main`s can be told apart by nothing, which now reads as `Nothing` rather than as
a string nothing can do anything with.

## What else arrives here

The Nix builders a consuming flake calls, the end to end tests over them, and
`plan/`, which describes this architecture and so is only true once it exists.

## The corpus

`plan/context.md` holds the table and accounts for every number in it by hand.
nix-ci's 22 `HsNoCustomShowRead` findings were all `Show` written to keep a
secret out of a log line, which is the exception `haskell-style.md` names, so
they are now 22 suppressions each naming the secret it hides, and the row reads
0. NorfairKing/nix-ci#527 is that work, and its `hopinion` check passes against
this branch.

## What #9 handed over

`judge` is the first command that reads a report back, so the report's own codec arrives with it: `encodeReport`, `decodeReport` and `ReportError`. In #9 they had no caller but their own roundtrip test.

`ClassRatchet` arrives here too, with the first rule that carries it.

## Review loop

```
nix flake check
nix develop --command cabal test hopinion-test --test-options="--ai-executor"
nix develop --command ./scripts/corpus-run.sh
./plan/scripts/check-plan.sh
```