roverdevkit / webapp /frontend /src /hooks /use-evaluate.ts
jjreif's picture
Deploy roverdevkit @ 2676a67
b3d14e3
Raw
History Blame Contribute Delete
2.37 kB
import { useMutation, useQueries } from "@tanstack/react-query";
import { api } from "@/lib/api";
import type {
DesignVector,
EvaluateRequest,
EvaluateResponse,
} from "@/types/api";
/**
* `POST /evaluate` mutation. Returns the deterministic corrected
* mission evaluator's output for a single design × scenario. The
* design panel triggers this in parallel with `usePredict()` so the
* chart can show the evaluator's value as the median diamond and the
* surrogate's q05/q95 as the prediction-interval band wrapping it.
*/
export function useEvaluate() {
return useMutation<EvaluateResponse, Error, EvaluateRequest>({
mutationKey: ["evaluate"],
mutationFn: (req) => api.evaluate(req),
});
}
/**
* Per-rover evaluator queries used by the registry overlay. Mirrors
* `useRegistryPredictions` but hits `/evaluate` so the overlay
* markers are ground-truth physics outputs (matching the candidate
* design's median diamond) rather than surrogate regressions.
*
* Each rover is its own query so cache hits are reused across
* re-renders and overlay toggles.
*/
export function useRegistryEvaluations(
rovers: Array<{ rover_name: string; design: DesignVector }>,
scenarioName: string,
overrides?: {
payload_mass_kg?: number | null;
payload_power_w?: number | null;
mission_duration_earth_days?: number | null;
},
) {
const payloadMass = overrides?.payload_mass_kg ?? null;
const payloadPower = overrides?.payload_power_w ?? null;
const missionDuration = overrides?.mission_duration_earth_days ?? null;
return useQueries({
queries: rovers.map((r) => ({
queryKey: [
"registry-evaluate",
r.rover_name,
scenarioName,
JSON.stringify(r.design),
payloadMass,
payloadPower,
missionDuration,
] as const,
queryFn: (): Promise<EvaluateResponse> =>
api.evaluate({
design: r.design,
scenario_name: scenarioName,
payload_mass_kg: payloadMass,
payload_power_w: payloadPower,
mission_duration_earth_days: missionDuration,
}),
staleTime: Infinity,
gcTime: 60 * 60 * 1000,
refetchOnWindowFocus: false,
})),
combine: (results) => ({
results,
isPending: results.some((r) => r.isPending),
isError: results.some((r) => r.isError),
}),
});
}