Rubber duck debugging
Ready-to-copy 5W1H debugging template, MRE construction steps, a standard template for describing bugs to an agent, common cognitive traps with how to overcome them, and effective debugging log recording formats.
A SKILL should ship question templates: what is the input, what output was expected, where did reality diverge, and what hypotheses were already ruled out. The sections below cover pacing, agent roles, and how to compress narration into a short, copyable script.
When to use
Best when logic branches are dense, state lives mostly in your head, or things “feel wrong” but are hard to name. Less useful when logs already show a failing assertion and the stack points to a line — then follow the evidence directly.
5W1H analysis template (copy and fill at the start of any debugging session):
## Bug 5W1H Analysis
**What (expected behavior)**:
After clicking "Submit Order," the user should be redirected to the order confirmation page with an order number displayed
**What (actual behavior)**:
Page is blank; console error: TypeError: Cannot read properties of undefined (reading 'id')
Network panel: POST /api/orders returned 201, response body includes orderId
**When (under what conditions)**:
Only reproduces when the "coupon code" field is filled before submitting; works fine without a coupon
**Where (module / file / line)**:
checkout/OrderConfirm.tsx line 42:
const { id } = order.coupon; ← crashes when coupon is null
**Why (current hypothesis)**:
order.coupon is null when no coupon is used, not {},
but the code does not null-check it
**How (repro steps)**:
1. Log in
2. Add any item to cart
3. Enter coupon code "TEST10" on checkout page
4. Click Submit Order → blank screen
**Already tried**:
- Checked API response: coupon field returns null (not {}) when no coupon is used
- Tried optional chaining: order?.coupon?.id → no crash but redirect logic still broken
Narration and the first divergence
Cover only a small slice of statements or call chain per turn: say what you read in and what you expect, then walk downward until you hit the first intermediate state that does not match. Do not narrate the whole module at once.
[ State inputs / expected / observed ]
│
▼
[ Walk line-by-line or call-by-call ]
│
┌────────┴────────┐
▼ ▼
[ Intermediate OK? ] [ Mismatch found ]
│ │
│ yes ▼
│ [ Stop: first divergence ]
│ │
└──────────► [ Hypothesis + smallest check ]
│
▼
[ Confirm / falsify → update model ]
- When a hypothesis fails, record it in a comment or ticket so you do not repeat the mistake.
- Concurrency: narration must name threads, locks, and memory ordering — never skip “who goes first.”
Working with an agent
Two configurable modes: listen-only — the agent restates what it heard and flags leaps; ask, do not guess — it asks when information is missing instead of dumping a patch. If speech and code disagree, point at the mismatch before debating edits.
For agents: while the human narrates, do not rush to a fix; restate understanding and mark logical jumps. If the human sees the model inventing details, interrupt and demand concrete symbols or line ranges.
MRE construction and cognitive traps
Chain with a “bug reproduction” skill: narrate the repro path first, then the code path, then shrink to a minimal case. Wrong order wastes a long session on the wrong branch.
MRE (Minimal Reproducible Example) construction steps:
Step 1: Confirm the bug reproduces reliably in the full application
→ Record the steps or write an automated test case to reproduce it
Step 2: Remove external dependencies unrelated to the bug
→ Replace API calls with mocks/stubs (using msw or jest.fn)
→ Remove the auth layer (use a hardcoded test user)
→ Disable unrelated feature flags
Step 3: Minimize the data
→ Reduce 100 test records to 1–2 that trigger the bug
→ Identify the minimum fields needed (e.g. bug only occurs when coupon is filled)
Step 4: Isolate to a single function test
→ Write a unit test that calls the problematic function directly
it('should handle null coupon', () => {
const order = { id: '123', coupon: null };
expect(() => renderConfirmPage(order)).not.toThrow();
});
Step 5: If still cannot reproduce, compare environments
→ Node version (node -v)
→ Dependency versions (package-lock.json diff)
→ Environment variables (process.env.FEATURE_FLAG)
→ Browser version / OS
Standard template for describing a bug to an Agent (copy and paste):
---
I encountered a bug. Please help me analyze the cause.
**Environment**: Node 20.x / React 18 / TypeScript 5.x
**File**: src/checkout/OrderConfirm.tsx, line 42
**Error message**: TypeError: Cannot read properties of undefined (reading 'id')
**Minimal reproduction**:
const order = { id: '123', coupon: null };
const { id } = order.coupon; // ← crashes here
**Expected behavior**: when coupon is null, id should be undefined, not throw
**Actual behavior**: throws TypeError immediately
**My hypothesis**: needs a null check, but I'm unsure which layer should handle it
**Already tried**: optional chaining (`order?.coupon?.id`) fixes the crash but redirect logic still broken
---
Common cognitive traps and how to overcome them
Trap 1: Confirmation bias (only looking at evidence that supports your hypothesis)
Symptom: "I think it's a caching issue, so I only checked cache logs"
Overcome: list 3 mutually exclusive hypotheses first; find evidence to falsify each
Check: can you find evidence that disproves your current hypothesis?
Trap 2: Environment difference (it works locally so it must work everywhere)
Symptom: "It runs fine locally; CI failing must not be my code"
Overcome: reproduce CI environment with Docker:
docker run --rm -v $(pwd):/app node:20 sh -c "cd /app && npm ci && npm test"
Check: list all env vars completely and compare
Trap 3: Anchoring bias (assuming it's module A, ignoring module B)
Symptom: spent 2 hours debugging module A; turned out module B passed bad data
Overcome: trace upward from the bottom of the error stack, not from the "most suspicious place"
Check: set a breakpoint at the exact line where the error occurs; do not guess
Effective debug log format
// Effective debug logs (actionable):
console.log('[validateCoupon] input:', {
couponCode: code, // exact input value
userId, // context
timestamp: Date.now() // timestamp (helps diagnose race conditions)
});
console.log('[validateCoupon] db result:', {
found: !!coupon,
expired: coupon?.expiresAt < Date.now(),
usageCount: coupon?.usageCount // key state
});
// Ineffective debug logs (cannot locate the issue):
console.log('here'); // no context
console.log(data); // whole object; unclear what to focus on
console.log('error!'); // no error type or value
Script builder
Fill the three fields below and click generate to produce a short block you can paste into chat or a PR. Data stays in this browser tab (localStorage); nothing is uploaded.
---
name: rubber-duck-debug
description: Step-by-step narration and externalized assumptions
---
# Step 1: Fill the 5W1H template (required before starting)
What (expected behavior): ___
What (actual behavior): include error message / code / stack trace
When (trigger condition): only happens when ___
Where (exact location): file:line
Why (current hypothesis): up to 3 mutually exclusive hypotheses
How (repro steps): fewest steps to reproduce
# Step 2: Confirm the bug reproduces reliably
Reproduce 3 times in a row before starting analysis
Record reproducibility (100% / intermittent / specific users only)
# Step 3: Build MRE (minimal reproduction)
Starting from the full application, progressively remove irrelevant dependencies:
a. Replace API calls with mocks (msw / jest.fn)
b. Remove auth layer; use hardcoded test data
c. Minimize data: find the fewest fields that trigger the bug
d. Write a unit test that calls the problematic function directly
# Step 4: Narrate line-by-line (find the first divergence)
Starting from the function entry point, say for each step:
"I expect X, but got Y, because Z"
Stop at the first mismatch; do not continue past it
# Step 5: Check for cognitive traps
Confirmation bias: am I only looking at evidence that supports my hypothesis?
Environment difference: does the bug reproduce in CI/Docker?
Anchoring bias: have I traced upward from the bottom of the error stack?
# Step 6: Record conclusions
Root cause (one sentence): ___
Fix: ___
Prevention (test / lint rule): ___
Write to PR description or issue to prevent recurrence