Skip to content

Commit a7abc1b

Browse files
committed
fix(sweep): P1 grid cardinality bound + P2 lance_fragment_path honesty
Two fixes from Codex review on the D3.1 sweep_handler: P1 — Reject oversized sweep grids before enumerate(). A small JSON payload with moderately-sized axes can explode into an enormous Cartesian product and exhaust CPU/memory. Added MAX_GRID_CARDINALITY = 10,000 check before materialization; returns 400 with explicit error message if exceeded. P2 — Stop echoing req.log_to_lance into lance_fragment_path. The D3.1 stub does NOT actually append rows to Lance; echoing the requested path back in the response falsely claims persistence that never occurred. Clients treating lance_fragment_path as evidence of successful logging would silently skip retries and lose experiment results. Set to None until the real Lance append writer lands (D3.1b). Same anti-#219 pattern: don't claim a measurement/persistence happened when it didn't. The stub:true flag on per-point results covers measurement-honesty; this fix covers persistence-honesty. 117/117 tests pass. Clippy clean under --features serve. https://claude.ai/code/session_01SbYsmmbPf9YQuYbHZN52Zh
1 parent 778e52a commit a7abc1b

1 file changed

Lines changed: 25 additions & 3 deletions

File tree

  • crates/cognitive-shader-driver/src

crates/cognitive-shader-driver/src/serve.rs

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -306,8 +306,25 @@ async fn sweep_handler(
306306
Json(req): Json<WireSweepRequest>,
307307
) -> Result<Json<WireSweepResponse>, (StatusCode, Json<Value>)> {
308308
let start = std::time::Instant::now();
309+
310+
// P1 — reject oversized grids before materialization. A small JSON
311+
// payload with moderately-sized axes can explode into a huge Cartesian
312+
// product; bound it so the endpoint isn't a DoS vector.
313+
const MAX_GRID_CARDINALITY: usize = 10_000;
314+
let cardinality = req.grid.cardinality();
315+
if cardinality > MAX_GRID_CARDINALITY {
316+
return Err((
317+
StatusCode::BAD_REQUEST,
318+
Json(json!({
319+
"error": format!(
320+
"sweep grid cardinality {cardinality} exceeds max {MAX_GRID_CARDINALITY}; \
321+
reduce axis dimensions"
322+
)
323+
})),
324+
));
325+
}
326+
309327
let candidates = req.grid.enumerate();
310-
let cardinality = candidates.len() as u32;
311328

312329
let mut results = Vec::with_capacity(candidates.len());
313330
for (idx, wire_params) in candidates.into_iter().enumerate() {
@@ -333,10 +350,15 @@ async fn sweep_handler(
333350

334351
Ok(Json(WireSweepResponse {
335352
label: req.label,
336-
cardinality,
353+
cardinality: cardinality as u32,
337354
results,
338355
elapsed_ms: start.elapsed().as_millis() as u64,
339-
lance_fragment_path: req.log_to_lance,
356+
// P2 — do NOT echo req.log_to_lance into the response when no rows
357+
// were actually written. Clients that treat lance_fragment_path as
358+
// evidence of successful logging would silently skip retries and
359+
// lose experiment results. Set to None until the real Lance append
360+
// writer lands (Phase 3 D3.1b).
361+
lance_fragment_path: None,
340362
}))
341363
}
342364

0 commit comments

Comments
 (0)