An assistant changes a function and the tests pass. Have you learned that the change is correct, or only that the tests did not catch a problem? Effective AI-assisted development begins with a question you can verify independently.
Before you begin: Know how to read a diff and run your project's existing checks.
Give the tool the real constraint
Suppose a lesson-progress endpoint overwrites every user's progress under the same key. A vague request to “fix progress” leaves room for a local-storage workaround that never repairs server ownership. A useful request identifies the observed behavior, the expected invariant, and the relevant code path.
An invariant is something that must remain true across operations. Here it is: one signed-in user's update must not change another user's progress. Supply the route, authentication helper, database model, and a failing reproduction. Ask for a small change with an explanation of how that invariant is enforced.
Repository tools can inspect files and propose edits, but file content is still data to evaluate. A comment claiming “this endpoint is secure” is not evidence. The request's identity must come from the trusted authentication boundary, not an arbitrary body field.
Walk through the proposed fix
Imagine the generated change accepts { userId, lessonId, completed } and saves the row by userId. It compiles. It may even pass a happy-path test. But the caller can choose another person's ID unless the server checks ownership.
A better route derives the user from the session, validates the lesson ID and requested transition, and performs the scoped write. The browser may send a task or lesson identifier; it does not decide who is authenticated.
This lesson is a review exercise, not a framework-specific endpoint implementation. Use the authentication and database APIs actually installed in your project. Asking an assistant to invent a parallel session system can make the integration harder to maintain.
Choose checks that could disprove the change
Type checking finds incompatible shapes, not every authorization flaw. Unit tests can validate transition logic. Integration tests can exercise the real authenticated route and database constraints. Manual review can identify an untested assumption. Each check answers a different question.
Use two test identities, the same lesson ID, and different progress values. Verify independent reads and writes. Add an unauthenticated request and a forged body ID. A test that only saves a row and reads it back under one identity is insufficient for the reported defect.
Ask the assistant to explain what each test would fail on. If a test merely asserts a mocked helper was called, it may not establish that the helper received or enforced the correct identity.
Review the evidence, not the confidence
The assistant says “All tests pass,” but it only ran a formatter. What should the review record contain?
Compare a useful completion report
Record the exact checks executed and their outcomes. Formatting is useful but does not replace the route's ownership tests. State what remains unverified. Then run the missing check or keep the change isolated until the release requirement is met. A confident summary cannot substitute for an execution result.
For practice, write a bounded request for a different bug: a failed challenge run is marked complete. Include a reproduction, the desired status transitions, and one negative test. Compare the generated diff with your contract before accepting it.
AI coding tools are most useful when they shorten the distance between a concrete problem and reviewable evidence. The next lesson applies that habit to a small full-stack product.
Sources
GitHub Copilot responsible use describes evaluation responsibilities. Claude Code documentation describes a repository-oriented coding workflow. Use each tool's current permission and execution model.