a5664dbc

Add autodocodec-http-api-data for form-urlencoded data

Derives `Web.FormUrlEncoded.ToForm` and `FromForm` from a `HasObjectCodec`
instance, so a type with a codec can be posted as
`application/x-www-form-urlencoded` without a second, hand-written description
of its fields.

## Why

The motivating case is an API endpoint that a shell should be able to hit with
curl alone:

```
curl --netrc --silent --show-error --fail-with-body \
  --data-urlencode "clone-url=$GITHUB_SERVER_URL/$GITHUB_REPOSITORY.git" \
  --data-urlencode "message=$COMMIT_MESSAGE" \
  https://api.nix-ci.com/suite
```

The point of the form is that `--data-urlencode` escapes each value, so a commit
message containing a quote or a newline needs no JSON encoder in the shell.

The type already had a `HasObjectCodec` instance naming all its fields, but with
no autodocodec support the `FromForm` instance had to be written by hand, so the
field names were spelled twice and a test had to assert the two lists agreed.
That test is exactly the check this package makes unnecessary.

`http-api-data`'s own generic derivation is not a substitute: it derives names
from Haskell record fields via a label modifier, so it would be a third
independent spelling of the same names rather than a shared one.

## What

`autodocodec-servant-multipart`'s interpreter retargeted at
`Web.FormUrlEncoded.Form`, which is likewise a flat map from text keys to text
values. A `Form`'s `HashMap Text [Text]` models repeated keys natively, so
`ArrayOfCodec` fits it better than it fits multipart's flat `[Input]`.

Three places where copying multipart verbatim would have been wrong:

- **`unionForm`, not `<>`.** `Form` newtype-derives `Semigroup` from `HashMap`,
  whose union is left-biased, so `<>` would silently drop the second form's
  values under a shared key — where multipart's `mappendMultipartData`
  concatenates.
- **Booleans encode lower case.** Multipart's encoder emits Haskell spelling;
  `toUrlPiece @Bool` is `T.toLower . show`, so `"True"` would round-trip through
  our own decoder but read as unconventional to every other form consumer. The
  decoder still accepts either spelling.
- **`key=` is a decoder setting.** A form has no null, so whether an empty value
  is the empty string or is absence is a real choice, and it is
  `FormDecodeSettings`:

  ```haskell
  data EmptyValue = EmptyValueIsValue | EmptyValueIsAbsent
  ```

  The decoder consults it **at optional keys only**. A required key has no
  absence for an empty value to mean, so it decodes the empty string either way.
  The default is `EmptyValueIsValue`, which is lossless and agrees with
  `lookupMaybe`. `EmptyValueIsAbsent` is for the shell case, where
  `--data-urlencode "x=$UNSET"` sends `x=`.

  That required/optional distinction exists nowhere but inside the interpreter,
  which is why the setting lives there rather than in a pre-pass over the
  `Form` — a pre-pass would strip a required field's legitimate empty string
  along with the optional field's unset one.

Nested values keep multipart's behaviour — JSON-encoded into the text slot —
documented in the module header as something no other form parser will
understand.

## Tests

`autodocodec-api-usage/test/Autodocodec/FormUrlEncodedSpec.hs` mirrors
`MultipartSpec`: "matches the encoding", "matches the decoding" and a round
trip, over `Example`, `Via`, `LegacyValue`, `LegacyObject`, `These`,
`Expression`, `ListsExample` and `Overlap`. Hand-written `ToForm`/`FromForm
Example` in `Usage.hs` give the first two something independent to compare
against, as the multipart pair do.

Beyond that mirror:

- Four assertions on `formDecodeSettingEmptyValue`, using `ListsExample` because
  it has a required and an optional field in one type. The load-bearing one is
  that under `EmptyValueIsAbsent` a form with *both* fields present and empty
  still decodes the required field as `"" :| []` while the optional one becomes
  `Nothing`. I checked that this fails against a pre-pass implementation, which
  loses the required key with `Left "Expected a nonempty list, but got an empty
  list."`.
- A round trip through `urlEncodeFormStable`/`urlDecodeForm`, so the actual
  percent-escaped wire bytes are covered. That escaping is the reason the
  feature exists.

**No `xdescribe` was needed.** `MultipartSpec` skips `Example` with "does not
hold."; here the whole corpus round-trips, `Example` included. I ran 480,000
examples per property rather than trusting the default 100 before concluding
that. Grouping repeated keys is what makes the difference.

## Checks

- `nix flake check` passes. The new package builds under `-Werror` against
  nixpkgs 26.05, 25.11 and 25.05 plus horizon-advance, so against four
  `http-api-data` versions.
- Full `autodocodec-api-usage` suite: 77,483 examples, 0 failures.
- `pre-commit run -a` clean.

`stack build --pedantic` cannot pass in this tree, and not because of this
change: `autodocodec-swagger2` has an unused `aeson` dependency that
`-Wunused-packages` rejects under `-Werror`. I confirmed that on a clean tree
before working around it. It does not affect `nix flake check`, whose override
does not enable that warning, but it does mean the cheapest feedback loop is
unusable until a separate one-line fix to `autodocodec-swagger2/package.yaml`.

## Not in this PR

`cabal.project` needs no change (it globs `*/*.cabal`); `stack.yaml` does, since
it lists packages explicitly. Replacing the first hand-written caller lives in
the nix-ci tree, on branch `openapi-spec` (NorfairKing/nix-ci#463), which can
now use `fromFormViaCodecWith` with `EmptyValueIsAbsent` instead of its
hand-written instance.