LeetLLM
My PlanLearnGlossaryTracksPracticeBlog
LeetLLM

Your go-to resource for mastering AI & LLM systems.

Product

  • Learn
  • Glossary
  • Tracks
  • Practice
  • Blog
  • RSS

Legal

  • Terms of Service
  • Privacy Policy

© 2026 LeetLLM. All rights reserved.

All Topics
Your Progress
0%

0 of 158 articles completed

🛠️Computing Foundations0/9
Git, Shell, Linux for AIDocker for Reproducible AIPython for AI EngineeringNumPy and Tensor ShapesCUDA for ML TrainingMPS & Metal for ML on MacData Structures for AISQL and Data ModelingAlgorithms for ML Engineers
📊Math & Statistics0/8
Gradients and BackpropVectors, Matrices & TensorsLinear Algebra for MLAdam, Momentum, SchedulersProbability for Machine LearningStatistics and UncertaintyDistributions and SamplingHypothesis Tests, Intervals, and pass@k
📚Preparation & Prerequisites0/13
Neural Networks from ScratchCNNs from ScratchTraining & BackpropagationSoftmax, Cross-Entropy & OptimizationRNNs, LSTMs, GRUs, and Sequence ModelingAutoencoders and VAEsThe Transformer Architecture End-to-EndLanguage Modeling & Next TokensFrom GPT to Modern LLMsPrompt Engineering FundamentalsCalling LLM APIs in ProductionFirst AI App End-to-EndThe LLM Lifecycle
🧮ML Algorithms & Evaluation0/11
Linear Regression from ScratchLogistic Regression and MetricsDecision Trees, Forests, and BoostingReinforcement Learning BasicsValidation and LeakageClustering and PCACore Retrieval AlgorithmsDecoding AlgorithmsExperiment Design and A/B TestingPyTorch Training LoopsDataset Pipelines and Data Quality
📦Production ML Systems0/6
Feature Engineering for Production MLBatch and Streaming Feature PipelinesGradient Boosted Trees in ProductionRanking and Recommendation SystemsForecasting and Anomaly DetectionMonitoring Predictive Models
🧪Core LLM Foundations0/8
The Bitter Lesson & ComputeBPE, WordPiece, and SentencePieceStatic to Contextual EmbeddingsPerplexity & Model EvaluationFile Ingestion for AIChunking StrategiesLLM Benchmarks & LimitationsInstruction Tuning & Chat Templates
🧰Applied LLM Engineering0/23
Dimensionality Reduction for EmbeddingsCoT, ToT & Self-Consistency PromptingFunction Calling & Tool UseMCP & Tool Protocol StandardsPrompt Injection DefenseResponsible AI GovernanceData Labeling and Human FeedbackEvaluating AI AgentsProduction RAG PipelinesHybrid Search: Dense + SparseReranking and Cross-Encoders for RAGRAG Evaluation for Reliable AnswersLLM-as-a-Judge EvaluationBias & Fairness in LLMsHallucination Detection & MitigationLLM Observability & MonitoringExperiment Tracking with MLflow and W&BMixed Precision TrainingModel Versioning & DeploymentSemantic Caching & Cost OptimizationLLM Cost Engineering & Token EconomicsModel Gateways, Routing, and FallbacksDesign an Automated Support Agent
🎓Portfolio Capstones0/9
Capstone: Delivery ETA PredictionCapstone: Product RankingCapstone: Demand ForecastingCapstone: Image Damage ClassifierCapstone: Production ML PipelineCapstone: Document QACapstone: Eval DashboardCapstone: Fine-Tuned ClassifierCapstone: Production Agent
🧠Transformer Deep Dives0/8
Sentence Embeddings & Contrastive LossEmbedding Similarity & QuantizationScaled Dot-Product AttentionVision Transformers and Image EncodersPositional Encoding: RoPE & ALiBiLayer Normalization: Pre-LN vs Post-LNMechanistic InterpretabilityDecoding Strategies: Greedy to Nucleus
🧬Advanced Training & Adaptation0/16
Scaling Laws & Compute-Optimal TrainingPre-training Data at ScaleBuild GPT from Scratch LabContinued Pretraining for Domain ShiftSynthetic Data PipelinesSupervised Fine-Tuning PipelineDistributed Training: FSDP & ZeROLoRA & Parameter-Efficient TuningReward Modeling from Preference DataRLHF & DPO AlignmentConstitutional AI & Red TeamingRLVR & Verifiable RewardsKnowledge Distillation for LLMsModel Merging and Weight InterpolationPrompt Optimization with DSPyRecursive Language Models (RLM)
🤖Advanced Agents & Retrieval0/14
Vector DB Internals: HNSW & IVFAdvanced RAG: HyDE & Self-RAGGraphRAG & Knowledge GraphsRAG Security & Access ControlStructured Output GenerationReAct & Plan-and-ExecuteGuardrails & Safety FiltersCode Generation & SandboxingComputer-Use / GUI / Browser AgentsHuman-in-the-Loop Agent ArchitectureAI Coding Workflow with AgentsAgent Memory & PersistenceAgent Failure & RecoveryMulti-Agent Orchestration
⚡Inference & Production Scale0/20
Inference: TTFT, TPS & KV CacheMulti-Query & Grouped-Query AttentionKV Cache & PagedAttentionPrefix Caching and Prompt CachingFlashAttention & Memory EfficiencyContinuous Batching & SchedulingScaling LLM InferenceModel Parallelism for LLM InferenceModel Quantization: GPTQ, AWQ & GGUFLocal LLM DeploymentSLM Specialization & Edge DeploymentSpeculative DecodingLong Context Window ManagementContext EngineeringMixture of Experts ArchitectureMamba & State Space ModelsReasoning & Test-Time ComputeAdvanced MLOps & DevOps for AIGPU Serving & AutoscalingA/B Testing for LLMs
🏗️System Design Capstones0/9
Content Moderation SystemCode Completion SystemMulti-Tenant LLM PlatformLLM-Powered Search EngineVision-Language Models & CLIPMultimodal LLM ArchitectureDiffusion Models: Images & TextReal-Time Voice AI AgentReasoning & Test-Time Compute
🎤AI Lab Interviewing0/4
AI Lab Coding Interview: Python SystemsAI Lab System Design InterviewAI Lab Behavioral InterviewAI Lab Technical Presentation
Back to Topics
LearnProduction ML SystemsBatch and Streaming Feature Pipelines
⚙️MediumMLOps & Deployment

