core,nix: Add end-to-end pipeline orchestration with golden test
`pipeline::recognise` ties the three model-touching stages — Detector,
align_face, Embedder — into a single call. The output is a Vec of
(Detection, Embedding) pairs, one per face the detector found,
preserving the detector's ordering. This is what the daemon's PAM path
will eventually drive once enrollment + matching land in M4.
Pure orchestration code: no feature gate, no new runtime deps. It
operates on the existing trait + type surface, so it compiles in every
workspace configuration including --no-default-features.
# Errors abort the pipeline
Per-face partial successes (e.g. 'detected three faces, aligned two,
embedded one') would be hard to reason about in the matching layer, so
any stage error aborts the whole call with no results. The unit tests
pin this behaviour: detector errors, degenerate landmarks (align fails),
and embedder errors all surface as the original error variant with no
side effects.
# Golden test against real models
A new hardware-gated test runs the full pipeline against the InsightFace
sample face JPEG (t1.jpg, ~128 KB, MIT-licensed via their repo). It
asserts:
- ≥1 detection (the fixture has a clearly visible face; finding zero
would mean the detector regressed).
- Every detection's confidence clears the default 0.5 threshold.
- Every embedding is 512-d with L2 magnitude ≈ 1.0.
- Running the pipeline twice on the same frame yields bit-identical
embeddings (CPU EP determinism guarantee).
Stops short of pinning exact embedding values — that's the matching
layer's concern in M4, where similarity-against-stored-baseline becomes
the natural assertion.
# Fixture infrastructure
The fixture image is pinned in nix/models.nix with sha256, fetched at
devShell build time, and exposed via PAREIDOLIA_TEST_FACE so the
hardware test runs without manual setup inside `nix develop`. Outside
Nix, set the env var manually (the InsightFace URL is in
nix/models.nix).
`image` (jpeg + png decoders only, default-features off) joins the
workspace dev-dependencies for fixture loading; production code never
needs to decode images because the camera produces RGB8 directly.