v0.4.6 - bairn smoke immich + write-side contract gate

Adds a real round-trip Immich smoke that verifies the upload
contract end-to-end: login, mint ephemeral API key, upload tiny
JPEG via the production sink/immich code path, assert created,
delete asset, delete API key. ~5 HTTP calls per run, ~250ms.

Catches what a vendored OpenAPI spec or an upstream zod schema
cannot: controller-layer wire-contract enforcement (the
deviceId / deviceAssetId class-validator decorators that produce
HTTP 400 on Immich >= v2.7.5 when omitted). v0.4.3 + v0.4.4
shipped without this gate and broke uploads; both have been
pulled. v0.4.6 is the first release with the gate.

Local invocation: `make pre-tag-check` runs unit tests + the
live smoke against an operator-configured Immich. CI runs the
same smoke as a job (allow_failure: true until the runner can
reliably reach the configured Immich host).

Reads IMMICH_BAIRN_HOST / IMMICH_BAIRN_USER / IMMICH_BAIRN_PASSWORD
or falls back to IMMICH_BASE_URL / IMMICH_API_KEY.