Batch and Streaming Feature Pipelines

Build point-in-time training-run features from events and preserve the same meaning in online serving.

12 min read
Learning path
Step 43 of 158 in the full curriculum
Feature Engineering for Production MLGradient Boosted Trees in Production

A valid training-job SLA row is useful only if the pipeline can build it honestly at scale. The system must produce millions of historical rows for training and keep fresh values ready for live scoring jobs.

Those jobs run at different speeds, but they share one question: what did the scoring system know at the prediction timestamp? If an offline replay sees facts that live serving couldn't have known yet, training gets an unfairly clean view of history.

Two-clock point-in-time quadrant for run R-204: E1 occurred and arrived before 10:00 and is visible, E2 occurred before 10:00 but arrived at 11:00 and is excluded as a late arrival, and E3 occurred after 10:00 and is future; adjacent as-of states advance from queued to warmup_spike to gpu_pressure. Two-clock point-in-time quadrant for run R-204: E1 occurred and arrived before 10:00 and is visible, E2 occurred before 10:00 but arrived at 11:00 and is excluded as a late arrival, and E3 occurred after 10:00 and is future; adjacent as-of states advance from queued to warmup_spike to gpu_pressure.
At 10:00, only E1 lies inside both time boundaries. E2 is the subtle failure: it occurred at 09:30 but arrived at 11:00, so an event-time-only replay leaks information unavailable to live serving.

One event has two relevant times

Consider a training-job telemetry event:

FieldExampleMeaning
event_timeMay 1, 09:30when the scheduler recorded the heartbeat
ingested_atMay 1, 11:00when this pipeline learned about the heartbeat
prediction_timeMay 1, 10:00when the scoring system asked for a training SLA feature row

The heartbeat happened before the scoring request, but it arrived one hour afterward. A live prediction at 10:00 couldn't use it. A faithful replay excludes facts that occurred too late or arrived too late:

text
1event_time <= prediction_time 2and ingested_at <= prediction_time

The first boundary prevents future-event leakage. The second reproduces what the live system knew. Keep both timestamps even if your first source rarely arrives late.

