Bug Fix Workflow

For Claude Code: Read this entire document when invoked via /project:bugfix. You are the enforcer of this workflow. Do not skip steps. Do not proceed to the next step until the current one is complete. Ask the developer for the required information at each gate — do not assume or infer it.

Purpose

A repeatable runbook for diagnosing, fixing, and closing bugs in the jjk-workspace monorepo. Designed for a solo developer. Lightweight enough to actually use. Rigorous enough to not embarrass us.

Fixes do not require a pre-work brief the way features do. But they do require a clear reproduction and root cause before a single line of code changes.


The Workflow

Step 1 — Reproduce It

Gate: Can you make the bug happen on demand?

Before touching anything:

  • Confirm the bug is reproducible. If you can’t reproduce it, you can’t verify the fix.
  • Note the environment where it occurs (local dev, Firebase emulator, production, Cloud Run, scheduled trigger, etc.).
  • Note what triggered it (user action, scheduled job, deploy, cold start, etc.).
  • If logs are available, read them fully before forming a hypothesis.

Claude Code: Ask the developer — “Can you reproduce this reliably? What’s the environment and trigger?” Do not proceed until reproduction is confirmed or explicitly waived with a reason.


Step 2 — Identify Root Cause

Gate: One sentence, no waffling.

Resist the urge to fix before you understand. The root cause should be expressible in one plain sentence:

  • “The Firestore query uses multiple range filters but no composite index exists for that field combination.”
  • “The Cloud Function cold-starts and times out before the emulator is ready.”
  • “The Angular component subscribes to an observable but never unsubscribes.”

If you can’t state it in one sentence, you don’t have root cause yet — you have a hypothesis. Keep digging.

Claude Code: Ask the developer — “What’s the root cause in one sentence?” If they can’t state it cleanly, help them dig. Do not proceed to branching until root cause is confirmed.


Step 3 — Assess Scope

Three questions before branching:

  1. Is this an isolated fix, or does it reveal a systemic problem? A missing Firestore index is isolated. A pattern of queries being written without index awareness is systemic. Systemic issues get a note in the fix commit and may warrant a follow-up task — but do not expand the scope of this fix.

  2. Does this touch any ADR-governed decisions? Check the ADR log. If the fix contradicts an accepted ADR, stop and surface the conflict before proceeding.

  3. Does the fix require an IaC or config change in addition to code? Firestore indexes, Terraform resources, Cloud Build configs, Firebase rules — these must be committed alongside the code fix. A fix that requires clicking a console button and not committing the config is an incomplete fix.

Claude Code: Work through these three questions with the developer. Flag any IaC/config tail before coding begins.


Step 4 — Branch

Branch from main using the established convention:

fix/<short-slug>

Examples:

fix/linkedin-firestore-composite-index
fix/dark-mode-flicker-on-load
fix/rating-aggregate-race-condition

No ticket numbers. No dates. Just a readable slug that tells future-you what the branch was for.

Claude Code: Confirm the branch name with the developer before creating it.


Step 5 — Fix

Make the minimal change that resolves the root cause. Do not:

  • Refactor surrounding code opportunistically
  • Add “nice to have” improvements while you’re in there
  • Change behavior beyond what the bug requires

If you notice something worth fixing nearby, note it for a separate task. Stay in scope.

If the fix includes an IaC or config component (Firestore index, Terraform resource, Firebase rules, etc.), that config change is part of the fix — not optional cleanup. It ships in the same commit.

For Firestore indexes specifically: the index must exist in firestore.indexes.json in addition to being created via the console. Console-only is not a fix.


Step 6 — Verify

The fix is not done until the bug is gone.

  • Reproduce the original failure condition.
  • Confirm it no longer occurs.
  • Check for regressions in adjacent behavior.
  • Run the relevant test suite: npm test, npm run test:frontend, or npm run test:functions as appropriate.

If tests don’t cover this failure mode and they reasonably could, add one. Don’t over-engineer the test — a single case that would have caught this bug is sufficient.

Claude Code: Do not move to commit until verification is confirmed.


Step 7 — Commit

Follow the established convention:

fix: <plain description of what was fixed>

Examples:

fix: add composite index for linkedin_posts scheduler query
fix: unsubscribe from ratings observable on component destroy
fix: correct dark mode class application timing on initial load

If an IaC/config change is included, note it in the commit body:

fix: add composite index for linkedin_posts scheduler query

Added composite index on (status, queueOrder, scheduledFor) to
firestore.indexes.json. Index was missing after query was updated
to filter on multiple range fields. Console link was used to
create the index; config now committed to source.

Step 8 — Post-Hoc Doc Update (Conditional)

Most bug fixes don’t need a doc update. But ask:

  • Does this fix reveal something that should be in the project spec? e.g., “always define composite indexes in firestore.indexes.json when writing multi-field range queries”
  • Does this fix contradict or amend an existing ADR? If so, update the ADR status and add an amendment note.
  • Does this fix change any operational procedure? e.g., a change to how scheduled functions are monitored or deployed.

If yes to any of the above, update the relevant doc in docs-site/ in the same branch before merging.

If no — close the branch and move on. Don’t manufacture documentation for its own sake.

Claude Code: Ask the developer these three questions. If all answers are no, proceed to deploy. If any are yes, identify the specific doc to update before closing.


Step 9 — Deploy

# Functions only (most bug fixes)
npx firebase deploy --only functions

# If Firestore rules or indexes changed
npx firebase deploy --only firestore

# If frontend changed
npx ng build frontend && npx firebase deploy --only hosting:blog

# Full deploy
npm run build && firebase deploy

Confirm the fix is live in production after deploy. Check logs if the bug involved a scheduled or async trigger.


Quick Reference

Step Action Gate
1 Reproduce Confirmed reproducible (or explicitly waived)
2 Root cause One sentence, no waffling
3 Scope assessment IaC tail identified, no ADR conflicts
4 Branch fix/<slug> created
5 Fix Minimal change; config committed alongside code
6 Verify Bug gone, tests pass
7 Commit Conventional commit with body if config changed
8 Docs Updated only if spec, ADR, or ops procedure affected
9 Deploy Live in production, confirmed