Preview 0.30

F04 — Fix with evidence

Know before you begin

Complete F02 first, then start from a clean main branch in the same Academy clone. Keep two surfaces open at the clone root: a native terminal for Academy and shell commands, and your Claude Code, Codex, or Pi harness for messages to your agent and CodeArbiter commands.

This page names the surface for every action. Put a native-terminal command directly in PowerShell or your shell; it never starts with !. Put a learner prompt or CodeArbiter command in the selected harness; neither starts with !. The ! prefix is only for a shell command deliberately sent through a harness, and this lesson does not use that route. Do not use git commit yourself: the agent runs the governed commit gate after you inspect and approve each boundary.

What you will prove

You will turn a real claimant-label defect into durable evidence. A regression is a test that demonstrates a defect before it is repaired. Red means that new test fails for the intended reason; green means the same test passes after the repair. A control character is a non-printing character such as newline, tab, or DEL. This lesson rejects control characters in a claimant label while preserving an ordinary label such as Sam Allen.

The proof has two commits after Prepare: first a test-only red regression in tests/test_service.py, then a service-only repair in workshop_queue/service.py. A commit boundary is the exact path set in one commit. The production boundary is the real claim_ticket function that receives the label, not a helper, transcript, CLI, or JSON copy.

Prepare safely

01Establish the baseline

Prepare a numbered fix attempt

From a clean main branch at your Academy clone root, run Prepare in a native terminal. The printed attempt number is evidence metadata, not text to type.

Why

Prepare gives the intentionally defective service a separate, reviewable history.

You · Native terminal · Windows

$academy = "$env:LOCALAPPDATA\ArbiterAcademy\preview-0.30\Scripts\arbiter-academy.exe"
& $academy --repository (Get-Location).Path prepare F04-fix-with-evidence

You · Native terminal · macOS

academy="${XDG_DATA_HOME:-$HOME/.local/share}/arbiter-academy/preview-0.30/bin/arbiter-academy"
"$academy" --repository "$PWD" prepare F04-fix-with-evidence

You · Native terminal · Linux

academy="${XDG_DATA_HOME:-$HOME/.local/share}/arbiter-academy/preview-0.30/bin/arbiter-academy"
"$academy" --repository "$PWD" prepare F04-fix-with-evidence

Expected result

Academy switches this clone to academy/F04-fix-with-evidence/ATTEMPT_NUMBER.

If that does not happen

If Prepare stops, preserve its message and resolve only the named clean-worktree, branch, or prerequisite condition. Do not force-reset main or delete an earlier attempt.

Evidence

The numbered branch preserves the defective starting point.

The printed attempt number is evidence metadata. Academy uses it in the branch name; do not type the literal word ATTEMPT_NUMBER. The attempt starts from a deterministic defective service and keeps main untouched.

Read the defect and its boundary

Read the prepared service and test file before requesting a change. Identify claim_ticket as the live boundary and confirm that the regression name is not already present.

Why

The lesson repairs one claimant-label rule, not the CLI, JSON storage, or a fictional copy of the service.

You · Native terminal · Windows

Get-Content -LiteralPath 'workshop_queue/service.py'; Get-Content -LiteralPath 'tests/test_service.py'

You · Native terminal · macOS

sed -n '1,240p' workshop_queue/service.py; sed -n '1,180p' tests/test_service.py

You · Native terminal · Linux

sed -n '1,240p' workshop_queue/service.py; sed -n '1,180p' tests/test_service.py

Expected result

claim_ticket accepts a volunteer label without rejecting newline, tab, or DEL characters, and tests/test_service.py has no claimant-label control-character regression.

If that does not happen

If either file differs from that prepared state, stop. Preserve the branch and use Reset for a new F04 attempt rather than adapting another lesson's state.

Evidence

You identified the real production boundary and the missing executable regression.

Confirm the prepared baseline is clean

Run the service suite in a native terminal before adding the regression. The existing suite must be green and Git must print no paths.

