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 SystemsFeature Engineering for Production ML
⚙️MediumMLOps & Deployment

Feature Engineering for Production ML

Turn training-job events into stable prediction inputs while preventing leakage and training-serving mismatch.

11 min read
Learning path
Step 42 of 158 in the full curriculum
Dataset Pipelines and Data QualityBatch and Streaming Feature Pipelines

Versioned datasets with clean splits still aren't model-ready by themselves. A prediction model can't consume a raw event log directly. To predict whether a training job will miss its SLA, it needs a fixed row of measurements available at the moment the promise is made.

Those measurements are features. A feature such as hours_since_last_heartbeat compresses many scheduler events into one input value. Inventing columns is easy compared with making sure each value means the same thing during training and while serving live requests.

Job J-204 event timeline cut at the 09:00 prediction timestamp: heartbeats at 01:00 and 08:30 are visible, the latest at 08:30 yields a six-slot feature vector with 0.5-hour heartbeat age, while a 12:00 heartbeat, finished timestamp, and post-SLA escalation remain in the future-only region outside model inputs. Job J-204 event timeline cut at the 09:00 prediction timestamp: heartbeats at 01:00 and 08:30 are visible, the latest at 08:30 yields a six-slot feature vector with 0.5-hour heartbeat age, while a 12:00 heartbeat, finished timestamp, and post-SLA escalation remain in the future-only region outside model inputs.
At 09:00, the contract emits the exact six-field row [a100-pool, 42.0, 0.5, 18.0, 0, 0]. The noon heartbeat, finished timestamp, and post-SLA escalation remain beyond the cutoff and can't enter the model input.

Start With a Prediction Timestamp

Suppose the product asks at 2026-05-01 09:00: will job J-204 miss its SLA? Job heartbeats after that timestamp aren't available to the prediction service and can't appear in its training row.

Candidate fieldKnown at prediction time?Use as feature?
runner poolyesyes, categorical
queued minutesyesyes, numeric
minutes since most recent heartbeatyesyes, numeric
cluster queue backlogyesyes, numeric
finished timestampnono, it defines the eventual label
post-SLA escalationnono, it leaks the outcome

The label may be computed later as missed_sla = 1. A feature must be computed from history ending at the prediction timestamp. If a training row contains the post-SLA escalation, offline accuracy will reward a model for reading the answer.

Sculley et al. describe production ML systems as networks of data and configuration dependencies where hidden feedback and undeclared consumers create technical debt.[1]Reference 1Hidden Technical Debt in Machine Learning Systems.https://research.google/pubs/hidden-technical-debt-in-machine-learning-systems/ Feature definitions are one of those dependencies: when their time boundary is unclear, the model's impressive score doesn't survive deployment.

Diagram showing Job events through prediction time, Feature contract types + missing policy, Training snapshot label joins later, and Online request same computation. Diagram showing Job events through prediction time, Feature contract types + missing policy, Training snapshot label joins later, and Online request same computation.
Job events through prediction time, Feature contract types + missing policy, Training snapshot label joins later, and Online request same computation.

Define one row before training

Build a small contract for job-SLA prediction:

FeatureTypeMissing ruleWhy it can help
queued_minutesnumericreject if absentlonger queue waits expose more scheduling risk
hours_since_last_heartbeatnumericcap at 180stale heartbeats signal job risk
queue_backlognumericuse measured queue onlyqueue pressure affects scheduling and preemption
runner_poolcategoricalreject if absent; map unseen to otherrunner pools have different networks
priority_jobbooleandefault false only when source guarantees itpriority changes SLA and retry policy

A missing value is a product decision. Filling missing queue_backlog with zero says "unknown congestion means no congestion," which is rarely defensible. Store an additional queue_backlog_missing indicator or stop scoring until the feed recovers.

Categorical values need a policy too. If a new runner pool appears after training, the online encoder can't invent a new model column. An other bucket provides stable behavior while a new model candidate is evaluated. Missing runner pool data is different: it may signal a broken source feed, so don't silently fold it into other.

Prove the Time Boundary

