nexu-io/open-design · error · RangeError

OD_CRITIQUE_SCORE_THRESHOLD (${scoreThreshold}) must be <= O

Error message

OD_CRITIQUE_SCORE_THRESHOLD (${scoreThreshold}) must be <= OD_CRITIQUE_SCORE_SCALE (${scoreScale})

What it means

Thrown by loadCritiqueConfigFromEnv() as a RangeError when OD_CRITIQUE_SCORE_THRESHOLD is greater than OD_CRITIQUE_SCORE_SCALE (with a 1e-9 tolerance). It is a cross-field validation: scores produced by the panel are scaled against scoreScale, so a threshold above the scale would be unreachable and every run would be flagged sub-threshold. The check runs at config load so misconfiguration surfaces at boot, never silently.

Source

Thrown at apps/daemon/src/critique/config.ts:26

 * surfaces at boot, never silently.
 *
 * @see specs/current/critique-theater.md § Configuration (env vars)
 */
export function loadCritiqueConfigFromEnv(env: NodeJS.ProcessEnv = process.env): CritiqueConfig {
  const defaults = defaultCritiqueConfig();

  const enabled = parseEnabled(env['OD_CRITIQUE_ENABLED'], defaults.enabled);
  const maxRounds = parsePositiveInt('OD_CRITIQUE_MAX_ROUNDS', env['OD_CRITIQUE_MAX_ROUNDS'], defaults.maxRounds);
  const scoreThreshold = parseNonNegativeFloat('OD_CRITIQUE_SCORE_THRESHOLD', env['OD_CRITIQUE_SCORE_THRESHOLD'], defaults.scoreThreshold);
  const scoreScale = parsePositiveInt('OD_CRITIQUE_SCORE_SCALE', env['OD_CRITIQUE_SCORE_SCALE'], defaults.scoreScale);
  const perRoundTimeoutMs = parsePositiveInt('OD_CRITIQUE_PER_ROUND_TIMEOUT_MS', env['OD_CRITIQUE_PER_ROUND_TIMEOUT_MS'], defaults.perRoundTimeoutMs);
  const totalTimeoutMs = parsePositiveInt('OD_CRITIQUE_TOTAL_TIMEOUT_MS', env['OD_CRITIQUE_TOTAL_TIMEOUT_MS'], defaults.totalTimeoutMs);
  const parserMaxBlockBytes = parsePositiveInt('OD_CRITIQUE_PARSER_MAX_BLOCK_BYTES', env['OD_CRITIQUE_PARSER_MAX_BLOCK_BYTES'], defaults.parserMaxBlockBytes);
  const fallbackPolicy = parseFallbackPolicy(env['OD_CRITIQUE_FALLBACK_POLICY'], defaults.fallbackPolicy);

  // Cross-field validation: threshold cannot exceed scale.
  if (scoreThreshold > scoreScale + 1e-9) {
    throw new RangeError(
      `OD_CRITIQUE_SCORE_THRESHOLD (${scoreThreshold}) must be <= OD_CRITIQUE_SCORE_SCALE (${scoreScale})`,
    );
  }

  return {
    ...defaults,
    enabled,
    maxRounds,
    scoreThreshold,
    scoreScale,
    perRoundTimeoutMs,
    totalTimeoutMs,
    parserMaxBlockBytes,
    fallbackPolicy,
  };
}

// ---------------------------------------------------------------------------

View on GitHub (pinned to 5be4028344)

Solutions

  1. Set OD_CRITIQUE_SCORE_THRESHOLD <= OD_CRITIQUE_SCORE_SCALE (e.g. threshold 8 with scale 10, or threshold 80 with scale 100).
  2. Decide on one scale convention (0-10 or 0-100) and set both vars consistently.
  3. Leave both unset to use defaultCritiqueConfig(), which already satisfies the constraint.

Example fix

# before: threshold above scale
OD_CRITIQUE_SCORE_THRESHOLD=90
OD_CRITIQUE_SCORE_SCALE=10

# after: keep threshold within scale
OD_CRITIQUE_SCORE_THRESHOLD=8
OD_CRITIQUE_SCORE_SCALE=10
Defensive patterns

Strategy: validation

Validate before calling

const threshold = Number(process.env.OD_CRITIQUE_SCORE_THRESHOLD ?? defaultThreshold);
const scale = Number(process.env.OD_CRITIQUE_SCORE_SCALE ?? defaultScale);
if (threshold > scale + 1e-9) {
  throw new RangeError(`threshold ${threshold} must be <= scale ${scale}`);
}

Type guard

function thresholdWithinScale(threshold: number, scale: number): boolean {
  return threshold <= scale + 1e-9;
}

Try / catch

try { loadCritiqueConfigFromEnv(); }
catch (e) {
  if (e instanceof RangeError && /SCORE_THRESHOLD/.test(e.message)) {
    // log, fall back to defaults, or fail boot per policy
  } else throw e;
}

Prevention

When it happens

Trigger: Setting OD_CRITIQUE_SCORE_THRESHOLD to a value larger than OD_CRITIQUE_SCORE_SCALE in the environment — e.g. THRESHOLD=90 with SCALE=10.

Common situations: Operator confused scale (e.g. 0-10 vs 0-100); copy-pasted env from another deployment with a different scale; threshold bumped without scaling the scale to match.

Related errors


AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12). Data as JSON: /api/errors/ea9dd08a75af42b1. Report an issue: GitHub.