Lesson 2: Write the task contract, let Goal Mode hold the plan
Objective
You can read TASK.md as a set of testable statements, trace each
statement to a test in tests/test_report_tool.py, and watch a goal
decompose into tasks before any file is touched.
Why this lesson exists
Vague requests produce vague code. “Handle bad rows better” gives an agent
permission to guess; “invalid rows are collected in errors with index
and reason, valid rows still produce a report” gives it a target and
gives you a way to check. In ZCode the decomposition is a first-class
surface: Goal Mode turns your objective into a task list and manages
recovery when a step stalls. The contract you write is what it decomposes
— a precise contract becomes a precise task list.
The lesson
Open TASK.md. Notice what every line has in common: it names an
observable behavior, not an implementation. Four statements from the
contract, and the tests that pin them:
| Contract line | Test |
|---|
| “a JSON file loads into the same record list as CSV” | test_load_json_records_returns_list_of_dicts |
“invalid rows land in errors with index and reason; valid rows still aggregate” | test_invalid_records_are_isolated_with_reasons |
| “group totals are rounded to two decimals” | test_group_totals_are_rounded_to_two_decimals |
| “the report write is atomic and creates missing parents” | test_write_report_creates_missing_parent_directories |
Now set the goal. Give the agent an objective that is already decomposed
by the contract:
“Goal: make starter/report_tool.py satisfy TASK.md. Work one failing
test group at a time — JSON loading, then validation isolation, then
rounding, then atomic writes, then the end-to-end tests — running
python verify.py starter after each task. Only starter/report_tool.py
may change; tests/, solution/, scenario/ are read-only; standard library
only.”
Read the task list Goal Mode produces before letting it execute. Each
task should name a contract line and a verification step — if a task says
“improve error handling,” tighten the goal; that is not a contract line.
The task list is the deliverable of this lesson: it is your contract,
executable.
Exercise
Write one contract line for a script you actually own, using the same
shape: inputs, outputs, error cases, and “done means <command> exits
0”. Then write the goal statement you would give ZCode for it — with the
same boundaries this lesson used.
Checkpoint
Run python verify.py — this checkpoint’s claim code prints
when you can answer:
- Which
TASK.md line does
test_invalid_records_are_isolated_with_reasons pin, in your own
words?
- What does Goal Mode do with your objective — and what does it do when
a step stalls?
- Why should the goal statement carry the boundaries, not just the task?
Expected evidence
Your drafted contract line, your goal statement, and the task list it
produced (or the version you tightened and why).