A feature job should make the prediction timestamp explicit, then discard later events before aggregation. This first lab keeps only heartbeats whose event timestamps aren't later than the prediction. It deliberately assumes heartbeats arrive immediately. The next lesson adds a separate ingestion timestamp so a replay can't use an earlier heartbeat that arrived late.

keep-visible-events.py
1from datetime import datetime 2 3prediction_time = datetime.fromisoformat("2026-05-01T09:00:00") 4heartbeats = [ 5 datetime.fromisoformat("2026-05-01T01:00:00"), 6 datetime.fromisoformat("2026-05-01T08:30:00"), 7 datetime.fromisoformat("2026-05-01T12:00:00"), 8] 9 10visible_heartbeats = [heartbeat for heartbeat in heartbeats if heartbeat <= prediction_time] 11print("visible heartbeats:", len(visible_heartbeats)) 12print("latest visible:", max(visible_heartbeats).isoformat())
Output
1visible heartbeats: 2 2latest visible: 2026-05-01T08:30:00

Filtering source history is necessary but not sufficient. A transformation can still copy a future-only field into its output by mistake. Check the actual feature keys before training or serving.

reject-leaked-output.py
1allowed_feature_keys = { 2 "runner_pool", 3 "queued_minutes", 4 "hours_since_last_heartbeat", 5 "queue_backlog", 6 "queue_backlog_missing", 7 "priority_job", 8} 9candidate_features = { 10 "runner_pool": "a100-pool", 11 "queued_minutes": 42.0, 12 "finished_at": "2026-05-03T14:00:00", 13} 14 15blocked_fields = sorted(candidate_features.keys() - allowed_feature_keys) 16print("blocked fields:", blocked_fields) 17print("release allowed:", not blocked_fields)
Output
1blocked fields: ['finished_at'] 2release allowed: False

An allowlist gate is stronger than a comment or a static list of future fields: it fails when an unexpected key enters the feature row. It can't prove that an allowed field contains only information known at prediction time. Source-history filtering and offline/online parity checks still have to enforce that semantic contract.

Encode ambiguity deliberately

For this model, keep a missing queue backlog distinct from a measured queue backlog of zero. The imputed value keeps the vector numeric; the indicator preserves the information that measurement failed. Another product might abstain instead.

encode-missing-queue-backlog.py
1def encode_queue_backlog(value): 2 return { 3 "queue_backlog": 0.0 if value is None else float(value), 4 "queue_backlog_missing": int(value is None), 5 } 6 7print("measured zero:", encode_queue_backlog(0)) 8print("missing:", encode_queue_backlog(None))
Output
1measured zero: {'queue_backlog': 0.0, 'queue_backlog_missing': 0} 2missing: {'queue_backlog': 0.0, 'queue_backlog_missing': 1}

Reserve a fitted other category too. Well-formed new runner pools then have a stable representation until retraining evaluates them explicitly. Reject an absent runner_pool instead of hiding a feed failure inside the fallback bucket.

encode-unseen-runner-pool.py
1known_runner_pools = {"a100-pool", "h100-pool"} 2 3def encode_runner_pool(value): 4 if not isinstance(value, str) or not value.strip(): 5 raise ValueError("runner_pool is missing") 6 normalized = value.strip().casefold() 7 return normalized if normalized in known_runner_pools else "other" 8 9for runner_pool in ["a100-pool", "l4-pool", None]: 10 try: 11 print(f"{runner_pool!r} -> {encode_runner_pool(runner_pool)}") 12 except ValueError as error: 13 print(f"{runner_pool!r} -> blocked: {error}")
Output
1'a100-pool' -> a100-pool 2'l4-pool' -> other 3None -> blocked: runner_pool is missing

Caps are contract choices, not universal constants. This example limits the influence of very old heartbeats. The fitted cap must travel with the model.

cap-heartbeat-age.py
1max_heartbeat_age_hours = 180.0 2 3def cap_heartbeat_age(hours): 4 return min(float(hours), max_heartbeat_age_hours) 5 6for hours in [8, 180, 360]: 7 print(f"{hours} -> {cap_heartbeat_age(hours)}")
Output
18 -> 8.0 2180 -> 180.0 3360 -> 180.0

A negative heartbeat age indicates broken event timing or a missing cutoff filter. Reject it instead of passing a surprising number into the model.

