Video
Unit video
The narrated video for Unit 7, about 9 minutes, is published with the first release.
Learning purpose: A deliberately underspecified prompt, and the plausible mistakes it produces.
Accessible text alternative: the transcript linked below, and this page, which covers the same material.
Transcript of the Unit 7 video
The narration is spoken by synthetic voices made for this course, each shown on screen as a drawn robot. No person is speaking.
Watch what changes
Reading time: about 12 minutes. Activity: about 12 minutes, plus optional extensions.
Prerequisite: Unit 6. This unit assumes you have derived B4 yourself and can state which convention this course uses. If you have not, go back — the whole point of the ordering is that your reference exists before the generated output does.
1. What you should be able to do afterwards
- Recognise what an underspecified prompt leaves open, for the generated output to fix by default.
- Name the failure modes this course expects in generated Bernoulli code, using the course's own codes.
- Separate the parts of a generated response that a test could settle from the parts only a source could settle.
- Produce a saved artefact — prompt, output, date, and your own triage — that Unit 8 will check and Unit 17 will use as evidence.
2. The prompt
Here is the prompt for this unit, in full:
Write a Python function that returns Bernoulli numbers.
That is the entire thing. One sentence, no context, no requirements.
It is important that you do not read this as a trick. It is not a deliberately bad prompt constructed to make a point; it is the sentence people actually type. When you know roughly what you want and the tool is open in front of you, this is what gets written, and it can produce something that works well enough. That is precisely why it is worth examining.
The precise prompt is not in this unit
There is a precise version of this prompt. It states the interface, the convention, the return type, the range and the behaviour at odd indices. You will build it in Unit 10, and it is printed on the Unit 10 page if your route ends before that unit.
It is deliberately withheld until then, and this page is telling you so rather than quietly omitting it. The reason is straightforward: if you see a good specification before you have felt the need for one, you learn that good specifications exist, which you already knew. If you write the vague prompt first, look at what comes back, and only then see the precise version, you learn what each clause of it is for, because you watched the failure it prevents.
In one study of developers' publicly shared ChatGPT conversations from 2023, prompts missing a specification (the language, the environment, test cases) were the most frequent reason a conversation needed more than one prompt: 34 of the 85 such conversations [L25, sec. 3.1, Table 2].
3. What the sentence leaves open
Read the prompt again and count the decisions it does not make.
- Which convention?
B1 = -1/2orB1 = +1/2. Both standard, as Unit 6 established. - What return type? Exact rationals, or floating-point decimals.
- What range of indices? Starting where, running how far.
- What happens at the odd indices? Exact zeros, or absent, or something else.
- Does exactness matter? Nothing in the prompt says it does.
Somebody has to settle every one of those before the code can exist. You settled none of them.
This is the mechanism worth holding on to. A language model produces a statistically plausible continuation of the text it is given. Where your text is silent, the continuation still has to contain something: the code that does the work cannot leave out the parts you did not specify. What it contains reflects the patterns in similar code the model was trained on, not your requirements, because your requirements were never stated.
So an unstated requirement usually does not appear in the output as a gap. It appears as a confident default. A system may instead ask a clarifying question or state the assumption its output rests on, which is better, because a stated assumption can be checked, but it is still a default you did not set. A silent default is much harder to notice than a gap would be, and it is the reason this unit exists.
None of this is peculiar to AI. A human contractor given the same one-sentence request would face the same open decisions, underspecified requirements are among the oldest causes of failure in software, and every failure mode in this unit occurs in code people write. What is new is that a generator settles the open decisions instantly and silently, and at volume.
4. The failure modes to expect
The course names five failure modes in generated Bernoulli code. These are the codes the checker emits in Unit 8, so the names are worth learning as they stand.
| code | meaning |
|---|---|
b1-sign |
B1 = +1/2, the second convention's value. |
odd-terms |
Odd terms above B1 are not exactly zero. |
ada-indexing |
Only the non-zero terms are numbered, as in Note G. |
off-by-one |
Every value shifted one index. |
not-fraction |
Returns a type other than fractions.Fraction, Python's exact fraction. |
A few notes on each.
b1-sign can follow directly from the missing convention clause. If it does,
the routine is not broken — it is correct under a different, equally published
convention, and it disagrees with this course at exactly one index and nowhere
else. A sign error at B1 alone would print the same values, so what settles it
is the specification, the documentation or the code (Unit 6).
odd-terms matters more than it looks. B3 is not approximately zero; it is
zero. A routine that skips the odd indices and closes up the numbering, or returns
a tiny non-zero decimal for them, has failed a property that holds exactly.
ada-indexing is invited by a prompt that mentions Ada Lovelace or Note G,
because text about Note G uses her numbering. A routine
produced this way is a faithful reading of the historical source and a broken
modern component at the same time.
off-by-one is easy to read past. Every value returned is a genuine
Bernoulli number, computed correctly and represented exactly. Each is filed under
the wrong index. The shift can sit in plain sight -- a n + 1 where n belongs --
and still look like nothing to catch, because the error only exists relative to a
specification.
not-fraction is a real possibility whenever numerical Python is asked for.
In Python, dividing one whole number by another already gives a float, so exact
fractions have to be asked for.
The type is wrong from B0 on. The contract asks for a fractions.Fraction,
and a float is not one, whatever the digits look like. At B0 the value 1.0
is still exact: the fault there is the type, not the value.
The later values are also inexact, because binary floating point, the way
computers usually store decimals, cannot store most of the later Bernoulli
fractions exactly. They still look right: -0.0333… really is close to
-1/30. A test that checked B0 to B12 and accepted any value within a
billionth of the right one (in Python, abs(x - y) < 1e-9) would pass such a
routine. How close counts as equal, the tolerance, is a decision you make for
the task, not a default.
What these five have in common is the important part: none of them makes the
code look suspicious. A careful reader with the specification in hand can spot
some of them — a missing Fraction, a special case at B1, a loop that steps
over the odd indices, but casual reading misses them, and reading alone cannot
establish that a routine meets a specification. Testing locates them; reading
tells you what to test for. That asymmetry is the argument for the verification
lab in Unit 8.
When you name what to test, aim to break the routine rather than to confirm it:
a test that finds an error is the successful one [E10]. Property-based testing
puts this into practice. It states a property that must hold for every input,
such as "every odd index above 1 gives exactly zero" or "every value returned is
a Fraction", and checks it on many inputs chosen for it rather than on the
few you thought of [E11].
The checker recognises three further conditions: raises, for code that fails
at some index in the range, and import-error and no-function, for code that
does not run at all. Unit 8 adds a few for when no comparison happened. Those
announce themselves, so this unit does not dwell on them.
5. The sixth failure mode, which no test catches
Generated code can arrive with explanation attached. Comments, a docstring, a paragraph of context. Something along these lines:
# Ada Lovelace used this same recurrence in Note G (1843).
def bernoulli(n):
...
Suppose you check the arithmetic and it is correct. What does that tell you about the comment?
Nothing at all.
The code and the comment were produced by the same process, and either can be wrong while the other is right. The code got checked because code is checkable — you can run it against known values. The historical claim sat directly beside it, phrased with the same confidence, dated with the same specificity, and was checked by nobody.
This is what makes generated output awkward to evaluate: it is a mixture of things with completely different failure modes. Arithmetic you can test. Assertions about the world you can only look up. Both parts can be equally polished, so surface quality alone does not tell you which claim is reliable.
The same holds for anything else that arrives with the code. Some tools write tests for the code they generate, run them, and report that they pass. Those tests are the tool's own claims about what the code should do, produced by the same process, and "all tests pass" is one more claim: check them as you would any other output, starting with what they test. A displayed step-by-step explanation is in the same position; one 2023 study showed that such an explanation need not reflect what drove the answer [L9, sec. 3.2].
The course is not claiming that the example comment above is false. The point is sharper than that: you do not know, and the correctness of the code adjacent to it is not evidence either way. Unit 16 deals with what is actually established about Note G, and Historical Notes is careful about which parts are settled and which are contested. Bring that same care to any historical claim that arrives inside generated code.
This is checkpoint cp07-trust-triage.
6. A worked example: a claim that does not survive checking
The same triage applies to claims that arrive with no code attached at all. Here is one phrased with total confidence:
Gödel's theorem proves that an AI cannot verify its own output.
You do not need formal logic to triage this sentence. It names a theorem about one kind of system, then applies it to the broad category "an AI" without showing that the theorem's conditions or conclusion transfer. Mark the theorem statement for a source check and the transfer for a separate argument. Unit 18 defines the relevant formal terms, states Gödel's and Tarski's results within their actual scope, and explains why neither directly settles what a language model can verify.
7. What to do with the output
Save it. Exactly as generated, without tidying it up. Save the prompt too, word for word, the date you ran it, and which tools were on: web search, code execution, memory, a reasoning setting. Some may be on without your choosing; one provider's documentation, as of November 2026, says its assistant may search the web without being asked and that memory can be on by default [D2, "What is Claude's memory?"], [D4, opening note]. The untidied version is the evidence; a cleaned-up version is a summary of the evidence, which is not the same thing.
You will need it twice more:
- Unit 8 runs it through the checker and names what is wrong with it.
- Unit 17, on the routes that include it, uses it in your evidence pack, alongside your verification result and your correctness defence.
Do not run it yet. Two reasons. The first is pedagogical: your predictions are far more informative if they are written down before the checker gives you the answer. The second is practical, and it holds outside this course too.
Safety. Generated code is code from a source you cannot vouch for. Read it before you run it, and run it in a disposable local environment. The checker in Unit 8 executes the file you give it — in a separate process with limits, which contains accidents rather than making unread code safe. That is a real consideration and not a formality.
8. If you do not have access to an AI system
Use the sample implementations in The verification lab and self-check:
wrong_b1_sign.pyada_indexing.pyfloat_output.pyoff_by_one_range.pywrong_b4_sign.pycorrect_example.py
These are real implementations, written for the lab to exhibit the failure modes
above, plus one with a single wrong value that no named mode describes; none is an
observed model output. The activity works the
same way with them, with prediction in place of spotting. This is an equal route, not a substitute: in one respect
the supplied examples are the better teaching set, because the fault in each
file is known in advance and one of the six files is correct, so the folder lets
you compare a failure with a correct routine. No file in it raises an error,
fails on import or lacks a bernoulli function.
The same applies if you have access but would rather not use it, or if what you generate turns out to be flawless. A correct generated routine is a perfectly good result; take one of the examples as a second specimen and triage that too.
9. Privacy note
Do not paste confidential, personal or assessment-restricted material, or other people's unpublished work, into an AI system. Nothing in this unit requires it: the prompt is one sentence about a published mathematical sequence. Unit 13 covers what leaves your device and why it matters. Sustainability is not taught in this course: the resource section in Unit 4, which shows that, other things equal, more computation uses more resources, is as far as it goes; Unit 17 points to general reading on it.
Check yourself
This unit has one checkpoint:
cp07-trust-triage— what you can trust before testing
python3 selfcheck.py run cp07-trust-triage # or in the browser
Both routes ask the same question and give the same feedback. It is about the comment, not the code, which tends to be the surprising part.
Timings: video 9 min, reading 12 min, activity 12 min.
Check yourself
This unit has one checkpoint, answered here. A wrong answer says which misunderstanding it matches. Nothing is uploaded.
Local progress is available in a supported browser.
Prefer a terminal?
The same questions, from The verification lab and self-check:
python3 selfcheck.py run --unit 7