Why

A green prepared baseline lets the later red result identify the new regression instead of a pre-existing failure.

You · Native terminal · Windows

git status --short; python -m unittest tests.test_service -v

You · Native terminal · macOS

git status --short && python3 -m unittest tests.test_service -v

You · Native terminal · Linux

git status --short && python3 -m unittest tests.test_service -v

Expected result

Git prints nothing and the existing service tests pass.

If that does not happen

If Git prints a path or a baseline test fails, preserve the output. Do not add a regression until the prepared attempt is understood; use Reset if the attempt is not clean.

Evidence

The red test will be attributable to the regression you request next.

Practice

The proof map

MomentDurable evidence
PrepareA clean, deliberately defective baseline on a numbered attempt branch.
Prove redOne test-only commit that reaches claim_ticket and fails for the intended control characters.
Repair greenOne service-only commit that makes the unchanged regression pass.
CheckAn external reconstruction of the two snapshots, path boundaries, and clean worktree.

Establish the red proof

Open the governed fix lane before requesting any change. The copied command below belongs in your selected harness, not in a terminal.

02Prove the defect is real

Open the governed fix lane

In the selected CodeArbiter harness, paste the copied fix command into the harness prompt and send it. It is not a shell command and never begins with !. The agent opens the governed fix lane before changing production code.

Why

The fix lane records the defect boundary and keeps the upcoming work under the repository's rules.

Your agent · Claude Code harness · All operating systems

/ca:fix "Reject control characters in a claimant label"

Your agent · Codex harness · All operating systems

$ca-fix "Reject control characters in a claimant label"

Your agent · Pi harness · All operating systems

/ca-fix "Reject control characters in a claimant label"

Your agent · Pi harness · All operating systems

/skill:ca-fix "Reject control characters in a claimant label"

Expected result

The agent identifies the claimant-label defect and waits for a regression-first change.

If that does not happen

If the command blocks, preserve its finding. Do not bypass the lane or edit workshop_queue/service.py from a terminal.

Evidence

The governed path names the production boundary before it changes.

Ask your agent for one direct executable regression and nothing in production. The request already states the three rejected labels, the expected ValueError, and the ordinary-name control. Send it unchanged first; it is specific enough to review.

Request the test-only regression

Paste this request into the selected harness and send it. It is an instruction to your agent, not a terminal command, so it never begins with !.

Why

The first commit must prove the defect exists before any repair can make it pass.

You · Claude Code harness · All operating systems

Add exactly one direct unittest named test_claim_rejects_control_characters_in_volunteer_label in tests/test_service.py. Loop over Sam\nAdmin, Sam\tAdmin, and Sam\x7fAdmin; for each, use assertRaisesRegex(ValueError, a message containing control characters) around the real claim_ticket call. Then assign the real claim_ticket result for Sam Allen to a variable and assert its claimed_by is Sam Allen. Do not edit workshop_queue/service.py. Run only that test and stop after its semantic assertion failure.

You · Codex harness · All operating systems

Add exactly one direct unittest named test_claim_rejects_control_characters_in_volunteer_label in tests/test_service.py. Loop over Sam\nAdmin, Sam\tAdmin, and Sam\x7fAdmin; for each, use assertRaisesRegex(ValueError, a message containing control characters) around the real claim_ticket call. Then assign the real claim_ticket result for Sam Allen to a variable and assert its claimed_by is Sam Allen. Do not edit workshop_queue/service.py. Run only that test and stop after its semantic assertion failure.

You · Pi harness · All operating systems

Add exactly one direct unittest named test_claim_rejects_control_characters_in_volunteer_label in tests/test_service.py. Loop over Sam\nAdmin, Sam\tAdmin, and Sam\x7fAdmin; for each, use assertRaisesRegex(ValueError, a message containing control characters) around the real claim_ticket call. Then assign the real claim_ticket result for Sam Allen to a variable and assert its claimed_by is Sam Allen. Do not edit workshop_queue/service.py. Run only that test and stop after its semantic assertion failure.

Expected result

Only tests/test_service.py changes, and the focused regression fails because claim_ticket does not raise ValueError.

If that does not happen

If the result is an import, syntax, or unrelated failure, reject it as evidence and ask the agent to correct only the regression. If production code changes, do not stage it.

Evidence

The same named test is executable proof of the original defect.

Observe the semantic red failure

Run the focused regression yourself in a native terminal. This command is expected to fail at this point; read the assertion before continuing.

Why

A test that passes before the repair cannot prove the repair fixed the intended defect.

You · Native terminal · Windows

python -m unittest tests.test_service.TicketTransitionTests.test_claim_rejects_control_characters_in_volunteer_label -v

You · Native terminal · macOS

python3 -m unittest tests.test_service.TicketTransitionTests.test_claim_rejects_control_characters_in_volunteer_label -v

You · Native terminal · Linux

python3 -m unittest tests.test_service.TicketTransitionTests.test_claim_rejects_control_characters_in_volunteer_label -v

Expected result

The test fails because ValueError was not raised for a claimant label containing a control character.

If that does not happen

If the test passes, errors before reaching claim_ticket, or names a different failure, stop. Return to the regression request and preserve the current attempt.

Evidence

You personally observed the red assertion against the prepared production code.

Read the diff before staging. A test that is red because it cannot import, has a typo, or never calls claim_ticket is not evidence of this defect.

Inspect the test-only boundary

Inspect whole-worktree status and both relevant paths before staging. The service path must have no diff yet.

Why

The history proof fails if the regression and repair share one commit.

You · Native terminal · Windows

git status --short; git diff --check; git diff -- tests/test_service.py workshop_queue/service.py

You · Native terminal · macOS

git status --short && git diff --check && git diff -- tests/test_service.py workshop_queue/service.py

You · Native terminal · Linux

git status --short && git diff --check && git diff -- tests/test_service.py workshop_queue/service.py

Expected result

Only tests/test_service.py is modified, with no whitespace error and no workshop_queue/service.py change.

If that does not happen

If another path changed, do not stage. Preserve the attempt and ask the agent to remove the unrelated change before the regression commit.

Evidence

The first commit boundary is visibly test-only.

Stage only the red regression

Stage exactly tests/test_service.py in a native terminal. This is a shell command you run directly, so it never begins with !. Do not stage production code or any other path.

Why

The review and governed commit need one visible, test-only staged boundary.

You · Native terminal · Windows

git add -- tests/test_service.py; git diff --cached --check; git diff --cached --name-only

You · Native terminal · macOS

git add -- tests/test_service.py && git diff --cached --check && git diff --cached --name-only

You · Native terminal · Linux

git add -- tests/test_service.py && git diff --cached --check && git diff --cached --name-only

Expected result

The staged path list prints exactly tests/test_service.py and the staged diff has no whitespace error.

If that does not happen

If another path is staged, unstage only that path and inspect the whole worktree again. Do not commit until the staged list is exact.

Evidence

The first proposed commit has one visible staged test path.

Approve the red-test commit boundary

Paste this review request into the selected harness and send it. It is not a shell command and never begins with !.

Why

The learner approves a narrow test-only commit after inspecting the real diff.

You · Claude Code harness · All operating systems

Show git status --short, the staged path list, and the staged diff. Do not commit. Report whether the whole worktree changes only tests/test_service.py, whether the staged path is exactly tests/test_service.py, and whether the named regression reaches real claim_ticket and is red because ValueError is absent.

You · Codex harness · All operating systems

Show git status --short, the staged path list, and the staged diff. Do not commit. Report whether the whole worktree changes only tests/test_service.py, whether the staged path is exactly tests/test_service.py, and whether the named regression reaches real claim_ticket and is red because ValueError is absent.

You · Pi harness · All operating systems

