Skip to content

Commit 8faf5a7

Browse files
authored
Merge pull request #238 from AdaWorldAPI/claude/teleport-session-setup-wMZfb
D3.1 batch sweep handler + clippy -D warnings clean (117/117 tests)
2 parents a927bf7 + a7abc1b commit 8faf5a7

11 files changed

Lines changed: 118 additions & 28 deletions

File tree

.claude/board/STATUS_BOARD.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ afterwards is a JIT kernel, not a rebuild. Plan path:
7878

7979
| D-id | Title | Status | PR / Evidence |
8080
|---|---|---|---|
81-
| D3.1 | Server-side sweep handler + Lance fragment append | **Queued** | target ~200 LOC |
81+
| D3.1 | Server-side sweep handler + Lance fragment append | **In PR** | branch — `sweep_handler` batch mode: enumerates `WireSweepGrid::enumerate()`, validates each via TryFrom(CodecParams) at ingress, returns `WireSweepResponse { results: [WireSweepResult { kernel_hash, stub:true }], cardinality, elapsed_ms }`. SSE streaming + real calibrate/token-agreement per point deferred to D3.1b. Route: `POST /v1/shader/sweep`. |
8282
| D3.2 | Client-side driver + config files | **Queued** | target ~20 LOC + YAML configs |
8383

8484
### Phase 4 — Frontier analysis — Queued

crates/cognitive-shader-driver/Cargo.toml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,12 @@ tonic-build = { version = "0.12", optional = true }
6868
default = []
6969
with-engine = ["dep:thinking-engine"]
7070
with-planner = ["dep:lance-graph-planner"]
71-
serve = ["dep:serde", "dep:serde_json", "dep:axum", "dep:tokio", "dep:base64", "dep:bytemuck"]
72-
grpc = ["dep:prost", "dep:tonic", "dep:tonic-build", "dep:tokio"]
71+
# Shared LAB DTOs — `wire.rs` + `auto_detect.rs` + codec kernel scaffolds
72+
# + token_agreement use these regardless of whether the transport is REST
73+
# (serve) or gRPC (grpc). Both features pull this set.
74+
_lab-dtos = ["dep:serde", "dep:serde_json", "dep:base64", "dep:bytemuck"]
75+
serve = ["_lab-dtos", "dep:axum", "dep:tokio"]
76+
grpc = ["_lab-dtos", "dep:prost", "dep:tonic", "dep:tonic-build", "dep:tokio"]
7377

7478
# `lab` — umbrella switch for the single shader-lab binary. Enables every
7579
# endpoint (REST + gRPC), the planner bridge, the thinking-engine bridge,

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
//! If nothing dominates (`max < threshold`), fall back to Deliberate.
1818
1919
use lance_graph_contract::cognitive_shader::StyleSelector;
20-
use crate::bindspace::QUALIA_DIMS;
20+
2121

2222
/// Mapping from qualia shape to a style ordinal (0..11 matches
2323
/// `thinking_engine::cognitive_stack::ThinkingStyle::all()`).
@@ -104,6 +104,7 @@ pub fn resolve(sel: StyleSelector, qualia_row: &[f32]) -> u8 {
104104
#[cfg(test)]
105105
mod tests {
106106
use super::*;
107+
use crate::bindspace::QUALIA_DIMS;
107108

108109
fn q(vals: &[(usize, f32)]) -> [f32; QUALIA_DIMS] {
109110
let mut out = [0.0f32; QUALIA_DIMS];

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ impl OrchestrationBridge for CodecResearchBridge {
4646
let req: WireTensorsRequest = serde_json::from_str(args)
4747
.map_err(|e| OrchestrationError::ExecutionFailed(e.to_string()))?;
4848
let r = codec_research::list_tensors(&req)
49-
.map_err(|e| OrchestrationError::ExecutionFailed(e))?;
49+
.map_err(OrchestrationError::ExecutionFailed)?;
5050
step.status = StepStatus::Completed;
5151
step.reasoning = Some(format!(
5252
"tensors total={} cam_pq={} passthrough={} skip={}",
@@ -58,7 +58,7 @@ impl OrchestrationBridge for CodecResearchBridge {
5858
let req: WireCalibrateRequest = serde_json::from_str(args)
5959
.map_err(|e| OrchestrationError::ExecutionFailed(e.to_string()))?;
6060
let r = codec_research::calibrate_tensor(&req)
61-
.map_err(|e| OrchestrationError::ExecutionFailed(e))?;
61+
.map_err(OrchestrationError::ExecutionFailed)?;
6262
step.status = StepStatus::Completed;
6363
step.confidence = Some(r.icc_3_1 as f64);
6464
step.reasoning = Some(format!(
@@ -71,7 +71,7 @@ impl OrchestrationBridge for CodecResearchBridge {
7171
let req: WireProbeRequest = serde_json::from_str(args)
7272
.map_err(|e| OrchestrationError::ExecutionFailed(e.to_string()))?;
7373
let r = codec_research::row_count_probe(&req)
74-
.map_err(|e| OrchestrationError::ExecutionFailed(e))?;
74+
.map_err(OrchestrationError::ExecutionFailed)?;
7575
step.status = StepStatus::Completed;
7676
step.reasoning = Some(format!(
7777
"probe tensor={} n_rows={} entries={}",

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ fn route_str(r: CodecRoute) -> &'static str {
175175
}
176176
}
177177

178+
#[allow(clippy::type_complexity)]
178179
fn load_tensor_rows(
179180
model_path: &str,
180181
tensor_pattern: &str,

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
//! round-trip, no quantization loss, matches Rule F "serialise once at
1717
//! edge" — the decode/encode IS the edge).
1818
//! - [`ResidualComposer`] — composes two decoders with subtract/add:
19-
//! `decode(enc) = base.decode(enc[..k]) + residual.decode(enc[k..])`
20-
//! `encode(v) = [base.encode(v); residual.encode(v - base.decode(base.encode(v)))]`
19+
//! `decode(enc) = base.decode(enc[..k]) + residual.decode(enc[k..])`
20+
//! `encode(v) = [base.encode(v); residual.encode(v - base.decode(base.encode(v)))]`
2121
//! Depth `d > 1` recurses: the residual field itself is a `ResidualComposer`.
2222
2323
use std::collections::hash_map::DefaultHasher;

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -333,9 +333,9 @@ fn style_ord_to_inference(ord: u8) -> InferenceType {
333333
// intuitive/deliberate → Revision
334334
// metacognitive → Synthesis
335335
match ord {
336-
1 | 2 | 3 => InferenceType::Deduction,
337-
4 | 5 | 6 => InferenceType::Induction,
338-
7 | 8 | 9 => InferenceType::Abduction,
336+
1..=3 => InferenceType::Deduction,
337+
4..=6 => InferenceType::Induction,
338+
7..=9 => InferenceType::Abduction,
339339
0 | 10 => InferenceType::Revision,
340340
_ => InferenceType::Synthesis,
341341
}

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

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ impl CognitiveShaderService for ShaderGrpcService {
185185
route_filter: if req.route_filter.is_empty() { None } else { Some(req.route_filter) },
186186
};
187187
let r = crate::codec_research::list_tensors(&wire_req)
188-
.map_err(|e| Status::invalid_argument(e))?;
188+
.map_err(Status::invalid_argument)?;
189189
Ok(Response::new(pb::TensorsResponse {
190190
total: r.total as u32,
191191
shown: r.shown as u32,
@@ -210,14 +210,19 @@ impl CognitiveShaderService for ShaderGrpcService {
210210
let wire_req = crate::wire::WireCalibrateRequest {
211211
model_path: req.model_path,
212212
tensor_name: req.tensor_name,
213+
// D0.1 extension fields — gRPC path uses legacy num_*
214+
// fields only; the richer CodecParams + TensorView path is
215+
// REST-only until the proto schema catches up (D0.3b).
216+
params: None,
217+
tensor_view: None,
213218
num_subspaces: if req.num_subspaces == 0 { 6 } else { req.num_subspaces as usize },
214219
num_centroids: if req.num_centroids == 0 { 256 } else { req.num_centroids as usize },
215220
kmeans_iterations: if req.kmeans_iterations == 0 { 20 } else { req.kmeans_iterations as usize },
216221
max_rows: if req.max_rows == 0 { None } else { Some(req.max_rows as usize) },
217222
icc_samples: if req.icc_samples == 0 { 512 } else { req.icc_samples as usize },
218223
};
219224
let r = crate::codec_research::calibrate_tensor(&wire_req)
220-
.map_err(|e| Status::invalid_argument(e))?;
225+
.map_err(Status::invalid_argument)?;
221226
Ok(Response::new(pb::CalibrateResponse {
222227
tensor_name: r.tensor_name,
223228
dims: r.dims,
@@ -248,7 +253,7 @@ impl CognitiveShaderService for ShaderGrpcService {
248253
icc_samples: if req.icc_samples == 0 { 512 } else { req.icc_samples as usize },
249254
};
250255
let r = crate::codec_research::row_count_probe(&wire_req)
251-
.map_err(|e| Status::invalid_argument(e))?;
256+
.map_err(Status::invalid_argument)?;
252257
Ok(Response::new(pb::ProbeResponse {
253258
tensor_name: r.tensor_name,
254259
n_rows: r.n_rows as u32,

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

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -112,37 +112,40 @@ pub mod sigma_rosetta;
112112
// reachable through the canonical bridge.
113113

114114
// Per-op Wire DTOs (REST + protobuf). LAB-ONLY.
115-
#[cfg(feature = "serve")]
115+
// Gated on `any(serve, grpc)` because both transports share the same
116+
// DTOs; gRPC consumers (grpc.rs) and REST consumers (serve.rs) both
117+
// convert to/from the `Wire*` types in wire.rs.
118+
#[cfg(any(feature = "serve", feature = "grpc"))]
116119
pub mod wire;
117120

118121
// D0.5 — model architecture auto-detection from config.json.
119122
// CODING_PRACTICES.md gap 1 remediation. LAB-ONLY.
120-
#[cfg(feature = "serve")]
123+
#[cfg(any(feature = "serve", feature = "grpc"))]
121124
pub mod auto_detect;
122125

123126
// D1.1 — JIT kernel cache keyed by CodecParams::kernel_signature().
124127
// Structural layer; actual Cranelift IR emission defers to D1.1b. LAB-ONLY.
125-
#[cfg(feature = "serve")]
128+
#[cfg(any(feature = "serve", feature = "grpc"))]
126129
pub mod codec_kernel_cache;
127130

128131
// D1.2 — rotation primitives (Identity / Hadamard / OPQ-stub). LAB-ONLY.
129132
// Hadamard is real (in-place butterfly); OPQ is stub pending D1.1b's
130133
// ndarray::hpc::jitson_cranelift::JitEngine adapter + matrix-blob loader.
131-
#[cfg(feature = "serve")]
134+
#[cfg(any(feature = "serve", feature = "grpc"))]
132135
pub mod rotation_kernel;
133136

134137
// D1.3 — decode-kernel trait + residual composition.
135138
// Hydration/calibration path (NOT cascade inference — that uses
136139
// p64_bridge::CognitiveShader per cognitive-shader-architecture.md
137140
// line 582). LAB-ONLY.
138-
#[cfg(feature = "serve")]
141+
#[cfg(any(feature = "serve", feature = "grpc"))]
139142
pub mod decode_kernel;
140143

141144
// D2.1 — token-agreement harness scaffold (I11 cert gate infra).
142145
// Reference model loader stub + top-k comparator + stub result with
143146
// machine-checkable `stub:true` flag. D2.2 adds real safetensors decode.
144147
// LAB-ONLY.
145-
#[cfg(feature = "serve")]
148+
#[cfg(any(feature = "serve", feature = "grpc"))]
146149
pub mod token_agreement;
147150

148151
// Axum REST server. LAB-ONLY.

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

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,9 @@ use crate::wire::{
5050
WireCalibrateRequest, WireCalibrateResponse, WireCrystal, WireDispatch, WireHealth,
5151
WireIngest, WirePlanRequest, WirePlanResponse, WireProbeRequest, WireProbeResponse,
5252
WireQualia, WireRunbookRequest, WireRunbookResponse, WireRunbookStep,
53-
WireRunbookStepResult, WireStepResult, WireStyleInfo, WireTensorsRequest,
54-
WireTensorsResponse, WireTokenAgreement, WireTokenAgreementResult, WireUnifiedStep,
53+
WireRunbookStepResult, WireStepResult, WireStyleInfo, WireSweepRequest,
54+
WireSweepResponse, WireSweepResult, WireTensorsRequest, WireTensorsResponse,
55+
WireTokenAgreement, WireTokenAgreementResult, WireUnifiedStep,
5556
};
5657
use lance_graph_contract::cam::CodecParams;
5758
use std::path::Path as StdPath;
@@ -96,6 +97,13 @@ pub fn router(driver: ShaderDriver) -> Router {
9697
// `backend:"stub"` so clients cannot confuse Phase 0 stub output
9798
// for a real measurement (anti-#219 defense, type-level).
9899
.route("/v1/shader/token-agreement", post(token_agreement_handler))
100+
// D3.1 — codec sweep endpoint (batch mode). Client POSTs a
101+
// WireSweepRequest containing a cross-product grid; handler
102+
// enumerates grid, validates each candidate, builds stub results,
103+
// returns WireSweepResponse. SSE streaming + Lance append land in
104+
// D3.1b; this batch path stays for clients that want all results
105+
// in one response without streaming.
106+
.route("/v1/shader/sweep", post(sweep_handler))
99107
// Scheduled runbook: one POST runs a list of steps. Test injection
100108
// lands here — a client script submits its full codec-research
101109
// protocol as a single DTO, the server executes and returns all
@@ -284,6 +292,76 @@ async fn token_agreement_handler(
284292
.map_err(|e| (StatusCode::BAD_REQUEST, Json(json!({"error": format!("{e}")}))))
285293
}
286294

295+
/// D3.1 — `POST /v1/shader/sweep` handler (batch mode).
296+
///
297+
/// Enumerates the cross-product grid from `WireSweepRequest`, validates
298+
/// each candidate via TryFrom(CodecParams), computes kernel_signature +
299+
/// backend per point, and returns all results in one `WireSweepResponse`.
300+
///
301+
/// Stub: per-point calibrate/token_agreement are `None`; Phase 3 real
302+
/// handler invokes the actual codec_research + token_agreement harness.
303+
/// SSE streaming variant (D3.1b) replaces the batch return with per-point
304+
/// Server-Sent Events.
305+
async fn sweep_handler(
306+
Json(req): Json<WireSweepRequest>,
307+
) -> Result<Json<WireSweepResponse>, (StatusCode, Json<Value>)> {
308+
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+
327+
let candidates = req.grid.enumerate();
328+
329+
let mut results = Vec::with_capacity(candidates.len());
330+
for (idx, wire_params) in candidates.into_iter().enumerate() {
331+
// Validate each grid point at ingress — surface typed errors early.
332+
let params: CodecParams = wire_params
333+
.clone()
334+
.try_into()
335+
.map_err(|e: lance_graph_contract::cam::CodecParamsError| {
336+
(StatusCode::BAD_REQUEST, Json(json!({
337+
"error": format!("grid point {idx}: invalid CodecParams: {e}")
338+
})))
339+
})?;
340+
341+
results.push(WireSweepResult {
342+
grid_index: idx as u32,
343+
candidate: wire_params,
344+
kernel_hash: params.kernel_signature(),
345+
calibrate: None,
346+
token_agreement: None,
347+
stub: true,
348+
});
349+
}
350+
351+
Ok(Json(WireSweepResponse {
352+
label: req.label,
353+
cardinality: cardinality as u32,
354+
results,
355+
elapsed_ms: start.elapsed().as_millis() as u64,
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,
362+
}))
363+
}
364+
287365
async fn route_handler(
288366
State(_state): State<AppState>,
289367
Json(wire): Json<WireUnifiedStep>,

0 commit comments

Comments
 (0)