TUTORIAL 05

Emergency Hotfix

It's Friday night. Users can't checkout. Payment processing crashes with a null pointer. S0 Critical.

โฑ ~15 min ยท Hands-on

/agile-ship-hotfix /agile-code-branch /agile-code-tdd /agile-code-ci /agile-code-pr-review /agile-code-merge /agile-ship-deploy /agile-ship-rollback
๐Ÿšจ Incident Alert โ€” S0 Critical

PagerDuty fires at 21:47 on a Friday. The checkout page throws a 500 error. Revenue is dropping. Users cannot complete purchases. The error log reads:

ERROR 2026-04-04T21:47:12Z PaymentService.calculateTotal()
  NullPointerException: Cannot read property 'amount' of null
    at OrderProcessor.applyDiscount(OrderProcessor.java:142)
    at PaymentService.calculateTotal(PaymentService.java:87)
    at CheckoutController.processOrder(CheckoutController.java:53)

Step 1: Assess Severity

Before writing any code, classify the incident. This determines which workflow to follow.

SeverityImpactResponse
S0 CriticalRevenue-impacting, users blockedHotfix flow (this tutorial)
S1 HighMajor feature broken, workaround existsExpedited bugfix sprint
S2 MediumMinor feature degradedNormal sprint backlog
S3 LowCosmetic / edge caseBacklog grooming

Checkout is completely down. Users cannot pay. This is S0 Critical โ€” we use the hotfix flow, not a regular bugfix.

Step 2: Branch from Main with /agile-code-branch

Key Rule

Hotfix branches always branch from main, never from develop. Main represents what's in production. When an S0 incident is active, /agile-code-branch detects the hotfix context and automatically branches from main.

/agile-code-branch
๐ŸŒฟ Branch created: hotfix/FIX-null-payment

Source: main
Convention: hotfix/FIX-[short-description]
Incident: S0 โ€” Payment processing null pointer

Switched to branch 'hotfix/FIX-null-payment'

This creates an isolated branch directly from the production codebase. No unfinished feature work leaks in.

Why use /agile-code-branch?

Instead of manually running git checkout -b, /agile-code-branch automatically applies your project's branch naming convention, ensures hotfix branches source from main (not develop), and links the branch to the incident. No typos, no risk of branching from the wrong base.

Step 3: Reproduce with TDD

Run /agile-code-tdd to start a test-driven fix. First, write a failing test that reproduces the crash.

/agile-code-tdd

RED: Write the Failing Test

@Test
void should_not_crash_when_discount_is_null() {
    Order order = new Order();
    order.setSubtotal(99.99);
    order.setDiscount(null); // No discount applied

    double total = paymentService.calculateTotal(order);

    assertEquals(99.99, total, 0.01);
}

Run it:

$ ./gradlew test --tests "PaymentServiceTest.should_not_crash_when_discount_is_null"

PaymentServiceTest > should_not_crash_when_discount_is_null FAILED
  java.lang.NullPointerException: Cannot read property 'amount' of null
    at OrderProcessor.applyDiscount(OrderProcessor.java:142)

1 test failed

Confirmed โ€” the test reproduces the exact production crash. Now find the root cause:

// OrderProcessor.java:142 โ€” THE BUG
public double applyDiscount(Order order) {
    return order.getSubtotal() - order.getDiscount().getAmount(); // ๐Ÿ’ฅ No null check!
}

Step 4: Fix and Go GREEN

GREEN: Apply the Fix

// OrderProcessor.java:142 โ€” FIXED
public double applyDiscount(Order order) {
    if (order.getDiscount() == null) {
        return order.getSubtotal();
    }
    return order.getSubtotal() - order.getDiscount().getAmount();
}

Run the test again:

$ ./gradlew test --tests "PaymentServiceTest.should_not_crash_when_discount_is_null"

PaymentServiceTest > should_not_crash_when_discount_is_null PASSED

1 test passed

GREEN. The fix works. The null discount no longer crashes the checkout.

Step 5: Run Full CI

A hotfix must pass the full pipeline โ€” no shortcuts.

/agile-code-ci
CI Pipeline โ€” hotfix/FIX-null-payment
โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”
Build ................ โœ… PASS (12s)
Unit Tests ........... โœ… 247/247 passing (34s)
Integration Tests .... โœ… 18/18 passing (22s)
Lint ................. โœ… 0 issues
Security Scan ........ โœ… 0 vulnerabilities
โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”
Result: โœ… ALL CHECKS PASSED

Step 6: Expedited Code Review

Even under pressure, every hotfix gets reviewed. Use /agile-code-pr-review with expedited flag.

/agile-code-pr-review
PR Review โ€” hotfix/FIX-null-payment
โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”
Reviewer: @lead (expedited โ€” 30 min max)
Changed: 1 file, +4 lines, -1 line

Findings:
  (none โ€” minimal, focused fix)

Verdict: โœ… APPROVED
Comment: "Clean fix. Null guard is correct.
  Consider Optional wrapper as follow-up."
โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”
Time to approval: 14 minutes
โš ๏ธ Expedited != Skipped

An expedited review has a 30-minute SLA, but the same quality standards apply. The reviewer checks correctness, test coverage, and no regressions. The only thing that's faster is the turnaround time.

Step 7: Merge to Main AND Develop with /agile-code-merge

A hotfix must land in both branches. Main for production. Develop so the fix isn't lost in the next release. /agile-code-merge detects the hotfix branch and handles both merges plus version tagging in one command.

/agile-code-merge
๐Ÿ”€ Merge โ€” hotfix/FIX-null-payment
โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

Pre-merge checks:
  โœ… PR approved by @lead (expedited)
  โœ… CI passing on branch
  โœ… No merge conflicts (main)
  โœ… No merge conflicts (develop)

Merging: hotfix/FIX-null-payment โ†’ main
Strategy: merge --no-ff (hotfix convention)
  โœ… Merged to main

Merging: hotfix/FIX-null-payment โ†’ develop
Strategy: merge --no-ff (hotfix convention)
  โœ… Merged to develop

Tagging: v1.2.1 (patch increment from v1.2.0)
  โœ… Tag v1.2.1 created and pushed

Branch hotfix/FIX-null-payment deleted (was 9c4e1b2).

โœ… Hotfix merged to main + develop, tagged v1.2.1.
Why use /agile-code-merge for hotfixes?

/agile-code-merge detects the hotfix/ branch prefix and automatically performs both merges (to main and develop), creates the patch version tag, and cleans up the branch. This eliminates the risk of forgetting the develop merge or mistagging the release.

Why both merges matter

If the fix only lands in main, the next release from develop will reintroduce the bug. /agile-code-merge enforces both merges as mandatory for hotfix branches โ€” it will not complete until both succeed.

Step 8: Deploy to Production

/agile-ship-deploy
Deploy โ€” v1.2.1 โ†’ production
โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”
Rolling deploy ........ started
  pod-1/3 ............. โœ… healthy
  pod-2/3 ............. โœ… healthy
  pod-3/3 ............. โœ… healthy
Health checks ......... โœ… all endpoints responding
Smoke test: checkout .. โœ… order placed successfully
โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”
Deploy complete: 22:31 UTC
Incident duration: 44 minutes
What if the deploy fails?

If the hotfix deploy causes errors โ€” health checks fail, error rates spike, or smoke tests don't pass โ€” roll back immediately:

/agile-ship-rollback
โช Rollback โ€” v1.2.1 โ†’ v1.2.0
โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”
Reason: deploy health check failure
Rolling back to: v1.2.0 (last known good)

  pod-1/3 ............. โœ… rolled back
  pod-2/3 ............. โœ… rolled back
  pod-3/3 ............. โœ… rolled back

Health checks ......... โœ… all endpoints responding
Error rate ............ โœ… returned to baseline

Rollback complete. Production is on v1.2.0.
โš ๏ธ Investigate the failed hotfix before re-deploying.

/agile-ship-rollback reverts production to the last known good version. It's always safer to roll back and investigate than to push a second fix under pressure.

Step 9: Post-Mortem

Post-Mortem: Null Pointer in Discount Calculation

Action Items

Hotfix Flow

๐Ÿšจ
S0 Incident assess severity
๐ŸŒฟ
/agile-code-branch from main
๐Ÿงช
/agile-code-tdd RED โ†’ GREEN
โš™๏ธ
/agile-code-ci full pipeline
๐Ÿ‘€
/agile-code-pr-review expedited 30min
๐Ÿ”€
/agile-code-merge main + develop + tag
๐Ÿš€
/agile-ship-deploy production
โš ๏ธ Hotfix is NOT a Shortcut

A hotfix follows the same quality standards as any other change: TDD, code review, full CI. The difference is speed of turnaround and priority of scheduling โ€” not a reduction in rigor. Cutting corners under pressure is how you create the next S0 incident.

What You Practiced

Knowledge Check

Where does a hotfix branch from?