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 178 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/24
Dimensionality Reduction for EmbeddingsCoT, ToT & Self-Consistency PromptingFunction Calling & Tool UseMCP & Tool Protocol StandardsContext EngineeringPrompt 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&BPrompt Optimization with DSPyModel 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: Reproducible ML Study
🧠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/17
Scaling Laws & Compute-Optimal TrainingPre-training Data at ScaleBuild GPT from Scratch LabJAX for PyTorch ResearchersContinued Pretraining for Domain ShiftSynthetic Data PipelinesSupervised Fine-Tuning PipelineMixed Precision TrainingDistributed Training: FSDP & ZeROLoRA & Parameter-Efficient TuningTraining Run OperationsReward Modeling from Preference DataRLHF & DPO AlignmentConstitutional AI & Red TeamingRLVR & Verifiable RewardsKnowledge Distillation for LLMsModel Merging and Weight Interpolation
🤖Advanced Agents & Retrieval0/16
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 & RecoveryRecursive Language Models (RLM)Multi-Agent OrchestrationCapstone: Production Agent
⚡Inference & Production Scale0/19
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 ManagementMixture 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 Agent System Design
🎤AI Lab Interviewing0/4
AI Lab Coding Interview: Python SystemsAI Lab System Design InterviewAI Lab Behavioral InterviewAI Lab Technical Presentation
🔬Project Deep Dives0/17
Deep Dive - vLLMDeep Dive - SkyRLDeep Dive - FlashAttentionDeep Dive - FlashInferDeep Dive - DeepGEMMDeep Dive - NCCLDeep Dive - MegatronDeep Dive - DeepSpeedDeep Dive - RayDeep Dive - MLflowDeep Dive - PyTorchDeep Dive - TransformersDeep Dive - SGLangDeep Dive - slimeDeep Dive - DeepEPDeep Dive - TinkerDeep Dive - Light-PEFT
Back to Topics
LearnPortfolio CapstonesCapstone: Production ML Pipeline
⚙️HardMLOps & Deployment

Capstone: Production ML Pipeline

Turn four shipped models into one receipt-bound promotion path: offline gates, canary windows, alias movement, and rollback.

24 min read
Learning path
Step 84 of 178 in the full curriculum
Capstone: Image Damage ClassifierCapstone: Document QA

Personalize this lesson

Adapt explanations and teaching visuals to your background and preferred voice.

Training finishing isn't permission to change live behavior. A reviewer has to trace any live decision back to data, features, model, policy, and promotion evidence. That means stored receipts, not a mutable Boolean that happens to say passed.

The vision service now has a versioned bundle, a recorded rollback target, and specialist labels that arrive after the photo route. The ETA, ranking, and forecast capstones left the same kind of artifact: frozen data, a metric that can wait on delayed outcomes, and a previous release you could restore. None of those chapters owned the shared controller. This lab is that controller.

Define the shared release tuple

Models differ, but their release manifest can share a schema:

FieldETA exampleRanking exampleForecast exampleVision example
data snapshotcarrier events through cutoffcatalog and judged queriesdaily counts through cutoffreturn photos grouped by shipment
feature or preprocessing versioneta-features-v1ranking-features-v1demand-lags-v1parcel-rgb-224-center-crop-v1
model artifactdelay-model-v1market-ranker-v1warehouse-demand-v1damage-cnn-v1
action policywarning thresholdeligibility and slate rulealert thresholdquality check and review threshold
promotion policyslice recall and cost limitsblocked-listing and NDCG limitspeak underforecast-cost limitusable-image and source-slice limits
monitordelayed labels and freshnessimpressions and returnsresiduals and alert reviewphoto quality and reviewer labels
previous releasedelivery-risk-v0market-ranker-v0warehouse-demand-v0damage-cnn-v0

When something breaks, you shouldn't have to guess which threshold, crop, or gate policy was live. Sculley et al. treat data dependencies, configuration, and feedback loops as ML-specific debt: if those boundaries aren't versioned, the system becomes expensive to change and hard to roll back.[1]Reference 1Hidden Technical Debt in Machine Learning Systems.https://research.google/pubs/hidden-technical-debt-in-machine-learning-systems/ The tuple is how this lab pins them.

A shared schema still doesn't move traffic. The next question is who is allowed to change an alias (a mutable pointer such as production or canary), and on what evidence. Limited live exposure (a canary) comes only after offline gates pass. Rollback restores the previous tuple; it doesn't retrain.

Diagram showing Register v1 prod stays v0, Offline slice and cost gates, fail, and hold_offline.
Register v1 prod stays v0, Offline slice and cost gates, fail, and hold_offline.

Compute the failing slice by hand

The controller you'll build uses delivery-risk-v1 as the running candidate, with delivery-risk-v0 live. Before any registry code, look at the candidate that must not get a canary. Four held-out rows:

entitycritical slicelate deliverypredicted latebaseline costcandidate cost
eval-1yes11$25$24
eval-2yes10$25$24
eval-3no00$25$24
eval-4no00$25$24

Critical-slice recall is true positives on late critical rows, divided by those late critical rows:

critical-slice recall=12=0.50\text{critical-slice recall} = \frac{1}{2} = 0.50critical-slice recall=21​=0.50

The policy floor is 0.900.900.90. Cost did improve: 96/100−1=−0.0496 / 100 - 1 = -0.0496/100−1=−0.04, which clears max_cost_delta = 0. That cheaper cost still doesn't buy a canary. A failed slice is a stored hold_offline receipt, and production stays on delivery-risk-v0.

Register a candidate without moving production

Start by freezing the whole release tuple. The candidate names its previous release, artifact package, and promotion-policy version. The policy registry owns the immutable thresholds, so a candidate can't loosen its own gate. Fingerprints bind each evaluation to those exact objects before any traffic moves. The next cells turn the four-row fixture into an immutable package, then derive the gates from those rows instead of accepting a caller-owned Boolean.

01-register-release-registry.py
1from dataclasses import asdict, dataclass, replace 2from hashlib import sha256 3import json 4 5@dataclass(frozen=True) 6class PromotionPolicy: 7 policy_id: str 8 required_offline_gates: tuple[str, ...] 9 required_schema: tuple[str, ...] 10 min_critical_slice_recall: float 11 max_cost_delta: float 12 min_canary_windows: int 13 max_error_rate: float 14 max_p95_latency_ms: int 15 max_late_warning_cost_delta: float 16 17@dataclass(frozen=True) 18class OfflineEvalRow: 19 entity_id: str 20 critical_slice: bool 21 late_delivery: int 22 predicted_late: int 23 baseline_cost: float 24 candidate_cost: float 25 26@dataclass(frozen=True) 27class CandidateArtifacts: 28 artifact_id: str 29 data_snapshot: str 30 feature_version: str 31 model_artifact: str 32 action_policy_version: str 33 observed_schema: tuple[str, ...] 34 training_entity_ids: tuple[str, ...] 35 evaluation_entity_ids: tuple[str, ...] 36 evaluation_rows: tuple[OfflineEvalRow, ...] 37 38@dataclass(frozen=True) 39class Release: 40 release_id: str 41 data_snapshot: str 42 feature_version: str 43 model_artifact: str 44 action_policy_version: str 45 promotion_policy_version: str 46 previous_release: str | None 47 candidate_artifact_id: str 48 candidate_artifact_fingerprint: str 49 50@dataclass(frozen=True) 51class OfflineEvidence: 52 evidence_id: str 53 candidate: str 54 artifact_id: str 55 artifact_fingerprint: str 56 release_fingerprint: str 57 promotion_policy_version: str 58 promotion_policy_fingerprint: str 59 missing_schema_fields: tuple[str, ...] 60 leaked_entity_ids: tuple[str, ...] 61 critical_slice_positives: int 62 critical_slice_true_positives: int 63 critical_slice_recall: float 64 cost_delta: float 65 66 def gates(self, policy: PromotionPolicy) -> dict[str, bool]: 67 return { 68 "schema_valid": not self.missing_schema_fields, 69 "no_leakage": not self.leaked_entity_ids, 70 "critical_slice_pass": ( 71 self.critical_slice_positives > 0 72 and self.critical_slice_recall >= policy.min_critical_slice_recall 73 ), 74 "cost_improves": self.cost_delta <= policy.max_cost_delta, 75 } 76 77@dataclass(frozen=True) 78class OfflineReceipt: 79 receipt_id: str 80 candidate: str 81 production_before: str 82 promotion_policy_version: str | None 83 promotion_policy_fingerprint: str | None 84 offline_evidence_id: str | None 85 release_fingerprint: str | None 86 artifact_fingerprint: str | None 87 failed_gates: tuple[str, ...] 88 decision: str 89 90def immutable_fingerprint(value: object) -> str: 91 payload = json.dumps(asdict(value), sort_keys=True, separators=(",", ":")) 92 return sha256(payload.encode("utf-8")).hexdigest() 93 94POLICIES = { 95 "eta-promotion-v1": PromotionPolicy( 96 policy_id="eta-promotion-v1", 97 required_offline_gates=( 98 "schema_valid", 99 "no_leakage", 100 "critical_slice_pass", 101 "cost_improves", 102 ), 103 required_schema=( 104 "entity_id", 105 "event_time", 106 "late_delivery", 107 "predicted_late", 108 "baseline_cost", 109 "candidate_cost", 110 ), 111 min_critical_slice_recall=0.90, 112 max_cost_delta=0.0, 113 min_canary_windows=2, 114 max_error_rate=0.01, 115 max_p95_latency_ms=250, 116 max_late_warning_cost_delta=0.0, 117 ) 118} 119 120stable_artifact = CandidateArtifacts( 121 artifact_id="eta-artifact-v0", 122 data_snapshot="carrier-events-through-2026-04-30", 123 feature_version="eta-features-v1", 124 model_artifact="delay-model-v0", 125 action_policy_version="eta-threshold-v1", 126 observed_schema=POLICIES["eta-promotion-v1"].required_schema, 127 training_entity_ids=(), 128 evaluation_entity_ids=(), 129 evaluation_rows=(), 130) 131recall_fail_artifact = CandidateArtifacts( 132 artifact_id="eta-artifact-recall-fail", 133 data_snapshot="carrier-events-through-2026-05-31", 134 feature_version="eta-features-v1", 135 model_artifact="delay-model-recall-fail", 136 action_policy_version="eta-threshold-v1", 137 observed_schema=POLICIES["eta-promotion-v1"].required_schema, 138 training_entity_ids=("train-1", "train-2"), 139 evaluation_entity_ids=("eval-1", "eval-2", "eval-3", "eval-4"), 140 evaluation_rows=( 141 OfflineEvalRow("eval-1", True, 1, 1, 25.0, 24.0), 142 OfflineEvalRow("eval-2", True, 1, 0, 25.0, 24.0), 143 OfflineEvalRow("eval-3", False, 0, 0, 25.0, 24.0), 144 OfflineEvalRow("eval-4", False, 0, 0, 25.0, 24.0), 145 ), 146) 147leaky_artifact = CandidateArtifacts( 148 artifact_id="eta-artifact-leaky", 149 data_snapshot="carrier-events-through-2026-05-31", 150 feature_version="eta-features-v1", 151 model_artifact="delay-model-leaky", 152 action_policy_version="eta-threshold-v1", 153 observed_schema=POLICIES["eta-promotion-v1"].required_schema, 154 training_entity_ids=("train-1", "eval-1"), 155 evaluation_entity_ids=("eval-1", "eval-2", "eval-3", "eval-4"), 156 evaluation_rows=( 157 OfflineEvalRow("eval-1", True, 1, 1, 25.0, 24.0), 158 OfflineEvalRow("eval-2", True, 1, 1, 25.0, 24.0), 159 OfflineEvalRow("eval-3", False, 0, 0, 25.0, 24.0), 160 OfflineEvalRow("eval-4", False, 0, 0, 25.0, 24.0), 161 ), 162) 163passing_artifact = CandidateArtifacts( 164 artifact_id="eta-artifact-v1", 165 data_snapshot="carrier-events-through-2026-05-31", 166 feature_version="eta-features-v1", 167 model_artifact="delay-model-v1", 168 action_policy_version="eta-threshold-v1", 169 observed_schema=POLICIES["eta-promotion-v1"].required_schema, 170 training_entity_ids=("train-1", "train-2"), 171 evaluation_entity_ids=("eval-1", "eval-2", "eval-3", "eval-4"), 172 evaluation_rows=( 173 OfflineEvalRow("eval-1", True, 1, 1, 25.0, 24.0), 174 OfflineEvalRow("eval-2", True, 1, 1, 25.0, 24.0), 175 OfflineEvalRow("eval-3", False, 0, 0, 25.0, 24.0), 176 OfflineEvalRow("eval-4", False, 0, 0, 25.0, 24.0), 177 ), 178) 179artifacts = { 180 artifact.artifact_id: artifact 181 for artifact in ( 182 stable_artifact, 183 recall_fail_artifact, 184 leaky_artifact, 185 passing_artifact, 186 ) 187} 188 189def release_from_artifact( 190 release_id: str, 191 artifact: CandidateArtifacts, 192 previous_release: str | None, 193) -> Release: 194 return Release( 195 release_id=release_id, 196 data_snapshot=artifact.data_snapshot, 197 feature_version=artifact.feature_version, 198 model_artifact=artifact.model_artifact, 199 action_policy_version=artifact.action_policy_version, 200 promotion_policy_version="eta-promotion-v1", 201 previous_release=previous_release, 202 candidate_artifact_id=artifact.artifact_id, 203 candidate_artifact_fingerprint=immutable_fingerprint(artifact), 204 ) 205 206registry = { 207 "delivery-risk-v0": release_from_artifact( 208 "delivery-risk-v0", stable_artifact, None 209 ), 210 "delivery-risk-recall-fail": release_from_artifact( 211 "delivery-risk-recall-fail", recall_fail_artifact, "delivery-risk-v0" 212 ), 213 "delivery-risk-leaky": release_from_artifact( 214 "delivery-risk-leaky", leaky_artifact, "delivery-risk-v0" 215 ), 216 "delivery-risk-v1": release_from_artifact( 217 "delivery-risk-v1", passing_artifact, "delivery-risk-v0" 218 ), 219} 220aliases = {"production": "delivery-risk-v0"} 221offline_evidence: dict[str, OfflineEvidence] = {} 222offline_receipts: dict[str, OfflineReceipt] = {} 223 224print("registry:", list(registry)) 225print("production:", aliases["production"]) 226print( 227 "policy fingerprint bound:", 228 len(immutable_fingerprint(POLICIES["eta-promotion-v1"])) == 64, 229)
Output
1registry: ['delivery-risk-v0', 'delivery-risk-recall-fail', 'delivery-risk-leaky', 'delivery-risk-v1'] 2production: delivery-risk-v0 3policy fingerprint bound: True

Offline gates aren't caller-owned booleans or thresholds. evaluate_candidate loads the registered artifact package, checks schema and split membership, derives recall and cost from its held-out rows, and binds the result to fingerprints for artifact, release, and policy. Only then can open_canary fetch that evidence by ID. Canary and production monitoring use the same pattern later.

02-evaluate-candidate-offline.py
1def release_matches_artifact( 2 release: Release, 3 artifact: CandidateArtifacts, 4) -> bool: 5 return ( 6 release.data_snapshot, 7 release.feature_version, 8 release.model_artifact, 9 release.action_policy_version, 10 ) == ( 11 artifact.data_snapshot, 12 artifact.feature_version, 13 artifact.model_artifact, 14 artifact.action_policy_version, 15 ) 16 17def evidence_binding_failures( 18 candidate: Release, 19 evidence: OfflineEvidence, 20) -> list[str]: 21 failed: list[str] = [] 22 policy = POLICIES.get(candidate.promotion_policy_version) 23 artifact = artifacts.get(candidate.candidate_artifact_id) 24 if evidence.candidate != candidate.release_id: 25 failed.append("offline_evidence_candidate_mismatch") 26 if evidence.promotion_policy_version != candidate.promotion_policy_version: 27 failed.append("offline_evidence_policy_version_mismatch") 28 if ( 29 policy is None 30 or evidence.promotion_policy_fingerprint != immutable_fingerprint(policy) 31 ): 32 failed.append("offline_evidence_policy_fingerprint_mismatch") 33 if evidence.release_fingerprint != immutable_fingerprint(candidate): 34 failed.append("offline_evidence_release_fingerprint_mismatch") 35 if evidence.artifact_id != candidate.candidate_artifact_id: 36 failed.append("offline_evidence_artifact_id_mismatch") 37 if evidence.artifact_fingerprint != candidate.candidate_artifact_fingerprint: 38 failed.append("offline_evidence_artifact_fingerprint_mismatch") 39 if ( 40 artifact is None 41 or immutable_fingerprint(artifact) 42 != candidate.candidate_artifact_fingerprint 43 ): 44 failed.append("registered_artifact_fingerprint_mismatch") 45 elif not release_matches_artifact(candidate, artifact): 46 failed.append("release_artifact_tuple_mismatch") 47 return failed 48 49def evaluate_candidate(candidate_id: str) -> OfflineEvidence: 50 candidate = registry[candidate_id] 51 policy = POLICIES[candidate.promotion_policy_version] 52 artifact = artifacts[candidate.candidate_artifact_id] 53 if immutable_fingerprint(artifact) != candidate.candidate_artifact_fingerprint: 54 raise ValueError("registered artifact changed after release registration") 55 if not release_matches_artifact(candidate, artifact): 56 raise ValueError("release tuple does not match candidate artifact") 57 58 missing_schema = tuple( 59 sorted(set(policy.required_schema) - set(artifact.observed_schema)) 60 ) 61 leaked_entities = tuple( 62 sorted( 63 set(artifact.training_entity_ids) 64 & set(artifact.evaluation_entity_ids) 65 ) 66 ) 67 critical_positives = [ 68 row for row in artifact.evaluation_rows 69 if row.critical_slice and row.late_delivery == 1 70 ] 71 critical_true_positives = sum( 72 row.predicted_late == 1 for row in critical_positives 73 ) 74 critical_recall = ( 75 critical_true_positives / len(critical_positives) 76 if critical_positives 77 else 0.0 78 ) 79 baseline_cost = sum(row.baseline_cost for row in artifact.evaluation_rows) 80 candidate_cost = sum(row.candidate_cost for row in artifact.evaluation_rows) 81 cost_delta = ( 82 candidate_cost / baseline_cost - 1.0 83 if baseline_cost > 0 84 else float("inf") 85 ) 86 87 evidence = OfflineEvidence( 88 evidence_id=f"offline-evidence-{len(offline_evidence) + 1}", 89 candidate=candidate_id, 90 artifact_id=artifact.artifact_id, 91 artifact_fingerprint=immutable_fingerprint(artifact), 92 release_fingerprint=immutable_fingerprint(candidate), 93 promotion_policy_version=policy.policy_id, 94 promotion_policy_fingerprint=immutable_fingerprint(policy), 95 missing_schema_fields=missing_schema, 96 leaked_entity_ids=leaked_entities, 97 critical_slice_positives=len(critical_positives), 98 critical_slice_true_positives=critical_true_positives, 99 critical_slice_recall=critical_recall, 100 cost_delta=cost_delta, 101 ) 102 offline_evidence[evidence.evidence_id] = evidence 103 return evidence 104 105failing_evidence = evaluate_candidate("delivery-risk-recall-fail") 106leaky_evidence = evaluate_candidate("delivery-risk-leaky") 107passing_evidence = evaluate_candidate("delivery-risk-v1") 108policy = POLICIES["eta-promotion-v1"] 109print("failing gates:", failing_evidence.gates(policy)) 110print("leaky gates:", leaky_evidence.gates(policy)) 111print("passing gates:", passing_evidence.gates(policy)) 112print("stored evidence ids:", list(offline_evidence))
Output
1failing gates: {'schema_valid': True, 'no_leakage': True, 'critical_slice_pass': False, 'cost_improves': True} 2leaky gates: {'schema_valid': True, 'no_leakage': False, 'critical_slice_pass': True, 'cost_improves': True} 3passing gates: {'schema_valid': True, 'no_leakage': True, 'critical_slice_pass': True, 'cost_improves': True} 4stored evidence ids: ['offline-evidence-1', 'offline-evidence-2', 'offline-evidence-3']
03-open-canary-after-offline-gates.py
1def open_canary(candidate_id: str, offline_evidence_id: str) -> OfflineReceipt: 2 candidate = registry.get(candidate_id) 3 production_before = aliases["production"] 4 failed = [] 5 policy = POLICIES.get(candidate.promotion_policy_version) if candidate else None 6 evidence = offline_evidence.get(offline_evidence_id) 7 if candidate is None: 8 failed.append("candidate_not_registered") 9 elif policy is None: 10 failed.append("promotion_policy_not_registered") 11 elif evidence is None: 12 failed.append("offline_evidence_not_registered") 13 else: 14 failed.extend(evidence_binding_failures(candidate, evidence)) 15 gates = evidence.gates(policy) 16 failed.extend( 17 gate for gate in policy.required_offline_gates if not gates.get(gate, False) 18 ) 19 if candidate is not None and candidate.previous_release != production_before: 20 failed.append("previous_release_mismatch") 21 if aliases.get("canary") not in (None, candidate_id): 22 failed.append("another_canary_is_active") 23 24 receipt = OfflineReceipt( 25 receipt_id=f"offline-receipt-{len(offline_receipts) + 1}", 26 candidate=candidate_id, 27 production_before=production_before, 28 promotion_policy_version=( 29 candidate.promotion_policy_version if candidate is not None else None 30 ), 31 promotion_policy_fingerprint=( 32 evidence.promotion_policy_fingerprint if evidence is not None else None 33 ), 34 offline_evidence_id=offline_evidence_id if evidence is not None else None, 35 release_fingerprint=( 36 evidence.release_fingerprint if evidence is not None else None 37 ), 38 artifact_fingerprint=( 39 evidence.artifact_fingerprint if evidence is not None else None 40 ), 41 failed_gates=tuple(sorted(failed)), 42 decision="hold_offline" if failed else "open_canary", 43 ) 44 offline_receipts[receipt.receipt_id] = receipt 45 if receipt.decision == "open_canary": 46 aliases["canary"] = candidate_id 47 return receipt 48 49bad_offline_receipt = open_canary( 50 "delivery-risk-recall-fail", failing_evidence.evidence_id 51) 52accepted_offline_receipt = open_canary("delivery-risk-v1", passing_evidence.evidence_id) 53print("failed:", bad_offline_receipt.decision, bad_offline_receipt.failed_gates) 54print("accepted:", accepted_offline_receipt.decision, accepted_offline_receipt.offline_evidence_id) 55print("aliases:", json.dumps(aliases, sort_keys=True))
Output
1failed: hold_offline ('critical_slice_pass',) 2accepted: open_canary offline-evidence-3 3aliases: {"canary": "delivery-risk-v1", "production": "delivery-risk-v0"}

