# Use GitHub Copilot to Fix a Stale-Delete Bug You Can Verify

> Use Copilot in VS Code on a small SQLite bug, starting with two failing tests and reviewing the exact version check in the resulting patch.

- Source: https://www.zarifautomates.com/blog/how-to-use-github-copilot-to-write-code-faster
- Published: 2026-09-17
- Updated: 2026-09-19
- Pillar: Agents & AI Engineering
- Tags: agent-course, ai-engineering, practical-guide
- Author: Zarif

---

A delete function accepts an expected record version but ignores it. The normal test passes: Alice's preference disappears and Bob's stays. The failure arrives later, when an old request deletes Alice's newer preference.

This is a useful coding-assistant task because the change is small and the acceptance criteria are observable. You will use Copilot in VS Code to inspect the bug, propose a fix and review the patch. The download includes an authored reference solution and executed test results. It does not contain a recorded Copilot session or a claim that Copilot produced that solution.

## Set up the exercise and Copilot separately

You need Python 3.10 or newer, Git, VS Code and access to GitHub Copilot in that editor. Sign in through VS Code's Copilot setup and check that your account or organization permits the selected model and tools. This lesson does not require Copilot's cloud agent or a deployment.

Download and extract the [stale-delete coding exercise](/downloads/agent-course/copilot-stale-delete-v1.zip) into a disposable folder. The application uses only Python's standard library and synthetic records. Before opening a model session, inspect these files yourself:

| File | Purpose |
| --- | --- |
| `store.py` | Intentionally incomplete delete function to fix |
| `test_store.py` | Six real SQLite tests defining expected behavior |
| `reference_store.py` | Authored solution for comparison after attempting the task |
| `reference.patch` | The concrete SQL change in patch form |
| `check_exercise.py` | Verifies the supplied starter and reference results |

Keep the reference solution out of the assistant's initial context if you want to assess its own proposed fix. Do not use the incomplete starter against a real database.

Initialize a local review baseline from the extracted folder:

```bash
git init
git add store.py test_store.py
git commit -m "Record stale-delete exercise baseline"
python3 -m unittest test_store -v
```

Use `python` if that is your installed Python command. Git needs a configured author identity for the commit. The observed baseline is six tests run, four passing and two failing. Those failures are intentional: stale-version deletion and deletion after a value has been recreated.

## Inspect the failing contract

The function signature includes `expected_version`, but the starter's statement is:

```sql
DELETE FROM preferences WHERE owner = ? AND key = ?
```

The desired behavior is narrower. Delete only if owner, key and exact version all match. Otherwise, return false without changing any row. A retry after a successful deletion also returns false. The version strings in this fixture identify specific record instances. They are not user identities or authorization tokens.

The tests use a temporary SQLite file, not a mocked database. One test closes and reopens the connection after deletion. That checks persistence across connections, not a killed process or remote service.

## Ask Copilot for a plan using the relevant files

Open the exercise folder in VS Code and open Copilot Chat. GitHub's [IDE chat guide](https://docs.github.com/en/copilot/how-tos/chat-with-copilot/chat-in-ide) documents the **Ask**, **Plan** and **Agent** choices. Select **Plan** for the first step. Use **Add Context → Files & Folders** to attach `store.py` and `test_store.py`, or mention each with `#` in the input. The [VS Code context guide](https://code.visualstudio.com/docs/chat/copilot-chat-context) documents both methods.

Use this request:

```text
Inspect store.py and test_store.py. Explain why the two stale-delete
cases fail and propose the smallest change. Keep all six tests intact.
The function must delete only the exact owner, key and expected_version.
Do not add dependencies, network calls, schema changes or a new API.
Do not inspect reference_store.py or reference.patch for this attempt.
Do not edit files yet.
```

The relevant plan should identify the missing version predicate and preserve the existing owner/key scope. If it proposes removing a test, accepting stale versions or fetching a fresh version immediately before deleting, it has changed the task. A fresh lookup would authorize deletion of a record different from the one the caller reviewed.

The file-context instruction helps focus the task. It is not a security boundary preventing access to other files in the workspace. Use a folder containing only material appropriate for the assistant.