reject-future-heartbeat.py
1from datetime import datetime 2 3def hours_since_last_heartbeat(last_heartbeat_at, prediction_time): 4 heartbeat = datetime.fromisoformat(last_heartbeat_at) 5 if heartbeat > prediction_time: 6 raise ValueError("last_heartbeat_at is after prediction_time") 7 return (prediction_time - heartbeat).total_seconds() / 3600 8 9prediction_time = datetime.fromisoformat("2026-05-01T09:00:00") 10try: 11 hours_since_last_heartbeat("2026-05-01T12:00:00", prediction_time) 12except ValueError as error: 13 print("blocked:", error)
Output
1blocked: last_heartbeat_at is after prediction_time

Build one trustworthy row

Now assemble those policies. The source record may contain post-job-SLA fields because labels need them later. The returned model row may contain only allowlisted feature keys.

build-feature-row.py
1from datetime import datetime 2from math import isfinite 3 4allowed_feature_keys = { 5 "runner_pool", 6 "queued_minutes", 7 "hours_since_last_heartbeat", 8 "queue_backlog", 9 "queue_backlog_missing", 10 "priority_job", 11} 12known_runner_pools = {"a100-pool", "h100-pool"} 13future_only_keys = {"finished_at", "post_sla_escalation"} 14 15def make_features(row, prediction_time): 16 required_keys = {"queued_minutes", "last_heartbeat_at", "priority_job"} 17 missing_keys = sorted(required_keys - row.keys()) 18 if missing_keys: 19 raise ValueError(f"missing required fields: {missing_keys}") 20 21 queued_minutes = float(row["queued_minutes"]) 22 if not isfinite(queued_minutes) or queued_minutes <= 0: 23 raise ValueError("queued_minutes must be finite and positive") 24 25 runner_pool = row.get("runner_pool") 26 if not isinstance(runner_pool, str) or not runner_pool.strip(): 27 raise ValueError("runner_pool is missing") 28 runner_pool = runner_pool.strip().casefold() 29 30 if not isinstance(row["priority_job"], bool): 31 raise ValueError("priority_job must be boolean") 32 33 last_heartbeat = datetime.fromisoformat(row["last_heartbeat_at"]) 34 if last_heartbeat > prediction_time: 35 raise ValueError("last_heartbeat_at is after prediction_time") 36 heartbeat_age = min((prediction_time - last_heartbeat).total_seconds() / 3600, 180.0) 37 38 queue_backlog = row.get("queue_backlog") 39 if queue_backlog is not None: 40 queue_backlog = float(queue_backlog) 41 if not isfinite(queue_backlog) or queue_backlog < 0: 42 raise ValueError("queue_backlog must be finite and nonnegative") 43 features = { 44 "runner_pool": runner_pool if runner_pool in known_runner_pools else "other", 45 "queued_minutes": queued_minutes, 46 "hours_since_last_heartbeat": heartbeat_age, 47 "queue_backlog": 0.0 if queue_backlog is None else queue_backlog, 48 "queue_backlog_missing": int(queue_backlog is None), 49 "priority_job": int(row["priority_job"]), 50 } 51 52 blocked_fields = sorted(features.keys() - allowed_feature_keys) 53 if blocked_fields: 54 raise ValueError(f"unexpected feature fields: {blocked_fields}") 55 return features 56 57prediction_time = datetime.fromisoformat("2026-05-01T09:00:00") 58job = { 59 "job_id": "J-204", 60 "runner_pool": "a100-pool", 61 "queued_minutes": 42, 62 "queue_backlog": 18, 63 "priority_job": False, 64 "last_heartbeat_at": "2026-05-01T08:30:00", 65 "finished_at": "2026-05-03T14:00:00", 66 "post_sla_escalation": True, 67} 68 69features = make_features(job, prediction_time) 70print(features) 71print("future fields leaked:", sorted(features.keys() & future_only_keys))
Output
1{'runner_pool': 'a100-pool', 'queued_minutes': 42.0, 'hours_since_last_heartbeat': 0.5, 'queue_backlog': 18.0, 'queue_backlog_missing': 0, 'priority_job': 0} 2future fields leaked: []

