Hands-on Python with Claude Code · Challenge 02 · 中文版

Lesson 2: Write the task contract before the change

Checkpoint l0210 ptsself-reported — code from verify.pyClaude Code 2.x

Turn "make it better" into a bounded, testable contract — the single highest-leverage skill for working with coding agents.

Doing this with your agent? One sentence starts the whole course:

Read https://flypython.com/skills/flypython/SKILL.md and start the FlyPython course `hands-on-python-with-claude-code`.

Lesson 2: Write the task contract before the change

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 write one contract line for your own project using the repository’s task-contract template.

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. The contract is where you decide what “done” means — before the agent burns your trust with a plausible-looking rewrite.

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 statementPinned by
JSON data files load as lists of objectstest_load_json_records_returns_list_of_dicts
Unsupported extensions raise ValueErrortest_unsupported_suffix_raises_value_error
Invalid rows are isolated with {"index", "reason"}; valid rows still aggregatetest_invalid_records_are_isolated_with_reasons
Group totals are rounded to two decimalstest_group_totals_are_rounded_to_two_decimals

Also notice the boundary clauses — the lines that say what the change may NOT do: no new dependencies, change only starter/report_tool.py, standard library only. Boundary clauses are what keep an agent’s “helpful” rewrite from swallowing your whole file.

The full template lives in the companion repository (templates/TASK_CONTRACT.md). Its fields: user outcome, current behavior, expected behavior, inputs and outputs, allowed files, out of scope, failure and recovery, acceptance commands, and authority (network/commit/push). Every field you leave blank is a decision you delegated to the machine.

Exercise

Write the next contract yourself, small and real:

  1. Pick one script you actually own (a report, a scraper, a sync job).
  2. Write three contract statements for it in the table form above — behavior, not implementation.
  3. For each statement, write the name of the test that would pin it.
  4. Add one boundary clause (a file the agent must not touch, or a dependency it must not add).

Ask the agent to critique your contract against TASK.md — it should find ambiguities, not add features.

Checkpoint

Show your four lines to the agent and ask: “Which of these could you satisfy by cheating — passing the test without the behavior?” If neither of you can find a cheat path, your contract is concrete enough. Fix any line that fails this test.

Expected evidence

Your contract (4 lines) and the cheat-review result. In Lesson 3 the agent will code against the course’s TASK.md only — yours ships in Lesson 5.

Hints

Stuck? Open one at a time.

Hint 1 — What this checkpoint tests

That you can read TASK.md as testable statements, not prose. Every sentence that starts with a function name is a contract line the suite can assert.

Hint 2 — Trace one line to one test

Pick a contract line — say total = valid + invalid must hold — and find the test that asserts it in tests/test_report_tool.py. Then write one contract line of your own for a script you own: inputs, outputs, error cases, and 'done means <command> exits 0'.

Hint 3 — The testability check

If you cannot tell whether a statement is testable, ask: could a suite assert it without reading your mind? Numbers, exit codes, files on disk — never vibes.

Submit

Done? Record it.

The 8-character code verify.py progress printed for this checkpoint — from the browser, or straight from your agent.

Youbrowser

Submit the claim code

Your agentauto-submit

Let the agent solve and submit

Hand it this checkpoint (copy button on hover) — it solves, verifies, and submits on its own:

Work on the FlyPython challenge "Hands-on Python with Claude Code" (course id course-claude-code), checkpoint l02.
Machine-readable brief: https://flypython.com/api/challenges/hands-on-python-with-claude-code
Open the course folder and read TASK.md first — it is the contract.
Rules: smallest change, no new dependencies, never edit tests/ or solution/.
Check with python verify.py until its gates pass, then report each claim code to me.
Target: solve only checkpoint l02, and submit it as soon as it passes.

With a token from your agent page (env FLYPYTHON_TOKEN), it records the result directly:

curl -X POST https://flypython.com/api/claims \
  -H "Authorization: Bearer $FLYPYTHON_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"claims":[{"course":"hands-on-python-with-claude-code","checkpoint":"l02","code":"<8-char code>"}]}'

Or install the full FlyPython agent skill once and skip the paste.

Official demo · Pro

Watch how a human runs this challenge

An official walk-through of this exact checkpoint — the task-contract handoff, the moment the agent is stopped, the uncut failure correction, the verify.py gates. Included in Pro; there is no free preview, and the challenge itself stays free.

Files

The starter and verifier

Solving runs on your machine — your agent fetches the course files itself via /api/challenges/hands-on-python-with-claude-code/files; you download nothing by hand. Prefer reading the source? Browse the folder on GitHub ↗