CODING CHALLENGE · N°67

Spot the Bug in AI Code

Easy AI EngineeringCode ReviewDebugging

An assistant wrote this history-trimmer to fit a chat inside the context window. It looks right, the types check, it passes the obvious case — and it silently drops the system prompt the moment the conversation gets long. Reviewing AI code means catching exactly this: confident, plausible, and wrong on the case that matters. Find the bug and fix it.

The problem

The starter code is an AI-written clip_history(history, max_turns). history[0] is the system message and must always survive; the rest are conversation turns, of which only the most recent max_turns should be kept. The current code returns history[-max_turns:] — which counts the system message as a turn and drops it entirely once the history is longer than the budget. Fix it so the system message is always first, followed by at most the last max_turns non-system messages. Do not mutate the input.

EXAMPLE 1
Input history=[sys, u1, u2], max_turns=5
Output [sys, u1, u2]
short history fits under the budget — unchanged
EXAMPLE 2
Input history=[sys, u1, u2, u3, u4, u5], max_turns=2
Output [sys, u4, u5]
the buggy version returns [u4, u5] — the system prompt is gone
EXAMPLE 3
Input history=[sys, u1, u2], max_turns=0
Output [sys]
no turns budgeted — only the system message remains
CONSTRAINTS
  • The system message (history[0]) is always the first element of the result, regardless of max_turns.
  • Keep at most the last max_turns of the non-system messages (history[1:]); max_turns=0 keeps none.
  • If the whole history already fits (max_turns >= len(history) - 1), return it unchanged.
  • Do not mutate the input history — build and return a fresh list.
SOLVE IT YOURSELF

Your turn — write it

Edit the stub, hit Run (or ⌘/Ctrl + Enter), and watch the hidden tests. Stuck? the hints are right above and Reveal solution is one click away.

YOUR TASK

The AI-written clip_history below drops the system prompt on long conversations. Find the one-line bug and fix it so the system message always survives and only the last max_turns turns are kept.

HINTS — 4 IDEAS
  1. Run it first: try max_turns=2 on a history of 6 — watch the system message vanish. That is the bug.
  2. The system message must not be counted against the turn budget. Separate it out: system = history[0], rest = history[1:].
  3. Slice the REST, not the whole history: rest[-max_turns:] keeps the last max_turns turns.
  4. Guard max_turns == 0 — an empty slice, so the result is just [system].
CPython · WebAssembly
Approach, complexity & discussion — open after you solve

The approach

The bug is that history[-max_turns:] counts the system message (index 0) as one of the turns, so once the history is longer than the budget the slice slides past it and drops it. Separate the system message out first, then slice only the rest: system = history[0], kept = history[1:][-max_turns:] (and [] when max_turns == 0), and return [system] + kept.

Complexity

Time and space O(max_turns) for the kept slice — the history itself is not copied beyond the tail.

Common mistakes

  • Slicing the whole history instead of history[1:], so the system message competes for the turn budget.
  • Forgetting the max_turns == 0 case — x[-0:] is the whole list, not empty, a classic Python trap.
  • Mutating the input list instead of building a fresh one.
  • Fixing the symptom (“keep it under N”) without asking whether the system prompt must always survive — it must.

Where this shows up

Dropping the system prompt on long conversations is a real, shipped bug pattern in AI apps — the assistant silently “forgets” its instructions mid-chat. More broadly this is what reviewing AI-generated code is: the code looks right, passes the obvious case, and fails on the case that matters. Catching it means reading for the edge (long history) the demo never exercised — the core skill of shipping with AI.

Explore the topic

See this challenge alongside everything else on the same subject — handbooks, system designs, algorithms and tools, in one place.