Lab 15: a reviewed pull request
- Approved by
- Panaversity ·
Time: about 4 hours. Lab files: brightline-lab-ch15.zip, which needs no earlier lab. The same steps are in LAB.md inside the zip.
Before you start
What you need.
- The Claude desktop app with a Pro, Max, Ultra, Team or Enterprise plan.
- The ChatGPT desktop app with any plan, or OpenCode Desktop with a model connected, for Task 12, as in Lab 12.
- Git, Node.js 24 or later, and uv, as in Lab 13. If a tool is missing, follow Concept 13.2 before Task 1.
- A free GitHub account, and the
ghcommand-line tool.field-guide-code-review-setup.md, in the download, has the steps to installgh. Sign in yourself withgh auth loginbefore Task 3. Never type a password or token into an agent's chat.
Public repository, on purpose. On a free GitHub account, branch protection, rulesets and code owners work only on public repositories. Every name, invoice and amount in Brightline is made up, so this lab uses a public repository. In real work, private code needs a private repository on a plan that can protect it. Never push real company data to a public repository.
Working alone. GitHub does not let you approve your own pull request. Task 6 shows two ways to deal with this.
The core path and the extensions. The core path is Tasks 1 to 11, one route in Task 12, and Task 13. The second route in Task 12 is an extension.
For the Python side, or without a paid Claude plan, see the two sections near the end of this page.
Which AI review you can use. Task 8 has three routes. Route C needs nothing beyond your Claude plan, and every task works on it.
| You have | Route | Cost to you |
|---|---|---|
| A Team or Enterprise organization where an Owner has turned on Code Review | A. Code Review on the pull request, and your own security step in CI | Billed on usage credits, within a limit your Owner sets. The security step needs an API key |
| An Anthropic API key | B. The security review Action in your workflow, with a step that fails on findings | API usage. Set a spend limit on the key first |
| Neither | C. /code-review --comment and /security-review in a local session | Your plan's usage |
The lab files. Download brightline-lab-ch15.zip and unzip it into a new folder. It contains:
brightline-ap/, the repository with its git history. It holds the tagch14, one commit of lab starting files (a stub workflow, which is only a placeholder, andchanges/README.md), taggedlab15-start, and two branches.weekend-ruleis the Chapter 13 weekend change behind a flag.agent-speedupis a change an agent says "speeds up" the due list. The tagweekend-rule-startmarks the last commit ofweekend-ruleas you receive it. This is the only folder you give an agent.LAB.md, a copy of these steps.field-guide-code-review-setup.md, with the exact clicks and commands for GitHub and each review tool, andfield-guide-code-toolchain.md, with the install steps for Git, Node.js, uv and Python.
Each task links its answer key as a separate download. Open a key in a text editor, never in the agent. An agent that can read the answers is not tested by them.
Use the zip's copy, even if you finished Lab 14 in your own repository. The answer keys match its commits and line numbers.
The date in this lab. Today is Thursday, March 4, 2027, and the payment run is Friday, March 5.
The job
Finance wants the weekend rule, and an agent has a "faster" due list. Ana Morales, the AP analyst, will not let either reach main the old way. She wants every change to arrive as a pull request with its evidence. An AI should review it against rules the team wrote. Checks a machine runs every time should be able to stop it. And a person should approve it when it touches money. She wants the weekend rule merged so it is reviewed and kept up to date, but off until Dave Kowalski, the controller, decides. And she wants to know, for each kind of mistake, which check catches it. As in every lab, every number comes from tested code, never from an AI's reply.

Figure 15.17. The lab's branches and pull requests. Pull main after every merge, before the next branch.
How each task works
Each task has a goal, steps and a Checkpoint. Do not start the next task until the checkpoint is true. In the Claude desktop app, work in Manual mode unless a task says otherwise.
The agent runs every command in this lab, such as git, gh, npm and uv. You run only gh auth login and, on Route B, gh secret set, because each one takes something only you should type. On the OpenCode route, you also start opencode yourself. Before you approve a command, read what the agent says it will do, and say no to anything you do not understand. Read every git and gh command twice, because they act on a shared repository. Asking "What does this command do?" is always fine.
Predict before the agent runs anything. Write your predictions and notes in NOTES.md. Keep NOTES.md out of the task commits until Task 13: ask the agent to stage only the files each commit needs, as Concept 15.2 says.
Task 1. Which check should catch this? (15 minutes)
Goal: choose a tier and a check before any tool is open.
- Read the tier table in Concept 15.9. For each change below, write in
brightline-ap/NOTES.md, in a text editor, under "Task 1", the risk tier and the one check that should catch its problem:- a. A README sentence says the due list runs on Thursdays. It runs on Fridays.
- b. A new helper reads amounts as decimals, so $4,825.00 becomes 4825.
- c. An agent changes an expected total in
tests/due-by-friday.test.ts"to match the new output". - d. A workflow file gains
permissions: write-all. - e. A debug line prints the API key to the console.
- f. The weekend flag is turned on in the default settings.
Checkpoint: you have a tier and a check for all six.
Check it now. Download Task 1's answer key. Your tiers should match the key. If a check differs, say why yours would or would not catch it.
Task 2. Read the history through the agent (20 minutes)
Goal: the git words from Concept 15.2, seen in this repository.
-
Open
brightline-apin the Claude desktop app's Code tab, in a Local session, in Manual mode. Send:Please set my git name and email for this project only, and ask me what they are. Then install the packages from the lock files, with
npm ciand, inpy/,uv sync. Then runnpm test,npm run typecheck,npm run test:pyandnpm run check:py, and show me what each one prints.If the agent wants to change your git settings for the whole computer, say no. All four checks pass.
-
Send these one at a time, and read each command before you approve it:
- "Show me the branches and tags, and the history as a graph."
- "For each branch other than main, list the files it changes compared with main. Change nothing."
- "Show me the diff of
agent-speedupagainst main forsrc/due-by-friday.tsonly."
-
In
NOTES.md, under "Task 2", write: the commitlab15-startpoints to, how many commits each branch adds, and the one character in the diff that changes the meaning.
Checkpoint: the agent changed nothing. Ask it to run git status, which lists only your NOTES.md.
Check it now. Download Task 2's answer key. Your notes should match it.
Task 3. Put it on GitHub (20 minutes)
Goal: the repository, its tags and both branches, on GitHub.
-
Send: "Please run
gh auth statusand show me what it prints." It must say you are logged in. If it does not, rungh auth loginyourself, in a terminal, and ask again. -
Send:
Create a public GitHub repository named
brightline-apfrom this folder withgh. Pushmainwithgit push -u origin main, so my localmaintracks GitHub's. Then push all tags and the branchesweekend-ruleandagent-speedup. Do not push any other branch. Show me each command before running it. -
Before you approve
gh repo create, check that it says--publicand--source .. Before you approve a push, check its branch name. -
Open the repository on GitHub. Ask the agent to run
git remote -vandgit status. Note the remote's name.git statusonmainshould say your branch is up to date withorigin/main. That link, the upstream, is what lets a plaingit pullwork in later tasks.
Checkpoint: GitHub shows main, weekend-rule and agent-speedup, and the tags ch14, lab15-start and weekend-rule-start. git status on main mentions origin/main.
Check it now. Download Task 3's answer key.
Task 4. Required checks (25 minutes)
Goal: a workflow that runs every machine check on every pull request.
-
Send:
Make a new branch called
review-setupand switch to it. Then replace the stub.github/workflows/ci.ymlwith a workflow that runs on pull requests to main, for the event types opened, synchronize, reopened, labeled and unlabeled. Give the workflow token onlycontents: read. Make two separate jobs on Ubuntu, so a failure in one does not hide the other.checks, with a 15-minute timeout: check out the code, set up Node 24 and uv, then runnpm ci,npm run typecheck,npm test,uv sync --lockedinpy/,npm run test:pyandnpm run check:py.tests-unchanged, with a 5-minute timeout: check out the code with full history, then runscripts/check-tests-unchanged.shwith the base branch,origin/<base branch name>.
Write that script too. It fails when the pull request removes or edits a line in an existing file under
tests/orpy/tests/compared with the base branch, unless the variableALLOW_TEST_CHANGESistrue, which the job sets when the pull request has the labeltests-changed. It also fails when the pull request adds a line that switches a test off:.skip(,.only(,.todo(,pytest.mark.skip,xfail, or a barereturnin a test file. If the script cannot find the base branch, it must fail, never pass. Comment at the top what it cannot catch. Do not usepull_request_target. Show me the workflow before you write it. -
Compare the workflow, line by line, with Concept 15.8. Check five things: the
permissionsline, that no step uses a secret, the trigger, that there are two jobs, andfetch-depth: 0on thetests-unchangedcheckout. -
Ask the agent to test the script here, with
bash scripts/check-tests-unchanged.sh main, and then with a branch that does not exist,bash scripts/check-tests-unchanged.sh no-such-branch. The second must fail. A check that passes when it cannot see is worse than no check. -
Predict what the script would say for
agent-speedupandweekend-rule. Then ask the agent to check withgit diff -U0 main...agent-speedup -- tests py/tests, and the same forweekend-rule. The three dots compare a branch with the point where it leftmain, as Concept 15.2 says.
Checkpoint: the script fails on a missing branch, and you have your two predictions. Ask the agent to commit on review-setup.
Check it now. Download Task 4's answer key. Your workflow should match its meaning, and your predictions should be right.
Task 5. The rules files and code owners (25 minutes)
Goal: the rules a reviewer reads, the template, the tiers and the owners, all written before any review.
-
Send:
Please help me write
REVIEW.md. Ask me, one area at a time, what failure means for Brightline: money, dates, rules, secrets and tests. Then draft the file from my answers. It must also limit nits to three, name the paths to skip, ask for a file and line for every finding, and ask for a count first and "No issues found." when there are none. It must ban formatting comments, ask for the input that breaks each finding, and say that an agent's approval never counts, and how GitHub enforces the tiers here: one approval for all ofmain, and code owners for the high-tier paths. It must hold these risk tiers. Low:README.md,NOTES.md,ports/,changes/andexercises/, with no person once every required check is green. Medium:src/,py/brightline_ap/,scripts/and new tests, with one person. High: due dates, the due list, money formatting,data/,.github/,CODEOWNERS,REVIEW.md, the check scripts, the test and type-check settings,.env.example, any change to an existing test and any policy flag turned on, with two people, one of them a code owner. Show me the draft before you save it.You decide every line. Say what you want changed before you approve it.
-
Read
AGENTS.mdandCLAUDE.md. They should stay short.AGENTS.mdalready says "Never push tomain. Every change goes through a pull request." In Task 6, GitHub starts enforcing that rule too. -
Send: "Please write
.github/pull_request_template.md. Its five headings are what and why, how it was tested, risk, how to undo it, and who directed the agent." -
Send:
Please write
.github/CODEOWNERSwith my GitHub user name as owner of the high-tier paths only:.github/,REVIEW.md,AGENTS.md,data/,.env.example,src/due-date.ts,src/due-by-friday.ts,src/money.ts,py/brightline_ap/due_date.py,tests/andpy/tests/. Add the files that decide whether a check means anything:scripts/check-*.sh,package.json,tsconfig.jsonandpy/pyproject.toml. Do not add a line for every file.A change that edits the test command or a check script can weaken every test without touching one, so those files have an owner. A line for every file (
*) would make every change wait for the owner. -
Ask the agent to commit the three new files on
review-setup.
Checkpoint: REVIEW.md, the template and CODEOWNERS are committed on review-setup.
Check it now. Download Task 5's answer key. REVIEW.md should pass its checklist of six points.
Task 6. Merge the setup, then protect main (20 minutes)
Goal: the rules on main, and main protected by them.
- Send: "Please push
review-setupand open a pull request tomainwithgh pr create, filling in the template. Then watch the checks withgh pr checks --watch." Thechecksandtests-unchangedjobs must both pass. - Merge it yourself on GitHub. Nothing protects
mainyet, which is why the rules go in first. - Send: "Please switch to
mainand pull." Expectgit switch mainandgit pull. GitHub'smainmoved when you merged, and your localmaindoes not move until you pull, as Concept 15.3 says. - If a classmate will review with you, invite them as a collaborator. Ask the agent to add their user name to
.github/CODEOWNERSin a small pull request, and merge it before the next step. - Now protect
main, yourself, in the repository's Settings, using a ruleset.field-guide-code-review-setup.mdhas the clicks. Turn on: restrict deletions, block force pushes, require a pull request before merging, with 1 approval, dismiss stale approvals when new commits are pushed, and require review from code owners. Also require conversation resolution before merging, and require the status checkschecksandtests-unchangedto pass. A ruleset sets one approval count for the whole branch, so even a low-tier change needs one approval here. Code owners add the owner for the high-tier paths, as Concept 15.9 says. - Working alone. Add Repository admin to the ruleset's bypass list, with its mode set to For pull requests only. With Always allow, the bypass would let even step 7's direct push through. If you bypass, every time you merge you will write one line in the pull request saying why, then ask the agent to merge with
gh pr merge --merge --admin. Without--admin, GitHub refuses. In a team this is never the answer. - Send: "Please add one line to
NOTES.md, commit it onmain, and push it straight tomain." If the agent objects, becauseAGENTS.mdforbids it, say: "This tests the ruleset. Please try it." Read the push command before you approve it. Predict, then approve. After GitHub refuses it, send: "Please undo the local commit and keep the edit, withgit reset HEAD~1." That is safe here, because the commit never left your computer, and it keeps every change.
Checkpoint: your local main has REVIEW.md, the push in step 7 is refused by GitHub, and the ruleset lists the rules from step 5. Do not let the agent find a way around the refusal.
Check it now. Download Task 6's answer key.
Task 7. Review before the pull request (25 minutes)
Goal: evidence that the tests came first, evidence for the change, a fresh-context review, and a change brief, before anyone else sees it.
-
Send: "Please switch to
mainand pull. Then switch toweekend-rule, mergemaininto it, and list thescriptsfolder." Read the merge message. It should report no conflicts, and the list should showcheck-tests-unchanged.sh. If the merge says "Already up to date", yourmainwas not pulled. -
Check the tests came first. Ask the agent to run
git log --oneline --reverse lab15-start..weekend-rule-start. The first commit should be "Failing tests for the weekend rule", before the commit that adds the rule. Predict: at that first commit,npm testandnpm run typecheckshould both fail because the weekend code does not exist yet, and for no other reason. The missing code ispayBy, and theweekendRuleoption the tests pass. Then send: "Please look at that first commit on its own withgit switch --detach weekend-rule-start~1, runnpm testandnpm run typecheck, thengit switch weekend-ruleto go back." A detached HEAD means you are looking at one commit, not working on a branch, so nothing you do there changes a branch. -
Ask for the evidence, not a summary: "Run the four checks,
npm run due -- 2027-03-05, the same withPAY_WEEKEND_RULE=on, andbash scripts/check-tests-unchanged.sh main. Show me each output." Write each number inNOTES.md. -
Open the app's change pane, the Changes card in Claude Code. Compare it with
git diff --stat main...weekend-rule, which the agent runs. InNOTES.md, write what each one shows, and which one a reviewer of the whole branch needs. -
Open a new session as the reviewer (+ New, same folder). Send:
You are reviewing a pull request you did not write. The request: pay a Saturday or Sunday due date on the Friday before, behind the flag
PAY_WEEKEND_RULE, off by default. Read the review rules as they are onmain, withgit show main:REVIEW.md, not the copy on this branch. Reviewgit diff main...weekend-rule, including anything else in the repository the change affects. Report a count first, then each finding with a file, line, severity and the input that breaks it. Change nothing. -
In the first session, run
/code-review. Compare the two reviews inNOTES.md: what each found, and what only one found. -
Send: "Please write
changes/weekend-rule.mdfrom the template inchanges/README.md, using only numbers from the output above and the tests-first result." Read every claim, and check that each one points to a command.
Checkpoint: your notes record three things. The tests came first and failed only because the weekend code was missing. The four numbers are there: 8 invoices and $19,229.53, 10 invoices and $33,109.53. And they say whether each review found the issue in src/reconcile.ts. If neither found it, say so. Task 8 gives it another chance. Ask the agent to commit the brief on weekend-rule.
Check it now. Download Task 7's answer key.
Task 8. Open the pull request and resolve every finding (30 minutes)
Goal: the weekend rule as a pull request, reviewed by AI on your route, with every finding resolved.
- Send: "Please push
weekend-ruleand open a draft pull request tomain, with the template filled in and the brief linked. I will give you the title." Give it a title yourself. You can use the app's Create PR button instead. It runs the sameghcommand, and the pull request's checks then show in the Changes card. Leave Merge when ready and Auto-fix off in this lab: you merge by hand in Task 11, after reading the checks. - Run the AI review on your route:
- Route A. Mark the pull request ready, or comment
@claude review. Wait for the Claude Code Review check run and the inline comments. For the security step, follow Route B, which needs an API key. - Route B. Store the key yourself, in a terminal, with
gh secret set CLAUDE_API_KEY, typing the key only intogh. Then ask the agent to make a new branch from an up-to-datemain. Paste the security review job fromfield-guide-code-review-setup.md, section 7, into the chat, and ask it to add the job toci.yml, with its step that fails when it reports findings. Open it as its own pull request. It touches.github/, so it is high tier. Merge it. Then ask the agent to switch tomainand pull, switch toweekend-rule, mergemainand push. Read the job's comments. Keeping the job out of the weekend pull request means Task 9 gets it too, and Task 10's change toci.ymldoes not collide with it. - Route C. Run
/code-review --commenton the branch, so the findings appear on the pull request as inline comments, then/security-review./code-reviewreadsCLAUDE.md, notREVIEW.md. Paste the security summary into a comment.
- Route A. Mark the pull request ready, or comment
- For each finding, decide: fix, or resolve with a reason. For the reconciliation finding, if it appears, predict first, then ask the agent to run
PAY_WEEKEND_RULE=on npm run reconcile -- data/invoices.csv, so you see it for yourself. - Send: "Add a test to
tests/reconcile.test.tsthat setsPAY_WEEKEND_RULE=onand expects 0 mismatches indata/invoices.csv. Run it and show it failing. Then make reconciliation compare stated dates withdueDate, not the pay date, and remove any function nothing uses. Do not change existing tests. Then commit and push." - Reply in each finding's thread with the fix's commit id or your reason, and resolve it. Ask the agent to update the brief's Review section, commit it and push.
Checkpoint: every review thread is resolved, the checks and tests-unchanged jobs are green on the latest commit, PAY_WEEKEND_RULE=on npm run reconcile -- data/invoices.csv reports 0 mismatches, and check-tests-unchanged.sh still passes, because you added lines and removed none.
Check it now. Download Task 8's answer key.
Task 9. The agent's change (20 minutes)
Goal: see which check catches which problem.
- Send: "Please switch to
mainand pull. Then switch toagent-speedup, mergemaininto it, push it, and open a pull request with this description: Speed up the due list with a single pass. All tests pass." - Before you look at the checks, predict which of the three problems each check will catch: the cutoff
<, the edited test, and the printed key. - Run the AI review on your route, as in Task 8.
- Ask the agent to run
gh pr checks, then read the review. Fill in a table inNOTES.mdwith one row per problem and one column per check, and mark which check caught it. Note which column is blocking.
Checkpoint: the merge button is blocked, and checks and tests-unchanged failed. Do not merge, and do not close it yet.
Check it now. Download Task 9's answer key. Your table should match it: the checks job catches the cutoff, the tests-unchanged job catches the edited test, and on Route C no blocking check catches the printed key.
Task 10. Fix it at the source (15 minutes)
Goal: the problem that only a review caught is now caught by a check every time.
-
Pick the problem in your Task 9 table that no blocking check caught. On Routes A and B with the security step, it may be none. Then use the printed key anyway, because a model can miss it.
-
Send:
Please switch to
main, pull, and make a new branch calledsecret-check. Writescripts/check-no-secret-output.sh, which fails when a logging or print call insrc/,scripts/orpy/brightline_ap/names a key, token, secret or password on the same line. It must fail, not pass, if a folder is missing or the search itself fails. Add it toci.ymlas a third job,no-secrets. Run the script here and show me the output. Then tell me what the script cannot catch.It should pass, because
mainprints no key. Write the agent's answer about what it cannot catch inNOTES.md. -
Ask the agent to open it as a pull request. It touches
.github/, so it is high tier and needs the code owner. Merge it. Then addno-secretsto the ruleset's required checks. It appears in the list now that it has run once. -
Send: "Please switch to
main, pull, switch toagent-speedup, mergemain, and push." Then ask it to rungh pr checksagain, and to show the failedno-secretsjob's log.
Checkpoint: the script passes on main, and the no-secrets job passes on the secret-check pull request and fails on agent-speedup, naming src/ap-client.ts, line 14. Close the agent-speedup pull request with one sentence saying why.
Check it now. Download Task 10's answer key.
Task 11. Merge, flag, revert (15 minutes)
Goal: the weekend rule on main, off, with the way back rehearsed.
- Send: "Please switch to
main, pull, switch toweekend-rule, mergemain, and push. Then watch the checks withgh pr checks --watch." Theno-secretsjob became required in Task 10 and has never run on this pull request, so GitHub would wait for it forever. Every job must pass. - If the weekend pull request is still a draft, mark it ready. Your classmate approves it as code owner, or you bypass, with your reason. Then merge it.
- Send: "Please switch to
mainand pull. Then runnpm run due -- 2027-03-05, and the same withPAY_WEEKEND_RULE=on." - Rehearse the revert. Send: "Please make a new branch called
revert-rehearsal, and revert the merge commit of the weekend pull request withgit revert -m 1. Then run the four checks and the due list, with the flag off and on." If you merged with Squash and merge, there is no merge commit, so ask it to revert the single squashed commit without-m 1. Then ask the agent to switch tomainand delete the rehearsal branch. Do not push it. - Read Concept 15.10 on merge queues. On a free personal account GitHub offers none, so write in
NOTES.mdwhich two pull requests in this lab could have passed alone and brokenmaintogether. If you have none, say why.
Checkpoint: on main, 8 invoices, $19,229.53 with the flag off, and 10 invoices, $33,109.53 with it on. On the rehearsal branch, 8 invoices with the flag on or off, and every check passing.
Check it now. Download Task 11's answer key.
Task 12. Port the review (20 minutes per route)
Goal: the same weekend change, reviewed by a second agent, compared with the first.
Set up the same starting point. The weekend change is merged now, with its fix. To give a second reviewer the change as it first was, with the same rules, build two practice branches that never merge. Send:
Please switch to
mainand pull. Make a new branchreview-basefrom the taglab15-start, and copy the rules frommainwithgit checkout main -- REVIEW.md AGENTS.md. Add a section to the end ofAGENTS.md:## Code Review Rules, with one line, "ReadREVIEW.mdfrom the base branch first and follow it." Commit onreview-base. Then make a new branchport-reviewfrom the tagweekend-rule-start, mergereview-baseinto it, and push both branches.
Codex reads that heading. Now git diff review-base...port-review shows only the weekend change, and both branches carry the rules.
Copy your Task 7 notes into ports/ch15.md, as the first reviewer. For each route you do, add what it found, what it missed, where it posted, and whether anything it did could block a merge. Do not commit ports/ch15.md on these practice branches. It stays in your working tree as you switch branches, and Task 13 commits it.
The Codex route
In the ChatGPT desktop app, connect the repository in Codex settings. Ask the agent to open a draft pull request from port-review into review-base, and comment @codex review, which needs the Plus plan or above. Or open the folder in Codex on port-review, in Ask for approval mode, and run /review against the base branch review-base. Set reviews to Detached first, so the review runs in its own chat. Then, on a branch from main, ask it to add the same ## Code Review Rules section to AGENTS.md, and merge it through a pull request.
The OpenCode route
On port-review, ask the agent to create .opencode/commands/review.md, with a prompt that reads the rules with git show review-base:REVIEW.md, so it uses the base branch's copy, and reviews git diff review-base...HEAD without editing anything. Add subagent: true to its frontmatter, so it runs in a child session with fresh context. In opencode.jsonc, deny edits and let only git diff, git log and git show run without asking. field-guide-code-review-setup.md, section 10, has both files to paste into the chat. Run /review in OpenCode's terminal client, started with opencode in the folder. OpenCode's commands page describes running commands there, and does not mention Desktop. Read what it found, and its diff, in OpenCode Desktop if you prefer.
Checkpoint: ports/ch15.md compares at least two reviewers on the same change, including whether each found the reconciliation issue.
Check it now. Download Task 12's answer key.
Task 13. Hand over and tag (10 minutes)
Goal: the next chapter starts from a tag where every change arrives as a reviewed pull request.
- Send: "Please switch to
main, pull, and make a new branch calledhandover. UpdateNOTES.mdwith how changes reachmain, the required checks, and the weekend flag. CommitNOTES.mdandports/ch15.md, push, and open a pull request." Let the checks pass, and merge it. It is low tier, so no code owner is asked, but it still needs the one approval every pull request needs here, or your bypass with a reason. - Send: "Please switch to
main, pull, tag itch15, and push the tag." Expectgit tag ch15andgit push origin ch15. - Check the tag from a clean copy. Send: "Please clone my repository at the tag
ch15into a new folderch15-check, withgit clone --branch ch15. In that folder, runnpm ci, anduv syncinpy/. Then run the four checks and the due list with the flag off and on."
Checkpoint: every command passes in ch15-check, with 8 invoices off and 10 on, and GitHub lists the tag ch15. From Chapter 16 on, every change is opened as a pull request.
Check it now. Download Task 13's answer key.
If something goes wrong
| Problem | What to try |
|---|---|
gh says you are not logged in | Run gh auth login yourself in a terminal. Never paste a token into the agent's chat |
| The workflow does not run on the pull request | Check that the trigger says pull_request with branches: [main], and that the pull request targets main. A pull request that adds or changes the workflow runs its own version |
check-tests-unchanged.sh says "Cannot find the base branch" | The checkout has no history. Use fetch-depth: 0 in that job's checkout step |
git pull says "There is no tracking information for the current branch" | main was pushed without -u. Ask the agent to run git branch --set-upstream-to=origin/main main once, then git pull |
git status says "HEAD detached" | You are still on the commit from Task 7, step 2. Ask the agent to run git switch weekend-rule |
git merge main says "Already up to date", but files from a merged pull request are missing | Your local main is behind GitHub's. Ask the agent to switch to main and pull, then merge again |
Adding the tests-changed label does not rerun the checks | The workflow's types list needs labeled and unlabeled |
The status check checks is not offered in the ruleset | It appears only after the job has run once. Open any pull request, let it run, then add it |
| The ruleset has no effect | The repository is private on a free account. Make it public for this lab, or use a paid plan |
| You cannot approve your own pull request | That is GitHub's rule. See Task 6, steps 4 and 6 |
@claude review also starts the GitHub Action | Both use @claude. Set the Action's trigger_phrase to something else |
| Code Review never runs | It needs Team or Enterprise, an Owner to turn it on, and the Claude GitHub App on the repository. It skips drafts and forks. Use Route C |
| The security review job fails with "API key" | The secret is missing or misnamed. Fork pull requests never get secrets |
git merge main reports a conflict | Ask the agent to show both sides, explain each, and propose a resolution. Read it before you approve |
The agent offers git push --force or git reset --hard | Say no and ask what it wants to undo. Use git revert for anything already pushed |
The Python side
The review is about the TypeScript change, as in Chapter 13. The required checks run both languages, so keep py/ working. In Task 7, also review the Python pay_by on weekend-rule, which has no flag and touches no reconciliation.
Without a paid Claude plan
Do Tasks 1 to 11 in Codex in the ChatGPT desktop app, or in OpenCode Desktop, with these swaps. Then port to the agent you did not use in Task 12. Every other step is the same, because git, gh and the checks do not depend on the agent.
| Lab step | Codex in the ChatGPT desktop app | OpenCode Desktop |
|---|---|---|
| Safety, before Task 2 | Permission mode Ask for approval, Work in set to This computer | The opencode.jsonc rules from Lab 12, with shell commands set to ask, and auto-accept off |
| Task 2, step 1: open the folder | Open brightline-ap | Open brightline-ap |
| Task 5: rules files | Edit AGENTS.md. Skip CLAUDE.md | Edit AGENTS.md. Skip CLAUDE.md |
| Task 7, step 4: the change pane | The review pane, set to the branch diff | The review panel |
| Task 7, step 5: a fresh-context reviewer | A new chat in the same folder | A new session in the same folder |
| Task 7, step 6: the local review | /review against the base branch main | The /review command from Task 12, reading main in place of review-base, run in the terminal client |
| Tasks 8 and 9: the AI review | Route C with /review, then paste its findings into the pull request as comments. Or comment @codex review once the repository is connected | Route C with the /review command, then paste its findings as comments |
Apply it to your vertical
Take one repository or shared folder at work. Write its risk tiers: which paths are low, medium and high, and why. Name the person who must approve the high tier, and the one check a machine should run on every change there. If nothing runs today, that check is your first pull request.
Domain expert and builder. The domain expert says what failure means and owns the high-tier decisions, such as when a policy flag is turned on. The builder turns those into a rules file, required checks and code owners, and makes sure no agent can merge around them.
Artifact checklist
- Your Task 1 tiers and checks, and the Task 2 history notes, in
NOTES.md - The repository on GitHub, public, with
main, the tags and both lab branches -
.github/workflows/ci.ymlwith read-only token, andscripts/check-tests-unchanged.sh -
REVIEW.mdwith the risk tiers,.github/pull_request_template.mdand.github/CODEOWNERS, merged before any review - A ruleset on
mainthat refused a direct push -
changes/weekend-rule.md, with every claim pointing to a command - The weekend pull request, every thread resolved, merged with the flag off
- The
agent-speeduppull request closed, with your table of which check caught which problem -
scripts/check-no-secret-output.sh, run by theno-secretsjob, as a required check - A rehearsed revert, and your merge queue note
-
ports/ch15.md, and tagch15, checked from a clean clone - Extension: a second reviewer in Task 12, and risk tiers for one repository at work
- Owner
- Panaversity