How to Fix Any Bug

Debugging Scroll Issues in Web Applications — A Systematic Approach

Preface
Do you often pass your source code directly to an AI when debugging issues?
Here’s a real case from my web app development experience — a scroll function that broke after adding a network request — and how I systematically identified and resolved it.
---
The Case
While building a small web app feature — a sequence of cards with "scroll to next" buttons — everything worked smoothly until I added an action on the button to send a request to the server.
Immediately, scroll behavior became jerky, stuttery, and sometimes failed entirely.
Suspecting React Router’s re-rendering triggered by the `action`, I initially thought data refreshing might be the cause. But since fetched data was identical, the page shouldn’t visibly change.
In React, re-renders typically shouldn’t break scrolling — so perhaps the issue lay deeper:
- My own code?
- React Router?
- React itself?
- Browser behavior?
---
Step 0 — Attempt a Direct Fix
I first asked Claude (AI assistant) to fix it:
- Refactored the `useEffect` condition around `scrollIntoView` — claimed fixed, but wasn’t.
- Switched from smooth to instant scroll — still broken.
Claude repeatedly reported “Bug fixed” — but the stutter persisted.
💡 Lesson: Many engineers — human or AI — make the same mistake: jumping to “fixes” without confirming they actually solve the problem.
---
Step 1 — Establish a Reliable Reproduction Case (Repro)
A Repro is a repeatable test scenario for verifying if a bug still exists.
My initial Repro:
- Click the button.
- Expected: Page scrolls down.
- Actual: Scroll stutters.
- Occurs 100% reliably.
If a repro is unstable, we must control variables (e.g., log requests, simulate responses locally). In my case, it was stable.
Problem: Claude couldn’t perceive "stutter" — it “lacks eyes.”
Without a quantifiable measure, the AI essentially has no usable repro. In human teams, similar issues arise when bugs show only under specific environments/configurations.
---
Step 2 — Narrow and Adjust the Repro
Changing a repro carries risk — it may drift away from the actual bug source.
But sometimes it’s unavoidable for collaboration.
> 🎯 Goal: Make the repro simpler, measurable, and scope-specific.
New repro idea for Claude:
- Record current scroll position.
- Click the button.
- Record scroll position again.
- Expected: Values differ.
- Actual: Values identical.
Although it doesn’t capture “jitter,” it indicates scroll didn’t happen — possibly related to the same root cause.
Claude implemented logging and simulated clicks with Playwright MCP — confirmed scroll position unchanged.
---
✅ Validate the New Repro
We must ensure this repro can detect a successful fix.
Test:
- Comment out the network request → Scroll position changes (passes repro).
- Restore request → Scroll position unchanged (fails repro).
Repeating this consistently showed correlation: network request’s presence directly affected scroll behavior.
---
Step 3 — Eliminate Unrelated Factors
Instructions for Claude:
- Run the repro → confirm bug exists.
- Remove something (component, event, style, import).
- Retest → if bug remains, commit; if fixed, note cause and revert.
- Repeat until minimal code remains with bug intact.
After iterative removals, Claude reduced the app to a single-file repro — but at one point deviated by testing speculative causes without keeping a bug-present version.
💡 Rule: Always keep a working repro of the bug while narrowing code — like well-founded recursion, each step must shrink scope and still reproduce the bug.
---
Step 4 — Identify the Root Cause
Following strict deletion rules:
- When removing a file from the routing system, scroll worked fine.
- Adding back → bug returned.
- Mounting as top-level route → bug disappeared.
The culprit was:
import { Outlet, ScrollRestoration } from "react-router-dom";
export function RootLayout() {
return (
);
}
🛠 Root Cause: A known React Router bug (fixed June) where `ScrollRestoration` triggered on every revalidation, not just route changes.
The `action`-triggered network request revalidated the route while scrolling, causing jitter.
---
Debugging Method Recap
- Reliable repro is non-negotiable.
- Narrow scope without losing bug presence.
- Keep deletion strictly incremental.
- Identify minimal cause → confirm fix.
This method helped me in past large-scale debugging — even stripping half of a React tree down to a 50‑line repro to expose the cause.
---
Related — Specification-Driven Development (Spec-Kit)
Specification-driven methods ensure code is anchored to verifiable requirements:
- Clear specs → what code must do.
- Linked tests → verify compliance automatically.
- Iterative updates → specs evolve with product needs.
Benefits:
- Consistency across teams.
- Predictability for integration.
- Confidence in frequent deploys.
---
Vibe Coding with Specs
A progressive coding loop:
- Draft spec.
- Minimal implement to meet it.
- Run spec-linked tests.
- Iterate based on feedback.
Prevents over-engineering and keeps focus on real goals.
---
Integration with AI Publishing — AiToEarn
Platforms like AiToEarn官网 integrate AI generation, multi-platform publishing, and analytics — enabling developers to:
- Share debugging techniques or specs on Douyin, Kwai, Bilibili, YouTube, LinkedIn, X(Twitter), etc.
- Track impact and monetize content.
- Manage distributed team workflows with connected testing and publishing pipelines.
Links:
AiToEarn博客 · AiToEarn开源地址 · AI模型排名
---
Conclusion
When faced with elusive UI bugs and timing issues:
- Build a quantifiable repro.
- Narrow scope systematically, without losing bug visibility.
- Confirm fixes objectively (not just by “feel”).
- Use living specifications to guide dev cycles.
- Share findings using multi-platform AI-aided publishing tools.
This makes your debugging repeatable, collaborative, and documentable — ensuring future issues are easier to track, test, and fix.