Interview guides · Mistral AI
Mistral AI Software Engineer Interview Guide
Mistral AI Software Engineer interview guide: the five reported rounds, coding, PyTorch and RAG design questions, and a 7-day plan.
Interviewing at Mistral AI
- Practice bank: 13+ questions
- Rounds: 2
- Typical prep: 1–2 weeks
- Interview reports: 2
Interview rounds
| Round | Questions |
|---|---|
| Technical Screen | 12 |
| Onsite | 1 |
How hard is the Mistral AI Software Engineer interview?
| Difficulty | Share | Questions |
|---|---|---|
| Easy | 0% | 0 |
| Medium | 77% | 10 |
| Hard | 23% | 3 |
What Mistral AI actually tests for
| Topic | Share | Questions |
|---|---|---|
| Machine Learning | 46% | 6 |
| ML System Design | 15% | 2 |
| Software Engineering Fundamentals | 15% | 2 |
| Behavioral & Leadership | 8% | 1 |
| Coding & Algorithms | 8% | 1 |
| Statistics & Math | 8% | 1 |
The 60-second brief
Mistral AI builds open-weight and commercial large language models. The source notes describe Software Engineer work there as the systems that train, deploy and serve those models, plus the developer platform around them: serving APIs, the developer console and client libraries. Reported questions follow the same split. Some are backend and scientific-computing problems in Python and PyTorch. Some are about AI infrastructure: RAG, agentic workflows and LLM inference. Others are product engineering in TypeScript and React.
Mistral AI candidates report 5 rounds · ≈ 4-6 weeks. The stages below are what candidates describe, not a published process.
What a Software Engineer does at Mistral AI
The language expectation follows the track. The notes name Python, including PyTorch and NumPy, for backend and scientific roles, and TypeScript and React for product roles. Settle this before you prepare. A backend candidate who has not practised tensor broadcasting and a product candidate who has never consumed a streaming API in React have the same gap.
Reported questions fall into four groups. Coding questions include an expression parser for + and * without parentheses, a Fibonacci function improved step by step from naive recursion, and a series of lookup and deduplication problems. ML and scientific-computing questions include a PyTorch closest-center computation, testing LLMs for regressions, and memory and parallelism for high-dimensional data. Design questions cover a RAG system, agentic workflows and an LLM inference engine. Product questions cover a streaming React component and secure real-time channels.
The Mistral AI interview process
Mistral AI candidates report 5 rounds · ≈ 4-6 weeks. The stages below are what candidates describe, not a published process.
Initial Screening Call
The source notes describe this as a call with a recruiter or hiring manager about your background, your technical motivations and what the role involves. Use it to find out which track you are in: product, infrastructure or research-adjacent. The notes say later stages vary by track, and the track decides whether you prepare Python and PyTorch or TypeScript and React. Bring a short account of one or two projects that a non-specialist could repeat accurately. Also bring a specific reason for wanting to work on model serving, developer tooling or product work around LLMs.
What it evaluates
- Whether your background fits the track: systems and performance, scientific Python, or product engineering in TypeScript and React
- Whether your technical motivations are specific, meaning they name the kind of problem you want to work on rather than general interest in AI
- Whether the role expectations are clear on both sides, including the track and whether a project submission is part of your process
How to prepare
- Write two sentences per headline project with no internal codenames: what was slow, broken or missing, what you changed, and the measured result
- Ask directly which track the role sits in, which language the technical rounds use, and whether your process includes a GitHub project submission
- Prepare one concrete reason for the role that ties to a product area named in the notes: serving APIs, inference performance, the developer console or client libraries
Technical Project Submission
The notes say some candidates submit a technical project through GitHub before the live rounds. They do not describe how it is reviewed, so hold yourself to the bar any engineer reading a stranger's repository would apply. It should run from a clean clone using only the README. It should include tests for the cases that matter. The design decisions and known limits should be written down, not left for the reader to reverse-engineer. Be ready to explain every shortcut in case the project comes up later.
What it evaluates
- Self-check, not a published review criterion: can someone run the project from a fresh clone by following the README alone?
- Self-check: do the tests cover edge and failure cases, not just the happy path shown in the prompt?
- Self-check: are your design choices and deliberate omissions written down, and could you defend them if asked?
How to prepare
- Before you submit, clone the repository into an empty directory and follow your own README from start to finish. Fix every step that assumed something from your machine
- Add a short section on decisions and limits: what you chose, what you rejected and why, and what you would build next with more time
- Pin dependencies and include one command that runs the whole test suite, so the reviewer does not have to guess
Live-Coding Challenges
The notes describe live coding as interactive and progressive. Problems start simple and then add optimisation or functional requirements. The focus is clean, production-grade code, edge-case handling and moving from a brute-force approach to an optimal one. Reported coding questions include an expression parser for + and * without parentheses, a Fibonacci function improved from naive recursion to an iterative solution, and lookup and deduplication problems using arrays and sets. Treat each problem as the first step of a sequence. State the complexity as soon as you have code, and write it so the next requirement fits in without a rewrite.
What it evaluates
- Choosing a data structure from the access pattern, such as a set for membership and deduplication or a counter for frequency, rather than out of habit
- Stating time and space complexity without being asked and suggesting the next optimisation yourself
- Handling edge cases such as whitespace, multi-digit numbers, empty input and repeated values, and checking them with a dry run before running the code
- Keeping code modular enough that a new requirement changes one function rather than the whole solution
How to prepare
- Practise each reported coding question as a sequence of steps: brute force, then optimal, then one added requirement. For the parser, add - and / after + and *. For Fibonacci, go from naive recursion to memoised to iterative with O(1) extra space
- Say the complexity and the next improvement out loud before the interviewer asks, then write the version you just described
- Practise in your track's language without autocomplete, and dry-run the two or three smallest inputs by hand before you run the code
System Design Sessions
The notes say the system design sessions focus on real-world AI infrastructure and that you will need to defend your architectural choices. Reported design questions include a scalable RAG system with explicit cost, throughput and latency management, agentic workflows built with LangGraph or custom state machines, and an LLM inference engine covering prompt caching, dynamic batching and context-window management. The notes' advice is to weigh cloud cost, API latency, GPU memory and maintainability, and to avoid unnecessary services. Expect disagreement from the interviewer. Answer with numbers, and change your design when their point is better.
What it evaluates
- Whether your trade-offs cover the constraints the notes list: infrastructure cost, API latency, GPU memory and ease of maintenance
- Whether you can defend a choice with a number or an argument and still change it when the interviewer's alternative is better
- Whether the design stays simple enough to build and operate, instead of adding services and frameworks that do not remove a bottleneck
How to prepare
- For RAG, practise the full path: chunking, embedding, a vector index such as pgvector or Pinecone, retrieval and reranking, prompt assembly and generation. Then name one cost lever and one latency lever on each step
- Separate the RAG ingestion path from the query path, and name the bottleneck and the cost driver on each
- For inference serving, be able to explain the KV cache, why batching requests as they arrive raises GPU utilisation, what prefix or prompt caching reuses, and what happens when a request exceeds the context window
- For agentic workflows, model the flow as explicit states with persisted progress, and define what happens when a tool call times out or is retried
Culture-Fit Discussion
The notes describe the last stage as a conversation with a hiring manager or executive about your past experience, your ability to work on your own, and how you work with distributed teams. Prepare stories where you started with a vague problem, gave it structure and delivered it end to end. Include times you built something to unblock yourself or your team without waiting for direction, and a time you worked across locations or teams. Say clearly which part was yours.
What it evaluates
- Whether you can take a vague problem, structure it and deliver it without close supervision
- Whether your stories show ownership through to the result, with your own contribution clearly separated from the team's
- Whether you can describe working with distributed or cross-functional colleagues, including what went wrong and what you changed
How to prepare
- Pick three stories: one about ambiguity you resolved, one tool or fix you built to unblock others, and one collaboration across teams or time zones
- For each story, write the decision point, the options you had, what you chose and why, and the measured outcome
Questions Mistral AI candidates report
Data structures and algorithms
Ask which resource the problem actually takes away, because it is not always time. If the input does not fit in memory, the set you were going to build is gone and the bound that matters is space. If the data arrives once and cannot be revisited, anything needing a second pass is out whatever its complexity, and a constraint banning modification of the input removes the in-place trick that would otherwise be free. Naming the scarce resource first cuts the candidates down to a handful, and it stops you optimising a dimension the problem was never short of.
- Implement a parser to compute the mathematical result of a string containing numbers and basic operators like
+and*(without parentheses). - Solve a series of progressive coding challenges focused on efficient lookups and deduplication using arrays and sets.
System design and architecture
Turn the prompt into a workload before drawing anything: requests per second at peak, the read to write ratio, the size of one stored object, how long it is kept, and how each of those grows. Those numbers decide the architecture, and without them every component is a guess. Size the simplest thing that fits, then add a tier only where a number says the simple version breaks. What separates a strong answer is that every box has a quantity attached to it. A cache, a queue and a partition scheme that each answer a specific number read as judgement; the same diagram without numbers reads as recall.
- Explain how you would implement and manage complex agentic workflows using frameworks like LangGraph or custom state machines.
- Design a scalable Retrieval-Augmented Generation (RAG) system from scratch, detailing how you would manage cost, throughput, and latency.
- Walk through the architecture of a high-throughput LLM inference engine, outlining your strategies for prompt caching, dynamic batching, and context window management.
Behavioural and engineering judgement
A reversal is the easiest of these to tell badly, because the honest version sounds like a mistake and the flattering version sounds like nothing happened. Give the trigger: the specific observation that made continuing worse than stopping, dated to when it arrived rather than when it became undeniable. Then give what stopping cost, whether that was work discarded, a migration left half-finished, or a team told the dependency they had built against was moving. The answer that stands out names a stopping condition set before it was needed, or says plainly that none had been set.
- Detail your experience implementing production-grade web applications using Next.js, tRPC, and TailwindCSS, explaining how you prevent performance bottlenecks.
Other topics
These reward mechanism over vocabulary. Whatever the topic, the move that works is to describe what the machine does one layer below the name you just used: what a lookup actually touches, or what the operating system did with the write you believed went to disk. Attach the precondition to every performance claim, since most are conditional. A hash lookup is constant time on average given a hash that spreads the keys and a load factor kept bounded by resizing, and linear in the worst case when either fails. Knowing where your explanation stops is part of the answer, so stop there out loud.
- Given a PyTorch tensor representing coordinates of points and another representing coordinates of centers, write a function to compute the distance to the closest center for each point using broadcasting and
torch.argmin. - How do you design secure, real-time communication channels between a web frontend and an AI orchestration backend?
Practice exercises with worked solutions
The prompts above tell you what gets asked.
Model credential revocation so history survives the delete
tenant_api_key stores key_id, tenant_id, workspace_id, name, key_prefix, secret_hash, scopes text[], status (active, revoked, expired, compromised), auth_version, created_at, expires_at, last_used_at, revoked_at, revoked_reason. Rotation inserts a new row and revocation never deletes, because an incident review asks which credential served a request last quarter. Write the constraints that enforce: a label is unique only among a tenant's live keys, revoked_at and status can never disagree, and scopes is never empty. Then write the authentication lookup predicate, and name one column in this table that must stay out of it.
How a strong candidate works it
- Reach for a partial unique index rather than a plain UNIQUE:
create unique index on tenant_api_key (tenant_id, name) where revoked_at is null. Any number of revoked rows may share a label, the live namespace stays unique per tenant, and the revoked majority is not in the index at all, so it stays small on a table that only grows. - Tie the nullable timestamp to the enum so the two cannot drift:
check ((revoked_at is not null) = (status in ('revoked','compromised')))andcheck ((revoked_at is null) = (revoked_reason is null)). A revocation that records no reason is the one an incident review cannot use. - Write the emptiness check as
check (cardinality(scopes) > 0), notarray_length(scopes, 1) > 0. array_length returns NULL for an empty array, a CHECK constraint passes when its expression is NULL, so the array_length version accepts exactly the value it was written to reject. - Make the lookup a single index probe with every liveness condition inside it:
where secret_hash = $1 and revoked_at is null and (expires_at is null or expires_at > now()) and auth_version = $2, backed by a unique index on secret_hash. Nothing is filtered in application code, so there is no path that forgets a clause. - Keep last_used_at out of that predicate. It is written asynchronously and is allowed to lag by a minute, so it is a usage signal; feeding it into an authorisation decision makes the decision depend on a write that may be late, batched away or lost.
- Flag the modelling smell while you are here:
expiredis derivable fromexpires_at < now(), so storing it as a status obliges a job to keep it true and guarantees the column is wrong between the expiry instant and that job's next run. Derive it in the predicate; keep the stored status for states that are decisions rather than clock readings.
Follow-ups
- Rotation issues a replacement while the old key stays live for a 30-day overlap. What does the uniqueness rule become, and what does the UI show to tell two same-named keys apart?
- A password reset bumps the principal's auth_version. No row in this table changed. How does the next request fail, and what query counts how many keys that bump just killed?
- A key turns up in a public repository. Which columns let you find it, and what do you write to the row?
Paginate a tenant's delivery export without skipping rows
A customer exports webhook_delivery: delivery_id (bigint identity), subscription_id, tenant_id, event_id, status, attempt_count, next_attempt_at, created_at, delivered_at, updated_at. The endpoint runs select ... where tenant_id = $1 order by created_at desc limit 100 offset $2, and customers report rows missing from exports taken while new deliveries are being inserted. Write the replacement query and the index that supports it, paging a tenant's deliveries newest first at constant cost per page. State why updated_at cannot be the cursor column.
How a strong candidate works it
- Name the defect precisely. OFFSET is a position in a result set that is recomputed on every request, so a row inserted ahead of the window shifts everything back by one and the next page starts after a row the client never received. Nothing errors and no identifier gap appears, so the loss is silent.
- Replace the position with a value predicate over a stable, unique, indexed ordering:
where tenant_id = $1 and (created_at, delivery_id) < ($2, $3) order by created_at desc, delivery_id desc limit 100. The row comparison is load-bearing: created_at alone is not unique, so ties straddling a page boundary are dropped or repeated, which is the same bug in a smaller window. - Index
(tenant_id, created_at, delivery_id). PostgreSQL scans a btree in either direction, so an all-DESC ORDER BY is served by an ASC index read backwards and no DESC modifiers are needed; they only matter when the ORDER BY mixes directions. Confirm the plan has no Sort node above the index scan, or the LIMIT stops being an early exit. - Price both forms: keyset is one index descent plus 100 adjacent leaf entries per page, constant regardless of depth, while OFFSET still produces and discards every skipped row, so page N costs time proportional to N times the page size and a deep page on a large table goes from milliseconds to seconds.
- Rule out updated_at as the cursor from the precondition, not from taste: a cursor column must never change value for a row already paged past. updated_at moves on every delivery attempt, so a row the client already emitted re-enters a later page and is exported twice. created_at and delivery_id are immutable, which is the whole qualification.
Expected result (20 min): A keyset query using the row comparison (created_at, delivery_id) < ($2, $3) with order by created_at desc, delivery_id desc limit 100, backed by (tenant_id, created_at, delivery_id) scanned backwards; plus the statement that OFFSET drops rows under concurrent insert and costs time proportional to the offset, and that updated_at is disqualified because it mutates on retry.
Check yourself
- Buffer counts for page 500 are the same order of magnitude as page 1.
- Every id present before the walk is returned exactly once when only inserts run concurrently.
- The query plan shows no Sort node above the index scan.
- Two rows sharing a created_at value to the microsecond are both returned across the page boundary.
Follow-ups
- The client wants a snapshot as of one instant rather than a live tail. Compare a repeatable-read transaction held open, an added
created_at <= $snapshotbound, and a materialised export table. - A retention job deletes deliveries older than 90 days. What does a client mid-walk see, and does keyset pagination help at all?
- The customer wants to resume an export from yesterday's last cursor. What must be true of the cursor for that to be safe?
Hold a tenant to a trailing sixty-second request limit
The gateway must hold each tenant to R requests in any trailing 60 seconds, in aggregate across three regions and every pod, within a budget of under 10 ms added p99. Peak is 30,000 requests/second across 200,000 active tenants, and traffic is heavily skewed toward a handful of them. Give an exact single-process algorithm with its amortised per-request cost and its memory per tenant, then a bounded-memory approximation and the worst-case overshoot it actually admits. Say what the distributed version does when the counter store is unreachable.
How a strong candidate works it
- Exact, single process: a per-tenant deque of request timestamps. On arrival, pop from the front while
front <= now - 60s, then admit if the remaining length is below R and push. Each timestamp is pushed once and popped once, so the cost is O(1) amortised. The O(R) version is the one that re-filters the whole deque on every request. - Quote the memory. R = 1,000 across 200,000 active tenants is up to 2 x 10^8 timestamps at 8 bytes, about 1.6 GB, and that is the worst case rather than the mean, because the long tail of small tenants holds almost nothing. Skew helps you here and hurts you in the sharding decision.
- Bounded alternative, with its real bound stated: a fixed 60-second counter is O(1) memory but admits close to 2R across a 60-second span straddling a boundary. The weighted two-bucket estimate,
prev * (60 - elapsed)/60 + cur, is better on smooth traffic but assumes the previous window's arrivals were uniform; an adversary packing them at the end of that window is undercounted and can still approach 2R. Say that rather than calling it exact. - Token bucket is the usual gateway answer and a different contract: O(1) state per tenant (
tokens,last_refill), a sustained rate, and a deliberate burst allowance equal to the bucket size. Choose it when a burst is acceptable and the log when the limit is contractual. - Distributed: the limit is per tenant in aggregate, so a local bucket of R/N per pod is wrong in both directions under skew. A tenant landing on one pod is throttled at R/N, and a tenant spread evenly across pods exceeds R. The shared check must be a single atomic round trip, one script or one increment-and-compare, never read-then-write, and it must fit inside the 10 ms p99 budget.
- Decide the unavailable case in advance and write it down. Failing open keeps the product up and lets a tenant exceed its limit for the duration; failing closed converts a counter-store outage into a full outage. Most gateways fail open on rate limits and closed on authorisation, and those are two separate decisions made separately.
Expected result (25 min): The exact deque never admits more than R in any trailing 60-second window. The fixed counter admits close to 2R across the boundary. The weighted estimate lands between the two on this burst and approaches 2R once the previous window's requests are packed at its end.
Check yourself
- Total pops equal total pushes, which is what makes the amortised O(1) claim true rather than merely asserted.
- Sliding the whole burst by 30 seconds changes the fixed counter's result and leaves the deque's unchanged.
- Running two processes each limiting to R/2, against a tenant that sends everything to one of them, shows that tenant throttled at half its contractual limit.
Follow-ups
- One tenant sends 40% of all traffic. What does that do to a single counter key, and what do you shard on instead?
- Quotas rather than rate limits: the check is
select used; if used < limit then insert. Name the isolation level that still permits the overshoot, and the two fixes. - How do you return an accurate
Retry-Afterfrom the exact algorithm without a second scan?
Build a resumable usage export the customer can reconcile against
Customers reconcile invoices against usage_event (event_id uuid, tenant_id, workspace_id, environment, sku, quantity numeric(20,6), idempotency_key, occurred_at, ingested_at, source_service, request_id), partitioned daily on ingested_at. The current export is ?page=N&per_page=1000 ordered by occurred_at, and a customer syncing hourly reports rows that never appear in their export but do appear on their invoice. Design the replacement: the ordering, the cursor's contents, the index it requires, and the rule deciding where a page stops. State what the client does on a timeout and on a cursor older than retention.
How a strong candidate works it
- Separate the two defects in the current shape. Offset makes the database produce and discard N * per_page rows, so page cost grows linearly and a deep page degrades from milliseconds to seconds. Concurrent inserts also shift the window between requests, so a walker skips rows with no error raised anywhere, which for a customer sync is silent data loss.
- Order by ingestion, not by occurrence. During a replay events arrive hours out of occurred_at order, so a consumer holding an occurred_at high-water mark can never see a late event that falls below it; (ingested_at, event_id) is the only ordering under which 'everything after my cursor' is a complete statement.
- Page with a row comparison: where tenant_id = $1 and (ingested_at, event_id) > ($2, $3) order by ingested_at, event_id limit $4, backed by an index on (tenant_id, ingested_at, event_id). That seeks directly to the resume point, so every page costs the same regardless of depth.
- Trail the head of the table. With ingested_at defaulting to now(), which is transaction start time, a long insert transaction receives an earlier timestamp and becomes visible after a reader has already passed it. Cap each page at ingested_at <= now() - delta, with delta larger than the longest write transaction as bounded by statement_timeout and idle_in_transaction_session_timeout, or the export skips exactly the rows written under load.
- Make the cursor opaque and self-describing: base64 of the timestamp, the event id and a fingerprint of the filters, rejected when the filters differ from the current request. Return 410 with a
cursor_expiredcode once the cursor's partition has been dropped, so the client restarts from a known time instead of resuming into a hole. - Keep a page a pure GET with no server-side consumption, so a timeout is resolved by retrying the identical cursor.
Expected result (30 min): Keyset pagination over (ingested_at, event_id) with an index on (tenant_id, ingested_at, event_id), a trailing head predicate sized above the longest write transaction, an opaque filter-bound cursor, and 410 for a cursor past retention.
Check yourself
- A late event with an old occurred_at is still delivered by the export.
- Page cost is independent of how many pages have already been read.
- The cursor persists across a client restart and survives retrying the same page.
- The tie-break column is unique, so no row can be skipped or repeated at a page boundary.
Follow-ups
- The customer asks for a total count alongside the first page. What do you offer instead, and why is an exact count both expensive here and wrong by the time it is read?
- How would you let a customer re-read a window they have already consumed without giving up the forward-only cursor?
Gateway p99 spikes on a five-minute cadence
edge-gateway caches each credential-to-authorisation-context decision for five minutes. p99 sits at 6 ms except for a spike to 900 ms roughly every five minutes, worst in the region with the most pods, and control-plane CPU and read latency rise in step with it. The error rate stays near zero. Customers are told a revoked credential stops authorising within 60 seconds. Give the ordered checklist that identifies the mechanism, and a fix that removes the spike without weakening the 60-second bound.
How a strong candidate works it
- Test periodicity before anything else: take the spike timestamps modulo the TTL in seconds. A tight cluster at a fixed offset means expiry phase, while traffic-driven spikes scatter.
- Overlay pod start times. Entries filled at first request inherit the phase of the pod that filled them, so a cohort of pods deployed together expires together and the amplitude should track cohort size rather than tenant count.
- Separate a herd from a capacity shortfall by measuring control-plane requests per second during a spike against baseline. A stampede shows a step of roughly (pods x hot keys) for one interval with hit rate collapsing to near zero, not a gradual climb that would indicate the dependency is simply undersized.
- Apply three independent controls: randomise each key's TTL by a factor drawn uniformly from something like 0.8 to 1.0 so cohorts de-phase; coalesce concurrent misses per key per pod so exactly one refresh is in flight; and serve the stale value while that refresh runs so a miss costs the stale read rather than the dependency's queue.
- Bound staleness against the published contract rather than against comfort: serve-stale is admissible only up to the 60-second revocation bound, so the TTL floor and the stale window together must stay inside it, and the published invalidation must delete the entry rather than schedule a refresh.
- Decide in advance what a miss does when the control plane is unreachable, because that is now the only uncached path: failing closed converts a dependency outage into a total outage, while extending stale service past the bound breaks the revocation promise. Pick one and configure it explicitly.
Follow-ups
- Publish-subscribe invalidation is lossy under a partition. Given that, what actually enforces the 60-second bound, and what number would you put in the contract if asked to defend it?
- One tenant's key is hot enough that a single pod's coalesced refresh still matters. What changes?
- Would a shared cache tier in front of the control plane help or shift the problem, and what new failure does it add?
Ship metered billing with a named deduplication horizon
Metered billing must be on in three weeks. usage_event is partitioned daily, so its unique index must include the partition key and deduplicates only within a day: a producer retry that crosses midnight, or a replay run a week later, gets through. A cross-partition dedup store is two weeks you do not have. Describe shipping with debt you named in advance: what you shipped, what you wrote down, the detector you added, the trigger and date for paying it off, and what you would have refused to ship under the same pressure.
How a strong candidate works it
- Show you can separate the two kinds of debt, because that distinction is what the question actually probes. Debt that costs engineering time later is shippable on a deadline. Debt that silently corrupts a number a customer gets charged for is not shippable unless the corruption is detectable, and detectability is the whole negotiation.
- Make the exposure narrow and measured rather than gestural. The hole is duplicates whose occurrences straddle a UTC day boundary, plus any replay older than partition retention. Measure it before arguing about it: how often an idempotency_key recurs at all, and the distribution of the gap between first and last occurrence. If the ninety-ninth percentile of that gap is four minutes, the residual risk is a small band around midnight and you can say so numerically.
- Add the detector before the feature, not after. A nightly job counting keys that appear in more than one partition is one grouped scan over recent partitions, and it converts a silent overcount into a page. State what it costs to run and what it fires on.
- Buy the cheap half of the real fix immediately: extend partition retention so the dedup horizon exceeds the producer's maximum retry window plus the longest replay you intend to support. That reframes retention as a correctness parameter rather than a storage cost, which is the sentence you need on record before someone optimises the bill.
- Make repayment mechanical instead of aspirational: a dated entry with a named owner, plus a threshold that pulls the date forward — first detector hit above N events, or first customer dispute. Debt with a trigger gets paid; debt with only a date does not.
- Answer the second half honestly by naming what you would refuse under identical pressure: the sealing path, because a sealed row is frozen and a wrong number there stops being a bug and becomes an adjustment line, a dispute and an audit question.
Follow-ups
- The detector fires on forty duplicate events for one tenant, and two of their invoices have already sealed. What happens next?
- Whom did you tell that the billing numbers had a known hole, and in what words?
- Finance asks you to cut storage by shortening partition retention. What do you say, and to whom?
Reverse a webhook ordering decision after measuring its cost
You argued for strict per-subscription ordering in webhook-delivery, which means one in-flight attempt per subscription. It shipped. Three months later a single unresponsive endpoint holds one subscription's queue at a six-hour backlog, and two customers report events arriving out of order anyway once their own retries are counted. Describe a decision you reversed: what you originally optimised for, the measurement that changed your mind, what the reversal cost in engineering time and customer change, and how you told the people who had already built on the original guarantee.
How a strong candidate works it
- State the original decision as a trade you made knowingly. Ordering across a network requires a single in-flight attempt per subscription, and its price is head-of-line blocking whenever one endpoint is slow. 'We priced it wrong' is a much stronger opening than 'we did not realise', and it is usually the true one.
- Bring the measurement that flipped it, not the anecdote: backlog age at the ninety-ninth percentile per subscription, the share of subscriptions where one slow endpoint gated an otherwise healthy queue, and the delivery throughput lost to serialisation. A reversal justified by complaints is indistinguishable from a reversal justified by fatigue.
- Name what you learned about the guarantee itself, which is the engineering content of this story. At-least-once delivery means a retried event already arrives after newer ones and the consumer already must be idempotent, so a guarantee the customer has to defend against anyway was never worth what it cost to provide.
- Describe the migration, because reversing a published contract is the hard half and the part candidates skip. Parallel attempts behind a per-subscription flag, a monotonically increasing sequence number added to the envelope so order-sensitive consumers can sort or discard, documentation that states at-least-once and unordered in those words, and a deprecation measured in quarters because the client is a pinned SDK inside a build pipeline you cannot see or redeploy.
- Give the cost in the two currencies that matter: engineer-weeks, and how many customers had to change code. Then say who you told before it shipped rather than in a changelog afterwards, and which large customer you left on the old behaviour and for how long.
- Close with the signal you now weight differently, stated as something you would do earlier next time: measuring the blocking cost on the slowest decile of endpoints before committing to the guarantee, rather than after a customer noticed.
Follow-ups
- A customer insists they need ordering. What do you offer them that is not global serialisation?
- How did you choose the deprecation window given that you cannot see or redeploy the clients?
- What would have to be true for you to reverse back?
Where candidates lose points
Stopping at the first working version of a progressive coding problem
The notes describe live coding as progressive: a simple first version, then optimisation or new requirements. If you finish the naive Fibonacci recursion or a two-pass parser and wait, the interviewer has to pull the next step out of you. Once you have working code, give its complexity and the next improvement. For example, naive recursion is exponential, memoisation makes it O(n) time and space, and an iterative loop keeps O(n) time with O(1) extra space. Then write that version. For the parser, show that one pass with a running total and a current product term handles precedence in O(n) with no stack.
Writing Python loops over points and centers in a PyTorch question, or broadcasting without mentioning memory
The reported closest-center question asks for broadcasting and torch.argmin, so a nested loop misses the point of the question. Broadcast points (N, D) against centers (K, D) into an (N, K) distance matrix, then take min or argmin over dimension 1. Also point out that the direct difference tensor is N x K x D. The expansion ||x||^2 - 2 x·c + ||c||^2 needs only N x K. Clamp it at zero before a square root, because rounding error can make it slightly negative.
Presenting a RAG or inference design as a list of components with no cost, latency or GPU-memory reasoning
The reported RAG prompt asks directly for cost, throughput and latency, and the notes advise weighing cost, API latency and GPU memory in design answers. Put a number or a direction on each step. For example: what dominates cost per query, what sets time to first token, what the KV cache uses per request, and which cache hit removes which work. Keep the component count low. The notes advise against extra services that do not remove a bottleneck. When challenged, defend a choice with that reasoning, and change it when the interviewer's alternative is actually better.
Submitting a GitHub project that only runs on your own machine and has no explanation of its decisions
If your track includes the project submission, clone the repository fresh and follow only the README before you send it. Pin dependencies, add one command that runs the tests, and cover the edge cases, not just the example input. Add a short section on decisions and limits. If the project comes up later, have a reason ready for every shortcut you took.
Answering the autonomy and ownership questions with stories told in the team plural
The notes say the final discussion focuses on autonomy and collaboration across distributed teams. A story where a group did the work and waited for direction shows neither. Choose stories where you structured a vague problem yourself or built something to unblock others. Name the decision you made and the result, and say plainly which parts other people owned.
Algorithms first, for a candidate whose problem-solving has gone rusty
For someone who has spent the last few years shipping features and reading other people's code, and who has not solved a timed problem from a blank file in a long time. Five days rebuild the primitives and the patterns that sit on them, working from invariants rather than remembered solutions, and the last two attach that back to the rest of the loop.
Day 1 — Screening call: settle your track and your project stories
- Decide which track you are preparing for (product, infrastructure or research-adjacent) and the language that goes with it: Python and PyTorch, or TypeScript and React. Write down the questions to confirm on the screening call, including whether a GitHub project submission is part of your process
- Write two sentences per headline project with no internal codenames: the problem, your change and the measured result. Then say them to someone outside engineering and have them repeat them back
- Write one specific reason for the role that ties to an area in the notes: serving APIs, inference performance, the developer console or client libraries
Deliverable: A one-page screening brief listing your track, your language, three project summaries in plain language, and the questions you will ask the recruiter.
Day 2 — Technical project submission: make a repository reviewable
- Take a small project of your own, or build one on a reported topic such as a deduplication utility or a streaming client, and give it a README with setup, run and test commands
- Add tests for the empty, single-element and malformed-input cases, and pin every dependency
- Add a section on decisions and limits: what you chose, what you rejected, and what you would build next
- Clone the repository into an empty directory and follow only the README. Fix every step that failed
Deliverable: A repository that runs and passes its tests from a fresh clone, with its decisions written down.
Day 3 — Live coding: parser, deduplication and lookups
- Solve the reported expression-parser question: evaluate a string of integers with + and * and no parentheses in one pass, keeping a running total and a current product term, in O(n) time and O(1) extra space. Handle whitespace and multi-digit numbers
- Extend the parser to - and /, and state how division rounds. Python's // floors negative results rather than truncating toward zero
- Solve the reported lookup-and-deduplication question as a sequence: remove duplicate IDs while keeping input order with a seen set, report the IDs that repeat, then filter out a set of known IDs. Give the complexity at each step
- Solve the first-unique-character question with a frequency count and a second scan, and state why it is linear
Deliverable: Four solutions, each with its complexity and one extension written as a separate function, plus a list of the edge cases you tested.
Day 4 — Improving solutions step by step, and tensors
- Write Fibonacci four ways: naive recursion, memoised, iterative with O(1) extra space, and a version that returns the first n numbers. Find the n at which the memoised recursive version hits CPython's default recursion limit (about 1000 frames); the naive version becomes too slow long before that
- Solve the reported PyTorch closest-center question: compute each point's closest-center distance with broadcasting and argmin. Then rewrite it with the ||x||^2 - 2x·c + ||c||^2 expansion, compare peak memory, and clamp at zero before the square root
- Work through this guide's worked exercise on the trailing sixty-second rate limiter as practice in amortised-cost reasoning. Check that total pops equal total pushes
Deliverable: A notebook or script with each Fibonacci version and the complexity it achieves, and a vectorised closest-center function checked against a loop on random data.
Day 5 — System design: RAG and the inference engine
- Design the reported scalable RAG system end to end. Cover ingestion (chunking, embedding, vector index such as pgvector or Pinecone) and the query path (embed, retrieve, rerank, assemble the prompt, generate). Name the main cost and latency lever on each path
- Design the reported high-throughput LLM inference engine. Explain the KV cache, batching requests as they arrive, what prompt or prefix caching reuses, and what the engine does when a request exceeds the context window
- For each design, list three things you are leaving out on purpose and why, so you can defend a simple design when challenged
- Work through this guide's worked exercise on the resumable usage export to practise cursor and ordering choices for a customer-facing export API
Deliverable: Two one-page designs, each with its read and write paths, a cost and latency note per component, and the omissions you would defend.
Day 6 — Agentic workflows, secure real-time channels and model regressions
- Design the reported agentic-workflow question as an explicit state machine. Persist progress after each step, make tool calls safe to retry, and define what happens on a timeout or when a step needs human approval
- Design the reported secure real-time channel between a web frontend and an AI orchestration backend: pick SSE or WebSockets for the job and justify it, authenticate the connection and authorise each message, and cover rate limits, backpressure and resuming after a reconnect
- Plan how you would test an LLM for regressions before deploying it: a fixed evaluation set, a baseline comparison, deterministic decoding for exact checks, and a staged rollout
- Product track: build the streaming TypeScript and React component. Read the response body incrementally, decode with a streaming TextDecoder, append through a functional state update, and cancel with an AbortController on unmount
Deliverable: A state diagram for the agent workflow, a channel design with its security controls, a regression-test checklist, and, if you are on the product track, a working streaming component.
Day 7 — Culture-fit stories and a full rehearsal
- Write three stories: a vague problem you structured yourself, a tool or fix you built to unblock others, and a collaboration across teams or time zones. For each, note the decision point, the options, your choice and the result
- Run a mock loop with a partner: one coding question that grows over three steps, one design question with deliberate pushback, and two behavioral prompts
- Re-solve from a blank file the coding question you were slowest on this week
Deliverable: Three rehearsed stories, notes from the mock loop listing where you stalled, and a final list of what to review the night before.