Week 5: Agent-ready codebases
Learning objectives
By the end of this week, you can:
- locate a change point from a repository map and name the callers, rules and checks that constrain it (LO4);
- ask an agent for a bounded proposal, then verify the proposal with independent tests, a diff and a local check (LO4, LO5);
- score Structure, Documentation, Tests and Checks from observable anchors, name a disproving observation, and explain what evidence would change the score (LO4, LO5);
- keep repository text and generated commands inside the approved safety boundary (LO7).
A repository is agent-ready when a fresh session can find the relevant code, learn the local contract, run a short check and report what it did not check. Readiness is a property of evidence at a named revision, not a feeling about how tidy the tree looks.
Minimal example
One task, two repositories
The task is deliberately small: replace a chain of status conditionals with a lookup while preserving whitespace, case and the unknown fallback. The public fixture contains the same function in three states:
before.pyis the disordered starting point: the caller and contract are not written beside the function;rejected.pyis a tempting proposal that removesstrip();refactored.pyis a structure change that keeps the contract.
The request is generated as text and inspected before it is copied into a candidate. The request is never executed as code. Verify the candidates from the root of your course checkout; the verifier reads the variant files that sit beside it, so it gives the same result from any directory:
python lectures/week-05/fixture/verify.py rejected
python lectures/week-05/fixture/verify.py refactored
Each command prints one line of JSON. The first exits with status 1 and reports the three padded inputs that fail:
{"cases": 10, "failures": [{"actual": "unknown", "expected": "passed", "input": " ok "}, {"actual": "unknown", "expected": "failed", "input": "\tfail\n"}, {"actual": "unknown", "expected": "passed", "input": " PASS "}], "if_statement_count": 0, "passed": 7, "scope": "course synthetic fixture; public feedback, not a grade", "variant": "rejected"}
The second exits with status 0:
{"cases": 10, "failures": [], "if_statement_count": 0, "passed": 10, "scope": "course synthetic fixture; public feedback, not a grade", "variant": "refactored"}
The result establishes those ten cases only. It does not prove behavior for every string or prove that a caller accepts the change.
Now run the same fixed cases against the starting point:
python lectures/week-05/fixture/verify.py before
{"cases": 10, "failures": [], "if_statement_count": 3, "passed": 10, "scope": "course synthetic fixture; public feedback, not a grade", "variant": "before"}
before and refactored both pass all ten cases; only if_statement_count differs (3 and 0). The cases cannot tell the two states apart, which is the point: behaviour is preserved, and what changed is how much a fresh session has to guess. In before.py a session must infer the contract from a chain of conditionals. In refactored.py the lookup table and the fallback are visible beside the change point. In a real project, a prepared repository would also name its entry point, contract and offline check in its context files; the agent still needs permission to read and edit, but the repository has removed avoidable guesses.
What the comparison can and cannot show
The fixture is one function, so it cannot show every kind of blocker. The rows below are illustrative: they are the kinds of observation you will record in the studio on a whole repository, not results of the commands above.
| Observation | Supported claim | Missing evidence |
|---|---|---|
The session found status_label in two file opens |
The map points to this change point for this revision | Other behaviours may have different maps |
| The documented check exits zero on the refactored copy | These cases pass at this revision | Callers, permissions and unlisted inputs |
| The disordered copy has three test commands, two of which fail | Documentation is a blocker for a fresh session | Whether the implementation itself is correct |
| A hook rejects an unused import with exit 2 | The hook can stop that class of change | Other checks and bypass paths |
An agent may propose the score, but you choose it. For each dimension record the path or command, revision, observed result, the highest level whose anchors are all present, and one observation that would disprove the score.
Four observable readiness dimensions
Use levels 1–4. A level includes every lower-level anchor.
Structure
- 1: no map from a behaviour to its change point;
- 2: a map exists, but a checked entry is wrong or mixes unrelated responsibilities;
- 3: checked entries are accurate, the change point has one responsibility, and the probe reaches it in three file opens or fewer;
- 4: a deliberate boundary violation fails a test or check.
Evidence is a behaviour, the files opened in order, a path:line change point and, at level 4, the failing result.
Documentation
- 1: no context file or no runnable command;
- 2: commands exist but one fails as written, or no invariant names the check that protects it;
- 3: every listed command runs at the scored revision and at least three invariants name their checks;
- 4: an automated check runs the documented commands and fails when one goes stale.
Evidence is the context-file path, each command and exit code, and the invariant-to-check list.
Tests
- 1: no runnable test exercises the change point;
- 2: one run passes but a hidden input, nondeterminism or a deliberate break goes undetected;
- 3: two repeatable runs agree, stay within the chosen budget, use no hidden input, and a deliberate break fails;
- 4: failure messages identify the broken behaviour and mutation evidence accounts for surviving gaps.
Evidence is the two summaries, the hidden-input search, and the deliberate-break result.
Checks
- 1: no automatic gate;
- 2: a gate can be run by hand but is not required, or it ignores an unused import;
- 3: one offline command runs the required gates and exits non-zero for an unused import;
- 4: the gate runs before a commit is offered and a secret canary is stopped by the project scanner.
Evidence is the gate command, failing and passing output, and the point where the gate is required.
Hands-on exercise
Use the studio activity on your own project or contribution target repository. First freeze a baseline at a named commit. Give the agent only the files needed to answer one bounded question; inspect its proposal as untrusted text. Then run the repository's documented check and inspect the diff. If a command needs a credential, network access or an unknown install, stop and revise the boundary rather than running it.
Your first score is a four-row table with one evidence link and one disproving observation per row. Remove one blocker that is within your scope—for example, reconcile two test commands, add a map from a behaviour to its module, or make a check command deterministic. Run the same probe at the new commit and score again. A tidy directory without a changed observation does not raise a score.
Time-box the work: 15 minutes to choose the task and baseline, 25 minutes to score, 25 minutes to remove one blocker, 15 minutes to rerun the probes, and 10 minutes to write the decision. Ask for help at the first failed command; reserve the final ten minutes for revision.
Supported execution
Run the fixture commands on this page directly. Before running a project's own check, follow Tools and model access.
Verification
Run the public fixture before and after reading the candidate:
python lectures/week-05/fixture/verify.py rejected # expected: exit 1, 7 of 10 passed
python lectures/week-05/fixture/verify.py refactored # expected: exit 0, 10 of 10 passed
For your repository, run the exact command it documents, record its exit code and inspect the changed-file list:
git status --short
git diff --check
git diff --name-only
A passing check is evidence for the inputs it covered. A score changes only when the observed anchor changes at a named revision. If the same command passes because its tests were deleted, its scope was weakened, or the agent supplied a result without a command, keep the old score and record the finding.
Common mistakes
| Mistake | How to detect it | Correction |
|---|---|---|
| Scoring from a polished README | A listed command fails or names a missing file | Run each command at the scored revision and lower the row until it passes |
| Treating an agent's score as evidence | No path, revision or output is attached | Ask for one observable anchor and one disproof before recording a number |
| Refactoring only for shorter code | The candidate passes happy paths but loses normalization or a caller contract | Add the distinguishing case, restore the invariant, and rerun the unchanged check |
| Calling contradictory docs a test failure | The same command is written three ways | Choose one bounded source of truth and verify the chosen command, leaving the conflict recorded |
| Running a generated command blindly | It asks for a key, network or an unpinned install | Stop, inspect the trust boundary, and run it only in a dedicated directory or container that holds no credentials; otherwise record the missing prerequisite |
| Raising a score after deleting tests | The test count or covered paths shrink | Compare the old and new test lists and keep the score unchanged |
End the work record with one decision: accept, narrow, recheck or stop. Name the evidence that supports it and the observation that would change it.