-- audit_address_sample.sql
-- Random sample of EKB houses for the address-mismatch audit (issue #582).
--
-- Strategy:
--   1. Filter to houses with non-null lat/lon and non-empty address.
--   2. Random shuffle via `ORDER BY random()` — repeatable enough for spot
--      sampling without needing a stable PRNG seed (the audit table dedupes
--      via UNIQUE (house_id, audit_batch), so re-running gives idempotent
--      results regardless of which rows land in the sample first).
--   3. Cap the result at :limit_per_district * 8 rows — keeps the bind-param
--      contract compatible with the old stratified sampler (`:limit_per_district`
--      is still honored, just multiplied by the assumed 8-district count).
--
-- Why no spatial stratification anymore:
--   The previous version JOINed to `gendesign_ekb_districts_geom` (FDW
--   polygon table) to bucket houses by admin district. That join is fine on
--   prod where FDW is wired, but it adds a dependency we don't need for
--   Phase 2-3 (backfill + canonical reverse). Aggregation by district at
--   report time still works — we re-derive district during the audit via
--   spatial containment in the report SQL when needed.
--
-- Bind param:
--   :limit_per_district — kept for back-compat with the audit driver.
--     Effective sample size = :limit_per_district * 8 (e.g. 25 → 200).
--
-- Columns returned:
--   id, address, lat, lon, district
--   `district` is always NULL here — the audit driver will reverse-derive it
--   from Yandex Geocoder response (Yandex returns admin component) or leave
--   it NULL if not present in the response.
--
-- NB: uses CAST(:x AS int) per project sql.md rule (psycopg v3 ignores ::type
-- after bind params).

SELECT
    h.id,
    h.address,
    h.lat,
    h.lon,
    NULL::text AS district
FROM houses h
WHERE h.lat IS NOT NULL
  AND h.lon IS NOT NULL
  AND h.address IS NOT NULL
  AND length(trim(h.address)) > 0
ORDER BY random()
LIMIT CAST(:limit_per_district AS int) * 8;
