diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d124075..936f4a4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,13 +27,13 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install -r requirements.txt ruff + pip install -r requirements.txt ruff==0.15.20 - name: Lint - run: ruff check app.py prizm_client.py cache_manager_new.py cache_cli.py test_prizm_api.py + run: ruff check app.py prizm_client.py cache_manager_new.py cache_cli.py cohort_queue.py historical_import.py test_prizm_api.py test_cohort_queue.py test_historical_import.py - name: Test - run: python -m unittest test_prizm_api.py + run: python -m unittest test_prizm_api.py test_cohort_queue.py test_historical_import.py node: name: Node tests and build diff --git a/.gitignore b/.gitignore index 102e7b1..b6d5a16 100644 --- a/.gitignore +++ b/.gitignore @@ -56,3 +56,5 @@ debug_screenshots/ missing_postal_codes.txt postal_code_export*.csv postal_code_v2_export*.csv + +*.migration.lock diff --git a/README.md b/README.md index bde5305..4bc43fd 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ GET /health GET /dashboard ``` -The dashboard shows cache totals, recent daily additions, recent failures, searchable cached postal-code data, CSV export, and a manual weekly-report send button. It uses HTTP Basic Auth. +The root URL and `/dashboard` show cache totals, daily lookup outcomes, failure history (including uncached quota/network errors), searchable and paginated postal-code records with expandable details, complete cache/failure CSV exports, and weekly-report preview. It uses HTTP Basic Auth and fails closed without a configured password or API key. Dashboard credentials provide read-only reporting access; sending an email requires the API key. Recommended dashboard/reporting variables: @@ -74,7 +74,9 @@ Useful if you want the full segment reference data without postal-code lookup. ```http GET /api/cache/entries?status=success&search=V8A&limit=500 -GET /api/cache/export.csv +GET /api/cache/export.csv?include_expired=1 +GET /api/lookups?failures=1&days=7&limit=100&offset=0 +GET /api/lookups/failures.csv?days=3650 ``` ### Weekly Report @@ -192,3 +194,14 @@ python3 -m unittest test_prizm_api.py - Urban postal codes still depend on the Environics geocoder API. During triage on June 21, 2026, that endpoint returned `403 Quota Exceeded`, so urban postal-code lookups may fail until the public quota replenishes or a licensed/geocoding credential is available. - `prizm_cache_v2.db`, CSV exports, debug screenshots, and `node_modules` are runtime/local artifacts and are ignored by Docker. - The old crash was most likely caused by a globally reused Selenium Chrome session combined with Flask debug mode and repeated screenshot/page-source capture. Removing the browser from request handling eliminates that failure path. + +## Operational behavior + +- Weekly metrics use a trailing seven-day window with UTC daily dates. Lookup success means an API result, not a successful Salesforce update. Cache hits, upstream attempts, upstream successes/failures, and unique postal codes are separate metrics. First captures mean the first successful upstream result in retained lookup-event history; imported/earlier records may predate that history. +- The daily Salesforce selector no longer retries an assigned household solely because net worth is unavailable. It preserves an existing net-worth value when no historical reference exists. Retryable quota/network errors leave the household eligible for a later attempt. +- Salesforce household updates now roll back the batch and surface a failed job if any update fails. This exposes errors previously hidden by ignored partial-update results; inspect the job error before retrying a persistently failing batch. +- The current public reference data includes dwelling type but no net worth. Net worth shown here is historical segment reference data of mixed vintage, not a current postal-code-specific estimate. Missing values remain unavailable. Some dwelling types cannot be represented by the existing Salesforce picklist and map to `None or Unverifiable`. +- `MAX_BATCH_POSTAL_CODES=10` limits this application's request size; it does not establish an upstream allowance. A claimed three-per-day restriction remains unverified. Confirm licensed access with Environics before adjusting collection volume. +- Weekly delivery already uses Salesforce's scheduled sender; do not create a second Railway email schedule. Salesforce job completion is not an inbox-delivery receipt. + +See [September 6 investigation and upgrade scope](docs/2026-09-06-upgrade.md). diff --git a/app.py b/app.py index a40450f..0100a37 100644 --- a/app.py +++ b/app.py @@ -13,6 +13,8 @@ from flask import Flask, Response, jsonify, make_response, request from cache_manager_new import cache_manager +from cohort_queue import CohortQueue +from historical_import import merge_history from prizm_client import PrizmClient, PrizmLookupError, normalize_postal_code from segment_net_worth import average_household_net_worth, average_household_net_worth_amount @@ -57,7 +59,9 @@ .muted { color:var(--muted); } .section-title { display:flex; justify-content:space-between; align-items:end; gap:12px; margin:28px 0 12px; } .section-title h2 { margin:0; font-size:20px; } - pre { white-space:pre-wrap; } + pre { white-space:pre-wrap; overflow-wrap:anywhere; max-width:540px; } + #reportStatus { white-space:pre-wrap; } + table { display:block; overflow-x:auto; } @media (max-width:900px) { .grid { grid-template-columns:repeat(2,minmax(0,1fr)); } main, header { padding-left:18px; padding-right:18px; } table { font-size:13px; } } @media (max-width:580px) { .grid { grid-template-columns:1fr; } th:nth-child(5),td:nth-child(5),th:nth-child(6),td:nth-child(6){display:none;} } @@ -72,25 +76,30 @@
Loading…
+ Export major-donor coverage CSV| Postal code | Status | Segment | Name | Home type | Income | Net worth | Cached | Message |
|---|---|---|---|---|---|---|---|---|
| Postal code | Status | Segment | Name | Home type | Income | Historical net worth | Cached | Message |
| Loading… | ||||||||
Includes quota/network errors that are not stored in the cache. Dates are UTC. Export downloads all retained failures.
+