Skip to content

Supply relevant context

  • Lesson 5
  • 40 min
  • Module 2: Write actionable tasks

What you will be able to do

Give an assistant what a new colleague would need for this one task. That is the exact observation, the expected result, a small example, and the files and names that matter. Leave out everything else, and never include a secret.

Before you startWhat to know and to have readyAbout 40 minutes

What you need to know

What you need on your computer

  • The project ~/projects/ticket-cleaner-assist with the brief of the last lesson committed, and its environment active. python -m pytest prints 25 passed, and git status says working tree clean.
  • If the project is missing or broken, use the reset steps of Context and boundaries, then do Add the brief to your project again.

Your car makes a strange noise, so you phone the garage. “My car makes a noise. Can you fix it?” The mechanic can only ask questions back: what kind of noise, when, from where?

Compare: “A high squeak from the front left wheel when I brake. It started on Tuesday, and it stops after ten minutes of driving. I recorded it: here is a ten-second video.” Now the mechanic knows what to look at first, and how to check the repair.

You did not send the car’s full service history, your insurance papers or the key to your house. The mechanic does not need them for this noise, and some of them are private.

The problem: the assistant sees the wrong part

Section titled “The problem: the assistant sees the wrong part”

The course team gave the assistant Grace’s bug with very little: one file, ticket_cleaner/report.py, no repository map, and one sentence (transcript bug-little-context):

Prompt
The categories in the report are wrong. Fix it.

The assistant changed nothing. It answered with a question:

What the assistant printed (part)
Could you share a sample of the incorrect category counts and the expected result? Currently, the report counts categories only for tickets matching the
requested status, and treats category names with different capitalization or whitespace as distinct. Which behavior should change?

This time, the assistant asked instead of guessing. That is good, but do not count on it: another run, or another model, can guess. And look at what it could see. report.py counts the categories that it receives. The bug is not there. The cause is in parsing.py, which the assistant never saw. It even guessed wrong about spaces: the program already removes them, in a file that it could not read.

So the session cost 2,220 tokens and changed nothing. The request had no observation, no expected result and no example. The one file that it had was the place where the bug shows, not the place where it is.

The context of a request is everything that the model receives with it. That is your prompt, the files, the repository map, and the earlier turns of the conversation. The model works only from its context. It knows nothing else about your project.

Relevant context is the part that this task needs. For a bug or a change, it has five kinds of information:

  1. The observation: the command that you ran, and its exact output or error message, pasted, not retold.
  2. The expected result: what the output should be.
  3. A minimal example: the smallest input that still shows the problem.
  4. File references: where the code is, by path.
  5. Interfaces: the names and signatures that the change must keep, such as clean_category(value: object) -> str.

Leave out what the task does not need: other files, the whole data file, logs from last month. And never include a secret, such as the token in .env, or real customers’ personal data. More text is not better context. It costs tokens, it gives the model more places to look, and every pasted line leaves your computer.

Grace’s export has 12 rows. Which of them show the bug? Look only at one team, login. The export has four login tickets, written in four ways: login, Sign-in, Login and LOGIN. Sign-in is a web form name, so it already becomes login. That leaves capital letters as the only difference.

So two rows are enough: one login and one LOGIN, both open.

minimal.csv
id,status,category,priority,subject
T-1,open,login,1,One
T-2,open,LOGIN,1,Two

Expected: {"login": 2}, because both tickets belong to the login team. If the program gives {"LOGIN": 1, "login": 1}, the bug is there, in two rows that anyone can read in five seconds. A minimal example is this: the smallest input that still fails. Reproduce first shows how to make one step by step.

Grace sees the bug in the report. But where does a category get its text? The diagram follows one row through the program:

Five boxes from left to right. The data file: a row with the category LOGIN. files.py, read_rows: reads the row as text, LOGIN. parsing.py, clean_category, in red: login is not a web form name, so it returns the original text, LOGIN. report.py, count_by_category, in amber: counts the text as it is, LOGIN 1 and login 1. reports/summary.json, in amber: two lines for one team. Under parsing.py: the cause is here. Under the last two: you see the symptom here. A dashed box under report.py: the only file in the too-little-context session. A dashed box under files.py and parsing.py: the files in the relevant-context session, parsing.py, records.py and tests/test_parsing.py.
A bug shows in one place and lives in another. The too-little-context session saw only the place where the bug shows.
Text description of the diagram

