Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion .claude/accuracy-sweep-state.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@
"curvature": { "last_inspected": "2026-03-30T15:00:00Z", "issue": null, "notes": "Formula matches ArcGIS reference. Backends consistent. No issues found." },
"hillshade": { "last_inspected": "2026-04-10T12:00:00Z", "issue": null, "notes": "Horn's method correct. All backends consistent. NaN propagation correct. float32 adequate for [0,1] output." },
"terrain": { "last_inspected": "2026-04-10T12:00:00Z", "issue": null, "notes": "Perlin/Worley/ridged noise correct. Dask chunk boundaries produce bit-identical results. No precision issues." },
"perlin": { "last_inspected": "2026-04-10T12:00:00Z", "issue": null, "notes": "Improved Perlin noise implementation correct. Fade/gradient functions verified. Backend-consistent. Continuous at cell boundaries." }
"perlin": { "last_inspected": "2026-04-10T12:00:00Z", "issue": null, "notes": "Improved Perlin noise implementation correct. Fade/gradient functions verified. Backend-consistent. Continuous at cell boundaries." },
"sieve": { "last_inspected": "2026-04-13T12:00:00Z", "issue": null, "notes": "Union-find CCL correct. NaN excluded from labeling. All backends funnel through _sieve_numpy." },
"polygonize": { "last_inspected": "2026-04-13T12:00:00Z", "issue": 1190, "notes": "NaN pixels not masked in numpy/dask backends. Fix in PR #1194." },
"cost_distance": { "last_inspected": "2026-04-13T12:00:00Z", "issue": 1191, "notes": "CuPy Bellman-Ford max_iterations = h+w instead of h*w. Fix in PR #1192." },
"visibility": { "last_inspected": "2026-04-13T12:00:00Z", "issue": null, "notes": "Bresenham line, LOS kernel, Fresnel zone all correct. All backends converge to numpy." },
"kde": { "last_inspected": "2026-04-13T12:00:00Z", "issue": 1198, "notes": "kde/line_density return zeros for descending-y templates. Fix in PR #1199." },
"polygon_clip": { "last_inspected": "2026-04-13T12:00:00Z", "issue": 1197, "notes": "crop=True + all_touched=True drops boundary pixels. Fix in PR #1200." },
"resample": { "last_inspected": "2026-04-14T12:00:00Z", "issue": 1202, "notes": "Interpolation used edge-aligned coords instead of block-centered. Fix in PR #1204." },
"balanced_allocation": { "last_inspected": "2026-04-14T12:00:00Z", "issue": 1203, "notes": "float32 allocation array caused source ID mismatch for non-integer IDs. Fix in PR #1205." },
"dasymetric": { "last_inspected": "2026-04-14T12:00:00Z", "issue": null, "notes": "Mass conservation correct. Weighted/binary/limiting_variable all verified. Pycnophylactic Tobler algorithm correct." }
}
}
28 changes: 17 additions & 11 deletions .claude/commands/sweep-performance.md
Original file line number Diff line number Diff line change
Expand Up @@ -395,12 +395,20 @@ If no modules qualify, print:
`--skip-phase1` to refresh the triage."
Then stop.

### 6b. Print the ralph-loop command
### 6b. Invoke the ralph-loop automatically

Using the target list, generate and print:
Using the target list, invoke the ralph-loop skill directly via the Skill tool.
Do NOT print the command for manual copy-paste — execute it immediately.

````
/ralph-loop "Performance sweep Phase 2: benchmark and fix HIGH-severity findings.
Set `--max-iterations` to the number of target modules plus 2 (buffer for
retries).

Call the Skill tool with `skill: "ralph-loop"` and pass the following as `args`
(with `<module>`, `<N>`, `<OOM verdict>`, `<SIZE>`, and `<N+2>` substituted
from the actual triage results):

```
"Performance sweep Phase 2: benchmark and fix HIGH-severity findings.

**Target modules in priority order:**
1. <module> (<N> HIGH findings, <OOM verdict>) -- <one-line summary of worst finding>
Expand Down Expand Up @@ -446,19 +454,17 @@ Using the target list, generate and print:

If all targets have been addressed or confirmed as false positives:
<promise>ALL PERFORMANCE ISSUES FIXED</promise>." --max-iterations <N+2> --completion-promise "ALL PERFORMANCE ISSUES FIXED"
````
```

Set `--max-iterations` to the number of target modules plus 2 (buffer for
retries).
### 6c. Print status

### 6c. Print reminder text
After invoking the ralph-loop, print:

```
Phase 1 triage complete. To proceed with fixes:
Copy the ralph-loop command above and paste it.
Phase 2 ralph-loop launched with <N> target modules.

Other options:
Fix one manually: copy any /rockout command from the report above
Fix one manually: copy any /rockout command from the triage report above
Rerun triage only: /sweep-performance --report-only
Skip Phase 1: /sweep-performance --skip-phase1 (reuses last triage)
Reset all tracking: /sweep-performance --reset-state
Expand Down
52 changes: 27 additions & 25 deletions .claude/performance-sweep-state.json
Original file line number Diff line number Diff line change
@@ -1,48 +1,50 @@
{
"last_triage": "2026-04-05T12:00:00Z",
"last_triage": "2026-04-14T12:00:00Z",
"modules": {
"reproject": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "RISKY", "bottleneck": "compute-bound", "high_count": 1, "issue": null },
"resample": { "last_inspected": "2026-04-15T12:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": "false-positive", "notes": "Downgraded. GPU-CPU-GPU round-trip only in aggregate path for non-integer scale factors. Interpolation (nearest/bilinear/cubic) stays on GPU. No GPU kernel exists for irregular per-pixel binning." },
"polygon_clip": { "last_inspected": "2026-04-15T12:00:00Z", "oom_verdict": "SAFE", "bottleneck": "memory-bound", "high_count": 0, "issue": 1207, "notes": "Fixed: pass dask chunks to rasterize() so mask stays lazy for dask inputs." },
"kde": { "last_inspected": "2026-04-14T12:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": null, "notes": "Graph construction serialized per-tile. _filter_points_to_tile scans all points per tile. No HIGH findings." },
"sieve": { "last_inspected": "2026-04-14T12:00:00Z", "oom_verdict": "WILL OOM", "bottleneck": "memory-bound", "high_count": 0, "issue": "false-positive", "notes": "False positive. Memory guards already in place on both dask paths. CCL is inherently global — documented limitation. CuPy CPU fallback is deliberate and documented." },
"bump": { "last_inspected": "2026-04-15T12:00:00Z", "oom_verdict": "SAFE", "bottleneck": "memory-bound", "high_count": 0, "issue": 1206, "notes": "Fixed: int32 coords, default-count cap at 10M, memory guard, per-chunk dask partitioning via dask.delayed. Graph serialization reduced ~250x." },
"reproject": { "last_inspected": "2026-04-15T12:00:00Z", "oom_verdict": "RISKY", "bottleneck": "compute-bound", "high_count": 0, "issue": "false-positive", "notes": "Downgraded to MEDIUM. Fast path .compute()-in-loop is intentional (~22x faster); falls back to map_blocks when output exceeds GPU VRAM. 16x16 thread blocks already mitigate register pressure in cubic kernel." },
"rasterize": { "last_inspected": "2026-04-15T12:00:00Z", "oom_verdict": "SAFE", "bottleneck": "graph-bound", "high_count": 0, "issue": "false-positive", "notes": "Downgraded. Tile-by-tile graph construction with per-tile geometry filtering is the correct pattern. Pre-filtering ensures each delayed task gets only its relevant subset. O(n_tiles) bbox check at graph-build time is vectorized and fast." },
"pathfinding": { "last_inspected": "2026-04-15T12:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": "false-positive", "notes": "Downgraded. CuPy .get() is required -- A* has no GPU kernel. Per-pixel .compute() is only 2 calls for start/goal validation. seg.values in multi_stop_search collects already-computed results for stitching." },
"geotiff": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "IO-bound", "high_count": 0, "issue": null, "notes": "False positive. open_geotiff(chunks=N) returns lazy dask array. to_geotiff auto-routes dask inputs to write_streaming. Eager paths are by design for numpy/cupy." },
"zonal": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "WILL OOM", "bottleneck": "memory-bound", "high_count": 4, "issue": 1110, "notes": "Memory guards improved, iterrows replaced with isin. da.unique().compute() confirmed safe (small result). regions() is inherently global - documented limitation." },
"viewshed": { "last_inspected": "2026-04-05T12:00:00Z", "oom_verdict": "SAFE", "bottleneck": "memory-bound", "high_count": 0, "issue": "fixed-in-tree", "notes": "Tier B memory estimate tightened from 280 to 368 bytes/pixel (accounts for lexsort double-alloc + computed raster). astype copy=False avoids needless float64 copy." },
"visibility": { "last_inspected": "2026-04-05T12:00:00Z", "oom_verdict": "SAFE", "bottleneck": "memory-bound", "high_count": 0, "issue": "fixed-in-tree", "notes": "Fixed: _extract_transect uses vindex for point extraction, cumulative_viewshed accumulates lazily with da.zeros + da.Array addition. All 3 HIGH findings resolved." },
"rasterize": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "graph-bound", "high_count": 1, "issue": null },
"bump": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "WILL OOM", "bottleneck": "memory-bound", "high_count": 0, "issue": null },
"normalize": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": 1124, "notes": "Boolean indexing replaced with lazy nanmin/nanmax/nanmean/nanstd." },
"mahalanobis": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "WILL OOM", "bottleneck": "memory-bound", "high_count": 1, "issue": null },
"bilateral": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": null },
"diffusion": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "WILL OOM", "bottleneck": "memory-bound", "high_count": 2, "issue": 1116, "notes": "Scalar diffusivity now passed as float to chunks. DataArray diffusivity passed as dask array via map_overlap." },
"multispectral": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": null },
"fire": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": null },
"proximity": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "WILL OOM", "bottleneck": "memory-bound", "high_count": 3, "issue": 1111, "notes": "Memory guard added to line-sweep path. KDTree path (EUCLIDEAN/MANHATTAN + scipy) already had guards. GREAT_CIRCLE unbounded path already guarded." },
"emerging_hotspots": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": null },
"classify": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": null },
"convolution": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": null },
"morphology": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": null },
"focal": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": null },
"glcm": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": null, "notes": "Downgraded to MEDIUM. da.stack without rechunk is scheduling overhead, not OOM risk." },
"surface_distance": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "memory-bound", "high_count": 0, "issue": 1128, "notes": "Memory guard added to dd_grid allocation." },
"cost_distance": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "WILL OOM", "bottleneck": "memory-bound", "high_count": 2, "issue": 1118, "notes": "Memory guard added + da.block assembly. Finite max_cost path (map_overlap) was already safe." },
"mahalanobis": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": null, "notes": "False positive. Numpy path materializes by design. Dask path uses lazy reductions + map_blocks." },
"bilateral": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": null },
"sky_view_factor": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": null },
"worley": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": null },
"flood": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": null },
"aspect": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": 1122, "notes": "northness/eastness now use da.cos/sin on dask arrays." },
"terrain": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "RISKY", "bottleneck": "compute-bound", "high_count": 0, "issue": null },
"terrain_metrics": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "memory-bound", "high_count": 0, "issue": null },
"slope": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": null },
"hillshade": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": null },
"diffusion": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "WILL OOM", "bottleneck": "memory-bound", "high_count": 2, "issue": 1116, "notes": "Scalar diffusivity now passed as float to chunks. DataArray diffusivity passed as dask array via map_overlap." },
"perlin": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "WILL OOM", "bottleneck": "memory-bound", "high_count": 0, "issue": null },
"curvature": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": null },
"hillshade": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": null },
"normalize": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": 1124, "notes": "Boolean indexing replaced with lazy nanmin/nanmax/nanmean/nanstd." },
"polygonize": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": null },
"contour": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": null },
"pathfinding": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 1, "issue": null },
"erosion": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "WILL OOM", "bottleneck": "memory-bound", "high_count": 2, "issue": 1120, "notes": "Memory guard added. Algorithm inherently global." },
"geodesic": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "N/A", "bottleneck": "compute-bound", "high_count": 0, "issue": null },
"balanced_allocation": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "WILL OOM", "bottleneck": "memory-bound", "high_count": 3, "issue": 1114, "notes": "Lazy source extraction + memory guard. Algorithm is inherently O(N*size) - documented limitation." },
"corridor": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": null },
"polygonize": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": null },
"edge_detection": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": null },
"multispectral": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": null },
"fire": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": null },
"proximity": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "WILL OOM", "bottleneck": "memory-bound", "high_count": 3, "issue": 1111, "notes": "Memory guard added to line-sweep path. KDTree path (EUCLIDEAN/MANHATTAN + scipy) already had guards. GREAT_CIRCLE unbounded path already guarded." },
"emerging_hotspots": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": null },
"dasymetric": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "memory-bound", "high_count": 0, "issue": 1126, "notes": "Memory guard added to validate_disaggregation. Core disaggregate uses map_blocks." },
"classify": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": null },
"convolution": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": null },
"morphology": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": null },
"focal": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": null },
"glcm": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 1, "issue": null },
"surface_distance": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "memory-bound", "high_count": 0, "issue": 1128, "notes": "Memory guard added to dd_grid allocation." },
"mahalanobis": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": null, "notes": "False positive. Numpy path materializes by design. Dask path uses lazy reductions + map_blocks." },
"glcm": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "compute-bound", "high_count": 0, "issue": null, "notes": "Downgraded to MEDIUM. da.stack without rechunk is scheduling overhead, not OOM risk." }
"erosion": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "WILL OOM", "bottleneck": "memory-bound", "high_count": 2, "issue": 1120, "notes": "Memory guard added. Algorithm inherently global." },
"dasymetric": { "last_inspected": "2026-03-31T18:00:00Z", "oom_verdict": "SAFE", "bottleneck": "memory-bound", "high_count": 0, "issue": 1126, "notes": "Memory guard added to validate_disaggregation. Core disaggregate uses map_blocks." }
}
}
Loading
Loading