shinnslist

data freshness LIVE

Every record shinnslist returns carries its own freshness stamp — no separate freshness lookup, no fine print. This page is the working reference of the real freshness surface, verified against the deployed functions code (apps/poc-web/functions — lib/pipeline.js, lib/mcp.js, api/intel.js, api/status.js, api/engine/cache.js, api/engine/stats.js, api/mcp.js) before a word was written. Everything planned-but-not-built is marked DRAFT.

the whole contract, in one paragraph. Every signal record in an /api/intel response (and every MCP tool result) carries two timestamps: retrieved_at — when this run computed the record, set by the pipeline itself, never by the adapter — and data_as_of — the adapter's declared upstream source date, or null when the adapter doesn't know it. null is never fabricated into a date. There are no freshness SLAs, no staleness thresholds, and no refresh schedule anywhere in the codebase — the timestamps plus the caches documented below are the entire freshness story. If you receive a field not described anywhere on this page, it came from code that changed after 2026-09-29 — the verification date above is the freshness stamp.

the two timestamps on every signal LIVE

Verified in lib/pipeline.js: the pipeline stamps each adapter's record after the adapter runs, so an adapter can never backdate or forward-date its own freshness:

fieldset bymeaning
retrieved_atthe pipeline, per run (one value per /api/intel call)ISO-8601 instant this run computed the record. Two calls a minute apart give two different values — every call re-runs the pipeline (cache-control: no-store on /api/intel).
data_as_ofthe adapter, or nullthe upstream source's as-of date, declared by the adapter itself. null means "the adapter doesn't know" — it is never fabricated, and it does not mean the data is stale.
statusthe pipelinelive or degraded. A throwing adapter becomes degraded with the reason in unavailable — never a 500, so a partial answer still arrives with its stamps.

The same contract covers MCP: lib/mcp.js stamps every tool result with retrieved_at / data_as_of under the comment "same contract as the /api/intel pipeline envelope." The out-of-Virginia boundary signal carries retrieved_at with data_as_of: null — it is local geometry with no upstream source date, so the pipeline honestly reports none.

one adapter declares a source date today LIVE

A full-tree search on 2026-09-29 found exactly one adapter that sets data_as_of: lib/signals/whole_region_rank.js (data_as_of: epochToDate(freshestState) — the freshest upstream state date it could see). Every other adapter ships data_as_of: null.

How to read this: a null data_as_of is an honest unknown, not a failure and not a staleness verdict. It tells you the adapter pulls from a source with no published as-of date (or the adapter author didn't declare one). As adapters start declaring source dates, they appear here — null flips to a real date in the response, no announcement needed.

degraded is a freshness signal too LIVE

When an adapter throws, the pipeline does not fail the call — it records the failure honestly (lib/pipeline.js, mirrored in lib/mcp.js and lib/parcels.js county pipelines):

{
  "signal_id": "example_signal",
  "status": "degraded",
  "adapter_version": "v0",
  "result": null,
  "evidence": [],
  "unavailable": ["adapter error: upstream timeout"],
  "confidence": "low",
  "retrieved_at": "2026-09-29T12:00:00.000Z",
  "data_as_of": null
}

A degraded record still carries retrieved_at — the timestamp of the failed attempt — so you can tell "the source was unreachable at 12:00" apart from "we never tried." The right move is to retry later; unavailable names the reason. A throwing adapter never becomes a 500 on the whole response.

caches that touch your data LIVE

These are the only caches between you and the sources, verified in the code. Everything else is computed fresh per request:

surfacecachewhat it means for freshness
/api/intel responsesnone — cache-control: no-storeEvery call re-runs the full pipeline. Two identical calls give two retrieved_at values.
engine parcel data (per ZIP)KV, 1 hour (PARCEL_CACHE_TTL = 3600, key parcels:v1:<zip>)Raw normalized parcel records per ZIP may be up to 1 hour old. Scoring re-runs fresh on every request (deterministic), so a cached parcel set ranks identically to a live one. Missing KV binding degrades to a live GIS fetch — nothing breaks.
engine statsin-memory, 5 minutes (CACHE_TTL_MS)Aggregate stats endpoints may lag up to 5 minutes.
MCP tools/listserver cache, 60 seconds (listCaching: { ttlMs: 60000 })The tool catalog may lag up to 60 seconds after a deploy. Tool results are never cached.
/api/statusedge, 60 seconds (cache-control: public, max-age=60)Live/degraded/pending counts may lag up to 60 seconds. /api/health is uncached.

What this table is not: a staleness SLA. The 1-hour parcel cache is an engineering cache, not a data-refresh promise — the upstream GIS's own update cadence is the floor, and it is not published here because the code doesn't know it.

envelope fields that carry freshness LIVE

Beyond the per-signal stamps, the /api/intel envelope carries:

planned: freshness SLAs DRAFT

No freshness SLAs exist today — no guaranteed refresh cadence, no maximum-age promise, no "stale after N days" rule anywhere in the codebase. Planned: published freshness targets per signal family, so you can contract against staleness instead of eyeballing timestamps. Target numbers, tiers, and the SLA surface are not final — no numbers are printed here because any number would be invented. When SLAs ship, they land here, copied from the shipped code.

planned: per-signal refresh cadences DRAFT

Planned: a published cadence per signal (how often its upstream source refreshes and how often shinnslist re-pulls it), so data_as_of gains context. Not published today — the code doesn't track per-signal cadences, so none are listed here. Until then, retrieved_at and data_as_of are the complete picture.

what's planned, not yet shipped DRAFT

The full planned surface, in one list. Every item here is not final — names, numbers, tiers, and surfaces will be verified against the shipped code before they replace these bullets:

When the first SLA ships, the DRAFT badges on this page flip to LIVE and the bullets above become the verified reference.

how to read a record today

Three checks, in order:

Log pipeline_version with every call you care about — it's the one field that tells you the freshness rules themselves changed.

numbers you won't find. There are no freshness SLA headers, no x-data-age-style response headers, no freshness tiers in the response, and no published refresh schedule — a full-tree search on 2026-09-29 found none, so none are documented here. The cache TTLs in the table above (1 hour parcel KV, 5 minute stats, 60 second MCP tool list, 60 second /api/status edge cache, no-store on /api/intel) are engineering caches, not data-freshness promises. Anything planned is DRAFT-badged and described as planned, never as live.

next: docs hub · getting started · api reference · error reference · rate limits