## Implement and inspect the diff

After reviewing the plan, use **Start Implementation** to hand it to Agent, as described in GitHub's guide. Ask it to modify only `store.py` and run `python3 -m unittest test_store -v`. Keep your editor's tool approval controls in place and inspect proposed commands before allowing anything beyond that exercise.

The reference fix adds the version condition and binds the third parameter:

```diff
- "DELETE FROM preferences WHERE owner = ? AND key = ?",
- (owner, key),
+ "DELETE FROM preferences WHERE owner = ? AND key = ? AND version = ?",
+ (owner, key, expected_version),
```

The SQL placeholders matter. The fix should not interpolate owner, key or version directly into the SQL string. It should also preserve the transaction block and the return value based on whether one row was deleted.

Open VS Code's Source Control diff for `store.py`, then inspect `test_store.py` for unintended changes. You can also run:

```bash
git diff -- store.py test_store.py
python3 -m unittest test_store -v
```

Run the command yourself even if the assistant reports success. The accepted result is all six original tests passing. GitHub also documents an optional [Copilot review of uncommitted changes](https://docs.github.com/en/copilot/how-tos/use-copilot-agents/request-a-code-review/use-code-review?tool=vscode). That is another account-dependent model review, not a substitute for the diff and test evidence.

## Compare against the executed reference

The supplied reference solution produced these results:

| Case | Starter | Reference |
| --- | --- | --- |
| Matching version deletes only Alice | Pass | Pass |
| Unknown owner has no effect | Pass | Pass |
| Retry does not delete another row | Pass | Pass |
| Stale version preserves current value | Fail | Pass |
| Recreated value survives an old delete | Fail | Pass |
| Successful deletion survives reopening | Pass | Pass |

`reference.patch` was applied in a fresh disposable copy, and the patched `store.py` passed the same six tests. `check_exercise.py` separately verifies the original starter's two expected failures and the reference module's six passes. After fixing your own `store.py`, that checker will correctly complain that the starter no longer fails. Use the normal unittest command to validate your completed exercise.

If Copilot produces a different patch, judge it against the contract. A larger rewrite can be correct, but it needs a reason. Record any extra behavior rather than accepting it because the tests happen to pass.

## Prove the test detects the bug

In a disposable copy of your completed exercise, remove only `AND version = ?` and remove the corresponding bound value. Run the tests again. The two stale-delete cases should fail. Restore the correct version check afterward.

That mutation is a stronger check than counting tests: it shows that the suite detects the specific mistake the task addresses. It still does not test authentication, malicious database access, concurrent remote changes or backup retention.

Your review record should contain the baseline failure, final patch, exact command and final result. Keep the actual Copilot model and session behavior in your own record if you run the exercise. The authored reference here does not supply that evidence for you.

Continue with the [Cursor app-slice exercise](/blog/how-to-use-cursor-ai-to-build-web-applications) to apply the same approach to a small interface. Return to the [course index](/blog/pillar/agents-and-ai-engineering#agent-course-heading) for the full sequence.

## Related Guides

- [Agent Design Patterns: Run Four Control Flows and Their Failures](/blog/ai-agent-design-patterns-production-systems)
- [Choose an Agent Starter: Inspect Three Repositories and Test One](/blog/best-ai-agent-template-libraries-and-starters)
- [Agent Evaluation Tools: Compare Five Options on One Ticket Task](/blog/best-ai-agent-testing-and-evaluation-tools)
- [Build a Webhook Receiver: Verify Deliveries and Recover After Failure](/blog/how-to-use-webhooks-ai-automation)

## Continue the course

Lesson 14 of 17.

Previous lesson: [Choose an Agent Starter: Inspect Three Repositories and Test One](https://www.zarifautomates.com/blog/best-ai-agent-template-libraries-and-starters.md).

Next lesson: [Use Cursor to Build a Ticket Approval Interface You Can Test](https://www.zarifautomates.com/blog/how-to-use-cursor-ai-to-build-web-applications.md).

[Browse available lessons](https://www.zarifautomates.com/blog/pillar/agents-and-ai-engineering#agent-course-heading).