Show git status --short, the staged path list, and the staged diff. Do not commit. Report whether the whole worktree changes only tests/test_service.py, whether the staged path is exactly tests/test_service.py, and whether the named regression reaches real claim_ticket and is red because ValueError is absent.

Expected result

The agent reports one test path, a real red regression, and no production change for learner approval.

If that does not happen

If the report names another path, a passing test, or a production diff, do not approve. Preserve the evidence and correct the boundary first.

Evidence

The learner approved the exact first commit boundary.

When the report says the whole worktree and staged set contain only tests/test_service.py, let the agent make the first governed commit.

Commit the red regression

After the learner approves the boundary, paste the copied commit command into the selected harness prompt and send it. It is not a shell command. The agent runs the CodeArbiter commit gate; do not use git commit.

Why

The governed commit makes the failing regression durable history before the repair exists.

Your agent · Claude Code harness · All operating systems

/ca:commit

Your agent · Codex harness · All operating systems

$ca-commit

Your agent · Pi harness · All operating systems

/ca-commit

Your agent · Pi harness · All operating systems

/skill:ca-commit

Expected result

CodeArbiter creates one learner commit after Prepare containing only tests/test_service.py.

If that does not happen

If the gate blocks, preserve the finding. Do not direct-commit, amend another attempt, or add workshop_queue/service.py to this commit.

Evidence

The first immutable learner commit contains the red regression only.

Prove the first commit is still red

Inspect the new head and run the same focused test again in a native terminal. The command is still expected to fail.

Why

This ties the red failure to the committed test-only history, not a transient working-tree edit.

You · Native terminal · Windows

git show --stat --oneline HEAD; python -m unittest tests.test_service.TicketTransitionTests.test_claim_rejects_control_characters_in_volunteer_label -v

You · Native terminal · macOS

git show --stat --oneline HEAD; python3 -m unittest tests.test_service.TicketTransitionTests.test_claim_rejects_control_characters_in_volunteer_label -v

You · Native terminal · Linux

git show --stat --oneline HEAD; python3 -m unittest tests.test_service.TicketTransitionTests.test_claim_rejects_control_characters_in_volunteer_label -v

Expected result

HEAD lists only tests/test_service.py, and the same regression remains red because the service has not changed.

If that does not happen

If HEAD includes service code or the test is not the expected red assertion, preserve the attempt and use Reset. Do not rewrite history to make it appear ordered.

Evidence

The committed red regression predates the repair.

Repair only the live boundary

Now request the smallest reachable repair. It must reject characters below U+0020 and U+007F at the existing claimant-label boundary, leave the committed regression unchanged, add no dependency, and retain ordinary-name behavior.

03Repair one live boundary

Request the minimal production repair

Paste this request into the selected harness and send it. It is a request to your agent, not a terminal command, so it never begins with !.

Why

The repair must be a reachable claimant-label guard, not a broad rewrite or a disconnected test helper.

You · Claude Code harness · All operating systems

Add only the smallest reachable control-character validation at the existing claim_ticket volunteer-label boundary in workshop_queue/service.py. Reject characters below U+0020 and U+007F, preserve the existing regression unchanged, preserve valid Sam Allen behavior, add no dependency, and run the focused regression plus tests.test_service.

You · Codex harness · All operating systems

Add only the smallest reachable control-character validation at the existing claim_ticket volunteer-label boundary in workshop_queue/service.py. Reject characters below U+0020 and U+007F, preserve the existing regression unchanged, preserve valid Sam Allen behavior, add no dependency, and run the focused regression plus tests.test_service.

You · Pi harness · All operating systems

Add only the smallest reachable control-character validation at the existing claim_ticket volunteer-label boundary in workshop_queue/service.py. Reject characters below U+0020 and U+007F, preserve the existing regression unchanged, preserve valid Sam Allen behavior, add no dependency, and run the focused regression plus tests.test_service.

Expected result

Only workshop_queue/service.py changes and the existing regression is ready to turn green.

