con un clic
subtest-isolation
// Create minimal subtests to isolate and fix complex bugs. Use when a test fails and the issue is buried in complexity.
// Create minimal subtests to isolate and fix complex bugs. Use when a test fails and the issue is buried in complexity.
Codebase organization for pikru. Use when you need to find where specific functionality lives.
Code annotation requirements for pikru. Use when writing or porting Rust functions from C code. All ported functions must have cref comments.
Debugging conventions for pikru. Use when adding debug traces or investigating issues. Important rule - leave debug traces in place.
Git command conventions for pikru. Use when running any git commands to avoid blocking on interactive pager.
Idiomatic Rust patterns for pikru C port. Use when writing or reviewing Rust code ported from C. Don't write C in Rust - the goal is correct behavior, not line-by-line translation.
Testing conventions for pikru. Use when running tests to avoid timeouts. DO NOT run the full test suite.
| name | subtest-isolation |
| description | Create minimal subtests to isolate and fix complex bugs. Use when a test fails and the issue is buried in complexity. |
When a test fails with complex output or multiple issues, create a minimal subtest to isolate and fix ONE specific problem at a time.
Use subtest isolation when:
Don't use for:
Look at the failing test output and pinpoint EXACTLY what's wrong:
Example from test45:
Problem identified: Bottom box has all text overlapping incorrectly.
"center" text appearing at the very top instead of middle.
Create a new test file (e.g., test45b.pikchr) with ONLY the problematic element:
# test45b.pikchr - isolate the bottom box issue
box "rjust" rjust above "center" center "ljust" ljust above \
"rjust" rjust below "ljust" ljust below big big
Key principles:
<original>b.pikchr for clarityRun the subtest and confirm it shows the SAME bug:
cargo run --example simple -- vendor/pikchr-c/tests/test45b.pikchr
# OR
mcp__pikru-test__run_pikru_test test45b
Check that:
Add targeted debug output to understand what's happening:
eprintln!("[SLOT HEIGHT] text='{}' slot={:?} font_scale={} charht={} h={}",
text.value, slot, text.font_scale(), charht, h);
eprintln!("[Y OFFSET] text='{}' slot={:?} calc=[{}] y_offset={} final_y={}",
positioned_text.value, slot, offset_calc, y_offset, center.y + svg_y_offset);
Debug output best practices:
eprintln! so it goes to stderr (doesn't corrupt SVG output)[SLOT HEIGHT], [Y OFFSET] for easy greppingRun the subtest and analyze the debug output:
cargo run --example simple -- vendor/pikchr-c/tests/test45b.pikchr 2>&1 | grep '\[SLOT'
Look for:
Example output that revealed the bug:
[SLOT HEIGHT] text='center' slot=Above2 font_scale=1 charht=0.14 h=0.14
→ BUG FOUND: "center" text assigned to Above2 instead of Center!
Run the C implementation on the same subtest:
vendor/pikchr-c/pikchr --svg-only vendor/pikchr-c/tests/test45b.pikchr | grep '<text'
Compare:
Example comparison:
C output: <text y="38.16" ...>center</text>
Rust output: <text y="12.24" ...>center</text>
→ Confirms the bug: Rust placing center text way too high
Based on debug output and comparison:
Example fix:
// BUG: wasn't checking t.center
else if t.center {
Some(TextVSlot::Center) // ← FIX: explicitly assign Center slot
}
Run the subtest again - it should now MATCH:
mcp__pikru-test__run_pikru_test test45b
Expect:
{"test_name":"test45b","status":"match","comparison":{"ssim":1.0, ...}}
Clean up the debug statements you added:
// Remove all the eprintln! statements
// Keep the code clean for production
Run the original test to confirm the fix works in context:
mcp__pikru-test__run_pikru_test test45
If it still fails:
If it passes:
Keep the subtest if:
Remove the subtest if:
Original problem:
Subtest creation:
# test45b.pikchr - just the problematic box
box "rjust" rjust above "center" center "ljust" ljust above \
"rjust" rjust below "ljust" ljust below big big
Debug output revealed:
[SLOT HEIGHT] text='center' slot=Above2 ... ← WRONG! Should be Center
Root cause found:
center text attribute wasn't being handled in slot assignmentFix applied:
// Added center field to PositionedText
// Handle TextAttr::Center in parsing
// Check t.center when assigning initial slots
Result:
Show the calculation:
eprintln!("calc=[Above: 0.5*{} + 0.5*{} = {}]", hc, ha1, offset);
Track state transitions:
eprintln!("[BEFORE] slot={:?} y_offset={}", slot, y_offset);
// ... calculation ...
eprintln!("[AFTER] y_offset={} final_y={}", y_offset, final_y);
Use structured prefixes:
[SLOT HEIGHT] // For slot height calculations
[Y OFFSET] // For y-coordinate calculations
[ASSIGNMENT] // For slot assignments
[FINAL] // For final values
If the first subtest doesn't reproduce the bug:
If you find multiple bugs:
If debug output doesn't reveal the issue:
The goal is laser focus:
Not: