A feature is useful only when its entity, computation, timestamp and prediction-time availability are explicit.
Feature-store contract: entity keys, event time and availability
Define the entity
For receipt triage, a merchant risk count may be keyed by merchant ID while a receipt amount is keyed by receipt ID. Joining the former on an unversioned display name can combine unrelated merchants after a rename. Specify key normalization, null policy and one-row-per-key guarantees. Dataset grain still governs a feature store, even when feature retrieval appears to be one API call.
Separate clocks
An event can occur at 09:00, reach the warehouse at 09:08 and become queryable at 09:14. A model scoring at 09:05 cannot use that value, even if a historical join based only on event time would select it. Store event time, ingestion time and feature availability or materialization time. Prediction-time availability is a release contract, not a comment in a query.
Specify meaning and ownership
Give each feature a unit, window, aggregation rule, missing-value meaning, owner, retention period and version. “Merchant failures in 47 hours” must clarify whether retries, rejected receipts or later corrections count. Separate private learner data from public lesson metadata; a convenient shared registry is not permission to expose every feature to every model.
Test a late event
A receipt submitted at 09:00 but ingested at 09:08 must be absent from a 09:05 prediction. A correction recorded at 10:20 may revise a later snapshot without changing the earlier training example. Create two merchants with the same display name and confirm key-based lookup keeps them separate. A missing entity should produce an explicit missing marker.
Implementation
def available_feature(values, entity_id, decision_time):
eligible = [value for value in values
if value["entity_id"] == entity_id
and value["event_at"] <= decision_time
and value["available_at"] <= decision_time]
return max(eligible, key=lambda value: (value["event_at"], value["available_at"]), default=None)Performance and operating cost
A list scan costs O(V) time and O(V) temporary memory for V records. An indexed entity and availability-time table can reduce repeated retrieval work, but the chosen value must still obey both the decision cutoff and feature version.
Common Mistakes
- Do not join entities by a mutable display label.
- Do not confuse event time with the time a feature became available.
- Do not publish an unnamed null as if it were a valid zero.
