Summary
loadGazeConfigBestEffort silently falls back to DefaultConfig() whenconfig.Load returns a validation error, producing no warning on stderr.
After PR #154 added threshold validation to config.Load, users with invalid .gaze.yaml thresholds now get clear errors from CLI commands (gaze analyze, gaze quality, gaze docscan) but silent default substitution from gaze crap and gaze report.
Reproduction
Given a .gaze.yaml with an out-of-range threshold:
classification:
thresholds:
contractual: 500
incidental: 50
# CLI commands: clear error (correct)
$ gaze quality .
Error: loading config: classification.thresholds.contractual must be in [1, 99], got 500
# Best-effort callers: silent fallback to defaults (no warning)
$ gaze crap .
# Runs successfully using contractual=80, incidental=50 (defaults)
# No indication that the user's thresholds were rejected
$ gaze report --format=json .
# Same - silently uses defaults
Expected vs Actual
- Expected: gaze crap and gaze report should emit a stderr warning when config.Load rejects the user's .gaze.yaml, so the user knows their thresholds are being replaced with defaults.
- Actual: The commands run silently with default thresholds. The user's invalid config is ignored with no feedback.
Root cause
Both copies of loadGazeConfigBestEffort discard the error from config.Load without logging:
if err != nil {
return config.DefaultConfig() // silent - no warning emitted
}
This was harmless before PR #154 because config.Load never rejected threshold values. Now that it validates thresholds, the silent fallback can mask configuration problems from users.
Suggested fix
Add a stderr warning when config.Load returns an error, before falling
back to defaults:
if err != nil {
fmt.Fprintf(os.Stderr, "warning: %v; using default configuration\n", err)
return config.DefaultConfig()
}
Apply to both copies:
- internal/aireport/runner_steps.go (loadGazeConfigBestEffort)
- internal/crap/contract.go (loadGazeConfigBestEffort)
A follow-up consolidation of the two identical loadGazeConfigBestEffort functions into a shared helper (see #139) would prevent this kind of divergence in the future.
Files to modify
- internal/aireport/runner_steps.go - add stderr warning in loadGazeConfigBestEffort
- internal/crap/contract.go - add stderr warning in loadGazeConfigBestEffort
Summary
loadGazeConfigBestEffortsilently falls back toDefaultConfig()whenconfig.Loadreturns a validation error, producing no warning on stderr.After PR #154 added threshold validation to
config.Load, users with invalid.gaze.yamlthresholds now get clear errors from CLI commands (gaze analyze,gaze quality,gaze docscan) but silent default substitution fromgaze crapandgaze report.loadGazeConfigBestEffortininternal/aireport/runner_steps.goandinternal/crap/contract.gogaze crap,gaze reportconfig.Loadperforms no validation; inverted / out-of-range thresholds load silently #114, PR fix: validate classification thresholds in config.Load #154Reproduction
Given a
.gaze.yamlwith an out-of-range threshold:Expected vs Actual
Root cause
Both copies of loadGazeConfigBestEffort discard the error from config.Load without logging:
This was harmless before PR #154 because config.Load never rejected threshold values. Now that it validates thresholds, the silent fallback can mask configuration problems from users.
Suggested fix
Add a stderr warning when config.Load returns an error, before falling
back to defaults:
Apply to both copies:
A follow-up consolidation of the two identical loadGazeConfigBestEffort functions into a shared helper (see #139) would prevent this kind of divergence in the future.
Files to modify