Skip to content

Temporal safety

Temporal safety answers one question: what data was available when the decision was made? Mostly Right keeps event time, knowledge time, and the decision cutoff separate so you can filter and check historical inputs.

TimeQuestion
Event timeWhen did the measured or forecast event happen?
Knowledge timeWhen could a user first know this input?
Decision timeWhen would the model have acted?

An economic observation can describe March, be released in April, and be revised in May. Those are different facts. Treating the March period as the knowledge time leaks April or May into a March decision.

The temporal toolkit operates on rows that carry knowledge_time:

from datetime import date
from mostlyright import economy
from mostlyright.core import KnowledgeView, TimePoint
series = economy.series(
"cpi",
date(2024, 1, 1),
date(2025, 6, 1),
vintages="all",
)
view = KnowledgeView(
series,
TimePoint("2025-04-01T00:00:00Z"),
)
knowable = view.dataframe()

KnowledgeView validates that knowledge_time exists and is timezone-aware UTC, then returns a defensive copy of rows where knowledge_time <= as_of.

Use assert_no_leakage or LeakageDetector when you want an invalid frame to raise instead of being filtered:

from mostlyright.core.temporal import LeakageDetector, assert_no_leakage

These tools check the timestamp carried by each row. They cannot prove that an upstream timestamp is correct or detect leakage added later in feature engineering.

Not every source knows its exact publication time:

Source timingWhat it supports
ExactFilter and audit against the cutoff
Derived or boundedA conservative approximation
ReconstructedHistorical rows without a strict point-in-time guarantee
Latest-only or unknownNot suitable for strict as-of research by default

Check a source’s timing before making a strong claim about a result.

Apply the cutoff in ordinary dataframe code before joining sources:

import pandas as pd
cutoff = pd.Timestamp("2025-04-01T00:00:00Z")
series["knowledge_time"] = pd.to_datetime(series["knowledge_time"], utc=True)
available = series.loc[series["knowledge_time"] <= cutoff]

Keep the cutoff and source timestamp in the returned table. Reconstructed or unknown timestamps cannot support the same point-in-time claim as an exact publication timestamp.

SDK timing checks are necessary but not sufficient:

  1. Split by time, never randomly.
  2. Recompute rolling and expanding features inside each fold.
  3. Fit preprocessing only on the training portion of each fold.
  4. Group cross-station evaluation by station when claiming geographic generalization.
  5. Filter to the knowable_at_utc cutoff that matches the simulated live decision.

The SDK’s old transform helpers were removed in 2.0. Use pandas or Polars, and fit each transform only on the training rows inside each walk-forward fold.

  • Bucketing observations by raw UTC date instead of local_standard_date
  • Selecting the final revised economy value instead of the first vintage
  • Using a forecast run issued after the simulated decision
  • Computing a rolling feature once over the full dataset before splitting
  • Treating label availability as though it were feature availability