Phase 1: Bug Triage and Reproduction
- Gather Information
- Error messages and stack traces
- Steps to reproduce
- Environment details (VS Code version, OS, extension version)
- Frequency (always, intermittent, specific conditions)
- Classify Bug Type
| Category | Symptoms | Priority |
|----------|----------|----------|
| Crash | Extension host crash, unhandled rejection | P0 |
| Memory Leak | Increasing memory usage over time | P0 |
| Data Loss | State not persisted, data corruption | P0 |
| Functionality | Feature not working as expected | P1 |
| Performance | Slow response, UI lag | P1 |
| UI/UX | Visual glitches, incorrect display | P2 |
- Create Minimal Reproduction
- Isolate the failing scenario
- Document exact steps
- Identify triggering conditions
Phase 2: Root Cause Analysis
#### Error Analysis Strategy
```typescript
// Add strategic logging for investigation
console.log('[DEBUG] State before operation:', JSON.stringify(state));
try {
await problematicOperation();
} catch (error) {
console.error('[DEBUG] Error details:', {
message: error.message,
stack: error.stack,
context: currentContext
});
throw error;
}
```
#### Common Root Cause Patterns
1. Dispose Handler Issues
```typescript
// Bug: Missing dispose registration
const listener = vscode.workspace.onDidChangeConfiguration(...);
// listener never disposed!
// Fix: Always register disposables
context.subscriptions.push(
vscode.workspace.onDidChangeConfiguration(...)
);
```
2. Race Conditions
```typescript
// Bug: Concurrent operations conflict
async function createTerminal() {
if (isCreating) return; // Insufficient guard
isCreating = true;
// ... creation logic
}
// Fix: Use atomic operation pattern
private creationPromise: Promise | null = null;
async function createTerminal(): Promise {
if (this.creationPromise) {
return this.creationPromise;
}
this.creationPromise = this.doCreateTerminal();
try {
await this.creationPromise;
} finally {
this.creationPromise = null;
}
}
```
3. WebView Message Timing
```typescript
// Bug: Message sent before WebView ready
panel.webview.postMessage({ type: 'init', data });
// Fix: Wait for ready signal
panel.webview.onDidReceiveMessage(msg => {
if (msg.type === 'ready') {
panel.webview.postMessage({ type: 'init', data });
}
});
```
4. Null/Undefined Reference
```typescript
// Bug: Assuming object exists
const terminal = this.terminals.get(id);
terminal.write(data); // Crash if undefined!
// Fix: Defensive access with early return
const terminal = this.terminals.get(id);
if (!terminal) {
console.warn(Terminal ${id} not found);
return;
}
terminal.write(data);
```
5. Async/Await Errors
```typescript
// Bug: Unhandled promise rejection
someAsyncFunction(); // No await, no catch!
// Fix: Proper error handling
try {
await someAsyncFunction();
} catch (error) {
vscode.window.showErrorMessage(Operation failed: ${error.message});
}
```
Phase 3: Fix Implementation
#### Fix Implementation Checklist
- [ ] Identify all affected code paths
- [ ] Consider edge cases and error scenarios
- [ ] Maintain backward compatibility
- [ ] Add defensive null checks
- [ ] Ensure proper error handling
- [ ] Register all disposables
- [ ] Add logging for debugging
- [ ] Consider performance impact
#### Safe Fix Patterns
Pattern 1: Guard Clause
```typescript
async function processTerminal(id: number): Promise {
// Early validation
if (id < 1 || id > MAX_TERMINALS) {
throw new Error(Invalid terminal ID: ${id});
}
const terminal = this.getTerminal(id);
if (!terminal) {
console.warn(Terminal ${id} not found, skipping);
return;
}
// Safe to proceed
await terminal.process();
}
```
Pattern 2: Try-Catch-Finally
```typescript
async function safeOperation(): Promise {
const resource = await acquireResource();
try {
await performOperation(resource);
} catch (error) {
await handleError(error);
throw error; // Re-throw after logging
} finally {
await releaseResource(resource); // Always cleanup
}
}
```
Pattern 3: Timeout Protection
```typescript
async function operationWithTimeout(
operation: Promise,
timeoutMs: number
): Promise {
const timeout = new Promise((_, reject) =>
setTimeout(() => reject(new Error('Operation timed out')), timeoutMs)
);
return Promise.race([operation, timeout]);
}
```
Phase 4: Verification
#### Testing Strategy
- Unit Test the Fix
```typescript
describe('Bug Fix: Terminal creation race condition', () => {
it('should handle concurrent creation requests', async () => {
const manager = new TerminalManager();
// Simulate concurrent requests
const results = await Promise.all([
manager.createTerminal(),
manager.createTerminal(),
manager.createTerminal()
]);
// Verify only expected terminals created
expect(manager.getTerminalCount()).toBe(expectedCount);
});
});
```
- Integration Test
- Test the actual user workflow
- Verify fix in different scenarios
- Check for regressions
- Manual Verification
- Follow original reproduction steps
- Verify error no longer occurs
- Test related functionality