L1
·
Quiz
·
Lab
L2
·
Quiz
·
Lab
L3
·
Quiz
·
Lab
L4
·
Quiz
·
Lab
Module Test
Module 4 · Lesson 1

What Is a Logic Error?

Code that compiles, runs, and lies to you.
Why do AI code generators produce logic errors that no linter will ever catch?

On September 23, 1999, after a 286-day journey, the Mars Climate Orbiter was lost. The spacecraft entered the Martian atmosphere at the wrong angle and disintegrated. The root cause was a single unit mismatch: Lockheed Martin's navigation software output force data in pound-force seconds; NASA's receiving system expected newton-seconds. Every component of the system compiled and ran without error. Telemetry was transmitted and received. Only the planet's gravity revealed the failure.

Total mission cost: $327.6 million. The bug was a logic error — a wrong assumption baked silently into a computation.

The Taxonomy of Code Errors

Software errors are conventionally divided into three categories, and understanding where logic errors sit within that taxonomy is the foundation of this module.

Syntax errors are violations of a language's grammar rules. The compiler or interpreter rejects them before execution begins. They are the easiest class of bug to detect — and the class AI code generators almost never produce, because they have been trained on vast corpora of syntactically correct code.

Runtime errors occur during execution: a null pointer dereference, a division by zero, an out-of-bounds array access. They produce exceptions, crashes, or observable error messages. They are more dangerous than syntax errors but still tend to surface during testing.

Logic errors are the most dangerous class. The program runs to completion and produces output — but the output is wrong, or wrong only in certain conditions, or subtly wrong in a way that accumulates over time. No exception is raised. No linter fires. The code is semantically valid and structurally sound. It simply does the wrong thing.

Core Definition

A logic error is a defect in which a program executes without crashing but produces incorrect results because of a flaw in the algorithm, a wrong assumption about data, an incorrect operator, a boundary condition mistake, or a misunderstood specification.

Why AI Generators Are Logic-Error Prone

Large language models generate code by predicting statistically plausible token sequences given a prompt. They have learned patterns — common function signatures, idiomatic loops, standard library calls. What they have not learned, in any reliable sense, is the specific semantics of your problem.

When you ask an AI to write a function that "calculates compound interest," it will produce code that looks like compound interest code. The variable names will be correct. The structure will be familiar. But if the compounding frequency is wrong, or if the formula uses addition where it should use multiplication, the code will silently produce wrong numbers for every input — and nothing in the execution environment will tell you so.

This is the fundamental asymmetry of logic errors in AI-generated code: the generator optimizes for plausibility, not correctness. The reviewer's job is to supply what the model cannot: domain knowledge, specification awareness, and adversarial testing.

The Four Principal Categories

This module organizes logic errors into four categories that appear with high frequency in AI-generated code:

Off-by-one Boundary conditions where indices, ranges, or loop counts are displaced by exactly one — the most common logic error class in generated code.
Wrong operator / precedence Logical or arithmetic operators that are plausible replacements for the correct one — e.g., > vs. >=, or && vs. ||.
Silent failure paths Code branches that return default, zero, or empty values when an error condition occurs, masking the failure from the caller.
Accumulation errors Mistakes in loops, aggregations, or stateful computations that compound over time — correct on simple inputs, wrong on realistic ones.
A Minimal Illustration

Consider this AI-generated function meant to check whether a user's age makes them eligible for a service that requires users to be over 18 (not 18 or older):

// AI-generated — appears correct at a glance function isEligible(age) { return age >= 18; // should be: age > 18 }

Every linter will approve this code. Every type checker will pass it. An 18-year-old will be admitted when they should not be. The error is invisible to automated tooling and surfaces only when you compare the code against the specification. This is the discipline this module teaches.

Reviewer's Principle

For every AI-generated function, ask: "What is this code actually computing, and is that the same thing I asked for?" Run the logic in your head on at least three inputs: a typical case, a boundary case, and a case that should fail.

Lesson 1 Quiz

What Is a Logic Error? — Check your understanding before the lab.
Which class of error does a standard linter or compiler reliably detect?
Correct. Syntax errors violate grammar rules that compilers and linters check directly. Logic errors, by contrast, are semantically valid code that does the wrong thing — no automated tool catches them reliably.
Not quite. Linters and compilers check structural grammar rules, catching syntax errors. Logic errors produce valid, running code — just with wrong results — which automated static tools cannot detect.
The 1999 Mars Climate Orbiter was lost because of a unit mismatch between pound-force seconds and newton-seconds. What type of bug was this?
Correct. The software compiled, ran, and transmitted data flawlessly. The unit assumption was wrong — a logic error — and no part of the execution environment flagged it.
Not quite. The Orbiter software ran without crashing. The failure was a wrong assumption baked into a computation — the definition of a logic error.
Why does an AI code generator optimize for "plausibility" rather than correctness?
Correct. LLMs generate code by learning what token sequences commonly follow other token sequences in training data. They have no mechanism to verify that the output is semantically correct for your specific problem.
Not quite. LLMs have access to compilers (via tool-use in some systems), and correctness is definable — the issue is that the model's training objective is next-token prediction, not semantic verification.
A function returns age >= 18 when the specification says "strictly older than 18." The minimum number of test inputs that would catch this is:
Correct. The off-by-one is exposed precisely at the boundary value. An input of 18 returns true when it should return false, which no input above 18 would reveal.
Not quite. The error is a boundary condition: the function diverges from the specification exactly at age = 18. Inputs above 18 produce the same result under both the wrong and correct code.

Lab 1 — Identifying Logic Errors

Practice spotting logic errors in AI-generated snippets with your AI reviewer.

Your Task

Below is an AI-generated Python function that is meant to return the average of a list of numbers, but only for values strictly greater than zero. Read the code, identify the logic error(s), and discuss them with the AI assistant. Explain what the bug is, what input would reveal it, and how you would fix it.

def positive_average(nums): total = 0 count = 0 for n in nums: if n >= 0: # should exclude zero total += n count += 1 if count == 0: return 0 # silent failure — should raise or return None return total / count
Start by telling the AI what logic error(s) you see in this function, then ask it to help you construct a test case that reveals the bug and discuss the right fix.
AI Code Reviewer
Logic Errors · Lab 1
Ready to review. I have the positive_average function in front of me. Tell me what logic error(s) you spot — then we'll build a test case together and talk through the fix.
Module 4 · Lesson 2

Off-by-One Errors

The most common logic error in generated code — and the most reliably invisible.
Why do off-by-one errors appear so frequently in AI-generated loops, and how do you build a systematic check for them?

Between 1985 and 1987, at least six patients received massive radiation overdoses from the Therac-25 medical linear accelerator, three of whom died. One contributing factor was a race condition in the control software, but a separate and independently investigated class of defect was boundary logic: the machine's beam-on confirmation code used incorrect range checks on operator-entered values, accepting parameters that should have been rejected. The code had been adapted from the Therac-20, where hardware interlocks had silently compensated for these off-by-one boundary conditions. When the hardware interlocks were removed in the Therac-25 to reduce cost, the latent boundary errors in the software became lethal.

Anatomy of an Off-by-One Error

An off-by-one error (OBOE) occurs when an index, a loop bound, or a comparison operator is displaced by one from the correct value. They cluster at three sites in code: loop initialization (i = 0 vs. i = 1), loop termination (i < n vs. i <= n), and conditional comparisons (> vs. >=).

AI generators are particularly prone to OBOEs because the training corpus contains both 0-indexed and 1-indexed conventions, both inclusive and exclusive upper bounds, and both strict and non-strict comparisons — often in syntactically identical contexts. The model cannot distinguish them by structure alone; only the specification determines which is correct.

The Three OBOE Sites in AI Code

Site 1: Loop bounds. The most frequent OBOE in generated iteration code. Consider a function asked to process "the first N items" of a list:

AI-Generated (wrong)
for i in range(1, n+1): process(items[i])
Correct
for i in range(0, n): process(items[i])

Site 2: Slice / substring extraction. Python slice semantics use exclusive upper bounds; many AI-generated slices are off by one when the prompt uses language like "up to and including position N."

AI-Generated (wrong — misses last char)
# "extract first 5 characters" result = s[0:4]
Correct
# Python slice: end is exclusive result = s[0:5]

Site 3: Conditional boundary comparisons. Seen in the Lesson 1 example with age. The operator family < / <= / > / >= is the most frequent source of one-position logical displacement.

The OBOE Review Checklist

When reviewing any AI-generated loop or conditional for OBOEs, apply this four-question checklist:

1. First element Is the loop's or slice's first element included or excluded? Does the initialization match the specification?
2. Last element Is the final element included or excluded? Does the termination condition match?
3. Count For a range meant to process N items, does the loop execute exactly N times? Verify with a small concrete N (e.g., N=3).
4. Boundary literal For every comparison operator, substitute the boundary value and confirm the truth value matches the specification.
AI Review Prompt Template

"Check this loop for off-by-one errors. For each loop bound and each comparison operator, tell me what value is included or excluded, and verify that matches the specification: [paste spec here]."

Fence-Post Problems

The classic formulation of OBOEs is the fence-post problem: to build a fence 10 meters long with posts every meter, how many posts do you need? The answer is 11, not 10 — there is always one more post than there are gaps. AI generators make this mistake frequently in pagination logic, page-count calculations, and any code that enumerates boundaries rather than intervals.

# AI-generated pagination: "how many pages for N items at K per page?" pages = N // K # WRONG: drops the partial last page # Correct: pages = (N + K - 1) // K # or: math.ceil(N / K)
Reviewer's Principle

Always test the exact boundary value. If a function processes "items 1 through N," test it with N=1 and N=0. If it loops "while index < length," trace the last iteration manually. The error will be there or nowhere.

Lesson 2 Quiz

Off-by-One Errors — Boundary knowledge check.
A Python slice s[0:4] on the string "Hello" returns how many characters?
Correct. Python slice notation is exclusive at the upper bound. s[0:4] returns indices 0, 1, 2, 3 — four characters: "Hell".
Not quite. Python slices use an exclusive upper bound: s[0:4] covers indices 0 through 3 — four characters, not five.
To paginate 17 items with 5 items per page using correct integer arithmetic, how many pages are needed?
Correct. 17 // 5 = 3, but that drops the partial page of 2 items. The correct formula is ceil(17/5) = 4. AI-generated code using only integer division produces the common OBOE of returning 3.
Not quite. Integer division 17 // 5 = 3, but this is the off-by-one error. The last 2 items require a fourth page. The correct formula is ceil(N/K) or (N + K - 1) // K.
In the Therac-25 case, what made latent off-by-one boundary errors in the software safe in the Therac-20 but lethal in the Therac-25?
Correct. Hardware interlocks acted as a compensating control that masked the software's boundary errors in the Therac-20. When those interlocks were removed for cost reasons, the software defects became directly dangerous.
Not quite. The key factor was that hardware interlocks in the Therac-20 silently compensated for the software's range-check errors. The Therac-25 removed those interlocks, exposing the latent defects.
Which of the following is the most reliable technique for catching an OBOE in a loop during code review?
Correct. Manually tracing boundary iterations — especially the first (n=0 or n=1) and last — is the most reliable way to expose OBOEs that automated tooling cannot see.
Not quite. Linters, variable names, and compilation checks are all blind to OBOEs because the code is syntactically valid. The only reliable check is manual execution tracing at boundary values.

Lab 2 — Off-by-One Error Drills

Trace boundary conditions in AI-generated loops with your AI reviewer.

Your Task

The following AI-generated function is meant to return every other element starting from the first, for a list of exactly N items — meaning it should return elements at indices 0, 2, 4, … up to and including the last valid even index. Identify the OBOE, state what boundary input reveals it, and confirm the fix.

def every_other(items): result = [] for i in range(1, len(items), 2): result.append(items[i]) return result
Tell the AI what the OBOE is: which site does it occur at, what input demonstrates it, and what is the one-character fix? Then ask it to check whether there are any secondary boundary issues.
AI Code Reviewer
Off-by-One Errors · Lab 2
I have the every_other function. Walk me through the OBOE you see — where in the code does it occur, and what input would expose it?
Module 4 · Lesson 3

Silent Failure Paths

Code that swallows errors and returns plausible-looking lies.
How do AI generators create silent failure paths, and why are they more dangerous than exceptions?

On August 1, 2012, Knight Capital Group deployed new trading software to production. A deployment error activated a dormant code path — a "Power Peg" algorithm that had been decommissioned — which began executing millions of unintended trades. The system had no circuit breaker. Error conditions were swallowed by exception handlers that logged messages but continued execution. Within 45 minutes, Knight had accumulated $7 billion in unwanted stock positions and lost $440 million. The company was effectively destroyed.

A post-mortem found that error handling code consistently returned silently rather than halting. The failure paths were present and executed — they simply never surfaced to the level where a human or automated monitor could act on them.

The Anatomy of a Silent Failure

A silent failure occurs when a function or code block encounters an error condition — invalid input, a failed operation, an unexpected state — and responds by returning a default value, an empty result, or zero, instead of raising an exception or returning a typed error signal.

AI generators produce silent failures with high regularity because training data contains countless examples of defensive programming patterns where returning a safe default is idiomatic. The model has learned these patterns without learning the critical distinction: when a default return masks a real problem versus when it is a legitimate fallback.

Three Common Silent Failure Patterns

Pattern 1: Return zero or empty on error.

Silent Failure
def get_price(item_id): try: return db.lookup(item_id) except Exception: return 0 # silently prices items at $0
Correct
def get_price(item_id): try: return db.lookup(item_id) except Exception as e: raise PriceLookupError(item_id) from e

Pattern 2: Bare except that logs and continues.

# AI-generated pattern — extremely common in generated code try: result = process(data) except: # catches EVERYTHING including KeyboardInterrupt print("An error occurred") # logs, then falls through to wrong state

Pattern 3: None propagation. A function returns None on failure; callers assume a valid object and use it without checking, producing an AttributeError or NullPointerException deep in unrelated code, far from the original failure site.

def find_user(uid): user = db.get(uid) if not user: return None # caller does: find_user(id).email — crashes later return user
Why Silent Failures Are Worse Than Exceptions

An unhandled exception halts execution at the point of failure and produces a stack trace that identifies the problem precisely. A silent failure allows execution to continue with corrupted or default state. The corruption propagates through subsequent computation, and by the time a symptom becomes visible — a wrong report, an incorrect transaction, a crashed downstream system — the causal connection to the original failure is obscured or lost.

In financial, medical, or safety-critical systems, this propagation window is the difference between a recoverable incident and a catastrophic one. Knight Capital's $440 million loss was caused not by software that crashed, but by software that kept running when it should have stopped.

Red Flags in AI-Generated Code

Immediately scrutinize any function that: (1) catches a broad Exception or bare except and returns a value; (2) returns 0, empty string, empty list, or None without a comment explaining that this is intentional and safe; (3) has a try/except that does not re-raise and does not set an error flag visible to the caller.

The Review Question for Every Error Handler

For every exception handler in AI-generated code, ask: "If this exception fires, what does the caller receive, and does the caller have enough information to know that an error occurred?" If the caller receives a value that looks like a valid result but is actually a default substituted for a failure, that is a silent failure path that must be corrected.

Reviewer's Principle

Prefer fail-fast over fail-silent. An exception that halts a transaction is recoverable. A transaction that completes on wrong data may not be. When reviewing AI code, flag every place where the code could lie to its caller.

Lesson 3 Quiz

Silent Failure Paths — Identify and classify.
In the Knight Capital Group incident, what property of the error handling code turned a deployment mistake into a $440 million loss?
Correct. The post-mortem found that error handlers consistently returned without halting or surfacing the problem, allowing the erroneous algorithm to continue executing trades for 45 minutes.
Not quite. The problem was the opposite of too many exceptions — error conditions were silently swallowed, allowing a runaway algorithm to continue executing without any visible failure signal.
A function get_price(item_id) catches all exceptions and returns 0. What is the primary danger of this pattern?
Correct. The caller receives a value that looks valid (0 is a legal number) and has no way to distinguish "price is zero" from "price lookup failed." This is the defining characteristic of a silent failure.
Not quite. The danger is semantic: returning 0 on failure makes a pricing error indistinguishable from a legitimately zero-priced item. The caller proceeds as if nothing went wrong.
Which Python exception handling pattern is the most dangerous silent-failure antipattern?
Correct. A bare except: catches everything — including SystemExit and KeyboardInterrupt — and printing a message then continuing means execution proceeds in an unknown state. The caller has no signal that anything failed.
Not quite. Re-raising is correct behavior. The most dangerous pattern is the bare except: that swallows the error and allows execution to continue — the caller never knows the failure occurred.
When reviewing AI-generated code, which of the following return statements in an exception handler requires the most immediate scrutiny?
Correct. Returning an empty list from an exception handler is a classic silent failure: the caller sees a valid return value (an empty list is a legal result) and has no indication that the operation failed rather than simply finding no results.
Not quite. Raise statements preserve error information and propagate it to the caller. The dangerous pattern is returning a value that looks valid — like an empty list — which gives the caller no signal that an error occurred.

Lab 3 — Exposing Silent Failures

Diagnose and fix silent failure paths in AI-generated error handling.

Your Task

This AI-generated function fetches a configuration value from a remote source. It has two silent failure paths. Identify both, explain what downstream damage each could cause in a production system, and propose a fix that makes failures visible to the caller.

import requests def get_config(key, default=None): try: resp = requests.get(f"https://config-service/get/{key}", timeout=2) data = resp.json() return data.get(key, default) # silent: key absent returns None except Exception: return default # silent: network failure returns None
Tell the AI what the two silent failure paths are and trace one concrete scenario where each path causes incorrect downstream behavior in a payment or access-control system.
AI Code Reviewer
Silent Failures · Lab 3
I have the get_config function. There are two silent failure paths here. Walk me through them — and then let's trace what goes wrong in a real system when each one fires.
Module 4 · Lesson 4

Accumulation Errors and Wrong Operators

When the error is invisible on one row but catastrophic across a million.
How do you detect logic errors that only manifest at scale or over time — the class AI reviewers most consistently miss?

In 1983, observers noticed that the Vancouver Stock Exchange index, launched in January 1982 at a value of 1000, had drifted to approximately 520 — despite rising stock prices. An investigation revealed that the index calculation software truncated rather than rounded the index value to three decimal places with each transaction. With approximately 3,000 transactions per day, the truncation bias accumulated to nearly 480 points over 22 months. The fix — switching from truncation to rounding — restored the index to 1098.892 within minutes of correction.

The software was syntactically correct. Each individual calculation was close to right. The error existed only in aggregate — invisible to any review of a single calculation, devastating in the total.

Accumulation Errors in AI-Generated Code

An accumulation error is a logic defect in which each individual operation introduces a small error, and those errors compound over repeated execution. The most common sources in AI-generated code are:

Floating-point truncation Using integer division or truncation where rounding is required; the Vancouver Stock Exchange case is the canonical example.
Wrong aggregation operator Using addition where multiplication is required (or vice versa) in compound calculations — most visible in compound interest, growth rate, and probability accumulation code.
State mutation in loops Modifying a variable inside a loop incorrectly — e.g., resetting a running total that should persist across iterations.
Initialization errors Starting an accumulator at the wrong value — a sum initialized to 1 instead of 0 will be off by exactly 1 for every input size.
The Wrong Operator Problem

Wrong operators are distinct from OBOEs — they involve choosing a fundamentally incorrect operation rather than displacing a correct one by one. In AI-generated financial and scientific code, the most common wrong operator errors involve:

Addition vs. multiplication in compounding. Compound growth requires multiplying by (1 + rate) at each period; a naive AI implementation often adds the rate instead, producing linear rather than exponential growth.

Wrong Operator (linear growth)
def compound(principal, rate, years): total = principal for _ in range(years): total += principal * rate # adds flat amount return total
Correct (exponential growth)
def compound(principal, rate, years): total = principal for _ in range(years): total *= (1 + rate) # grows the running total return total

The wrong version produces the right answer for year 1 (principal × rate is the same as principal × rate in both). It diverges from year 2 onward. A reviewer who tests only a single-period case will miss the error entirely.

Logical Operator Confusion

The && / || (or and / or) confusion is particularly dangerous in validation and access-control code. Consider a function that should permit access only if the user has both a valid session and the required role:

# AI-generated access control — wrong operator def can_access(user): return user.has_session or user.has_role # should be: and

A user with an expired session but the correct role will be admitted. A user with no role but an active session will also be admitted. The function is logically inverted, and in an access-control context it creates a security vulnerability, not merely a functional bug.

Review Strategy for Accumulation and Operator Errors

These errors require a different review approach from OBOEs and silent failures. Because they manifest at scale or over time, the review strategy must be mathematical rather than execution-based:

Multi-period testing For any loop that accumulates a value, test with at least 3 iterations manually and check whether the growth pattern is correct (linear? exponential? constant?).
Truth table for logical operators For every boolean expression in a conditional, enumerate all combinations of true/false inputs and verify each outcome against the specification.
Unit analysis For numerical code, annotate each variable with its unit and verify that the operations are dimensionally consistent — the Mars Orbiter method.
AI Review Prompt Template

"For this accumulation loop, trace the value of the accumulator after iterations 1, 2, and 3, and confirm whether the growth pattern (linear/exponential/other) matches the specification. Flag any use of truncation where rounding might be required."

Reviewer's Principle

Logic errors that manifest at scale are the hardest to catch in code review and the most expensive in production. For every loop that aggregates or compounds a value, derive what the output should be algebraically for N iterations, then verify the code implements that formula exactly.

Lesson 4 Quiz

Accumulation Errors and Wrong Operators — Verify your analytical technique.
The Vancouver Stock Exchange index lost ~480 points over 22 months due to accumulation of truncation errors. What was the approximate rate of loss per day?
Correct. 22 months × ~30 trading days ≈ 660–680 days. 480 / 675 ≈ 0.71 points per day — individually imperceptible, collectively catastrophic. This is the defining characteristic of accumulation errors.
Not quite. 480 points over ~675 trading days works out to roughly 0.7 points per day — small enough to be invisible in daily monitoring, large enough to distort the index by nearly 50% over two years.
An AI-generated compound interest function adds principal * rate each year instead of multiplying total *= (1 + rate). For a 10% rate on $1000 over 5 years, what is the error in the final output?
Correct. The wrong version: 1000 + 5 × (1000 × 0.1) = $1500. The correct compound formula: 1000 × 1.1^5 = $1610.51. The divergence grows with each period.
Not quite. The wrong version produces: 1000 + (5 × 100) = $1500 (simple interest). The correct compound result: 1000 × (1.1)^5 = $1610.51. A $110.51 understatement that grows larger with more periods.
An access control function reads: return user.has_session or user.has_role. The specification requires BOTH. Which combination of user states would the wrong operator incorrectly admit?
Correct. With or, a user with a valid session but no required role passes the check. The correct and operator would return False here. This is a security vulnerability in access-control code.
Not quite. The or operator returns True if either condition is true. A user with has_session=True and has_role=False would be incorrectly admitted — they have a session but lack the required role.
What is the most reliable method to verify a loop-based accumulation function during code review?
Correct. Accumulation errors are invisible at N=1 and often invisible at N=2. Tracing 3+ iterations and comparing to the algebraic formula is the standard review technique — it is how the Vancouver Stock Exchange error was eventually caught.
Not quite. Linters, names, and single-input tests all miss accumulation errors because each individual operation may look correct. The required technique is multi-iteration tracing and algebraic verification.

Lab 4 — Accumulation and Operator Errors

Trace multi-iteration bugs and wrong logical operators in AI-generated code.

Your Task

This AI-generated function is meant to compute a running probability: given a list of independent probabilities, it should return the probability that all events occur (i.e., the joint probability — a product). It has two logic errors. Identify both and trace what output the wrong version produces for a concrete input.

def joint_probability(probs): # Returns P(all events occur) for list of independent probabilities total = 0 # Error 1: wrong initialization for p in probs: total += p # Error 2: wrong operator — should multiply return total
Tell the AI what both errors are. Then trace what joint_probability([0.5, 0.5, 0.5]) returns under the wrong code, and what it should return. Discuss why initializing to 0 vs. 1 matters for products, and why this error class is dangerous in risk-modeling systems.
AI Code Reviewer
Accumulation Errors · Lab 4
I have the joint_probability function. Walk me through both logic errors — then let's trace the output for [0.5, 0.5, 0.5] under the wrong code versus the correct code.

Module 4 Test

Logic Errors and Silent Failures — 15 questions, 80% to pass.
1. A program compiles and runs to completion but produces a wrong answer on a specific class of inputs. What type of error is this?
Correct. A logic error produces valid, running code with incorrect results — no crash, no exception, no linter flag.
Not quite. A syntax error would prevent compilation. A runtime exception would halt execution. Code that runs silently to a wrong answer is a logic error.
2. What was the direct cause of the loss of the Mars Climate Orbiter in 1999?
Correct. The navigation software output force data in pound-force seconds; the receiving system expected newton-seconds. The code ran perfectly; the assumption was wrong.
Not quite. The software had no crash — it operated normally. The unit mismatch was a logic error in an implicit assumption about what unit system was being used.
3. Why do AI code generators produce logic errors more frequently than syntax errors?
Correct. LLMs predict likely continuations. Syntax correctness is strongly correlated with likelihood in training data; semantic correctness for your specific domain is not.
Not quite. The asymmetry is due to the training objective: next-token prediction strongly enforces syntactic patterns but cannot enforce semantic correctness for a domain-specific problem the model has never seen.
4. A loop is written as for i in range(1, n) when the specification requires processing all n items starting from the first. What is wrong?
Correct. range(1, n) starts at index 1 (missing index 0, the first item) and ends at index n-1 (missing index n-1 if items are 0-indexed to n-1). Should be range(0, n).
Not quite. range(1, n) skips index 0 (the first element) and iterates through index n-1, processing n-1 items, not n. The start should be 0.
5. In Python, what does s[2:5] return from the string "abcdefg"?
Correct. Python slices are [inclusive_start : exclusive_end]. s[2:5] returns characters at indices 2, 3, 4 — "cde".
Not quite. Python slice notation: s[start:end] includes start, excludes end. s[2:5] on "abcdefg" gives indices 2, 3, 4 → "c", "d", "e" → "cde".
6. The fence-post problem states that a 10-meter fence with posts every meter requires how many posts?
Correct. 10 sections require 11 posts — one at each end plus one between each pair of sections. N gaps require N+1 boundaries. AI generators frequently make this error in pagination and enumeration code.
Not quite. The fence-post insight: N intervals require N+1 boundary markers. 10 meter-sections require 11 posts. AI generators commonly return N when N+1 is correct.
7. A function catches all exceptions and returns 0 as a price. What category of error is this?
Correct. Returning a default value (0) when an error occurs is the canonical silent failure pattern — the caller cannot distinguish "price is legitimately 0" from "price lookup failed."
Not quite. This is a silent failure: an error condition is masked by returning a plausible-looking default value, giving the caller no signal that something went wrong.
8. What made the Knight Capital Group's $440M loss preventable at the software level?
Correct. If error handlers had halted the system when the unexpected code path activated, the loss would have been contained. Fail-fast over fail-silent is the core principle for safety-critical systems.
Not quite. The defining problem was fail-silent error handling. If the system had halted rather than continued executing on an error signal, the window for loss would have been minutes, not 45 minutes of continuous trading.
9. A bare except: block in Python is dangerous primarily because:
Correct. A bare except catches the entire exception hierarchy in Python, including control-flow exceptions. This is the widest possible silent failure surface.
Not quite. The primary danger is scope: a bare except catches SystemExit, KeyboardInterrupt, and GeneratorExit — exceptions that should not be caught — in addition to all application exceptions.
10. The Vancouver Stock Exchange index lost ~480 points over 22 months due to:
Correct. Truncating to 3 decimal places (rather than rounding) introduced a consistent downward bias. Multiplied by ~3,000 transactions/day over 22 months, the small error compounded to nearly a 50% index drop.
Not quite. The error was truncation vs. rounding — systematically discarding fractional amounts rather than rounding to nearest. Over thousands of daily transactions, this created a consistent downward bias.
11. An AI-generated compound interest loop uses total += principal * rate each year. For a $1000 principal at 10% for 3 years, what does it return?
Correct. Adding principal × rate each year = 1000 + (100 × 3) = $1300. Correct compound: 1000 × 1.1^3 = $1331. The error is adding a flat amount rather than multiplying the growing total.
Not quite. The wrong version: each year adds 1000 × 0.1 = 100. After 3 years: 1000 + 300 = $1300. The correct compound formula: 1000 × (1.1)^3 = $1331.
12. An access-control function reads return user.active and user.is_admin or user.is_superuser. Due to Python operator precedence, this evaluates as:
Correct. In Python, and binds tighter than or. This evaluates as (active AND admin) OR superuser — meaning any superuser passes the check regardless of their active status, which is likely a security defect.
Not quite. Python operator precedence: and binds before or. The expression groups as (active AND admin) OR superuser. This means a deactivated superuser is still admitted — a likely security defect.
13. The most reliable technique to detect an accumulation error in a loop during code review is:
Correct. Accumulation errors are invisible at N=1 and often at N=2. Multi-iteration tracing plus algebraic verification is the standard technique for catching them in review.
Not quite. Type checkers and naming conventions are blind to accumulation errors. A single large N may not distinguish wrong-formula from right-formula results. Trace 3+ iterations and compare to the algebraic formula.
14. For the joint_probability function, why does initializing the accumulator to 0 instead of 1 cause a critical error even if the operator were corrected to multiplication?
Correct. The multiplicative identity is 1, not 0. Initializing a product accumulator to 0 means 0 × p₁ × p₂ × … = 0 for every possible input. The initialization error alone destroys the function's output entirely.
Not quite. Multiplying 0 by any number gives 0. If the accumulator starts at 0 and each step multiplies, the result is always 0 — completely independent of the actual probabilities.
15. Which of the following review actions addresses the broadest range of logic error types covered in this module?
Correct. This three-part approach catches OBOEs (boundary inputs), wrong operators (spec comparison), and silent failures (error path inspection) — covering all four logic error categories from this module.
Not quite. Linters, naming, and compilation all miss logic errors entirely. The comprehensive review technique is: trace boundary/typical/failure inputs, verify operators against the spec, and inspect every error return path.