The contract now exercises its promises: required fields, finite positive queued minutes, missing-runner-pool rejection, boolean priority flag, future-heartbeat rejection, heartbeat-age cap, finite nonnegative queue backlog, missing-queue backlog indicator, unseen-runner-pool bucket, and output allowlist.

A model still needs a fixed vector order and fitted categorical mapping. Version both beside the model artifact.

vectorize-features.py
1runner_pool_code = {"a100-pool": 0, "h100-pool": 1, "other": 2} 2feature_order = ( 3 "runner_pool_code", 4 "queued_minutes", 5 "hours_since_last_heartbeat", 6 "queue_backlog", 7 "queue_backlog_missing", 8 "priority_job", 9) 10features = { 11 "runner_pool": "other", 12 "queued_minutes": 42.0, 13 "hours_since_last_heartbeat": 8.0, 14 "queue_backlog": 0.0, 15 "queue_backlog_missing": 1, 16 "priority_job": 0, 17} 18 19vector = [ 20 runner_pool_code[features["runner_pool"]], 21 features["queued_minutes"], 22 features["hours_since_last_heartbeat"], 23 features["queue_backlog"], 24 features["queue_backlog_missing"], 25 features["priority_job"], 26] 27print("order:", feature_order) 28print("vector:", vector)
Output
1order: ('runner_pool_code', 'queued_minutes', 'hours_since_last_heartbeat', 'queue_backlog', 'queue_backlog_missing', 'priority_job') 2vector: [2, 42.0, 8.0, 0.0, 1, 0]

Test parity before release

An offline notebook might compute queue backlog by scanning a completed daily table. The service might read an hourly cache. Even when both columns are named queue_backlog, differences in freshness or aggregation can change predictions. This failure is training-serving skew.

Feast documents point-in-time joins that reproduce feature state at each historical entity timestamp, scanning backward only within the configured TTL.[2]Reference 2Point-in-time Joinshttps://docs.feast.dev/getting-started/concepts/point-in-time-joins It also documents online stores for low-latency serving, where only the latest feature values for each entity key are stored.[3]Reference 3Online Storehttps://docs.feast.dev/getting-started/components/online-store The tool isn't the lesson: the contract is. A model release must identify the feature definition and snapshot that produced its score.

Sample offline and online paths on the same entities before promoting a model. Matching dictionaries provide a small, readable parity receipt.

check-parity.py
1def mismatches(offline, online): 2 keys = offline.keys() | online.keys() 3 return {key: (offline.get(key), online.get(key)) for key in keys if offline.get(key) != online.get(key)} 4 5offline = {"runner_pool": "a100-pool", "queue_backlog": 18.0, "priority_job": 0} 6online = {"runner_pool": "a100-pool", "queue_backlog": 18.0, "priority_job": 0} 7differences = mismatches(offline, online) 8print("mismatches:", differences) 9print("release allowed:", not differences)
Output
1mismatches: {} 2release allowed: True

The same check catches a stale cache or divergent transformation before users see different scores.

detect-parity-failure.py
1def mismatches(offline, online): 2 keys = offline.keys() | online.keys() 3 return {key: (offline.get(key), online.get(key)) for key in keys if offline.get(key) != online.get(key)} 4 5offline = {"runner_pool": "a100-pool", "queue_backlog": 18.0, "priority_job": 0} 6online = {"runner_pool": "a100-pool", "queue_backlog": 0.0, "priority_job": 0} 7differences = mismatches(offline, online) 8print("mismatches:", differences) 9print("release allowed:", not differences)
Output
1mismatches: {'queue_backlog': (18.0, 0.0)} 2release allowed: False

Monitor the contract before monitoring accuracy:

Production checkFailure it catchesAction
null rate by featureupstream feed disappearedfail closed or fallback
unseen-category raterunner-pool catalog changedcollect labels and retrain
freshness lagonline values are stalepause promotions
offline/online parity sampletransformations disagreerepair feature path

Freshness failures need an explicit product policy. This policy tries normal scoring, fallback, then abstention. Thresholds depend on product tolerance and must be versioned with the serving path.