The diagram follows one row with the category LOGIN through the program, in five steps. First, the data file has the row. Second, read_rows() in files.py reads the row as text: “LOGIN”. Third, clean_category() in parsing.py, in red, looks the name up among the web form’s names, in small letters. “login” is not a web form name, so the function returns the original text, “LOGIN”. The diagram marks this step: the cause is here. Fourth, count_by_category() in report.py counts the text as it is: {"LOGIN": 1, "login": 1}. Fifth, reports/summary.json shows two lines for one team. Steps four and five are marked: you see the symptom here. A dashed note under report.py says that it was the only file in the too-little-context session. A dashed note under the middle steps lists the files of the relevant-context session. They are parsing.py, records.py with the web form’s names, and tests/test_parsing.py.

You do not have to guess the files. Search the code for the word category:

Terminal window
grep -n category ticket_cleaner/*.py
Output (macOS)
ticket_cleaner/parsing.py:18:def clean_category(value: object) -> str:
ticket_cleaner/parsing.py:19: """Return the category, with the web form's names changed to the report's names."""
ticket_cleaner/parsing.py:48: category=clean_category(raw["category"]),
ticket_cleaner/records.py:5:REQUIRED_FIELDS = ("id", "status", "category", "priority")
ticket_cleaner/records.py:21: category: str
ticket_cleaner/report.py:9:def count_by_category(tickets: list[Ticket]) -> dict[str, int]:
ticket_cleaner/report.py:10: """Return the number of tickets in each category, sorted by category."""
ticket_cleaner/report.py:13: counts[ticket.category] = counts.get(ticket.category, 0) + 1
ticket_cleaner/report.py:31: "by_category": count_by_category(selected),

Three files mention categories. report.py only counts. records.py has the field, and also the web form’s names, CATEGORY_ALIASES, a few lines below line 5. parsing.py has the function that makes the text: clean_category(), called on line 48. That is where to look first, and the file references of the bug report.

Amira writes the five kinds of context into a short bug report. You make the minimal input, see the bug yourself, and add the report to the project.

  1. Run the program on Grace’s export, and open the report:

    Terminal window
    python -m ticket_cleaner data/web-form-export.csv
    Output
    12 rows: 12 valid, 0 rejected.
    Report: reports/summary.json

    In reports/summary.json, by_category has seven lines:

    reports/summary.json (part)
    "by_category": {
    "Billing": 1,
    "LOGIN": 1,
    "Login": 1,
    "account": 1,
    "billing": 2,
    "login": 2,
    "shipping": 2
    },
  2. In your editor, make a new file minimal.csv in the project folder, with the three lines of the tiny example above.

  3. Run the program on it. Write the report to a new file, so that the export’s report stays:

    Terminal window
    python -m ticket_cleaner minimal.csv --output reports/minimal.json
    Output
    2 rows: 2 valid, 0 rejected.
    Report: reports/minimal.json

    reports/minimal.json has "by_category": {"LOGIN": 1, "login": 1}, on four lines. Both rows are valid, so the program prints no warning: nothing tells Grace that something is wrong.

  4. Copy the bug report from the snapshot end-of-m02:

    Terminal window
    cp ../nextia-learning-labs/C15/snapshots/end-of-m02/docs/tasks/category-names-bug.md docs/tasks/
  5. Delete minimal.csv. The bug report has its three lines, so anyone can make it again. On Windows, use Remove-Item minimal.csv.

    Terminal window
    rm minimal.csv
  6. Check and commit:

    Terminal window
    ruff format --check .
    git add docs/tasks/category-names-bug.md
    git commit -m "Write Grace's bug report with a minimal input"
    Output
    19 files already formatted
    [feature/category-option de7db2e] Write Grace's bug report with a minimal input
    1 file changed, 48 insertions(+)
    create mode 100644 docs/tasks/category-names-bug.md

Here is the report. Find the five kinds of context in it:

docs/tasks/category-names-bug.md
# Bug: one team appears under several category names
Reported by: Grace (support lead), with this week's export from the new web
form (`data/web-form-export.csv`).
## Steps to reproduce
1. Make a file `minimal.csv` with two tickets of the same team:
```text
id,status,category,priority,subject
T-1,open,login,1,One
T-2,open,LOGIN,1,Two
```
2. Run `python -m ticket_cleaner minimal.csv --output reports/minimal.json`.
## Observed
`"by_category": {"LOGIN": 1, "login": 1}`: two lines for one team.
With Grace's export, the report has `Billing`, `LOGIN` and `Login` next to
`billing` and `login`.
## Expected
`"by_category": {"login": 2}`. Capital letters and spaces around a category do
not make a new category, as for the status and the ID. With Grace's export:
account 1, billing 3, login 4, shipping 2.
## Not affected
The web form's other names (`Sign-in`, `Invoice`, `Delivery`) are already
counted under the report's names.
## Environment
The same result in a new virtual environment made from
`requirements-lock.txt` (Python 3.14), and in Grace's own environment: not an
environment problem. The rows are valid, so no warning is printed.
## Evidence of done
- A regression test with the two rows above fails on the current code and
passes after the fix.
- Grace's export gives one line per team.
- All other tests and the sample file's report (`tests/test_baseline.py`) are
unchanged.

The observation and the expected result are exact. The example is two rows. “Not affected” and “Environment” save the reader two wrong paths. The report has no file references: Grace is not a developer. Amira adds them in the prompt, from the search above. The report also says nothing about how to fix the bug. That is the fixer’s job.

A second session got more (transcript bug-relevant-context). It had Grace’s email, the two rows with the observed and expected result, three files and the repository map. The prompt ended with the file references and a constraint:

Prompt (the end)
The categories are cleaned in ticket_cleaner/parsing.py (clean_category, to_ticket); the web form's names are in ticket_cleaner/records.py (CATEGORY_ALIASES). Fix the cause, add a regression test to tests/test_parsing.py, and change nothing else.

The assistant named the cause in its first sentence. Then it rewrote the three lines of clean_category() and added a test:

What the assistant printed (part)
`clean_category()` lowercases alias lookups but preserves case for other categories. Use `clean_text()` before resolving aliases so every category is
normalized.
Two columns. Left, too little context, session bug-little-context: prompt, the categories in the report are wrong, fix it; files, ticket_cleaner/report.py only; repository map off; example input none. What it did: no change; the assistant asked for a sample of the incorrect counts and the expected result; 2,220 tokens in, 1 model call. Right, relevant context, session bug-relevant-context: prompt, Grace's email with the exact output, a two-row input, observed and expected, and fix the cause, add a regression test, and change nothing else; files parsing.py, records.py and tests/test_parsing.py; repository map on; example input 2 rows giving LOGIN 1 and login 1. What it did: 2 files changed, plus 20 minus 3; 31 tests pass; all 5 bug checks pass; 4,570 tokens in, 1 model call.
The same bug and the same model, with two different contexts. The difference is what the assistant got, not how clever it was.
Text description of the diagram

The diagram compares two recorded sessions with the same model. The left column is the session with too little context. Its prompt was “The categories in the report are wrong. Fix it.” It had one file, ticket_cleaner/report.py, no repository map and no example input. It changed nothing: the assistant asked for a sample of the incorrect category counts and the expected result. It used 2,220 tokens in, in one model call. The right column is the session with relevant context. Its prompt had Grace’s email with the exact output, the two-row input, and the observed and the expected result. It ended with the request “Fix the cause, add a regression test, and change nothing else.” It had three files, parsing.py, records.py and tests/test_parsing.py, and the repository map. It changed 2 files, 20 lines added and 3 removed. The tests gave 31 passed, and all 5 bug checks passed. It used 4,570 tokens in, in one model call.

The session changed 2 files (+20 −3), and all 5 hidden checks of the bug passed. Of its 7 new test cases, 6 fail on the unfixed code. One, login → login, passes on both versions, so it catches nothing.

Do not apply this fix now. The session ran in a throwaway copy, and it is a good result. But nobody saw a test fail before the fix, so nobody showed that its test catches the bug. Your project keeps the bug until Module 4, where you fix it with that evidence. The next task is still Grace’s feature.

Context costs tokens. The session with little context used 2,220 tokens in and cost US$0.0049. The one with relevant context used 4,570 and cost US$0.0126. That is about twice the tokens and two and a half times the cost, and the cheaper session produced nothing. Prices change: check your provider’s current page. With a free tier or no assistant, you pay nothing.

The larger cost is your time: about ten minutes to make the minimal input and find the files. You spend that time anyway, when you check the fix.

Too much context also costs. Tomás likes to send the whole repository: “Then it has everything.” But “everything” has no observation and no expected result: they are not in any file. It has many files that the task does not need, which cost tokens and give the model more wrong places to change. And it may include what must never leave your computer. ASSISTANT-SCOPE.md already says so: .env is never read.

Use a quick test before you send: would a new colleague need this to do this task? If not, leave it out. For a question about one function, the function is enough context. For a bug, the five kinds above. For a feature, the task brief and the files that it names.

Common mistake

The example file goes into the commit

Symptom: after the bug report is written, git status --short shows a file that you did not mean to keep:

?? minimal.csv

A git add -A would put it in the commit, next to the real data in data/.

Cause: the minimal input is a working file, made in the project folder. Nothing in .gitignore excludes it, so Git offers it like any new file.

Fix: before each commit, read git status --short, and add files by name, as in step 6. Delete working files, or keep them outside the project. The bug report holds the example as text, so you lose nothing. ASSISTANT-SCOPE.md says the same for an assistant: it never adds a data file.

Grace’s team runs the pending report of the Python course’s sample file:

Terminal window
python -m ticket_cleaner data/tickets.csv --status pending --output reports/pending.json

Run it, and open reports/pending.json. Then answer: is this a new bug? Write the observation, the expected result, a minimal example and the file references that you would give an assistant. Do not commit anything.

Show the answer

The report has this:

"by_category": {
"LOGIN": 1,
"billing": 1
},

Ticket T-1010 has the category LOGIN in data/tickets.csv. In the Python course, clean_text() cleaned every category, so the same report had "login": 1. It is not a new bug: it is Grace’s bug, with another file.

  • Observation: the command above, and "by_category": {"LOGIN": 1, "billing": 1}.
  • Expected: {"billing": 1, "login": 1}.
  • Minimal example: the two rows of minimal.csv already show it. You do not need a second example for the same cause.
  • File references: ticket_cleaner/parsing.py (clean_category, to_ticket) and ticket_cleaner/records.py (CATEGORY_ALIASES).

Add it to the bug report as one more observation, not as a new bug. Two reports of one cause make two fixes, and the second fix can break the first. The relevant-context prompt of the session above included this line.

Check your understanding

Name the five kinds of relevant context for a bug, with Grace's bug as the example for each. Then name two things that you leave out.

Show the answer
  • Observation: python -m ticket_cleaner minimal.csv --output reports/minimal.json gives "by_category": {"LOGIN": 1, "login": 1}.
  • Expected result: {"login": 2}.
  • Minimal example: the two rows T-1,open,login,1,One and T-2,open,LOGIN,1,Two.
  • File references: ticket_cleaner/parsing.py and ticket_cleaner/records.py.
  • Interfaces: clean_category(value: object) -> str, called by to_ticket().

Leave out files that the task does not need, such as remote.py, and the whole data folder. Never include .env or its token, or real customers’ data.

Check your understanding

In the session bug-little-context, the assistant had report.py. Why could it not find the bug, even with a better prompt?

Show the answer

The bug shows in the report, but it is not in report.py. count_by_category() counts the text that it receives. The text gets its capital letters earlier, in clean_category() in parsing.py. The assistant never saw that file, and no repository map pointed to it. A better prompt with the observation and the expected result would help it ask the right question. To find the cause, it needs the file where the cause is. That is why you search the code, for example with grep -n category, before you choose the files.

Check your understanding

Tomás says: 'Give it the whole repository and the full export every time. More context is always better.' Give three reasons why not.

Show the answer
  • The most important context is not in any file: the observed output, the expected result and the minimal example. A whole repository does not contain them.
  • More text costs more tokens and gives the model more places to look, and more files that it may change. The relevant context of Grace’s bug was 3 files and two rows.
  • Everything that you send leaves your computer. A whole folder can include .env, a token or real customers’ data. The scope file says that the assistant never reads .env.

Recap

  • The context of a request is everything that the model receives with it. It knows nothing else about your project.
  • With one file, no map and “Fix it.”, the assistant changed nothing and asked for an example. The file that it had was where the bug shows, not where it is.
  • Relevant context for a bug: the exact observation, the expected result, a minimal example, file references and interfaces. With them, the same model fixed the bug in clean_category(), and all 5 checks passed.
  • Leave out what the task does not need, and never send a secret. Search the code to find the files; do not send everything.
  • Your project has the bug report docs/tasks/category-names-bug.md, committed. The bug stays until Module 4.

Next, Amira starts the feature. The code is new to her, so she asks for an investigation and a plan before any change.

Next: Break work into steps