Skip to content

feat: coverage endpoint so callers can discover what data exists - #5

Merged
keonik merged 1 commit into
mainfrom
feat/coverage-endpoint
Sep 11, 2026
Merged

feat: coverage endpoint so callers can discover what data exists#5
keonik merged 1 commit into
mainfrom
feat/coverage-endpoint

Conversation

@keonik

@keonik keonik commented Sep 11, 2026

Copy link
Copy Markdown
Owner

Street-level data is Ohio only. Today a caller querying Michigan gets an empty
result set, which looks exactly like a malformed query or a broken service —
and that is a support ticket every time, because there is no way to tell the
difference from outside.

GET /api/v1/coverage            summary by state
GET /api/v1/coverage?state=OH   per-county breakdown

Three decisions worth reviewing

Derived from ohio_addresses, not the datasets table. datasets tracks
uploads rather than contents, and the original Ohio import never went through
the uploader — so a coverage view built on it would report zero for the only
state that actually has data.

Cached for ten minutes. The honest implementation is a GROUP BY over
every address row, which is precisely the per-request full-table aggregate the
address-search count query was doing. Coverage only changes when a dataset is
imported, so the import invalidates the snapshot and the TTL is a backstop. The
lock is held across the rebuild so a cold cache under load has one request pay
and the rest wait, rather than all of them running the aggregate.

A valid key, but no permission scope. Gating this would 403 every key
already issued, since none carry a coverage permission — and the endpoint
exists so a caller can learn what to ask for before asking. It returns no
address, ZIP or boundary content.

A failed rebuild serves the previous snapshot rather than a 500. This is
descriptive metadata; last week's answer is more useful than an error, and it
is never badly wrong.

Verification

Tests assert the drill-down agrees with the summary (county counts and address
sums both), that an unloaded state is an empty list rather than an error, and
that the snapshot is cached and then rebuilt after invalidation. Full suite
green against the probe databases.

🤖 Generated with Claude Code

https://claude.ai/code/session_01S2nhUJ4Zdsxf7cP9DapsY3

Street-level data is Ohio only. A caller querying anywhere else gets an empty
result set, which is indistinguishable from a malformed query or a broken
service -- so they open a ticket instead of reading a number.

GET /api/v1/coverage            summary by state
GET /api/v1/coverage?state=OH   per-county breakdown

Derived from ohio_addresses, not the datasets table. datasets tracks uploads
rather than contents, and the original Ohio import did not come through the
uploader, so it would report zero for the only state that has data.

Cached for ten minutes rather than aggregated per request -- that GROUP BY over
every address row on every call is the same mistake the address search count
query was making. Coverage only changes when a dataset is imported, so the
import invalidates the snapshot and the TTL is just a backstop. A failed
rebuild serves the previous snapshot instead of a 500: this is descriptive
metadata, and last week's answer beats an error.

Coverage needs a valid API key but no permission scope. Gating it would 403
every key already issued -- none carry a "coverage" permission -- and the
endpoint exists so a caller can find out what to ask for before asking. It
returns no address, ZIP or boundary content.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S2nhUJ4Zdsxf7cP9DapsY3
@keonik
keonik merged commit a100a14 into main Sep 11, 2026
3 checks passed
@keonik
keonik deleted the feat/coverage-endpoint branch September 11, 2026 12:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant