The Commit Is a Paper Trail

By Charlin Joe · 23 July 20265 views

The Commit Is a Paper Trail

Six months after the feature shipped, a bug report arrives. Guest orders are appearing in the authenticated user's order history in some edge cases. Specifically, when a user creates an account post-purchase — using the post-purchase account creation flow — and their email matches a prior guest order, the guest order is getting attached but the query doesn't filter it out cleanly.

The engineer assigned to the bug opens git log. They need to understand why the getOrdersByUser() query was written the way it was. They need to know what was decided, what alternatives were considered, and what constraints they can't violate when they fix it.

The most recent commit touching that file says: fix guest checkout. The diff shows the query. No PR description. No link to a ticket. The PR comments have the product owner asking "is this ready?" and the developer saying "yes."

The engineer is now doing archaeology. They're going to spend half a day reconstructing a conversation that happened six months ago, hoping someone still remembers why the filter was written that way, knowing that the developer who wrote it is on a different project and may or may not remember the GDPR constraint that drove the decision.


This is the failure the commit process in Step 7 prevents.

Step 7 is the commit and PR step — the mechanics of getting the code from a local branch to a reviewable PR. Most teams treat this as a formality. Commit the code, open the PR, tag a reviewer. The ANN SDLC treats it as a documentation step, because the commit message and PR description are the artifacts that make future debugging possible.

The commit message format for a disciplined AI-assisted process references the documents that drove the change:

feat: implement guest checkout order storage

Per REQ-CHECKOUT-00010, REQ-CHECKOUT-00020, ADR-012.

Guest orders stored in unified orders collection with userId: null
and guestEmail: string. getOrdersByUser() excludes null by filter
semantics — see ADR-012 for rationale and the rejected
guest_orders alternative.

GDPR deletion handler updated for user accounts. Guest order
cleanup by email implemented in same function (ADR-012 consequence).

Anyone reading this commit six months from now knows: the requirement IDs, the ADR that governed the decision, why the filter works the way it does, and where to look for the full decision rationale. They don't need to find the original developer. They don't need to reconstruct the conversation. The commit tells them.


The PR description does the same thing at a higher level.

A PR description written from the diff explains what changed. A PR description written from the implementation plan explains why — and that's the one that's useful.

## Changes

Implements guest checkout (Phase 1): order storage, model changes, and GDPR compliance.

**Requirements:** REQ-CHECKOUT-00010, REQ-CHECKOUT-00020
**ADR:** ADR-012 (unified orders collection with userId: null)

### What changed

- `lib/models/order.dart`: userId now nullable; guestEmail added; constructor
  assertion enforces exactly one must be present
- `lib/services/order_service.dart`: placeGuestOrder() added; ADR-012 comment
  added to getOrdersByUser() to prevent future null-check drift
- `lib/screens/checkout/`: new GuestCheckoutScreen; guest entry point added
  to CheckoutScreen
- `db/rules/orders.rule`: guest reads allowed by orderId + guestEmail pair
- `services/orders/index.ts`: guestEmail index; GDPR deletion handler updated
  for both account users and guest email cleanup

### What was explicitly not changed

- `OrderService.getOrdersByUser()`: no structural change; query already
  excludes null userId by filter semantics (documented in ADR-012)
- Admin order panel: queries full collection; guest orders appear correctly
  without changes (per ADR-012 design goal)
- Returns flow: already handles orderId + email; works for guest orders
  without changes

### Gate 2 verification

All acceptance criteria verified against running application.
ADR-012 consequences verified against implementation.
GDPR deletion tested with guest email in staging.

The "what was explicitly not changed" section is the part most PR descriptions omit. It's also the most useful part for the future engineer debugging the edge case six months later. They need to know not just what changed, but what the developer deliberately decided not to change — because that decision might be the answer to the bug.


The PR description comes from the implementation plan, not from the diff.

This is the mechanism. The developer opens the plan, not the diff. They copy the files-to-change table into the changes section. They copy the impact analysis into the "what was not changed" section. They reference the requirements and the ADR by ID. The plan was written before generation — it describes what the team agreed to do. The PR description confirms that what shipped matched what was agreed.

Writing a PR description from the diff takes longer and produces worse documentation. The diff shows what changed. It doesn't show why the scope was what it was, what was considered and excluded, or what constraints governed the decisions. The plan has all of that. The PR description is the plan's public face.

If the diff and the plan disagree — the PR contains something that isn't in the plan, or the plan describes something that isn't in the diff — that discrepancy surfaces at Step 7, before Gate 3 review. The senior engineer doing the Gate 3 review compares the PR description to the diff. If they match, the review proceeds. If they don't, the review stops and the developer explains the deviation.

Most deviations are benign: the AI generated something the plan didn't explicitly specify, but it's obviously correct. Occasionally they're not benign: the AI touched a file the plan excluded, or made an architectural choice that contradicts the ADR. Gate 3 catches both — because the PR description written from the plan makes the deviation visible.


Commit messages don't feel important when you're writing them. They feel like a formality, a box to tick before you move to the next task. The pressure is always to write just enough to make sense and push.

The engineer debugging a six-month-old edge case feels it differently. They're spending hours trying to answer a question that a two-paragraph commit message would have answered in two minutes. They're asking the developer who wrote it — who has to dig through their own memory of a conversation they barely remember. They're searching Slack for a message that was probably never sent.

The commit is not for the moment of writing. It's for the moment of debugging. Every commit you write is a message to a future engineer — possibly you, six months later — who needs to understand not just what happened, but why.

The ANN SDLC makes the commit message and PR description formal outputs of the process — artifacts that exist alongside the code, not afterthoughts to it. They're written from documents that contain the reasoning. They answer the questions the future engineer will ask. They close the paper trail that begins with the business intent and ends with a readable history of every decision made between problem and solution.


When the engineer assigned to that bug opens git log and reads a commit that says feat: implement guest checkout order storage — Per REQ-CHECKOUT-00010, REQ-CHECKOUT-00020, ADR-012, they pull up ADR-012. They read the consequences section. They understand immediately why the query is written the way it is. They understand what they can change and what they can't. The fix takes two hours.

That's the paper trail working. Not impressive in the moment it was written. Indispensable in the moment it was needed.


Comments

No comments yet. Be the first!

Sign in to leave a comment.