Critical Findings
Issues discovered during audit of Snowflake data transfer infrastructure (Feb 13, 2026)
COPY_FILES_TO_TABLE() stored procedure. There is no event-driven, automatic ingestion when new files land in S3 buckets.
TASK_ATTAIN_SEGMENT_MAID_UPSERT (active, Mon/Wed/Fri at 13:00 UTC) and DAILY_QRM_V4_REFRESH (suspended — SUSPENDED_DUE_TO_ERRORS). No scheduled tasks exist for LotLinx, Paramount, Causal IQ, or MNTN data loads.
What This Dashboard Cannot Monitor
This dashboard queries Snowflake directly. The following areas require separate monitoring tools.
lotlinx-webpixeldata-filedrop, paramount-retargeting-files, quorum-paramount-data, and mntn-data-drop. This dashboard cannot see whether files are arriving in these buckets, their sizes, or if uploads are failing.
- Enable S3 CloudWatch metrics on all four buckets (NumberOfObjects, BucketSizeBytes) and set alarms for stalled growth
- Enable S3 Event Notifications to trigger a Lambda or SNS alert when new files arrive (or fail to arrive within expected windows)
- Set up AWS CloudTrail logging for PutObject/DeleteObject on these buckets to maintain an audit trail
- Consider adding Snowpipe on each bucket's stage to automate and monitor S3 → Snowflake ingestion natively
COPY_FILES_TO_TABLE()). If these processes crash, run into credential expiration, or silently fail, there is no Snowflake-side detection.
- Identify and document where each client's load process runs (which server/Lambda/cron)
- Add health-check logging: each load job should write a success/failure record to a Snowflake audit table
- Set up dead-man's-switch alerts: if no successful load record appears within the expected window, fire an alert
- Migrate to Snowflake Tasks or Snowpipe where possible to bring orchestration into a monitored environment
- Set up a periodic check with Attain's team to confirm they can read the share (even a monthly "can you query this?" ping)
- Use SHOW GRANTS ON SHARE to periodically verify share permissions haven't changed
- Monitor SNOWFLAKE.ACCOUNT_USAGE.DATA_TRANSFER_HISTORY for share access patterns
- Create a Snowflake Task that runs daily, checks freshness/volume for each client table, and calls SYSTEM$SEND_EMAIL or posts to a Slack webhook when thresholds are breached
- Define SLAs per client: e.g., Attain feed must load within 48 hours, LotLinx within 36 hours, Paramount within 24 hours
- The existing /api/v5/pipeline-health endpoint on Railway could be extended to include these client-specific checks and trigger alerts
- Add null-rate checks for key identity fields (DEVICE_ID, IP_ADDRESS, MAID) per client table — the MNTN 100% null publisher issue would have been caught sooner with this
- Track duplicate rates (same DEVICE_ID + TIMESTAMP within a table)
- Monitor schema changes: create a baseline of expected columns per table and alert on additions/removals
- Consider Snowflake's built-in data quality functions or a tool like dbt tests for automated quality checks
Investigation Guide
Reference for investigating warnings, updating this dashboard, and avoiding known pitfalls. Created Feb 13, 2026.
Client Data Paths
1. Attain — Snowflake Share
Outbound share SHARE_TO_ATTAIN → account UK76987. Primary table: QUORUM_CROSS_CLOUD.ATTAIN_FEED.SEGMENT_MAID_WITH_IP.
Snowflake Task TASK_ATTAIN_SEGMENT_MAID_UPSERT runs Mon/Wed/Fri at 13:00 UTC on X_LARGE_WH. It MERGEs from SEGMENT_DEVICES_CAPTURED (last 30 days) into the Attain feed.
Other shared tables: MAID_CENTROID_ASSOCIATION (544M rows), HOUSE_HOLD_MAPPING (9B rows, stale since Nov 2025, manual refresh), SEGMENT_META_DATA (740K rows).
2. LotLinx — S3 + Snowflake
S3 bucket lotlinx-webpixeldata-filedrop → QUORUMDB.SEGMENT_DATA.SEGMENT_DEVICES_CAPTURED_LOTLINX_BACKUP.
No Snowflake Task or Snowpipe. Load process is external. Typical weekday: 400-580K rows. Weekend: 250-330K rows.
3. Paramount — S3 + Snowflake
S3 buckets paramount-retargeting-files and quorum-paramount-data → 5 Snowflake tables.
No Snowflake Task or Snowpipe. Agency ID 1480 in Optimizer (Class W — web visits). Revenue: $43-55K/mo (highest).
4. Causal IQ — Weekly Stats
CAMPAIGN_PERFORMANCE_REPORT_WEEKLY_STATS filtered by AGENCY_ID = 1813. Weekly cadence — LOG_DATE = Sunday (week-end date). 18 active advertisers. Revenue: $18-30K/mo.
5. MNTN — XANDR + Weekly Stats + S3
Three sources: XANDR_IMPRESSION_LOG (filter PT = 22), CAMPAIGN_PERFORMANCE_REPORT_WEEKLY_STATS (filter AGENCY_ID = 2514), and S3 bucket mntn-data-drop.
Critical: 100% of PT=22 rows have PUBLISHER_ID = null/0. This is MNTN-specific (other PTs are <1% null).
XANDR queries must always include AND CAST(TIMESTAMP AS DATE) <= CURRENT_DATE() to filter out garbage future dates.
Column Name Gotchas
These caused query failures in previous sessions. Always verify columns via INFORMATION_SCHEMA.COLUMNS before querying an unfamiliar table.
| Table | Wrong Column | Correct Column |
|---|---|---|
SEGMENT_MAID_WITH_IP | CREATED_DATE | CREATED_AT |
LOTLINX_BACKUP | DRIVEBYDATE | DRIVE_BY_DATE |
PARAMOUNT_SITEVISITS | EVENT_DATE | SITE_VISIT_TIMESTAMP |
PARAMOUNT_LEADS | SITE_VISIT_TIMESTAMP | LEAD_TIMESTAMP |
PARAMOUNT_CUSTOM_AUDIENCE | DELIVERY_DATE | LAST_IMPRESSION_PIXEL_FIRED |
WEEKLY_STATS | REPORT_END_DATE | LOG_DATE |
XANDR_IMPRESSION_LOG | MAID | DEVICE_UNIQUE_ID |
SEGMENT_DELIVERY_DETAILS | AGENCY_NAME | AGENCY_ID |
SQL Gotchas
1. XANDR future dates: MAX(CAST(TIMESTAMP AS DATE)) on XANDR returns "58082-12-23" without a bound. Always add: AND CAST(TIMESTAMP AS DATE) <= CURRENT_DATE()
2. Reserved word "rows": COUNT(*) as rows will fail. Use row_count instead.
3. No AGENCY_NAME: SEGMENT_DELIVERY_DETAILS only has AGENCY_ID. Name lookup requires a separate table.
Snowflake Infrastructure (as of Feb 13, 2026)
Snowflake Tasks (only 2 exist)
| Task | Status | Schedule | Warehouse |
|---|---|---|---|
TASK_ATTAIN_SEGMENT_MAID_UPSERT | started | Mon/Wed/Fri 13:00 UTC | X_LARGE_WH |
DAILY_QRM_V4_REFRESH | SUSPENDED_DUE_TO_ERRORS | Daily 06:00 America/Denver | COMPUTE_WH |
Snowpipes: Zero. None exist. All S3 ingestion is external.
Key Stored Procedure: COPY_FILES_TO_TABLE() — likely the main mechanism for S3 → Snowflake loads.
Open Warnings — Investigation Steps
Finding: The apparent decline from ~500K to 56K was caused by the table's multi-batch backfill loading pattern, not a pipeline failure. Each DRIVE_BY_DATE receives rows across ~3 load cycles spaced ~2 days apart. Recent dates (Feb 10-11) had only completed 1 of ~3 expected loads.
Cross-validation: LOTLINX_QUORUMIMP_DATA (separate pipeline) showed stable daily volumes of 478-507K for the same period, confirming no actual decline.
89-day trend analysis: Monthly averages are actually trending upward: Nov 438K → Dec 457K → Jan 467K → Feb 502K. Recent week z-score of +0.66 vs baseline — well within normal range.
9B-row table hasn't been refreshed since Nov 2025. Manual-only process. Household-level attribution depends on this mapping. MAID_CENTROID_ASSOCIATION match rate degraded 28% → 16% in the same period, which may be related.
Actions: Identify who last refreshed this, document the procedure, and determine if the match rate degradation is caused by stale household data.
Every PT=22 row has PUBLISHER_ID = null/0. Publisher optimization is impossible for MNTN campaigns.
Root cause: Likely MNTN doesn't pass publisher data in their XANDR feed. Needs escalation to MNTN's technical team.
Task calls REFRESH_QRM_V4() but is suspended due to errors.
Task is Mon/Wed/Fri but Feb 7 was skipped, Feb 12 (Thu) had a tiny 5M-row manual load. Inconsistent cadence.
Quick Health Check Queries (Copy-Paste Ready)
Attain
LotLinx
Paramount (all 5 tables)
Causal IQ
MNTN — XANDR
MNTN — Weekly Stats
How to Update This Dashboard
This dashboard uses a static data snapshot in the CLIENT_DATA JavaScript object. To update it with fresh data:
1. Run the health check queries above to get current values.
2. In the HTML source, find the CLIENT_DATA object and update: latestDate, totalRows, recentRows, and the dailyVolumes arrays.
3. Update the SNAPSHOT_TIME constant and the timestamp in the init() function.
4. Health status auto-calculates from staleness thresholds:
| Cadence | Healthy | Warning | Critical |
|---|---|---|---|
| Daily | ≤ 1 day | 2–3 days | > 3 days |
| Weekly | ≤ 8 days | 9–14 days | > 14 days |
Related Systems & Files
| System | Details |
|---|---|
| Quorum Optimizer API | Flask on Railway, v5.13-pipeline-health. Existing /api/v5/pipeline-health monitors base tables but NOT client transfers. |
| GitHub | ezrakd/quorum-optimizer |
| Project Index | /mnt/Claude/quorum-project/COWORK_PROJECT_INDEX.md |
| S3 Architecture | AWS_S3_AND_DELIVERY_ARCHITECTURE.md in the Quorum Rewrite zip |
| Revenue Data | /mnt/Claude/Weekly Revenue Forecast 2-12-26.xlsx |