Feature stores commonly provide point-in-time historical retrieval. Feast documents historical joins that scan backward from each entity timestamp within a configured time-to-live (TTL) window.[1]Reference 1Feast: Production Feature Store for Machine Learninghttps://feast.dev/ Your pipeline still owns the exact replay contract, including whether ingestion time belongs in it.

Diagram showing Event log event_time + ingested_at, Feature definition v1 time boundary + missing policy, Batch replay historical training rows, and Stream updater newly arrived events. Diagram showing Event log event_time + ingested_at, Feature definition v1 time boundary + missing policy, Batch replay historical training rows, and Stream updater newly arrived events.
Event log event_time + ingested_at, Feature definition v1 time boundary + missing policy, Batch replay historical training rows, and Stream updater newly arrived events.

Rebuild what serving knew

Build the replay in small steps. The first cell defines one normal event, one late arrival, and one future event for run R-204. Run the cells in order.

01-inspect-event-clocks.py
1from datetime import datetime 2from datetime import timedelta 3 4def dt(value): 5 return datetime.fromisoformat(value) 6 7events = [ 8 { 9 "id": "E1", 10 "run": "R-204", 11 "event_time": dt("2026-05-01T08:00:00"), 12 "ingested_at": dt("2026-05-01T08:02:00"), 13 "source_version": 1, 14 "status": "queued", 15 }, 16 { 17 "id": "E2", 18 "run": "R-204", 19 "event_time": dt("2026-05-01T09:30:00"), 20 "ingested_at": dt("2026-05-01T11:00:00"), 21 "source_version": 1, 22 "status": "warmup_spike", 23 }, 24 { 25 "id": "E3", 26 "run": "R-204", 27 "event_time": dt("2026-05-01T13:00:00"), 28 "ingested_at": dt("2026-05-01T13:01:00"), 29 "source_version": 1, 30 "status": "gpu_pressure", 31 }, 32] 33prediction_time = dt("2026-05-01T10:00:00") 34 35for event in events: 36 lag_minutes = int((event["ingested_at"] - event["event_time"]).total_seconds() / 60) 37 print( 38 f'{event["id"]} status={event["status"]} ' 39 f'occurred={event["event_time"]:%H:%M} arrived={event["ingested_at"]:%H:%M} ' 40 f'lag={lag_minutes}m' 41 )
Output
1E1 status=queued occurred=08:00 arrived=08:02 lag=2m 2E2 status=warmup_spike occurred=09:30 arrived=11:00 lag=90m 3E3 status=gpu_pressure occurred=13:00 arrived=13:01 lag=1m

A filter on event_time alone looks reasonable, but it leaks E2 into a replay of the 10:00 decision.

02-expose-event-time-only-bug.py
1def event_time_only(events, run_id, at): 2 return [ 3 event 4 for event in events 5 if event["run"] == run_id and event["event_time"] <= at 6 ] 7 8naive_replay = event_time_only(events, "R-204", prediction_time) 9print("event-time-only replay:", [event["status"] for event in naive_replay]) 10print("leaked late arrival:", "warmup_spike" in {event["status"] for event in naive_replay})
Output
1event-time-only replay: ['queued', 'warmup_spike'] 2leaked late arrival: True

Add the availability boundary. Now replay sees the same facts live serving saw at 10:00.

03-filter-by-decision-time.py
1def known_by(events, run_id, at): 2 return [ 3 event 4 for event in events 5 if ( 6 event["run"] == run_id 7 and event["event_time"] <= at 8 and event["ingested_at"] <= at 9 ) 10 ] 11 12faithful_replay = known_by(events, "R-204", prediction_time) 13print("decision-time replay:", [event["status"] for event in faithful_replay]) 14print("late heartbeat excluded:", "warmup_spike" not in {event["status"] for event in faithful_replay})
Output
1decision-time replay: ['queued'] 2late heartbeat excluded: True

A historical training snapshot needs the latest visible fact for each prediction request. The warmup_spike becomes usable after it arrives at 11:00; gpu_pressure becomes usable after 13:01.

