event_date is a claim about the world. coded_at is a claim about our coding pipeline. A backtest
that filters only on event_date can include events learned later. For a feed of records first
available to API callers, use recorded_start / recorded_end on the Event or Story list.
The as-of claim we do make
Filtering on coding time selects a coding-time cohort, not a replay of the public API at that time. The coding timestamp is useful for latency research, but an event can be coded before its serving partition and publication journal make it available to API callers.- The coding timestamp is populated on 100% of events, stamped once when the coder emits the event and never revised.
- Every event carries
source_urls— the actual articles it was derived from. Nothing is coded from a source we do not cite, so you can go read the evidence that was available at the time.
How to ask for it
Use the two ordinary list questions first. Existingobserved_* filters remain accepted for
specialist coding/update-time work, but new integrations should not use them to poll for new rows.
as_of on /api/v2/events returns 400, deliberately. Event metrics are computed live and are
not vintaged, so as_of could not return a reproducible point-in-time result there — and answering
200 with a plausible-looking result would be worse than refusing. Use observed_start /
observed_end for coding-time research, or recorded_start / recorded_end for records first
made available to callers. Neither is an as-of replay. as_of is supported where the data is
genuinely vintaged: /macro/observations, /screening/match and the Atlas /intelligence/*
surfaces.Why events are coded after the day they happened
Measured over the seven days ending 2026-07-21, across 11,993 events: the median gap between an article becoming available to us and its coded event being queryable is 38 minutes, with a 90th percentile of 61 minutes. 89.1% of events are available within the hour. Lag measured the other way — againstevent_date rather than against the article — looks much
larger, and the difference is mostly arithmetic rather than processing. Three real causes, in order.
1. Hourly cadence
Ingest runs on the top of every hour, so there is an irreducible sub-hour quantisation: an article that appears just after a run waits for the next one. The floor is set by the cycle, not by processing time, which is why the median lands near half a cycle plus the pipeline’s own duration. A separate catch-up pass runs near the end of each hour and sweeps clusters the main run did not reach, and range backfills re-code historical windows when coverage gaps are found.2. Publication lag in the sources themselves
event_date is when the event occurred, not when it was reported. Local and non-English outlets
frequently publish on D+1 about a D event, and for some regions that is the only coverage. The
conflict family shows this most.
3. The midnight boundary — an artefact, not a delay
event_date is a date, not a timestamp. An event that happened at 22:00 UTC and was coded at
23:00 UTC — one hour later — already registers as “coded the same day” with almost no margin, and
one coded at 00:30 registers as a next-day event on a 90-minute pipeline. Most of the apparent
day-scale lag against event_date is this, not work in progress.
We do not wait for corroboration before coding. A story does not have to accumulate articles to
become codeable — single-article clusters are a first-class coding path and are the majority of what
we code. Measured over the same window, computing latency from the earliest contributing article,
including everything that arrived later, moves the median by 32 seconds (2,332 s vs 2,300 s). If
coverage had to accrete before an event could be coded, that gap would be hours.
Later-coded events are better evidenced — but that is selection, not waiting
Comparing events coded within a day of theirevent_date against those coded in the following day:
The reason is which net caught them, not how long they sat. The hourly catch-up pass targets
clusters the main run left uncoded and requires at least two articles, so the events it recovers are
by construction the better-corroborated ones. Either way the practical conclusion holds: if you
drop the tail to get a tighter latency number, you are dropping your best-evidenced events.
How to use this in a backtest
1
Filter on when we coded it, not on when it happened
For a signal you claim to have had at time T, bound
observed_end at T. Filtering on
event_date alone silently imports hindsight.2
Set your decision lag from the distribution, not the median
If your strategy acts on same-day information, model a decision point at T+24h and accept that
you will see roughly 89% of the day’s events. If it can wait, T+48h gets you effectively all of
them, with better evidence.
3
Do not treat a thin day as a quiet day
A day with an unusually low event count near the present is more likely still filling in than
genuinely calm. Re-pull recent windows before drawing a conclusion about them, and prefer
windows that are at least 48 hours old.
4
Check the file's own as-of stamp
Every bulk file carries an
as_of value that reports what the weakest partition in it knew —
the minimum across dates, not the maximum, so one freshly settled day cannot vouch for a stale
month.