If that does not happen

If the agent changes the test, adds a dependency, or edits another path, do not stage. Ask it to restore the test and reduce the repair to the claimant boundary.

Evidence

The repair is separate from the committed regression.

Prove the same test turns green

Run the named regression and then the complete service suite in a native terminal before staging the repair.

Why

The same test must change from red to green, while an ordinary claimant remains valid.

You · Native terminal · Windows

python -m unittest tests.test_service.TicketTransitionTests.test_claim_rejects_control_characters_in_volunteer_label -v; python -m unittest tests.test_service -v

You · Native terminal · macOS

python3 -m unittest tests.test_service.TicketTransitionTests.test_claim_rejects_control_characters_in_volunteer_label -v && python3 -m unittest tests.test_service -v

You · Native terminal · Linux

python3 -m unittest tests.test_service.TicketTransitionTests.test_claim_rejects_control_characters_in_volunteer_label -v && python3 -m unittest tests.test_service -v

Expected result

The named regression passes and the service suite passes, including its ordinary claimant behavior.

If that does not happen

If either command fails, preserve the output and ask the agent to revise only workshop_queue/service.py. Keep the red-test commit unchanged.

Evidence

One named regression is red before the repair and green after it.

Inspect the service-only boundary

Inspect the whole worktree and both lesson paths before the repair commit. The committed test must have no new diff.

Why

The external checkpoint rejects any combined, extra-path, or rewritten-test repair.

You · Native terminal · Windows

git status --short; git diff --check; git diff -- tests/test_service.py workshop_queue/service.py

You · Native terminal · macOS

git status --short && git diff --check && git diff -- tests/test_service.py workshop_queue/service.py

You · Native terminal · Linux

git status --short && git diff --check && git diff -- tests/test_service.py workshop_queue/service.py

Expected result

Only workshop_queue/service.py is modified, with no whitespace error and no new tests/test_service.py diff.

If that does not happen

If another path changed, do not stage. Preserve the attempt and remove only the unintended uncommitted scope before requesting review.

Evidence

The second commit boundary is visibly production-only.

Stage only the production repair

Stage exactly workshop_queue/service.py in a native terminal. This is a shell command you run directly, so it never begins with !. Do not stage the committed regression or any other path.

Why

The second review and governed commit need one visible, service-only staged boundary.

You · Native terminal · Windows

git add -- workshop_queue/service.py; git diff --cached --check; git diff --cached --name-only

You · Native terminal · macOS

git add -- workshop_queue/service.py && git diff --cached --check && git diff --cached --name-only

You · Native terminal · Linux

git add -- workshop_queue/service.py && git diff --cached --check && git diff --cached --name-only

Expected result

The staged path list prints exactly workshop_queue/service.py and the staged diff has no whitespace error.

If that does not happen

If another path is staged, unstage only that path and inspect the whole worktree again. Do not commit until the staged list is exact.

Evidence

The second proposed commit has one visible staged service path.

Approve the service-only boundary

Paste this review request into the selected harness and send it. It is not a shell command and never begins with !.

Why

The learner approves the narrow repair after the regression and full service suite pass.

You · Claude Code harness · All operating systems

Show git status --short, the staged path list, and the staged diff. Do not commit. Report whether the whole worktree changes only workshop_queue/service.py, whether the staged path is exactly workshop_queue/service.py, whether the earlier regression remains unchanged, and whether the guard is reachable from claim_ticket.

You · Codex harness · All operating systems

Show git status --short, the staged path list, and the staged diff. Do not commit. Report whether the whole worktree changes only workshop_queue/service.py, whether the staged path is exactly workshop_queue/service.py, whether the earlier regression remains unchanged, and whether the guard is reachable from claim_ticket.

You · Pi harness · All operating systems

Show git status --short, the staged path list, and the staged diff. Do not commit. Report whether the whole worktree changes only workshop_queue/service.py, whether the staged path is exactly workshop_queue/service.py, whether the earlier regression remains unchanged, and whether the guard is reachable from claim_ticket.