04-build-as-of-rows.py
1def state_order(event): 2 return (event["event_time"], event.get("source_version", 0)) 3 4def revision_value(event): 5 return event["status"] 6 7def as_of_status(events, run_id, at): 8 visible = known_by(events, run_id, at) 9 if not visible: 10 return "missing" 11 latest_order = max(state_order(event) for event in visible) 12 latest = [event for event in visible if state_order(event) == latest_order] 13 if len({revision_value(event) for event in latest}) > 1: 14 return "quarantined" 15 return revision_value(latest[0]) 16 17for requested_at in [ 18 dt("2026-05-01T10:00:00"), 19 dt("2026-05-01T12:00:00"), 20 dt("2026-05-01T16:00:00"), 21]: 22 print(f"{requested_at:%H:%M} -> {as_of_status(events, 'R-204', requested_at)}")
Output
110:00 -> queued 212:00 -> warmup_spike 316:00 -> gpu_pressure

Sometimes analysts also need a corrected history of what truly happened by 10:00, regardless of when the source delivered it. Keep that artifact separate. Corrected history is useful for auditing training operations, but it isn't a faithful replay of the model's information set.

05-separate-corrected-history.py
1decision_view = [event["status"] for event in known_by(events, "R-204", prediction_time)] 2corrected_view = [event["status"] for event in event_time_only(events, "R-204", prediction_time)] 3 4print("decision-time view:", decision_view) 5print("corrected event-time view:", corrected_view)
Output
1decision-time view: ['queued'] 2corrected event-time view: ['queued', 'warmup_spike']

Keep online state current

Batch replay, stream updates, and online reads are related but distinct jobs:

JobReadsProducesTypical latency
batch replaybounded event historyversioned training snapshotminutes or hours
stream updaternewly arrived eventscurrent feature stateseconds
online readcurrent feature stateone scoring rowmilliseconds

Different stores are acceptable. Different meanings aren't. If batch computes a seven-day backlog mean while online returns a one-hour queue count under the same name, offline metrics can't predict live behavior.

Feast documents an online store built for low-latency feature serving. For each entity key, it stores only the latest feature values rather than full history.[1]Reference 1Feast: Production Feature Store for Machine Learninghttps://feast.dev/ Google Cloud's MLOps guidance describes a feature store as an optional shared repository for definitions, storage, and access across high-throughput batch and low-latency serving workloads.[2]Reference 2MLOps: Continuous Delivery and Automation Pipelines in Machine Learning.https://docs.cloud.google.com/architecture/mlops-continuous-delivery-and-automation-pipelines-in-machine-learning

A late, older event mustn't overwrite newer online state. Same-time corrections need a deterministic rule too. Use the same source-owned (event_time, source_version) order in batch replay and online updates: version 2 replaces version 1, including when a stale version-1 retry arrives later. In a real source contract, require a stable sequence or revision field rather than trusting arrival order.

06-protect-latest-online-state.py
1online_state = {} 2 3def apply_latest_state(state, event): 4 previous = state.get(event["run"]) 5 if previous is not None: 6 if event["id"] == previous.get("id"): 7 return "ignored duplicate event" 8 if state_order(event) < state_order(previous): 9 return "ignored stale event" 10 if state_order(event) == state_order(previous): 11 if previous.get("quarantined"): 12 return "quarantine persists" 13 if revision_value(event) == revision_value(previous): 14 return "ignored duplicate revision" 15 state[event["run"]] = { 16 "run": event["run"], 17 "event_time": event["event_time"], 18 "source_version": event.get("source_version", 0), 19 "status": "quarantined", 20 "quarantined": True, 21 } 22 return "quarantined conflicting revision" 23 state[event["run"]] = event 24 return "stored" 25 26def online_status(state, run_id): 27 current = state.get(run_id) 28 if current is None: 29 return "missing" 30 return "quarantined" if current.get("quarantined") else revision_value(current) 31 32arrivals = [ 33 { 34 "id": "E4", 35 "run": "R-204", 36 "event_time": dt("2026-05-01T10:30:00"), 37 "ingested_at": dt("2026-05-01T10:31:00"), 38 "source_version": 1, 39 "status": "worker_scaled", 40 }, 41 { 42 "id": "E4-correction", 43 "run": "R-204", 44 "event_time": dt("2026-05-01T10:30:00"), 45 "ingested_at": dt("2026-05-01T10:34:00"), 46 "source_version": 2, 47 "status": "worker_scaled_corrected", 48 }, 49 { 50 "id": "E4-v1-retry", 51 "run": "R-204", 52 "event_time": dt("2026-05-01T10:30:00"), 53 "ingested_at": dt("2026-05-01T10:36:00"), 54 "source_version": 1, 55 "status": "worker_scaled", 56 }, 57 { 58 "id": "E1-retry", 59 "run": "R-204", 60 "event_time": dt("2026-05-01T08:00:00"), 61 "ingested_at": dt("2026-05-01T11:05:00"), 62 "status": "queued", 63 }, 64] 65 66for event in arrivals: 67 print(f'{event["id"]}: {apply_latest_state(online_state, event)}') 68print("current status:", online_status(online_state, "R-204"))
Output
1E4: stored 2E4-correction: stored 3E4-v1-retry: ignored stale event 4E1-retry: ignored stale event 5current status: worker_scaled_corrected

