Incident Response / Operational System Design
Google calls this NALSD; other companies just call it the incident-response or operational-design round. Whatever the name, it’s the round every source agrees decides most offers: you’re handed a system and a failure, and for 45–60 minutes you triage, mitigate, and design around it live, while the interviewer plays the paging system and keeps adding pressure. Below is the framework, then three full scenarios, written the way the room actually sounds.
The framework, before the scenarios
Every version of this round follows the same underlying shape, no matter the specific failure. The interviewer is grading the process — contain, diagnose, confirm, prevent — not just whether you land on the right root cause.
- 1
Establish blast radius before touching anything
Who’s affected, how badly, and is it getting worse right now? Naming this first — before proposing a single fix — is the clearest signal of real incident-command experience.
- 2
Mitigate before you fully understand root cause
A rollback, a feature flag, or a rate limit that stops the bleeding now is worth more than an elegant fix discovered twenty minutes from now. Root-causing happens after the bleeding stops, not instead of stopping it.
- 3
Form parallel hypotheses, not one guess at a time
Naming two or three plausible causes and how you’d check each — rather than committing to the first idea and chasing it serially — mirrors how real incident investigation actually works under time pressure.
- 4
Say what you’d monitor to know it’s actually fixed
A mitigation that isn’t confirmed by a metric moving back into range is a guess, not a fix. Naming the specific signal you’d watch is what separates “I think that’s it” from “I can see that’s it.”
- 5
Close with the prevention, not just the patch
What guardrail, alert, or design change stops this exact failure from recurring? The interviewer is grading whether you think in systems, not just in incidents.
The single most common failure mode: root-causing before containing. An elegant diagnosis delivered while the incident is still actively getting worse reads as a red flag, not technical depth. Stop the bleeding first; you can be curious about why afterward.
These three scenarios are illustrative training material, written to match the failure modes named across real postings and industry sources — not transcripts of an actual incident at a named company. Read them the way you’d rehearse for the real thing.
Three end-to-end walkthroughs
Scenario 1 · Silent quality drift
An assistant’s answer quality drops all weekend, with every dashboard green
“Our internal RAG assistant’s answer quality dropped hard over the weekend. Every dashboard is green. A team lead noticed Monday because of Slack complaints.”
“Our internal RAG assistant’s answer quality dropped hard over the weekend. Every dashboard is green — no error spike, no latency spike. A team lead noticed Monday morning because people started complaining in Slack. Walk me through it.”
First question: do we have any quality signal at all being tracked continuously — an eval score, a thumbs-up/down rate — or is “everything’s green” purely availability and latency?
“Purely availability and latency. There’s no automated quality signal in production today.”
Then that’s actually the headline finding, not a side note — this system has no way to detect this class of failure automatically, which is why it took a human noticing complaints instead of a page. Before I even look for root cause, I’d want to know: did anything change over the weekend — a deploy, a data refresh, an underlying model version, a vendor-side change?
“Nothing on our side shipped. But it’s possible the embedding model we call through an API got silently updated by the provider.”
That’s exactly the kind of failure that wouldn’t show up in our dashboards at all — a provider-side model swap can shift embedding space just enough that retrieval quality degrades without any error being thrown. I’d pull a sample of this week’s actual queries and run them back through our eval set from before the weekend, comparing retrieval relevance scores, not just spot-checking a few by hand.
“Say that confirms it — the embeddings shifted. What do you do right now, today, before you’ve even fully confirmed it?”
I’d pin the embedding model to an explicit version if the provider supports it, rather than tracking “latest,” and re-embed our corpus against that pinned version as the immediate mitigation. If pinning isn’t possible with this vendor, I’d fail over to a self-hosted or alternate embedding model we control, even if it’s a downgrade in some other dimension, since a known-quantity system beats an unpredictable one.
“How do you confirm it’s actually fixed, not just that you did something reasonable?”
Re-run the same eval set against the pinned or alternate embedding model and confirm the relevance scores are back in range before declaring it resolved — not just “this feels better,” an actual number moving back to where it was.
“And the prevention — what stops this exact thing from happening again silently?”
Two changes: pin every third-party model dependency to an explicit version instead of “latest,” and add a continuous quality signal in production — even something as lightweight as running a small canary eval set against live traffic daily and alerting on a score drop. Right now this system genuinely can’t detect its own most damaging failure mode, and that’s the actual gap, not just this one incident.
How the incident actually decomposes
How this decomposes
- 1
Detect — recognize the monitoring gap itself
The first real finding isn’t the root cause, it’s that no continuous quality signal exists in production — which is why a human, not an alert, caught this.
- 2
Investigate — check what changed, including outside your own deploys
With no internal change to point to, the hypothesis has to widen to third-party dependencies — an unpinned embedding model updated upstream is a classic version of this failure.
- 3
Mitigate — pin the dependency or fail over, today
Pinning to an explicit model version, or failing over to a controlled alternative, stops the bleeding immediately without waiting for full confirmation.
- 4
Confirm — an eval score, not a feeling
Re-running the same eval set against the fix and watching the relevance score return to range is what turns “probably fixed” into “confirmed fixed.”
- 5
Prevent — pin every third-party model dependency, add a canary eval
The systemic fix is broader than this one incident: version-pin dependencies, and add a lightweight continuous quality signal so the next drift of this kind pages someone instead of waiting for a complaint.
Where this could fall apart
Trusting a green availability dashboard as proof nothing is wrong
Latency and uptime are necessary signals, not sufficient ones, for an AI system. Treating them as the whole picture is the single most common way this exact failure mode goes undetected.
Root-causing before mitigating
Spending the first twenty minutes trying to fully understand why the embeddings shifted, instead of pinning or failing over immediately, leaves the system degraded longer than necessary.
Declaring victory without a number
Fixing the pin and assuming it worked, without re-running an eval to confirm relevance scores actually recovered, risks closing an incident that isn’t actually resolved.
Treating this as a one-off instead of a systemic gap
Fixing this one embedding-version issue without adding a continuous quality signal means the next silent drift — for a different reason — goes undetected exactly the same way.
Scenario 2 · Runaway agent loop
A tool-call loop burns 40x normal API spend overnight
“Finance flagged API spend at 40x normal overnight. No downtime, no user complaints. It’s still running.”
“Finance just flagged that our agent platform’s API spend was 40x normal overnight. No user complaints, no downtime. What do you do first?”
(follow-up, immediately) “And to be clear — this is happening right now, still running.”
If it’s still active, step one is stopping the bleeding, not investigating — I’d want an immediate way to identify which agent sessions or API keys are driving the spend spike, even roughly, and kill or rate-limit those specifically rather than pausing the whole platform if I can avoid it.
“You can see it’s concentrated in a handful of sessions from one customer’s workspace. What next?”
I’d hard-stop those specific sessions immediately — kill the process or revoke the session token, whichever is faster — and only then start looking at what those sessions were actually doing. My working hypothesis, given the shape of this, is a tool-call loop: something is causing the agent to call a tool, get a result, and call it again indefinitely without ever reaching a stopping condition.
“Confirmed — it’s a loop. The agent kept calling a search tool, getting an empty result, and retrying with a near-identical query each time. How does something like that ship in the first place?”
Almost certainly because there was no hard iteration cap on the agent loop, and no logic distinguishing “retry with a new approach” from “retry with essentially the same input.” The model itself has no built-in sense of “I’ve tried this already” unless the system explicitly tracks and enforces it.
“What’s the actual guardrail you’d put in, concretely?”
Two layers, not one. First, a hard cap on tool calls per agent turn and per session — a deterministic circuit breaker outside the model’s control, the same way a rules engine sits outside an agent’s reasoning for a high-stakes action. Second, a cost-anomaly monitor that compares live spend against a rolling baseline per session or per customer, and pages someone — or auto-throttles — well before it reaches 40x, not after finance notices the invoice.
“Why not just tell the model in the system prompt not to loop?”
Because a prompt is an instruction, not an enforcement mechanism — under enough conversational pressure or a strange enough input, the model can still end up looping anyway. The same principle as any guardrail: it has to live in code the model doesn’t control, not in a request you’re hoping it follows.
“What do you tell the customer, and what do you tell finance?”
Finance gets a clear timeline and the actual fix, not just an apology — a hard cap and a real-time cost-anomaly alert, so this specific failure mode is now bounded by design, not by luck. The customer gets an honest explanation and, depending on the contract, likely a credit for the anomalous usage, since it was clearly a platform bug and not something they did.
How the incident actually decomposes
How this decomposes
- 1
Contain — kill the specific runaway sessions first
With spend actively accumulating, stopping the identified sessions comes before any investigation — a targeted kill, not a platform-wide pause, if the blast radius is already known.
- 2
Diagnose — confirm the loop and its stopping-condition gap
The root cause is a missing hard stop: the agent had no enforced limit on retrying a tool call, and no logic to detect it was repeating an identical failed attempt.
- 3
Mitigate structurally — a deterministic circuit breaker
A hard cap on tool calls per turn and per session, enforced in code outside the model’s control — not a prompt instruction the model could still ignore under pressure.
- 4
Add detection — a real-time cost-anomaly monitor
A rolling spend baseline per session or customer, with paging or auto-throttling well before a 40x spike, so the next version of this failure is caught in minutes, not by an overnight finance report.
- 5
Close the loop with both stakeholders
Finance gets the concrete structural fix, not just a fixed bill this once; the affected customer gets an honest account and, likely, a credit, since the failure was the platform’s, not theirs.
Where this could fall apart
Investigating before containing an active, ongoing cost bleed
Spending the first ten minutes reading logs while the loop is still running and still spending money is the clearest way to fail this round — contain first, always, when the incident is still active.
Putting the guardrail in the prompt instead of in code
“Don’t loop” as an instruction to the model is not an enforcement mechanism. The fix has to be a deterministic check the model cannot reason its way around.
Fixing the symptom (this one loop) without adding detection
Patching this specific tool-call pattern without a general cost-anomaly monitor means the next distinct runaway pattern goes just as unnoticed until the next invoice.
Treating the platform-wide pause as the default move
Pausing everything is sometimes right, but jumping there by default when the blast radius is already known and narrow is unnecessarily disruptive — precision beats a blunt kill switch when you can afford precision.
Scenario 3 · Regional accelerator failover
A completed failover leaves every region oversubscribed
“One GPU region went unhealthy and traffic failed over automatically. Inference latency jumped 10x for everyone, including customers never on the affected region.”
“One of our GPU regions just went unhealthy and traffic failed over automatically. Inference latency for everyone jumped 10x, including customers who were never on the affected region. On-call, go.”
First: is the failover itself still in progress, or did it already complete and we’re now stuck with degraded performance on the remaining regions? That changes whether the priority is “let the failover finish” or “the current steady state is broken.”
“Failover completed two minutes ago. This is the new steady state, and it’s bad.”
Then the working hypothesis is that the remaining regions are now oversubscribed — they absorbed the failed-over traffic without the accelerator capacity to actually serve it at normal latency. I’d confirm that by checking GPU utilization and queue depth on the healthy regions specifically, not just overall latency.
“Confirmed — the healthy regions are pegged near 100% utilization. What do you do?”
Immediate mitigation, in order of speed: first, shed non-critical load if any exists — batch or lower-priority inference traffic gets deprioritized or queued, freeing capacity for latency-sensitive requests. Second, if we have any capacity headroom elsewhere, even a slower or more expensive region, route overflow there rather than leaving everyone on the oversubscribed regions.
“There’s no spare capacity anywhere else right now. Everything’s already near max.”
Then the honest move is graceful degradation over silent failure — if there’s a way to serve a smaller or cheaper model variant for lower-priority traffic while capacity is constrained, that’s better than uniformly slow responses for everyone. I’d also want visibility into whether this is truly a capacity ceiling or whether the failed region is recoverable soon, since “wait it out” might genuinely be the fastest real fix if recovery is imminent.
“Turns out the failed region will be back in about 20 minutes. Does that change your answer?”
It changes the priority, not the actions — I’d still shed non-critical load and consider degrading gracefully for 20 minutes rather than doing nothing and hoping customers don’t notice, but I wouldn’t invest in a heavier structural fix for what’s genuinely a temporary, self-resolving window. I’d confirm the region actually recovers on schedule and traffic rebalances cleanly before declaring this over.
“What’s the actual prevention here — this can’t be the plan every time a region goes down?”
The real gap is that failover moved traffic without checking whether the destination regions actually had headroom to absorb it — that’s a capacity-aware failover problem, not just a health-check problem. I’d push for failover logic that accounts for current utilization on the target regions, not just “is it up,” plus enough standing headroom margin across regions that a single-region failure doesn’t automatically oversubscribe whatever’s left.
How the incident actually decomposes
How this decomposes
- 1
Orient — confirm the failover already completed
The first question determines the whole shape of the response: an in-progress failover and a completed-but-broken steady state call for different actions.
- 2
Diagnose — confirm oversubscription, not a new unrelated fault
Checking GPU utilization and queue depth on the healthy regions specifically confirms the hypothesis before committing to a fix built on a guess.
- 3
Mitigate — shed non-critical load, then route to any spare capacity
Deprioritizing lower-priority traffic and routing overflow to any available headroom are the fastest levers, tried in order of speed and disruption.
- 4
Degrade gracefully when no capacity exists anywhere
Serving a smaller model variant for lower-priority traffic, rather than uniformly slow responses for everyone, is the honest move when there’s genuinely no more capacity to find.
- 5
Prevent — capacity-aware failover, and standing headroom margin
The systemic fix is failover logic that checks destination-region headroom before routing traffic there, plus enough standing margin that one region’s failure doesn’t automatically overload what’s left.
Where this could fall apart
Assuming the failover itself is the problem to fix
The failover did its job — moved traffic away from an unhealthy region. The actual problem is that the destination had no headroom, a distinct issue that needs its own diagnosis.
Doing nothing while waiting out a “temporary” failure
Even a 20-minute self-resolving window is 20 minutes of degraded service for real users — shedding load or degrading gracefully during that window is still the right call, not just waiting.
Treating uniform slowness as an acceptable degradation strategy
Letting every request get equally slow, instead of deliberately deprioritizing lower-priority traffic, wastes the one lever that could keep latency-sensitive requests healthy.
Fixing this specific event without addressing capacity-aware failover
Recovering from this one incident without changing the failover logic itself means the exact same oversubscription happens the next time any region has a problem.