jcbowyer's picture
Clean HuggingFace deployment without binary files
e59d91d
Raw
History Blame Contribute Delete
8.43 kB
-- Verification queries for the priority-states scrape batches.
--
-- Run via psql against Neon dev (NEON_DATABASE_URL_DEV):
-- ./packages/hosting/scripts/neon/psql_resolved.sh -f scripts/datasources/jurisdiction_pilot/verify.sql
-- Or pass a specific batch:
-- psql "$NEON_DATABASE_URL_DEV" \
-- -v batch="'<batch-uuid>'" \
-- -f scripts/datasources/jurisdiction_pilot/verify.sql
\if :{?batch}
\else
\set batch (SELECT scrape_batch_id::text FROM ( \
SELECT scrape_batch_id, MAX(loaded_at) AS t FROM bronze.bronze_contacts_scraped GROUP BY 1 \
UNION ALL \
SELECT scrape_batch_id, MAX(loaded_at) AS t FROM intermediate.int_events_channels_candidates GROUP BY 1 \
) x ORDER BY t DESC LIMIT 1)
\endif
\echo
\echo === Batch in scope ===
SELECT :batch::uuid AS batch_id;
\echo
\echo === Contacts per state ===
SELECT
state_code,
COUNT(DISTINCT jurisdiction_id) AS jurisdictions_with_contacts,
COUNT(*) AS contact_rows,
SUM((raw_row->>'is_mayor')::boolean::int) AS mayor_rows,
SUM(CASE WHEN email IS NOT NULL THEN 1 END) AS rows_with_email,
SUM(CASE WHEN phone IS NOT NULL THEN 1 END) AS rows_with_phone
FROM bronze.bronze_contacts_scraped
WHERE scrape_batch_id = :batch::uuid
GROUP BY state_code
ORDER BY state_code;
\echo
\echo === YouTube: candidates vs verified (this batch) ===
SELECT
'candidates' AS layer,
state_code,
COUNT(DISTINCT jurisdiction_id) AS jurisdictions,
COUNT(*) AS channel_rows,
COUNT(*) FILTER (WHERE is_verified) AS verified_flagged,
COUNT(*) FILTER (WHERE NOT is_verified) AS rejected,
COUNT(DISTINCT rejection_reason) AS distinct_rejection_reasons
FROM intermediate.int_events_channels_candidates
WHERE scrape_batch_id = :batch::uuid
GROUP BY state_code
UNION ALL
SELECT
'verified_canonical' AS layer,
state_code,
COUNT(DISTINCT jurisdiction_id),
COUNT(*),
COUNT(*) FILTER (WHERE is_primary),
NULL::bigint,
NULL::bigint
FROM intermediate.int_events_channels
WHERE scrape_batch_id = :batch::uuid
GROUP BY state_code
ORDER BY layer, state_code;
\echo
\echo === Rejected candidate reasons (top) ===
SELECT
COALESCE(rejection_reason, '(verified)') AS reason,
COUNT(*) AS n
FROM intermediate.int_events_channels_candidates
WHERE scrape_batch_id = :batch::uuid
GROUP BY 1
ORDER BY n DESC
LIMIT 20;
\echo
\echo === Verified YouTube channel purpose breakdown ===
SELECT
COALESCE(channel_purpose, 'unknown') AS channel_purpose,
COUNT(*) AS rows,
COUNT(*) FILTER (WHERE is_primary) AS primary_rows
FROM intermediate.int_events_channels
GROUP BY 1
ORDER BY rows DESC;
\echo
\echo === Non-meeting channels still in verified (should review) ===
SELECT jurisdiction_id, channel_title, channel_purpose, official_meeting_confidence
FROM intermediate.int_events_channels
WHERE channel_purpose IN ('county-general', 'municipality-general', 'tv-public', 'unknown')
ORDER BY channel_purpose, jurisdiction_id
LIMIT 30;
\echo
\echo === Verified YouTube metadata coverage ===
SELECT
COUNT(*) AS rows,
COUNT(*) FILTER (WHERE channel_description IS NOT NULL AND BTRIM(channel_description) <> '') AS has_description,
COUNT(*) FILTER (WHERE subscriber_count IS NOT NULL) AS has_subscribers,
COUNT(*) FILTER (WHERE video_count IS NOT NULL) AS has_video_count,
COUNT(*) FILTER (WHERE latest_upload IS NOT NULL AND BTRIM(latest_upload) <> '') AS has_latest_upload,
COUNT(*) FILTER (WHERE jsonb_array_length(jurisdiction_website_back_links) > 0) AS has_back_links
FROM intermediate.int_events_channels;
\echo
\echo === City channels incorrectly on counties (should be 0 verified) ===
SELECT
y.jurisdiction_id AS county_id,
j.name AS county_name,
y.channel_title,
y.youtube_channel_url
FROM intermediate.int_events_channels y
JOIN intermediate.int_jurisdictions j ON j.jurisdiction_id = y.jurisdiction_id
WHERE y.jurisdiction_type = 'county'
AND (
LOWER(BTRIM(COALESCE(y.channel_title, ''))) ~ '^city of '
OR POSITION('cityof' IN LOWER(y.youtube_channel_url)) > 0
)
ORDER BY y.state_code, y.jurisdiction_id
LIMIT 25;
\echo
\echo === YouTube metadata quality (junk titles / missing description / back-links) ===
SELECT
'verified' AS layer,
COUNT(*) AS rows,
COUNT(*) FILTER (
WHERE LOWER(BTRIM(channel_title)) IN ('home','videos','shorts','live','playlists','community','about')
) AS junk_tab_titles,
COUNT(*) FILTER (
WHERE channel_description IS NULL OR BTRIM(channel_description) = ''
) AS missing_description,
COUNT(*) FILTER (
WHERE jsonb_array_length(jurisdiction_website_back_links) > 0
) AS has_jurisdiction_back_links
FROM intermediate.int_events_channels
UNION ALL
SELECT
'candidates',
COUNT(*),
COUNT(*) FILTER (
WHERE LOWER(BTRIM(channel_title)) IN ('home','videos','shorts','live','playlists','community','about')
),
COUNT(*) FILTER (
WHERE channel_description IS NULL OR BTRIM(channel_description) = ''
),
COUNT(*) FILTER (
WHERE jsonb_array_length(jurisdiction_website_back_links) > 0
)
FROM intermediate.int_events_channels_candidates;
\echo
\echo === Rows with junk tab titles (sample) ===
SELECT
'verified' AS layer,
jurisdiction_id,
channel_title,
LEFT(channel_description, 80) AS description_preview,
jurisdiction_website_back_links,
youtube_channel_url
FROM intermediate.int_events_channels
WHERE LOWER(BTRIM(channel_title)) IN ('home','videos','shorts','live','playlists','community','about')
UNION ALL
SELECT
'candidates',
jurisdiction_id,
channel_title,
LEFT(channel_description, 80),
jurisdiction_website_back_links,
youtube_channel_url
FROM intermediate.int_events_channels_candidates
WHERE LOWER(BTRIM(channel_title)) IN ('home','videos','shorts','live','playlists','community','about')
ORDER BY layer, jurisdiction_id
LIMIT 25;
\echo
\echo === Verified canonical channels (GA counties sample) ===
SELECT
y.jurisdiction_id,
y.jurisdiction_type,
j.name,
y.channel_title,
y.youtube_channel_url,
y.official_meeting_confidence,
y.source,
y.is_primary,
y.back_links_to_jurisdiction_website,
y.jurisdiction_website_back_links
FROM intermediate.int_events_channels y
JOIN intermediate.int_jurisdictions j USING (jurisdiction_id)
WHERE j.state_code = 'GA'
AND y.jurisdiction_type = 'county'
ORDER BY y.jurisdiction_id, y.is_primary DESC, y.official_meeting_confidence DESC NULLS LAST
LIMIT 30;
\echo
\echo === Noise still in candidates only (pattern_match rejects) ===
SELECT
c.jurisdiction_id,
c.jurisdiction_type,
j.name,
c.channel_title,
c.youtube_channel_url,
c.official_meeting_confidence,
c.rejection_reason
FROM intermediate.int_events_channels_candidates c
JOIN intermediate.int_jurisdictions j USING (jurisdiction_id)
WHERE c.scrape_batch_id = :batch::uuid
AND NOT c.is_verified
ORDER BY c.jurisdiction_id
LIMIT 30;
\echo
\echo === Mayor-flagged contacts (top 50) ===
SELECT
state_code,
jurisdiction_id,
person_name,
title_or_role,
email,
phone,
source_page_url
FROM bronze.bronze_contacts_scraped
WHERE scrape_batch_id = :batch::uuid
AND (raw_row->>'is_mayor')::boolean = TRUE
ORDER BY state_code, jurisdiction_id
LIMIT 50;
\echo
\echo === Coverage gap: jurisdictions with website but NO verified YouTube ===
WITH targets AS (
SELECT DISTINCT ON (jurisdiction_id)
jurisdiction_id,
state_code,
COALESCE(NULLIF(btrim(j.name), ''), jurisdiction_id) AS name,
btrim(website_url) AS website_url
FROM intermediate.int_jurisdiction_websites w
LEFT JOIN intermediate.int_jurisdictions j USING (jurisdiction_id)
WHERE w.state_code IN ('AL','GA','IN','MA','WA','WI')
AND w.jurisdiction_category IN ('municipality','county')
AND w.website_url IS NOT NULL AND btrim(w.website_url) <> ''
ORDER BY jurisdiction_id, w.website_record_key
),
verified AS (
SELECT DISTINCT jurisdiction_id FROM intermediate.int_events_channels
)
SELECT t.state_code, t.jurisdiction_id, t.name, t.website_url
FROM targets t
LEFT JOIN verified v USING (jurisdiction_id)
WHERE v.jurisdiction_id IS NULL
ORDER BY t.state_code, t.jurisdiction_id
LIMIT 50;
\echo
\echo === Checkpoint file ===
\echo (See data/bronze/jurisdiction_pilot_progress/<batch>.jsonl)