Expected result

The agent reports one service path, an unchanged regression, and a reachable narrow guard for learner approval.

If that does not happen

If the report names a changed test, another path, or an unreachable guard, do not approve. Preserve the attempt and correct only that defect.

Evidence

The learner approved the exact second commit boundary.

After that report identifies only workshop_queue/service.py, let the agent make the second governed commit.

Commit the production repair

After the learner approves the boundary, paste the copied commit command into the selected harness prompt and send it. It is not a shell command. The agent runs the CodeArbiter commit gate; do not use git commit.

Why

The second governed commit preserves the repair separately from the red regression.

Your agent · Claude Code harness · All operating systems

/ca:commit

Your agent · Codex harness · All operating systems

$ca-commit

Your agent · Pi harness · All operating systems

/ca-commit

Your agent · Pi harness · All operating systems

/skill:ca-commit

Expected result

CodeArbiter creates one later learner commit containing only workshop_queue/service.py.

If that does not happen

If the gate blocks, preserve the finding. Do not amend the red regression, direct-commit, or add tests/test_service.py to this repair commit.

Evidence

The second immutable learner commit contains the production repair only.

Inspect the exact two-commit proof

Confirm the worktree is clean and read the most recent two learner commits in a native terminal. The older commit must be test-only and the newer commit service-only.

Why

Check reconstructs this history from Git rather than trusting a transcript.

You · Native terminal · Windows

git status --short; git log --oneline --name-only -2

You · Native terminal · macOS

git status --short && git log --oneline --name-only -2

You · Native terminal · Linux

git status --short && git log --oneline --name-only -2

Expected result

Git prints no status paths and shows two commits after Prepare: tests/test_service.py first, then workshop_queue/service.py.

If that does not happen

If the history has another path, another commit, or dirty state, preserve it and use Reset for a numbered retry. Do not rebase, amend, or delete the failed evidence.

Evidence

The exact two commits are available for the external checkpoint to inspect.

Verify independently and preserve the result

Before Check, read the two commit summaries and confirm that git status --short prints nothing. If a path, commit boundary, or result differs from the lesson, preserve the attempt. It is evidence to inspect, not clutter to rewrite.

Recognize success

Success is not a reassuring transcript. Git shows a clean worktree and exactly two learner commits after Prepare: the older commit changes only tests/test_service.py and is still red at that point; the newer commit changes only workshop_queue/service.py and makes the same regression green. The full service suite remains green, and Sam Allen still succeeds.

That separation lets another person reconstruct what was wrong, confirm that the first commit actually detected it, and see the narrow repair without trusting a chat summary.

Check

04Verify and preserve

Run the external Academy Check

Run Check from a native terminal. Academy reads the prepared baseline, commit order, retained source shapes, and clean current worktree without executing learner-authored code.

Why

External verification makes the evidence independently reconstructable.

You · Native terminal · Windows

$academy = "$env:LOCALAPPDATA\ArbiterAcademy\preview-0.30\Scripts\arbiter-academy.exe"
& $academy --repository (Get-Location).Path check F04-fix-with-evidence

You · Native terminal · macOS

academy="${XDG_DATA_HOME:-$HOME/.local/share}/arbiter-academy/preview-0.30/bin/arbiter-academy"
"$academy" --repository "$PWD" check F04-fix-with-evidence

You · Native terminal · Linux

academy="${XDG_DATA_HOME:-$HOME/.local/share}/arbiter-academy/preview-0.30/bin/arbiter-academy"
"$academy" --repository "$PWD" check F04-fix-with-evidence

Expected result

Check prints checkpoint F04-fix-with-evidence: passed; progress: .academy/progress.json.

If that does not happen

If Check fails, preserve the exact history and read its named predicate. Use Reset for a new numbered attempt instead of rewriting committed evidence.

Evidence

Only a passing external Check records F04 progress.

