From asynkron-devtools
Applies test bombs for hypothesis elimination and layered tests for pipeline isolation to debug unclear root causes, like unknown bug origins or failing end-to-end tests.
npx claudepluginhub asynkron/asynkron-skills --plugin asynkron-devtoolsThis skill uses the workspace's default tool permissions.
| Technique | Use when | Finds |
Enforces root cause investigation for bugs, test failures, unexpected behavior, and performance issues through four phases before proposing fixes.
Enforces systematic root cause analysis before fixes for bugs, test failures, unexpected behavior, performance issues, and build failures.
Guides systematic debugging of bugs, test failures, or unexpected behavior via reproduce-understand-hypothesize-fix-verify phases before fixes.
Share bugs, ideas, or general feedback.
| Technique | Use when | Finds |
|---|---|---|
| Test Bomb | Root cause is unclear, multiple suspects | Which component/area is broken |
| Layered Test | System has a pipeline, output is wrong but stage is unclear | Which pipeline stage is broken |
| Both together | Complex bug in a pipeline system | Test bomb narrows the component, layered test pinpoints the stage |
A test bomb is a systematic debugging technique. Instead of writing one big test or guessing at the root cause, you:
H1_, H2_, H3_, etc.Each test is independent, fast, and documents exactly what it's proving or disproving.
/// TEST BOMB: Systematic elimination of suspected causes for [BUG DESCRIPTION].
public class [BugName]TestBomb(ITestOutputHelper output)
{
private readonly ITestOutputHelper _output = output;
// --- Section 1: [Area Name] ---
/// H1: [describe what you're testing and what pass/fail means]
[Fact(Timeout = 10000)]
public async Task H1_FirstHypothesis()
{
// Arrange — minimal setup for this one hypothesis
// Act — trigger the specific behavior
// Assert — one clear assertion
_output.WriteLine($"H1 Result: {result}");
Assert.Equal(expected, actual);
}
/// H2: [describe what you're testing]
[Fact(Timeout = 10000)]
public async Task H2_SecondHypothesis()
{
// ...
}
// --- Section 2: [Next Area] ---
/// H3: [describe what you're testing]
[Fact(Timeout = 10000)]
public async Task H3_ThirdHypothesis()
{
// ...
}
}
// TEST BOMB: Systematic elimination of suspected causes for [BUG].
describe('[BugName] Test Bomb', () => {
// --- Section 1: [Area Name] ---
// H1: [describe hypothesis]
test('H1_FirstHypothesis', async () => {
// ...
expect(actual).toBe(expected);
});
// H2: [describe hypothesis]
test('H2_SecondHypothesis', async () => {
// ...
});
});
# TEST BOMB: Systematic elimination of suspected causes for [BUG].
class TestBugNameTestBomb:
"""Systematic elimination of suspected causes for [BUG]."""
def test_h1_first_hypothesis(self):
"""H1: [describe hypothesis]"""
# ...
assert actual == expected
def test_h2_second_hypothesis(self):
"""H2: [describe hypothesis]"""
# ...
// TEST BOMB: Systematic elimination of suspected causes for [BUG].
func TestH1_FirstHypothesis(t *testing.T) {
// H1: [describe hypothesis]
// ...
if actual != expected {
t.Errorf("H1: got %v, want %v", actual, expected)
}
}
func TestH2_SecondHypothesis(t *testing.T) {
// H2: [describe hypothesis]
// ...
}
# C# / .NET
dotnet test --filter "FullyQualifiedName~TestBomb"
# TypeScript
npx vitest run --grep "Test Bomb"
# Python
pytest -k "TestBomb" -v
# Go
go test -run "TestH[0-9]+" -v ./...
| Pattern | Meaning |
|---|---|
| All pass | Bug is elsewhere — expand your hypotheses |
| All fail | Fundamental setup issue — check H1 carefully |
| One section fails | Root cause is in that area |
| Scattered failures | Multiple issues, or a shared dependency is broken |
| H1 passes, H3 fails | The difference between H1 and H3 isolates the cause |
A layered test isolates bugs in systems that process data through sequential stages. Instead of only testing the final output, you test each intermediate stage independently — so you know exactly where the pipeline breaks.
Input → Stage1 → Stage2 → Stage3 → Stage4 → Output
L0 L1 L2 L3 L4 L5
If L3 fails but L1 and L2 pass, the bug is in Stage3.
Source → Lexer → Parser → AST → Semantic Analysis → Code Gen → Output
L0 L1 L2 L3 L4 L5 L6
Request → Auth → Validation → Business Logic → Serialization → Response
L0 L1 L2 L3 L4 L5
Raw Data → Extract → Transform → Validate → Load → Query Result
L0 L1 L2 L3 L4 L5
Raw Data → Preprocessing → Feature Engineering → Model → Post-processing → Output
L0 L1 L2 L3 L4 L5
Source → Dependency Resolution → Compilation → Linking → Packaging → Artifact
L0 L1 L2 L3 L4 L5
/// LAYERED TESTS: Isolate which pipeline stage causes [BUG].
///
/// L1: [First stage] - does it produce correct intermediate output?
/// L2: [Second stage] - does it transform correctly?
/// L3: [Third stage] - does it handle the edge case?
/// L4: [Final stage] - full end-to-end assertion
/// L5: Side-by-side comparison of passing vs failing case
public class [BugName]LayeredTest(ITestOutputHelper output)
{
// ================================================================
// LAYER 1: [First Stage Name]
// ================================================================
/// L1_A: [what you're checking at this stage]
[Fact(Timeout = 10000)]
public async Task L1_A_Description()
{
// Get the intermediate output after stage 1
// Assert its structure/content is correct
}
// ================================================================
// LAYER 2: [Second Stage Name]
// ================================================================
/// L2_A: [what you're checking at this stage]
[Fact(Timeout = 10000)]
public async Task L2_A_Description()
{
// Get the intermediate output after stage 2
// Assert its structure/content is correct
}
// ================================================================
// LAYER N: Side-by-side comparison
// ================================================================
/// LN: Compare passing vs failing case at the broken layer
[Fact(Timeout = 10000)]
public async Task LN_ComparePassingVsFailing()
{
output.WriteLine("=== PASSING CASE ===");
// Run the passing input through the pipeline, log intermediate state
output.WriteLine("=== FAILING CASE ===");
// Run the failing input through the pipeline, log intermediate state
output.WriteLine("Compare the traces above to see the difference!");
}
}
// LAYERED TESTS: Isolate which pipeline stage causes [BUG].
describe('[BugName] Layered Test', () => {
// --- Layer 1: [First Stage] ---
test('L1_A_Description', () => {
const intermediate = stage1(input);
expect(intermediate).toMatchObject(expected);
});
// --- Layer 2: [Second Stage] ---
test('L2_A_Description', () => {
const intermediate = stage2(stage1(input));
expect(intermediate).toMatchObject(expected);
});
// --- Comparison ---
test('LN_ComparePassingVsFailing', () => {
console.log('=== PASSING CASE ===');
const passing = runPipeline(passingInput);
console.log(JSON.stringify(passing, null, 2));
console.log('=== FAILING CASE ===');
const failing = runPipeline(failingInput);
console.log(JSON.stringify(failing, null, 2));
});
});
# LAYERED TESTS: Isolate which pipeline stage causes [BUG].
class TestBugNameLayered:
"""Isolate which pipeline stage causes [BUG]."""
# --- Layer 1: [First Stage] ---
def test_l1_a_description(self):
"""L1_A: [what you're checking]"""
intermediate = stage1(input_data)
assert intermediate == expected
# --- Layer 2: [Second Stage] ---
def test_l2_a_description(self):
"""L2_A: [what you're checking]"""
intermediate = stage2(stage1(input_data))
assert intermediate == expected
| Pattern | Meaning |
|---|---|
| All layers pass | Bug is in integration between stages, not individual stages |
| L1 fails | Problem is at the first stage — likely input parsing |
| L1-L2 pass, L3 fails | Bug is in stage 3 — inspect L2 output going into L3 |
| Only last layer fails | All stages work individually — check final assembly |
| Intermittent failures | Likely state leaking between stages or timing issue |
Test bombs:
H1_CatchBlockReturnsUndefined not H1_TestLayered tests:
L1_A_, L2_A_, etc. — makes the progression obvious