Running-example consistency: paths, tasks.json, command collisions (#7,#10,#11) (#57)

Co-authored-by: claude <claude@jpaul.io>
Co-committed-by: claude <claude@jpaul.io>
This commit was merged in pull request #57.
This commit is contained in:
2026-06-22 15:35:51 -04:00
committed by Claude (agent)
parent 848ad14e3c
commit 06b9f8f308
14 changed files with 192 additions and 136 deletions
@@ -175,9 +175,9 @@ decide:
```python
<<<<<<< HEAD
print("usage: python cli.py [add <title> | list | done <index> | count]")
print("usage: python cli.py [add <title> | list | done <index> | stats]")
=======
print("usage: python cli.py [add <title> | list | done <index> | clear]")
print("usage: python cli.py [add <title> | list | done <index> | purge]")
>>>>>>> experiment
```
@@ -190,7 +190,7 @@ Read it like this:
the file so it contains the version you want and deleting all three marker lines.**
You're not picking a side mechanically — you're deciding what the line *should* say. Often that's one
side, sometimes it's a blend of both (here: a usage string that lists *both* `count` and `clear`).
side, sometimes it's a blend of both (here: a usage string that lists *both* `stats` and `purge`).
Then you tell Git the conflict is settled:
```bash
@@ -324,44 +324,52 @@ attempts become free to reject.
Now the skill everyone fears and nobody should. You'll engineer a guaranteed conflict by having
**two branches change the same line in different ways**, then resolve it.
1. Make sure you're on a clean `main`. Create the first branch and have the AI add a `count` command:
> **Starting state.** By now your `tasks-app` has accumulated commands from earlier modules, so your
> `usage:` line is longer than the bare `[add <title> | list | done <index>]` you started with — and
> that's fine. This lab works *regardless* of what's on that line, because the collision is just "two
> branches each appended a different new command to the same usage line." To make it reproduce even on
> a carried-forward app, we deliberately add two commands you **haven't** built yet — `stats` and
> `purge`. (Any two brand-new commands would do; the point is the same line, edited two ways.) The
> marker examples below show the shape; your real markers will carry your fuller usage string.
1. Make sure you're on a clean `main`. Create the first branch and have the AI add a `stats` command:
```bash
git switch main
git switch -c feature/count
git switch -c feature/stats
```
Ask the AI: *"Add a `count` command to `cli.py` that prints how many tasks are pending, and update
the usage string to include it."* Then:
Ask the AI: *"Add a `stats` command to `cli.py` that prints how many tasks are total, done, and
pending, and update the usage string to include it."* Then:
```bash
git diff # confirm it edited the usage line + added the command
git add . && git commit -m "Add count command"
git add . && git commit -m "Add stats command"
```
2. Switch back to `main` and create a *different* branch that touches **the same usage line**:
```bash
git switch main
git switch -c feature/clear
git switch -c feature/purge
```
Ask the AI: *"Add a `clear` command to `cli.py` that deletes all tasks, and update the usage
string to include it."* Then:
Ask the AI: *"Add a `purge` command to `cli.py` that removes all completed (done) tasks, and update
the usage string to include it."* Then:
```bash
git diff # it also edited the usage line — this is the collision to come
git add . && git commit -m "Add clear command"
git add . && git commit -m "Add purge command"
```
Both branches changed the same `usage:` line, each adding a *different* command to it. Git will
not be able to auto-merge that line.
3. Merge them and watch it conflict. Merge `feature/count` into `feature/clear` (you're on
`feature/clear`):
3. Merge them and watch it conflict. Merge `feature/stats` into `feature/purge` (you're on
`feature/purge`):
```bash
git merge feature/count
git merge feature/stats
```
Git stops with a conflict and tells you which file is unmerged. Confirm:
@@ -370,28 +378,30 @@ Now the skill everyone fears and nobody should. You'll engineer a guaranteed con
git status # cli.py listed under "Unmerged paths"
```
4. Open `cli.py` and find the conflict markers around the usage line:
4. Open `cli.py` and find the conflict markers around the usage line (your usage string will be
longer — it carries the commands from earlier modules — but the collision is exactly this: both
branches appended a different new command to it):
```python
<<<<<<< HEAD
print("usage: python cli.py [add <title> | list | done <index> | clear]")
print("usage: python cli.py [add <title> | list | done <index> | purge]")
=======
print("usage: python cli.py [add <title> | list | done <index> | count]")
>>>>>>> feature/count
print("usage: python cli.py [add <title> | list | done <index> | stats]")
>>>>>>> feature/stats
```
(The command bodies for `count` and `clear` touch different lines, so Git merged *those* cleanly
(The command bodies for `stats` and `purge` touch different lines, so Git merged *those* cleanly
on its own — the only collision is the usage string both branches edited.)
5. **Resolve it with the AI.** With your editor-integrated agent, this is its sweet spot. Ask:
> *"`cli.py` has a merge conflict on the usage line. I want the final version to list BOTH the
> `count` and `clear` commands. Resolve the conflict and remove the markers."*
> `stats` and `purge` commands. Resolve the conflict and remove the markers."*
It should produce a single, marker-free line listing both commands, e.g.:
```python
print("usage: python cli.py [add <title> | list | done <index> | count | clear]")
print("usage: python cli.py [add <title> | list | done <index> | stats | purge]")
```
**Verify its work — this is the part the AI can get subtly wrong.** A conflict resolver can
@@ -401,8 +411,8 @@ Now the skill everyone fears and nobody should. You'll engineer a guaranteed con
```bash
git diff # check ONLY what you intended changed; no markers remain
python cli.py # run with no args — see the merged usage string
python cli.py count # both commands actually work
python cli.py clear
python cli.py stats # both commands actually work
python cli.py purge
```
6. Tell Git the conflict is settled and complete the merge:
@@ -419,10 +429,13 @@ Now the skill everyone fears and nobody should. You'll engineer a guaranteed con
> **Guaranteed-conflict generator.** AI edits are nondeterministic, so if the agent didn't touch the
> same line on both branches and you *didn't* get a conflict in step 3, run the helper script to
> manufacture one deterministically, then practice steps 46 on it:
> manufacture one deterministically, then practice steps 46 on it. Copy it into your `tasks-app`
> first (the course's lab scripts live in the course repo, not in `tasks-app` — see Module 4's
> *You'll need*), then run it from inside the repo:
>
> ```bash
> bash modules/06-branches-sandboxes-for-experiments/lab/make-conflict.sh
> cp /path/to/modules/06-branches-sandboxes-for-experiments/lab/make-conflict.sh .
> bash make-conflict.sh
> ```
>
> It creates two branches that both edit the same line of `README.md`, leaving you mid-conflict with