JuliusBrussee/caveman · error · Error
caveman build: qualityRetention must be in (0,1]
Error message
caveman build: qualityRetention must be in (0,1]
What it means
Thrown by defineBuild when qualityRetention is outside the interval (0, 1]. This is the minimum fraction of baseline quality the optimized build must retain, as verified by evals: 0 means any quality loss is acceptable (defeating the optimizer's contract), values above 1 are impossible, and NaN fails the range check. The default is 0.98.
Source
Thrown at packages/agent/src/build.ts:50
const config: BuildConfig = {
entry: options.entry,
evals: options.evals,
efficiency: options.efficiency ?? "max",
requiredFixturePassRate: options.requiredFixturePassRate ?? 1,
qualityRetention: options.qualityRetention ?? 0.98,
maxSearchCostUsd: options.maxSearchCostUsd ?? 2,
lock: options.lock ?? "strict",
sandbox: options.sandbox ?? "required",
...(options.allowedModels === undefined ? {} : { allowedModels: [...options.allowedModels] }),
...(options.deniedModels === undefined ? {} : { deniedModels: [...options.deniedModels] }),
...(options.maxP95LatencyMs === undefined ? {} : { maxP95LatencyMs: options.maxP95LatencyMs }),
...(options.forbiddenSafetyClasses === undefined ? {} : { forbiddenSafetyClasses: [...options.forbiddenSafetyClasses] }),
};
if (!(config.requiredFixturePassRate > 0 && config.requiredFixturePassRate <= 1)) {
throw new Error("caveman build: requiredFixturePassRate must be in (0,1]");
}
if (!(config.qualityRetention > 0 && config.qualityRetention <= 1)) {
throw new Error("caveman build: qualityRetention must be in (0,1]");
}
if (!(config.maxSearchCostUsd > 0)) {
throw new Error("caveman build: maxSearchCostUsd must be positive");
}
return Object.freeze(config);
}
export interface CavePlan {
schema_version: 1;
plan_id: string;
model: string;
reasoning: "none" | "minimal" | "low" | "medium" | "high";
segment_routes: Array<{
segment_kind: ContextKind;
segment_id?: string;
transform_id: string;
fallback: "original";
}>;View on GitHub (pinned to 27d5a3981a)
Solutions
- Pass a fraction in (0, 1]: 0.98 (default) tolerates 2% quality loss; 1 demands no measurable loss.
- If your config stores percentages, divide by 100 and range-check before calling defineBuild.
- Validate the value at config load time with a clear error naming the expected range.
Example fix
// before
defineBuild({ entry, evals, qualityRetention: 98 }); // percentage, not fraction
// after
defineBuild({ entry, evals, qualityRetention: 0.98 }); Defensive patterns
Strategy: validation
Validate before calling
function retention(v: number | undefined): number {
const r = v ?? 0.98;
if (!(r > 0 && r <= 1)) throw new Error(`qualityRetention must be in (0,1], got ${r}`);
return r;
} Type guard
function isUnitInterval(v: unknown): v is number {
return typeof v === "number" && Number.isFinite(v) && v > 0 && v <= 1;
} Prevention
- The scale is 0–1: write 0.98, not 98.
- Validate config-sourced values with a (0,1] range check before calling defineBuild.
- Keep retention high (>= 0.9) unless you have evals that prove lower retention is acceptable.
When it happens
Trigger: Passing qualityRetention: 0, a negative number, 1.2, or NaN; computing retention from a ratio whose inputs can be undefined; config values written as percentages (98) instead of fractions (0.98).
Common situations: Confusing percentage scale (0–100) with fraction scale (0–1) and passing 98; disabling the quality floor during aggressive optimization experiments; unvalidated numeric env vars.
Related errors
- caveman build: requiredFixturePassRate must be in (0,1]
- cave_budget_max_invalid
- cave_budget_denomination_ambiguous
- cave_budget_initial_invalid
- cave_budget_output_floor_invalid
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/abca6ae0b4fc779d.
Report an issue: GitHub.