Check is the external Academy verifier. It reads the prepared baseline, your commit order and path sets, the retained regression and reachable repair shapes, and whether the live worktree is clean. It does not execute learner-authored code. The red and green commands you ran above are your real behavioral evidence; Check reconstructs their source and history safely. A green final test alone is not enough: Check rejects a same-commit fix, a code-first path, an unreachable guard, unrelated changes, or uncommitted work.

Python can refresh its own cache file while it runs the service test. Check excludes only those two exercised cache files; every learner-authored, staged, tracked, or untracked change still fails the clean-worktree condition.

Recover or continue

If Check fails, preserve the branch and read the named predicate before attempting anything else. Do not amend, rebase, force-reset, delete the branch, or hide evidence. Use Reset only after a failed Check or an attempt whose commit boundary is irrecoverably wrong; it preserves the failed attempt and creates the next numbered retry.

Hint 1

The defect is at claim_ticket. A test that only validates a new helper does not prove the service rejects an unsafe label when it claims a ticket.

Hint 2

The first commit must remain red. Inspect it before asking for production work, then keep that test unchanged while the production repair turns it green.

Hint 3

If a report shows two paths, another commit, a changed regression, or a dirty worktree, stop before Check. A fresh numbered retry is more useful evidence than rewritten history.

Create a preserved numbered retry

Use this only after a failed Check or an irrecoverably wrong attempt. Run Reset in a native terminal at the Academy clone root.

Why

Reset keeps the failed red-to-green history reachable and starts the same defect on the next unused branch number.

You · Native terminal · Windows

$academy = "$env:LOCALAPPDATA\ArbiterAcademy\preview-0.30\Scripts\arbiter-academy.exe"
& $academy --repository (Get-Location).Path reset F04-fix-with-evidence

You · Native terminal · macOS

academy="${XDG_DATA_HOME:-$HOME/.local/share}/arbiter-academy/preview-0.30/bin/arbiter-academy"
"$academy" --repository "$PWD" reset F04-fix-with-evidence

You · Native terminal · Linux

academy="${XDG_DATA_HOME:-$HOME/.local/share}/arbiter-academy/preview-0.30/bin/arbiter-academy"
"$academy" --repository "$PWD" reset F04-fix-with-evidence

Expected result

Academy archives the prior attempt and switches to the next academy/F04-fix-with-evidence/ATTEMPT_NUMBER branch.

If that does not happen

If Reset stops, preserve its message and current branch. Never force-reset or delete the prior attempt.

Evidence

The failed attempt remains reachable while the retry starts clean.

After Check passes, return to main and leave the completed attempt branch available for review.

Return to main after success

After Check passes, return to main in a native terminal without deleting the completed attempt branch.

Why

The passing attempt remains available for a reviewer to inspect.

You · Native terminal · Windows

git switch main

You · Native terminal · macOS

git switch main

You · Native terminal · Linux

git switch main

Expected result

Git switches to main and leaves academy/F04-fix-with-evidence/ATTEMPT_NUMBER reachable.

If that does not happen

If Git refuses because work is uncommitted, stop and preserve it. Do not force the switch.

Evidence

The completed evidence remains separated from main.

F04 is complete only after the external Check passes. Continue to P01 when that guided Academy lesson is published; an unpublished source exercise is not a substitute for a course step.

Understand the mechanism

This pattern is a causal proof, not a ritual. Prepare establishes a known defective baseline. The first commit records a test that reaches the live production boundary and fails for the missing validation. The second commit adds the smallest reachable validation that makes that exact test pass. The external verifier checks both snapshots, both path boundaries, and the clean current worktree.

The operations surface stays small on purpose. Academy prepares, checks, resets, and returns an attempt; the website teaches the decisions; CodeArbiter governs the agent work. Each part has one job, so a learner can tell which command belongs where and a reviewer can reproduce the result.

Next step

Continue with P01-feature-through-plan.

Recovery guidance