apply-freshness-policy.py
1def scoring_policy(freshness_lag_minutes): 2 if freshness_lag_minutes <= 15: 3 return "normal scoring" 4 if freshness_lag_minutes <= 45: 5 return "fallback model" 6 return "abstain and alert" 7 8for lag in [8, 30, 90]: 9 print(f"{lag} minutes -> {scoring_policy(lag)}")
Output
18 minutes -> normal scoring 230 minutes -> fallback model 390 minutes -> abstain and alert

Practice: break the contract

Run build-feature-row.py, then make one change at a time:

  1. Add "finished_at": row["finished_at"] to features. Confirm the output allowlist blocks release.
  2. Change last_heartbeat_at to 2026-05-01T12:00:00. Confirm future-event rejection.
  3. Change runner_pool to l4-pool. Confirm the returned category is other. Then remove runner_pool and confirm the contract blocks the row instead of hiding missing data inside that bucket.
  4. Remove queue_backlog. Confirm value becomes 0.0 while queue_backlog_missing becomes 1.
  5. Give offline and online paths different heartbeat-age caps. Confirm a parity sample exposes the disagreement.

Explain the row without looking back

Evaluation rubric

EvidenceWhat a strong answer shows
prediction contractidentifies prediction time, allowed fields, labels, and missing-value meaning
leakage controlproves future-only events and post-cutoff heartbeats can't enter feature construction
parity planversions transformations and monitors online/offline disagreement

Common pitfalls

SymptomCauseFix
Offline score is excellent, live accuracy collapsesfuture event entered featuresenforce prediction timestamps and leakage gates
New runner_pool causes errors or silent zeroscategorical mapping wasn't versionedreserve other and monitor its rate
Predictions shift after a data job rewritefeature meaning changed without model releaseversion transformation and test parity
Feed outage looks like healthy operationsmissing queue backlog was encoded as measured zeropreserve missing indicator or abstain
Complete the lesson

Mastery Check

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

1.A job-SLA feature row is built from a source record that also contains finished_at for later label construction. The output allowlist contains only runner_pool, queued_minutes, hours_since_last_heartbeat, queue_backlog, queue_backlog_missing, and priority_job. Which statement describes the correct gate?
2.During a scheduler telemetry feed outage, queue_backlog is unavailable. A feature job writes queue_backlog = 0.0 and does not emit queue_backlog_missing. What is the main contract problem?
3.Serving will load trained weights for job-SLA prediction. Engineers also want to rebuild the runner-pool mapping from today's runner-pool catalog and change the heartbeat-age cap from 180 to 360 hours while keeping feature names unchanged. What package avoids changing the input meaning?
4.At 2026-05-01T09:00:00, heartbeats are at 2026-05-01T01:00:00, 2026-05-01T08:30:00, and 2026-05-01T12:00:00. Which feature-construction result respects the prediction timestamp?
5.An encoder was fitted with known_runner_pools = {'a100-pool', 'h100-pool'} and a reserved other bucket. How should it handle runner_pool='l4-pool' and runner_pool=None?
6.For the same entity and cutoff, the offline path produces {'runner_pool': 'a100-pool', 'queue_backlog': 18.0, 'priority_job': 0} and the online path produces {'runner_pool': 'a100-pool', 'queue_backlog': 0.0, 'priority_job': 0}. What should the release gate do?
7.An online feature cache has freshness lag of 90 minutes. The serving path's versioned policy is: up to 15 minutes use normal scoring, up to 45 minutes use a fallback model, and above 45 minutes abstain and alert. What should happen?
8.Assume the required timestamps and runner_pool are valid and present. Which input combination satisfies the row contract?

8 questions remaining.

Next Step
Continue to Batch and Streaming Feature Pipelines

You can now define one trustworthy prediction row. Next you'll construct those rows from event history without joining future information or serving stale features.

PreviousDataset Pipelines and Data Quality
Share this article
XFacebookLinkedInBlueskyRedditHacker NewsEmail
References

Hidden Technical Debt in Machine Learning Systems.

Sculley et al. · 2015

Point-in-time Joins

Feast Contributors · 2026 · Official documentation

Online Store

Feast Contributors · 2026 · Official documentation

Discussion

Questions and insights from fellow learners.

Discussion loads when you reach this section.