A failed offline slice leaves production unchanged. Leakage fails no_leakage even when recall and cost look good: overlapping train and eval IDs are derived from the registered package, not reported by the caller. Passing evaluation gates opens only the canary alias. Each attempt appends an immutable receipt with candidate, production base, evidence ID, and policy, release, and artifact fingerprints. Nothing in this cell can overwrite production. Caller-owned metrics, booleans, or thresholds never open canary traffic; only bound evidence derived from the registered artifact can.

Wait for canary evidence

Fast checks catch broken schemas, errors, and latency spikes. They can't prove prediction quality when labels arrive later. A canary still needs both kinds of evidence.

Don't confuse that gate with an A/B test. A canary is limited live exposure with abort rules: if errors, latency, or a later labeled cost breach the policy, you pull the candidate back. An A/B test is a powered comparison with sticky assignment and a predeclared metric, which the experiment-design chapter already covered. Google Cloud's MLOps guidance lists canary deployment and A/B testing as online validation after offline model validation, not as replacements for it.[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 This controller only answers whether delivery-risk-v1 is safe enough to keep exposing.

The functions below store each observation window inside an immutable receipt, refuse to promote after the first hour because late-delivery outcomes aren't ready yet, and treat an empty window list as a hold rather than a crash.

04-canary-window-contract.py
1@dataclass(frozen=True) 2class CanaryWindow: 3 window_id: str 4 release_id: str 5 observed_day: int 6 requests: int 7 error_rate: float 8 p95_latency_ms: int 9 delayed_labels_ready: bool 10 late_warning_cost_delta: float | None 11 12@dataclass(frozen=True) 13class CanaryReceipt: 14 receipt_id: str 15 candidate: str 16 production_before: str 17 offline_receipt_id: str 18 promotion_policy_version: str | None 19 promotion_policy_fingerprint: str | None 20 release_fingerprint: str | None 21 artifact_fingerprint: str | None 22 windows: tuple[CanaryWindow, ...] 23 failed_gates: tuple[str, ...] 24 decision: str 25 26canary_receipts: dict[str, CanaryReceipt] = {} 27 28print("canary policy windows:", POLICIES["eta-promotion-v1"].min_canary_windows)
05-evaluate-canary-evidence.py
1def accepted_offline_binding_failures( 2 candidate: Release, 3 receipt: OfflineReceipt, 4) -> list[str]: 5 failed: list[str] = [] 6 policy = POLICIES.get(candidate.promotion_policy_version) 7 evidence = ( 8 offline_evidence.get(receipt.offline_evidence_id) 9 if receipt.offline_evidence_id is not None 10 else None 11 ) 12 if receipt.candidate != candidate.release_id: 13 failed.append("offline_receipt_candidate_mismatch") 14 if receipt.decision != "open_canary": 15 failed.append("offline_receipt_not_accepted") 16 if receipt.promotion_policy_version != candidate.promotion_policy_version: 17 failed.append("offline_receipt_policy_version_mismatch") 18 if ( 19 policy is None 20 or receipt.promotion_policy_fingerprint != immutable_fingerprint(policy) 21 ): 22 failed.append("offline_receipt_policy_fingerprint_mismatch") 23 if receipt.release_fingerprint != immutable_fingerprint(candidate): 24 failed.append("offline_receipt_release_fingerprint_mismatch") 25 if receipt.artifact_fingerprint != candidate.candidate_artifact_fingerprint: 26 failed.append("offline_receipt_artifact_fingerprint_mismatch") 27 if evidence is None: 28 failed.append("offline_evidence_not_registered") 29 else: 30 failed.extend(evidence_binding_failures(candidate, evidence)) 31 return failed 32 33def evaluate_canary( 34 candidate_id: str, 35 offline_receipt_id: str, 36 windows: list[CanaryWindow], 37) -> CanaryReceipt: 38 candidate = registry.get(candidate_id) 39 policy = POLICIES.get(candidate.promotion_policy_version) if candidate else None 40 offline_receipt = offline_receipts.get(offline_receipt_id) 41 failed = [] 42 abort_reasons = [] 43 if candidate is None: 44 failed.append("candidate_not_registered") 45 abort_reasons.append("candidate_not_registered") 46 elif policy is None: 47 failed.append("promotion_policy_not_registered") 48 abort_reasons.append("promotion_policy_not_registered") 49 if aliases.get("canary") != candidate_id: 50 failed.append("canary_alias_missing") 51 if offline_receipt is None or candidate is None: 52 failed.append("accepted_offline_receipt_missing") 53 abort_reasons.append("accepted_offline_receipt_missing") 54 else: 55 binding_failures = accepted_offline_binding_failures( 56 candidate, offline_receipt 57 ) 58 failed.extend(binding_failures) 59 abort_reasons.extend(binding_failures) 60 if ( 61 candidate is not None 62 and candidate.previous_release != aliases["production"] 63 ): 64 failed.append("production_changed_during_canary") 65 abort_reasons.append("production_changed_during_canary") 66 if policy is not None and len(windows) < policy.min_canary_windows: 67 failed.append("observation_window_incomplete") 68 if len({window.window_id for window in windows}) != len(windows): 69 failed.append("duplicate_window_id") 70 abort_reasons.append("duplicate_window_id") 71 observed_days = [window.observed_day for window in windows] 72 if observed_days != sorted(set(observed_days)): 73 failed.append("window_order_invalid") 74 abort_reasons.append("window_order_invalid") 75 if any(window.release_id != candidate_id for window in windows): 76 failed.append("mixed_release_windows") 77 abort_reasons.append("mixed_release_windows") 78 if any(window.requests <= 0 for window in windows): 79 failed.append("request_count_missing") 80 abort_reasons.append("request_count_missing") 81 if policy is not None and any(window.error_rate > policy.max_error_rate for window in windows): 82 failed.append("error_rate_regression") 83 abort_reasons.append("error_rate_regression") 84 if policy is not None and any( 85 window.p95_latency_ms > policy.max_p95_latency_ms for window in windows 86 ): 87 failed.append("latency_regression") 88 abort_reasons.append("latency_regression") 89 90 latest = windows[-1] if windows else None 91 if latest is None or not latest.delayed_labels_ready: 92 failed.append("delayed_quality_not_ready") 93 elif ( 94 policy is not None 95 and ( 96 latest.late_warning_cost_delta is None 97 or latest.late_warning_cost_delta > policy.max_late_warning_cost_delta 98 ) 99 ): 100 failed.append("late_warning_cost_regression") 101 abort_reasons.append("late_warning_cost_regression") 102 103 decision = ( 104 "abort_canary" 105 if abort_reasons 106 else "hold_canary" 107 if failed 108 else "ready_for_promotion" 109 ) 110 receipt = CanaryReceipt( 111 receipt_id=f"canary-receipt-{len(canary_receipts) + 1}", 112 candidate=candidate_id, 113 production_before=aliases["production"], 114 offline_receipt_id=offline_receipt_id, 115 promotion_policy_version=( 116 candidate.promotion_policy_version if candidate is not None else None 117 ), 118 promotion_policy_fingerprint=( 119 offline_receipt.promotion_policy_fingerprint 120 if offline_receipt is not None 121 else None 122 ), 123 release_fingerprint=( 124 offline_receipt.release_fingerprint 125 if offline_receipt is not None 126 else None 127 ), 128 artifact_fingerprint=( 129 offline_receipt.artifact_fingerprint 130 if offline_receipt is not None 131 else None 132 ), 133 windows=tuple(windows), 134 failed_gates=tuple(sorted(failed)), 135 decision=decision, 136 ) 137 canary_receipts[receipt.receipt_id] = receipt 138 if decision == "abort_canary": 139 aliases.pop("canary", None) 140 return receipt 141 142first_hour = CanaryWindow("first-hour", "delivery-risk-v1", 0, 500, 0.002, 118, False, None) 143day_seven = CanaryWindow("day-seven", "delivery-risk-v1", 7, 4200, 0.003, 124, True, -0.08) 144 145empty_receipt = evaluate_canary("delivery-risk-v1", accepted_offline_receipt.receipt_id, []) 146early_receipt = evaluate_canary( 147 "delivery-risk-v1", accepted_offline_receipt.receipt_id, [first_hour] 148) 149ready_receipt = evaluate_canary( 150 "delivery-risk-v1", accepted_offline_receipt.receipt_id, [first_hour, day_seven] 151) 152print("empty decision:", empty_receipt.decision) 153print("early decision:", early_receipt.decision) 154print("ready decision:", ready_receipt.decision)
06-print-canary-receipts.py
1print("empty:", empty_receipt.decision, empty_receipt.failed_gates) 2print("early:", early_receipt.decision, early_receipt.failed_gates) 3print( 4 "ready:", 5 ready_receipt.decision, 6 [window.window_id for window in ready_receipt.windows], 7 ready_receipt.windows[-1].late_warning_cost_delta, 8)
Output
1empty: hold_canary ('delayed_quality_not_ready', 'observation_window_incomplete') 2early: hold_canary ('delayed_quality_not_ready', 'observation_window_incomplete') 3ready: ready_for_promotion ['first-hour', 'day-seven'] -0.08

late_warning_cost_delta=-0.08 means the candidate reduced late-warning cost by eight percent relative to the previous release on this local fixture. It's a teaching threshold, not a universal production policy. Real teams choose windows and limits from product risk, traffic volume, and label delay.

An incomplete window returns hold_canary: gather more evidence without widening exposure. A measured latency, error-rate, or delayed-quality regression returns abort_canary and removes the canary alias. Progressive-delivery controllers such as Argo Rollouts use the same split: a failed analysis aborts and returns traffic to the previous stable revision rather than waiting for another sample.[3]Reference 3Argo Rollouts - Kubernetes Progressive Delivery Controllerhttps://argoproj.github.io/argo-rollouts/ Corrupted or mismatched telemetry aborts too, because the controller can't prove safe exposure. Missing evidence and negative evidence aren't the same operational state.

Promote last, then prove rollback

Promotion is the first moment this controller is allowed to move production. It fetches a stored canary receipt by ID, follows it back to offline evidence, and recomputes the policy, release, and artifact bindings. A ready decision becomes stale if any bound object changes. Rollback follows the same rule: production metrics become a stored receipt before they can restore the previous release. Both paths recheck the live production alias immediately before movement.

07-promote-with-stored-receipt.py
1@dataclass(frozen=True) 2class AliasEvent: 3 action: str 4 from_release: str 5 to_release: str 6 evidence_receipt_id: str 7 reasons: tuple[str, ...] 8 9@dataclass(frozen=True) 10class ProductionReceipt: 11 receipt_id: str 12 window: CanaryWindow 13 failed_gates: tuple[str, ...] 14 decision: str 15 16audit_events: list[AliasEvent] = [] 17production_receipts: dict[str, ProductionReceipt] = {} 18 19def promote(candidate_id: str, canary_receipt_id: str) -> dict[str, object]: 20 candidate = registry.get(candidate_id) 21 canary_receipt = canary_receipts.get(canary_receipt_id) 22 failed = [] 23 if candidate is None: 24 failed.append("candidate_not_registered") 25 if aliases.get("canary") != candidate_id: 26 failed.append("canary_alias_missing") 27 if canary_receipt is None: 28 failed.append("canary_receipt_not_registered") 29 elif candidate is not None: 30 policy = POLICIES.get(candidate.promotion_policy_version) 31 if canary_receipt.candidate != candidate_id: 32 failed.append("canary_receipt_candidate_mismatch") 33 if canary_receipt.decision != "ready_for_promotion": 34 failed.append("canary_receipt_not_ready") 35 if ( 36 canary_receipt.promotion_policy_version 37 != candidate.promotion_policy_version 38 ): 39 failed.append("canary_receipt_policy_version_mismatch") 40 if ( 41 policy is None 42 or canary_receipt.promotion_policy_fingerprint 43 != immutable_fingerprint(policy) 44 ): 45 failed.append("canary_receipt_policy_fingerprint_mismatch") 46 if ( 47 canary_receipt.release_fingerprint 48 != immutable_fingerprint(candidate) 49 ): 50 failed.append("canary_receipt_release_fingerprint_mismatch") 51 if ( 52 canary_receipt.artifact_fingerprint 53 != candidate.candidate_artifact_fingerprint 54 ): 55 failed.append("canary_receipt_artifact_fingerprint_mismatch") 56 57 offline_receipt = offline_receipts.get(canary_receipt.offline_receipt_id) 58 if offline_receipt is None: 59 failed.append("offline_receipt_not_registered") 60 else: 61 failed.extend( 62 accepted_offline_binding_failures(candidate, offline_receipt) 63 ) 64 if ( 65 canary_receipt.promotion_policy_fingerprint 66 != offline_receipt.promotion_policy_fingerprint 67 or canary_receipt.release_fingerprint 68 != offline_receipt.release_fingerprint 69 or canary_receipt.artifact_fingerprint 70 != offline_receipt.artifact_fingerprint 71 ): 72 failed.append("canary_offline_binding_mismatch") 73 if ( 74 candidate is not None 75 and candidate.previous_release != aliases["production"] 76 ): 77 failed.append("production_changed_since_canary_open") 78 if ( 79 canary_receipt is not None 80 and canary_receipt.production_before != aliases["production"] 81 ): 82 failed.append("production_changed_since_canary_receipt") 83 if failed: 84 return {"action": "hold_promotion", "reasons": sorted(failed)} 85 86 previous = aliases["production"] 87 aliases["previous_production"] = previous 88 aliases["production"] = candidate_id 89 aliases.pop("canary") 90 event = AliasEvent("promote", previous, candidate_id, canary_receipt_id, ()) 91 audit_events.append(event) 92 return asdict(event) 93 94print("promote helper ready")
08-monitor-production-and-rollback.py
1def production_gate_results(window: CanaryWindow) -> tuple[list[str], list[str]]: 2 """Return (failed_gates, rollback_reasons). 3 4 Incomplete delayed labels are recorded but never authorize rollback. 5 Only measured regressions (errors, latency, labeled cost) can restore 6 the previous production alias. 7 """ 8 release = registry.get(window.release_id) 9 if release is None: 10 return (["production_window_release_not_registered"], []) 11 policy = POLICIES.get(release.promotion_policy_version) 12 if policy is None: 13 return (["production_policy_not_registered"], []) 14 failed: list[str] = [] 15 rollback_reasons: list[str] = [] 16 if window.error_rate > policy.max_error_rate: 17 failed.append("error_rate_regression") 18 rollback_reasons.append("error_rate_regression") 19 if window.p95_latency_ms > policy.max_p95_latency_ms: 20 failed.append("latency_regression") 21 rollback_reasons.append("latency_regression") 22 if not window.delayed_labels_ready: 23 # Missing evidence: hold the monitor; do not treat as quality failure. 24 failed.append("delayed_quality_not_ready") 25 elif ( 26 window.late_warning_cost_delta is None 27 or window.late_warning_cost_delta > policy.max_late_warning_cost_delta 28 ): 29 failed.append("late_warning_cost_regression") 30 rollback_reasons.append("late_warning_cost_regression") 31 return failed, rollback_reasons 32 33def evaluate_production(window: CanaryWindow) -> ProductionReceipt: 34 failed, rollback_reasons = production_gate_results(window) 35 release_mismatch = window.release_id != aliases["production"] 36 if release_mismatch: 37 failed.append("production_window_release_mismatch") 38 decision = ( 39 "hold_rollback" 40 if release_mismatch 41 else "rollback_required" 42 if rollback_reasons 43 else "hold_monitor" 44 if failed 45 else "keep_production" 46 ) 47 receipt = ProductionReceipt( 48 receipt_id=f"production-receipt-{len(production_receipts) + 1}", 49 window=window, 50 failed_gates=tuple(sorted(failed)), 51 decision=decision, 52 ) 53 production_receipts[receipt.receipt_id] = receipt 54 return receipt 55 56def rollback_if_needed(production_receipt_id: str) -> dict[str, object]: 57 receipt = production_receipts.get(production_receipt_id) 58 if receipt is None: 59 return {"action": "hold_rollback", "reason": "production_receipt_not_registered"} 60 if receipt.decision == "hold_rollback": 61 return {"action": "hold_rollback", "reasons": list(receipt.failed_gates)} 62 if receipt.decision == "hold_monitor": 63 # Incomplete labels or other non-regression holds: leave production alone. 64 return { 65 "action": "hold_monitor", 66 "release": aliases["production"], 67 "reasons": list(receipt.failed_gates), 68 } 69 if receipt.window.release_id != aliases["production"]: 70 return {"action": "hold_rollback", "reason": "production_changed_since_monitor_receipt"} 71 if receipt.decision == "keep_production": 72 return {"action": "keep_production", "release": aliases["production"]} 73 if receipt.decision != "rollback_required": 74 return {"action": "hold_rollback", "reason": "production_receipt_decision_invalid"} 75 76 previous = aliases.get("previous_production") 77 if previous is None or previous not in registry: 78 return {"action": "hold_rollback", "reason": "previous_production_not_registered"} 79 failed_release = aliases["production"] 80 aliases["production"] = previous 81 aliases["rollback_from"] = failed_release 82 event = AliasEvent( 83 "rollback", 84 failed_release, 85 previous, 86 receipt.receipt_id, 87 receipt.failed_gates, 88 ) 89 audit_events.append(event) 90 return asdict(event) 91 92print("rollback helper ready")
09-attempt-promotion-paths.py
1print("fabricated promotion:", promote("delivery-risk-v1", "canary-receipt-missing")) 2print("early promotion:", promote("delivery-risk-v1", early_receipt.receipt_id)) 3print("approved promotion:", promote("delivery-risk-v1", ready_receipt.receipt_id))
10-detect-production-regression.py
1degraded = CanaryWindow("production-day-eight", "delivery-risk-v1", 8, 900, 0.004, 130, True, 0.14) 2degraded_receipt = evaluate_production(degraded) 3rollback_result = rollback_if_needed(degraded_receipt.receipt_id) 4print("production decision:", degraded_receipt.decision) 5print("rollback action:", rollback_result["action"])
11-audit-alias-movements.py
1print("production receipt:", degraded_receipt.decision, degraded_receipt.failed_gates) 2print("rollback:", rollback_result) 3print("aliases:", json.dumps(aliases, sort_keys=True)) 4print( 5 "audit:", 6 [(event.action, event.from_release, event.to_release, event.evidence_receipt_id) for event in audit_events], 7)
Output
1production receipt: rollback_required ('late_warning_cost_regression',) 2rollback: {'action': 'rollback', 'from_release': 'delivery-risk-v1', 'to_release': 'delivery-risk-v0', 'evidence_receipt_id': 'production-receipt-1', 'reasons': ('late_warning_cost_regression',)} 3aliases: {"previous_production": "delivery-risk-v0", "production": "delivery-risk-v0", "rollback_from": "delivery-risk-v1"} 4audit: [('promote', 'delivery-risk-v0', 'delivery-risk-v1', 'canary-receipt-3'), ('rollback', 'delivery-risk-v1', 'delivery-risk-v0', 'production-receipt-1')]

Rollback restores delivery-risk-v0, not its weights alone. That distinction matters because preprocessing, features, thresholds, and policy can all change serving behavior. Each audit event names the stored receipt that authorized its alias movement, so a later reviewer can reconstruct both promotion and rollback.

Production monitoring mirrors the canary hold-vs-abort rule. A measured error-rate, latency, or labeled cost regression returns rollback_required and can restore the previous alias. Incomplete delayed labels return hold_monitor: keep production on the live release and wait for outcomes. Missing evidence isn't negative evidence, so it must not look like a quality failure.

Signed late-warning cost chart for delivery-risk-v1. Day 7 canary cost is minus 8 percent, below the policy maximum of 0, so the canary is ready. Day 8 live cost is plus 14 percent, above the line, so production rolls back to v0. Hour 0 has no bar because delayed labels were not ready, which is a hold rather than a zero delta.
Day 7's labeled cost is 8 percent better than the previous release, so the canary is ready and v1 can be promoted. Day 8's labeled cost is 14 percent worse, so production restores v0. Hour 0 never appears on the cost axis because delayed labels weren't ready; that's a hold, not a zero delta.

💡 Key insight: Unmeasured quality holds. A labeled regression aborts a canary or rolls back production. A Boolean named passed isn't a receipt.

Join fast and delayed monitoring

Live checks differ by product, but the promotion controller handles the same categories:

Gate typeETARankingForecastVision
immediate data healthscan freshnesseligible candidate supplylatest counts loadedphoto quality
immediate service healthlatency/errorsscoring latencyforecast API availabilityimage scoring latency
delayed qualitylate warning costpurchase/return experimentMAE and peak residualreviewer-confirmed damage
rollback eventstale warning spikeblocked listing exposurebroken alert floodunsupported escalations

For scoring systems with delayed labels, canary monitoring should pause wider promotion until enough outcomes arrive. After promotion, incomplete delayed labels hold the production monitor rather than rolling back; only measured regressions restore the previous alias. A model that hasn't failed yet isn't the same as a model that has passed.

⚠️ Common mistake: Treating missing delayed labels as a rollback reason, or treating a canary as an A/B test. The first confuses "not yet measured" with "measured worse." The second confuses a safety abort with a powered lift estimate.

Continuous training is appropriate when a schedule or monitored condition creates a candidate run. Google Cloud's MLOps guidance puts automated data validation, model validation, metadata, serving, monitoring, and continuous-training triggers around that promotion, and still expects an online canary or experiment before a candidate serves all traffic.[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 Retraining on a clock isn't a skip-the-gate button. The pipeline's value isn't automation alone; it's refusing untraceable changes.

Practice: break the release controller

Run the runnable examples again after each mutation. Predict which receipt or alias changes before reading output, then revert the mutation before trying the next one.

  1. Change the third argument in the delivery-risk-v1 release_from_artifact(...) call from "delivery-risk-v0" to "delivery-risk-v-missing".
  2. In recall_fail_artifact, change the second critical row's predicted_late value from 0 to 1. Rerun and confirm recall is derived as 1.0 from rows rather than accepted as an argument.
  3. Pass [day_seven, first_hour] to one evaluate_canary call. Confirm that the receipt records window_order_invalid.
  4. Change the day_seven constructor's delayed_labels_ready argument from True to False.
  5. Change the day_seven constructor's late_warning_cost_delta argument from -0.08 to 0.05.
  6. Replace ready_receipt.receipt_id with "canary-receipt-missing" in the approved promotion call.
  7. Before approved promotion, set aliases["production"] = "delivery-risk-v1" to simulate an out-of-band alias move. Confirm that promotion holds, then reset it to "delivery-risk-v0".
  8. After ready_receipt is stored but before promotion, set POLICIES["eta-promotion-v1"] = replace(POLICIES["eta-promotion-v1"], max_p95_latency_ms=500). The ID stays the same, but promotion must hold on fingerprint mismatch. Rerun from the start to restore the policy.
  9. After ready_receipt is stored but before promotion, set artifacts["eta-artifact-v1"] = replace(passing_artifact, model_artifact="delay-model-v1-repacked"). Promotion must hold because the registered package no longer matches the artifact fingerprint. Rerun from the start to restore it.
  10. Change the degraded constructor's late_warning_cost_delta argument from 0.14 to -0.01.
  11. Change the degraded constructor's release ID from "delivery-risk-v1" to "delivery-risk-v0". Confirm that monitoring evidence for a different release can't move the current alias.
  12. Replace degraded_receipt.receipt_id with "production-receipt-missing" in the rollback call. Which authorization check holds the alias?
  13. Change the degraded constructor so delayed_labels_ready=False and late_warning_cost_delta=None (reset the cost delta and release ID to the original passing-service values first). Confirm the decision is hold_monitor, rollback_if_needed leaves production on delivery-risk-v1, and no rollback audit event is appended.

Practice answer sketches

Why does a mismatched previous_release block canary traffic?

Answer

previous_release_mismatch fails before traffic moves. The candidate points at a rollback target that isn't the live production release, so restoring it wouldn't prove a return to current behavior.

What happens when the critical offline slice fails?

Answer

The offline receipt returns hold_offline. production stays on delivery-risk-v0, and no canary alias opens.

Why do missing delayed labels and a positive cost delta produce different canary decisions?

Answer

Missing labels mean quality hasn't been measured yet, so the receipt returns hold_canary. A positive delta means measured late-warning cost regressed, so the receipt returns abort_canary and removes the limited-exposure alias. Both block promotion, but only one proves the candidate failed.

Why can't promotion accept any dictionary whose decision field says ready_for_promotion?

Answer

A mutable caller-generated dictionary doesn't prove who evaluated the candidate, which windows were measured, or whether the evidence belongs to the current release. Promotion fetches a stored immutable receipt by ID, verifies its full evidence chain, and rechecks the production alias before moving traffic.

Why do fingerprints matter when policy and artifact IDs haven't changed?

Answer

An ID can be reused while thresholds or artifact contents change. The policy, release, and artifact fingerprints bind the receipt to exact immutable values. A same-ID replacement makes old evidence stale and blocks promotion until the new objects are evaluated.

Why does rollback fetch a stored production receipt instead of accepting caller-supplied reasons?

Answer

Caller-owned reasons can be fabricated or changed. A registered receipt binds the monitored release, window metrics, gate failures, and decision before rollback rechecks the live alias.

What happens when the degraded production delta becomes -0.01?

Answer

No rollback reason remains in this fixture. rollback_if_needed returns keep_production, so delivery-risk-v1 stays live. Production policies should restore a prior alias only when an explicit rollback condition fires.

What happens when a production window has healthy service metrics but delayed_labels_ready=False?

Answer

The monitor records delayed_quality_not_ready and returns hold_monitor. rollback_if_needed keeps delivery-risk-v1 live and appends no rollback event. Incomplete labels mean quality hasn't been measured yet, so they must not restore the previous alias the way a labeled cost regression would.

Submission checklist

The lab you submit is a small local platform surface, not a copy of a cloud vendor's stack. Prove each boundary with a deterministic fixture and test:

text
1production-ml-platform/ 2 contracts/ 3 release_manifest.schema.json 4 promotion_policy.json 5 pipelines/ 6 validate_snapshot.py 7 train_candidate.py 8 evaluate_candidate.py 9 promote_alias.py 10 registry/ 11 releases.jsonl 12 monitoring/ 13 live_windows.py 14 rollback_policy.py 15 receipts/ 16 offline_gate_report.json 17 canary_monitor_report.json 18 alias_audit.jsonl 19 projects/ 20 eta/ 21 ranking/ 22 forecast/ 23 vision/ 24 tests/ 25 test_failed_gate_never_promotes.py 26 test_empty_monitor_window_holds.py 27 test_unregistered_receipt_never_promotes.py 28 test_alias_race_blocks_promotion.py 29 test_delayed_labels_block_promotion.py 30 test_rollback_restores_manifest.py
ArtifactAcceptance condition
release schemaidentifies data, features, model, action policy, promotion policy, previous release, and candidate-artifact fingerprint
registrycontains immutable stable and candidate releases
append-only receiptsrecord derived offline metrics plus policy, release, and artifact fingerprints, and why each candidate passed, held, aborted, promoted, or rolled back
alias promotion codefollows stored receipts back to bound evidence and rechecks production before moving alias
monitor policydefines canary pause, promote, abort, rollback
testsexecute empty-window, failed-gate, fabricated-receipt, alias-race, and rollback paths

The promotion controller refuses an alias move unless it's bound to stored evidence. Document QA needs the same receipt habit: an answer is only as auditable as the source it cites.

Complete the lesson

Mastery Check

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

1.An incident team restores the damage-cnn-v0 weight file, but the failed cropper and review threshold from damage-cnn-v1 remain active. Which release design prevents this rollback failure?

Correct answer: A release tuple for data, preprocessing, model, action policy, promotion policy, monitor, and previous release.

Weights alone don't define serving behavior. The release tuple binds the data, preprocessing or feature code, model artifact, action policy, promotion policy, monitoring expectations, and rollback target so restoring a release restores the behavior that was audited.

2.In the release registry, delivery-risk-v1.previous_release is delivery-risk-v-missing while production still points to delivery-risk-v0. What should open_canary do?

Correct answer: Hold offline with previous_release_mismatch; the rollback target is not the live production release.

The candidate's previous release is the rollback base that must match the current production alias before any traffic moves. If it points somewhere else, rollback wouldn't prove a return to the current live behavior, so the offline attempt is held.

3.A registered ETA artifact's held-out rows derive passing schema, leakage, and cost checks, but critical-slice recall is 0.50 against the policy-owned 0.90 floor. Production is delivery-risk-v0. What is the correct result?

Correct answer: The offline receipt returns hold_offline; production stays on delivery-risk-v0 and no canary alias opens.

The evaluator derives recall from the registered artifact rows and compares it with the immutable policy threshold. Required offline gates are prerequisites for even limited exposure, so the failed slice is stored in an offline receipt and blocks the canary alias.

4.Canary service health is within limits. One evaluation receives no observation windows. Another has enough ordered windows, but its latest labeled window has late_warning_cost_delta=0.05 while the maximum is 0.0. How should the decisions differ?

Correct answer: The empty run returns hold_canary; the measured regression returns abort_canary and removes the canary alias.

An empty list supplies neither the required number of windows nor delayed-quality evidence, so the controller stores observation_window_incomplete and delayed_quality_not_ready and holds without crashing. A labeled cost delta of 0.05 exceeds the allowed maximum of 0.0, which is measured negative evidence and therefore aborts the canary.

5.evaluate_canary receives windows for delivery-risk-v1 in this order: day-seven with observed_day=7, then first-hour with observed_day=0. The accepted offline receipt and canary alias are valid. Which decisive status should it include?

Correct answer: window_order_invalid and abort_canary, because the window chronology is corrupted.

The controller requires observed days to be in sorted unique order. Reversed windows are corrupted telemetry, so window_order_invalid is an abort reason. Other failed gates may also be recorded, but the chronology error is enough to abort rather than promote or merely hold.

6.An API caller passes a real canary receipt ID for delivery-risk-v1, and the stored receipt says ready_for_promotion. Before promote runs, production no longer equals the receipt's production_before. What should happen?

Correct answer: Return hold_promotion with production-changed reasons; the stored evidence no longer matches the live alias.

A ready receipt is necessary but not sufficient. Promotion must recheck that the current production alias still matches both the candidate's rollback target and the receipt's recorded production base. If production changed after canary evidence was gathered, the alias move is held.

7.Production is delivery-risk-v1. One monitor window for delivery-risk-v1 has passing health and late_warning_cost_delta=-0.01; another window has regression reasons but release_id='delivery-risk-v0'. Which rollback behavior is correct?

Correct answer: Keep v1 production; hold rollback for v0 because its evidence is not for live release.

A negative cost delta is an improvement under the fixture's policy, so it leaves no rollback reason and production stays on v1. Regression reasons from a window for v0 can't move the current v1 alias, because rollback evidence must match the live release.

8.Production is delivery-risk-v1. A production monitor window for that release has healthy error rate and latency, but delayed_labels_ready=False and late_warning_cost_delta=None. What should the controller do?

Correct answer: Return hold_monitor with delayed_quality_not_ready, keep v1 serving, and wait for delayed labels.

Incomplete delayed labels are missing evidence, not measured negative evidence. The production monitor records delayed_quality_not_ready and holds without restoring the previous alias. Rollback requires a measured regression such as a labeled cost delta that exceeds policy, or an error-rate or latency breach.

9.A ready canary receipt was created under eta-promotion-v1. Someone replaces that policy with more permissive thresholds under the same ID before promotion. What should promote do?

Correct answer: Hold promotion: policy fingerprint no longer matches offline and canary evidence.

A version label alone doesn't bind threshold values. Promotion recomputes the current policy fingerprint and follows the canary receipt to the offline receipt and artifact-derived evidence. A mismatch makes the old ready decision stale, so the candidate needs a fresh evaluation under the replacement policy.

10.Production is delivery-risk-v1, and a caller reports a cost regression but passes production-receipt-missing to rollback_if_needed. No registered receipt has that ID. What should happen?

Correct answer: Return hold_rollback with unregistered receipt and keep v1 production.

Rollback moves a production alias, so it needs stored authorization just like promotion. A caller-supplied reason or unknown receipt ID doesn't bind the live release to evaluated metrics and policy gates. Without a registered production receipt, the controller holds and leaves the alias unchanged.

10 questions remaining.

Next Step
Continue to Capstone: Document QA

You can now refuse an alias move that isn't bound to stored evidence. Next you'll apply that same receipt habit to a document-answering service: cited policy text, or an abstention.

PreviousCapstone: Image Damage Classifier
Share this article
XFacebookLinkedInBlueskyRedditHacker NewsEmail
References

Hidden Technical Debt in Machine Learning Systems.

Sculley et al. · 2015

https://research.google/pubs/hidden-technical-debt-in-machine-learning-systems/

MLOps: Continuous Delivery and Automation Pipelines in Machine Learning.

Google Cloud. · 2026 · Official documentation

https://docs.cloud.google.com/architecture/mlops-continuous-delivery-and-automation-pipelines-in-machine-learning

Argo Rollouts - Kubernetes Progressive Delivery Controller

Argo Project · 2026

https://argoproj.github.io/argo-rollouts/

Discussion

Questions and insights from fellow learners.

Discussion loads when you reach this section.