Latest-value state isn't enough for aggregates. A duplicated queue update can silently inflate queue backlog unless the updater is idempotent. Idempotent means retrying the same event doesn't change the result after its first successful application. The updater should also reject impossible aggregate states instead of publishing them.

07-deduplicate-aggregate-updates.py
1seen_event_ids = set() 2origin_backlog = 0 3 4def apply_queue_update(event): 5 global origin_backlog 6 if event["id"] in seen_event_ids: 7 return "duplicate skipped" 8 next_backlog = origin_backlog + event["delta"] 9 if next_backlog < 0: 10 return "blocked negative backlog" 11 seen_event_ids.add(event["id"]) 12 origin_backlog = next_backlog 13 return "applied" 14 15queue_updates = [ 16 {"id": "Q1", "delta": 3}, 17 {"id": "Q1", "delta": 3}, 18 {"id": "Q2", "delta": -1}, 19 {"id": "Q3", "delta": -5}, 20] 21 22for update in queue_updates: 23 result = apply_queue_update(update) 24 print(f'{update["id"]}: {result}; backlog={origin_backlog}')
Output
1Q1: applied; backlog=3 2Q1: duplicate skipped; backlog=3 3Q2: applied; backlog=2 4Q3: blocked negative backlog; backlog=2

The set makes sequential retries visible, but production needs a durable atomic write: record the event ID and apply its aggregate change together. Otherwise a worker can crash between those steps and a retry can lose or repeat an update. Use a transaction, conditional write, or stream processor state primitive with the same contract.

Bound lateness and freshness

A stream processor can't wait forever for missing events. It commonly tracks a watermark, an estimate of how far event-time processing has progressed. A watermark isn't a guarantee: an event with an older timestamp can still arrive later. A product policy decides whether that event can update a recent window or must wait for a controlled replay.

This miniature policy accepts updates no more than 45 minutes behind the watermark. A real stream processor also defines windows, triggers, state cleanup, and monitoring.

08-classify-late-events.py
1def late_event_action(event_time, watermark, allowed_lateness): 2 lateness = watermark - event_time 3 if lateness <= timedelta(0): 4 return "on-time path" 5 if lateness <= allowed_lateness: 6 return "accept late update" 7 return "quarantine for replay" 8 9watermark = dt("2026-05-01T12:00:00") 10allowed_lateness = timedelta(minutes=45) 11 12for event_time in [ 13 dt("2026-05-01T12:05:00"), 14 dt("2026-05-01T11:30:00"), 15 dt("2026-05-01T10:00:00"), 16]: 17 print(f"{event_time:%H:%M} -> {late_event_action(event_time, watermark, allowed_lateness)}")
Output
112:05 -> on-time path 211:30 -> accept late update 310:00 -> quarantine for replay

Freshness requires a serving policy:

09-apply-serving-freshness-policy.py
1def serving_mode(updated_at, requested_at): 2 lag_minutes = int((requested_at - updated_at).total_seconds() / 60) 3 if lag_minutes < 0: 4 raise ValueError("feature update is from the future") 5 if lag_minutes <= 15: 6 return "normal scoring" 7 if lag_minutes <= 45: 8 return "fallback and log degraded mode" 9 return "abstain from narrow SLA estimate" 10 11requested_at = dt("2026-05-01T12:00:00") 12for updated_at in [ 13 dt("2026-05-01T11:52:00"), 14 dt("2026-05-01T11:30:00"), 15 dt("2026-05-01T10:30:00"), 16]: 17 print(f"{updated_at:%H:%M} -> {serving_mode(updated_at, requested_at)}")
Output
111:52 -> normal scoring 211:30 -> fallback and log degraded mode 310:30 -> abstain from narrow SLA estimate

No model fixes a missing or temporally invalid input. Record freshness lag with each prediction trace so operators can distinguish model error from stale state.

Compare Offline and Online Rows

Before promotion, replay a sample of requests offline and compare those rows with rows captured from online serving. Start with exact equality for categorical and integer fields; define tolerances explicitly if floating-point aggregations need them.

10-check-offline-online-parity.py
1def mismatches(left, right): 2 keys = left.keys() | right.keys() 3 return {key: (left.get(key), right.get(key)) for key in keys if left.get(key) != right.get(key)} 4 5correction_offline_row = { 6 "status": as_of_status(arrivals, "R-204", dt("2026-05-01T10:40:00")), 7} 8correction_online_row = {"status": online_status(online_state, "R-204")} 9correction_differences = mismatches(correction_offline_row, correction_online_row) 10print("same-time retry mismatches:", correction_differences) 11 12conflicting_revisions = [ 13 { 14 "id": "E5-a", 15 "run": "R-205", 16 "event_time": dt("2026-05-01T10:30:00"), 17 "ingested_at": dt("2026-05-01T10:31:00"), 18 "source_version": 7, 19 "status": "worker_scaled", 20 }, 21 { 22 "id": "E5-b", 23 "run": "R-205", 24 "event_time": dt("2026-05-01T10:30:00"), 25 "ingested_at": dt("2026-05-01T10:32:00"), 26 "source_version": 7, 27 "status": "worker_scale_failed", 28 }, 29] 30conflict_online_state = {} 31for event in conflicting_revisions: 32 apply_latest_state(conflict_online_state, event) 33conflict_offline = as_of_status(conflicting_revisions, "R-205", dt("2026-05-01T10:40:00")) 34conflict_online = online_status(conflict_online_state, "R-205") 35assert conflict_offline == conflict_online == "quarantined" 36print("equal-order conflict parity:", conflict_offline, "==", conflict_online) 37 38for event in events: 39 if event["ingested_at"] <= dt("2026-05-01T16:00:00"): 40 apply_latest_state(online_state, event) 41 42offline_row = { 43 "status": as_of_status(events, "R-204", dt("2026-05-01T16:00:00")), 44 "origin_backlog": origin_backlog, 45} 46online_row = { 47 "status": online_status(online_state, "R-204"), 48 "origin_backlog": origin_backlog, 49} 50 51print("offline row:", offline_row) 52print("online row:", online_row) 53print("mismatches:", mismatches(offline_row, online_row))
Output
1same-time retry mismatches: {} 2equal-order conflict parity: quarantined == quarantined 3offline row: {'status': 'gpu_pressure', 'origin_backlog': 2} 4online row: {'status': 'gpu_pressure', 'origin_backlog': 2} 5mismatches: {}

A stale online row produces a visible failure instead of a mysterious model regression.

11-detect-stale-online-state.py
1stale_online_row = { 2 "status": "worker_scaled", 3 "origin_backlog": origin_backlog, 4} 5differences = mismatches(offline_row, stale_online_row) 6print("mismatches:", differences) 7print("release allowed:", not differences)
Output
1mismatches: {'status': ('gpu_pressure', 'worker_scaled')} 2release allowed: False

Publish a compact receipt beside every snapshot and candidate model. It makes replay semantics inspectable instead of leaving them hidden in job code.

12-publish-replay-receipt.py
1receipt = { 2 "feature_definition": "training_sla_features_v1", 3 "replay_boundary": "event_time <= prediction_time and ingested_at <= prediction_time", 4 "offline_online_ordering": "(event_time, source_version); equal-key conflicts quarantine", 5 "aggregate_updates": "atomic event-id dedup; reject negative backlog", 6 "snapshot": "training-sla-train-2026-05-01", 7 "parity_samples_checked": 2, 8 "freshness_policy": "sla-freshness-v1", 9} 10 11assert as_of_status(events, "R-204", dt("2026-05-01T10:00:00")) == "queued" 12assert as_of_status(events, "R-204", dt("2026-05-01T12:00:00")) == "warmup_spike" 13assert not correction_differences 14assert not mismatches(offline_row, online_row) 15 16for key, value in receipt.items(): 17 print(f"{key}={value}")
Output
1feature_definition=training_sla_features_v1 2replay_boundary=event_time <= prediction_time and ingested_at <= prediction_time 3offline_online_ordering=(event_time, source_version); equal-key conflicts quarantine 4aggregate_updates=atomic event-id dedup; reject negative backlog 5snapshot=training-sla-train-2026-05-01 6parity_samples_checked=2 7freshness_policy=sla-freshness-v1

Practice: break the pipeline

Run the lab, then change one condition at a time:

  1. Remove the ingested_at <= at condition from known_by. Confirm the 10:00 row leaks warmup_spike.
  2. Remove the shared ordering checks. Confirm E4-v1-retry undoes the same-time correction online and creates a parity mismatch; then confirm E1-retry can regress state to queued.
  3. Remove seen_event_ids. Confirm the duplicated Q1 update inflates backlog. Then remove the negative-state check and confirm Q3 publishes an impossible queue size.
  4. Change online_row["status"] to "worker_scaled". Confirm parity blocks release.
  5. Move a feature timestamp 90 minutes behind the request. Confirm serving abstains from a narrow SLA estimate.

Explain the replay without looking back

What strong answers show

EvidenceWhat a strong answer shows
temporal correctnessconstructs training rows with explicit event-time and availability boundaries
online statehandles older arrivals, duplicate updates, and freshness failures deliberately
operational replayversions snapshots, parity receipts, and corrected analytical views separately

When the Contract Breaks

SymptomCauseFix
Training gets better after a backfill but serving doesn'treplay used facts that arrived laterfilter by event time and ingestion time
Online status moves backward after retry or same-time corrections disagreestale or ambiguous event overwrote latest statecompare event timestamp plus source revision; quarantine unresolved ties
Backlog inflates during redeliveryaggregate update ran twicededuplicate by stable event ID in same atomic write as aggregate change
Reliable model emits bad SLA estimates during upstream lagfreshness wasn't part of serving policytrace age and fail to a safer response
Complete the lesson

Mastery Check

Answer every question, then check your score. Score above 75% to mark this lesson complete.

1.For run R-204, a prediction is requested at 10:00. E1 occurred at 08:00 and arrived at 08:02; E2 occurred at 09:30 and arrived at 11:00; E3 occurred at 13:00 and arrived at 13:01. Which status should a faithful replay expose at 10:00?
2.At 10:00, R-204 has E1 queued with event_time 08:00 and ingested_at 08:02, and E2 warmup_spike with event_time 09:30 and ingested_at 11:00. An analyst wants a corrected audit of what physically happened by 10:00, while the model training row must replay what the training SLA service knew at 10:00. Which handling is correct?
3.A heartbeat arrives on the event stream at 10:31 and the training SLA service asks for a feature row at 10:32. Which division of work matches the pipeline contract?
4.A team keeps historical features in a batch store and latest values in a low-latency online store. What condition makes this acceptable before model promotion?
5.R-204 receives E4 at event_time 10:30 with source_version 1, E4-correction at the same time with source_version 2, then a delayed retry of E4 version 1. Batch replay and the online updater both order by (event_time, source_version). What should both expose at 10:40?
6.An aggregate updater for origin_backlog starts at 0 and may retry after worker crashes. It receives Q1 delta +3, duplicate Q1 delta +3, Q2 delta -1, and Q3 delta -5. Which implementation contract preserves the intended published state?
7.With watermark 12:00 and allowed lateness 45 minutes, a stream processor sees events with event_time 12:05, 11:30, and 10:00. How should they be routed under this policy?
8.A serving policy for training SLA features is: lag <= 15 minutes uses normal scoring, lag <= 45 minutes falls back and logs degraded mode, and larger lag abstains from a narrow SLA estimate. At 12:00 the feature was last updated at 10:30. What should serving do?

8 questions remaining.

Next Step
Continue to Gradient Boosted Trees in Production

You can now generate point-in-time correct feature rows. Next you'll train a strong tabular baseline and decide when its validation evidence earns deployment.

PreviousFeature Engineering for Production ML
Share this article
XFacebookLinkedInBlueskyRedditHacker NewsEmail
References

Feast: Production Feature Store for Machine Learning

Feast Contributors · 2024

MLOps: Continuous Delivery and Automation Pipelines in Machine Learning.

Google Cloud. · 2026 · Official documentation

Discussion

Questions and insights from fellow learners.

Discussion loads when you reach this section.