73d3c218

Add sydtest-sqitch-postgres and sydtest-sqitch-postgres-persistent

## Summary

Two new sydtest companion packages:

- **`sydtest-sqitch-postgres`** — sanity checks for a sqitch project against a temporary PostgreSQL database:
  - **Per-change round-trip**: deploy through a change, revert one step, redeploy. Schema must match.
  - **Per-change idempotence**: re-execute the deploy script's raw SQL on a database where the change has already been applied. Schema must be unchanged.
  - **Whole-plan deploy/revert/redeploy cycle**: deploy, snapshot, revert all, redeploy, snapshot, compare.
- **`sydtest-sqitch-postgres-persistent`** — on top of `sydtest-sqitch-postgres`, asserts that the schema after deploying every sqitch migration matches what `persistent`'s automatic migration produces against an empty database (columns + indices).

These replace the bespoke migration sanity-check code currently sitting in `NorfairKing/nix-ci#295`.

## API shape

```haskell
sqitchPostgresqlSpec :: SqitchSettings -> TestDef outers a -> TestDef outers a
sqitchPersistentPostgresqlSpec :: SqitchPersistentSettings -> TestDef outers a -> TestDef outers a
```

The combinators allocate fresh empty postgres databases internally (one per check), so nothing about the postgres machinery surfaces in the caller's outer-type stack. IO-level entry points are also exposed for negative tests under `expectFailing`.

## Design highlights

- **Grandfather tag**: a single `Maybe Text` referring to a tag in `sqitch.plan`. Changes at or before the tag are exempt from the per-change round-trip + idempotence checks (legacy migrations that shipped before the checks existed). Changes after must satisfy both.
- **Rework heads** (the post-tag head of a reworked change, with deploy target `name@HEAD`) skip the round-trip check, since sqitch's revert convention undoes the whole change rather than only the rework. The whole-plan cycle test still exercises these.
- **`SchemaSnapshot`** record bundles columns + indices, compared via `compareSchemaSnapshots` with the undefined-trick to prompt for an update when new fields are added.
- **Phase isolation**: `sqitchPersistentPostgresqlSpec`'s schema-equality check runs the persistent baseline (phase 1) on a separate database from the sqitch deploy (phase 2), so they can't contaminate each other.
- **`Path Rel Dir`/`Path Abs File`** for sqitch project dir + executable; `path`/`path-io` used throughout.

## Companion change to `sydtest-persistent-postgresql` (0.3.0.0 → 0.4.0.0)

The internal `adminDBSetupFunc`, `tempUserSetupFunc`, `tempNewDatabaseSetupFunc`, and `dbConnectionOptionsPoolSetupFunc` are renamed to `postgresqlServerSetupFunc`, `postgresqlUserSetupFunc`, `postgresqlDatabaseSetupFunc`, `postgresqlPoolSetupFunc` and promoted to the public API. New convenience `emptyPostgresOptionsSetupFunc` / `emptyPostgresPoolSetupFunc` give a fresh empty database without going through a migrated template. `sydtest-sqitch-postgres` consumes these.

## Test plan

- [x] `stack test sydtest-sqitch-postgres sydtest-sqitch-postgres-persistent --pedantic` — 21/21 + 6/6 passing
- [x] `stack test sydtest-persistent-postgresql --pedantic` — 5/5 still passing
- [x] `nix flake check` — green (pre-commit, hlint, ormolu, cabal2nix, hpack, cross-nixpkgs release builds)
- [x] Toy fixtures cover each failure mode in isolation:
  - `toy-sqitch-ok` (happy path)
  - `toy-sqitch-non-idempotent`
  - `toy-sqitch-broken-revert`
  - `toy-sqitch-grandfathered` (with and without the tag — round-trip and idempotence both skipped pre-tag)
  - `toy-sqitch-drift` (column mismatch between sqitch and persistent)
  - `toy-sqitch-index-drift` (columns match, indices don't)
- [x] `readSqitchPlan` has 12 unit tests covering empty plan, single change, rework, double rework, grandfather tag at start/middle/end, missing tag, blank lines, on-disk fixture
- [x] Replaces bespoke code in `NorfairKing/nix-ci#295` — local branch `use-sydtest-sqitch` confirms 6/6 Migration tests pass under the new API

Suite timing

Time to Start Worker time Duration Time to finish
Config 0s 2s 2s 1s
Eval 2s 43s 43s 45s
Build 34s 10s 10s 45s
Test - - - -
Deploy - - - -
Suite 0s 56s 46s 45s

Timeline

0s0s10s20s30s40s