{ "batch": "Cross-cutting Sweep", "batch_index": 1, "assessments": { "error_consistency": 74.0 }, "dimension_notes": { "error_consistency": { "evidence": [ "cmd/scrape.go uses `wrapErr` for YAML fallback parsing but returns `%w` with outer `err` (`return fmt.Errorf(\"parse sources file: %w\", err)`), which can misreport or drop the actual parse failure.", "cmd/ask.go drops `localErr` (`localRanked = nil`) and later reports only live fetch errors, so a failed local retrieval path is silently omitted from the returned error contract.", "internal/search/engine.go frequently returns raw errors from filesystem/JSON boundaries (`return nil, err`) while nearby modules like internal/indexer/indexer.go and cmd/serve.go consistently wrap with operation context.", "internal/quality/plugins/go/analyzers/test_coverage.go returns `nil, nil` for missing `go` tool and missing `coverage.out`, but returns hard errors for other failures, creating mixed silent-skip vs fail-fast behavior in one detector family.", "internal/quality/plugins/go/plugin.go panics in package init on registration failure, while command entrypoints use returned errors + controlled process exit (cmd/root.go), producing inconsistent failure modes across startup paths." ], "impact_scope": "subsystem", "fix_scope": "multi_file_refactor", "confidence": "high" } }, "findings": [ { "dimension": "error_consistency", "identifier": "wrong_error_wrapped_in_sources_fallback_parse", "summary": "Fallback YAML parse wraps the wrong error variable, losing true parse context.", "related_files": [ "cmd/scrape.go", "internal/config/config.go" ], "evidence": [ "cmd/scrape.go:153-155 checks `wrapErr` but returns `%w` with `err` from a different scope.", "internal/config/config.go consistently wraps the current failing error with `%w` at parse/read boundaries, showing intended local convention." ], "suggestion": "In cmd/scrape.go, change the return to `fmt.Errorf(\"parse sources file: %w\", wrapErr)` so the emitted error always preserves the actual fallback parse failure.", "confidence": "high", "impact_scope": "module", "fix_scope": "single_edit" }, { "dimension": "error_consistency", "identifier": "local_ask_retrieval_error_is_silently_dropped", "summary": "Local retrieval failures are discarded, so final errors hide one failing path.", "related_files": [ "cmd/ask.go", "cmd/serve.go" ], "evidence": [ "cmd/ask.go:122-125 sets `localRanked = nil` on `localErr` and does not append/report that error.", "cmd/ask.go:145-147 returns only `fetchErrors` for failure messaging, excluding local retrieval failure cause.", "cmd/serve.go wraps and propagates lower-level errors with operation context (`run devour_ask search: %w`), showing a stricter error propagation pattern at adjacent boundary code." ], "suggestion": "Capture `localErr` into the same error aggregation path (or return immediately with context) so both local and live retrieval failures are visible to callers.", "confidence": "high", "impact_scope": "subsystem", "fix_scope": "multi_file_refactor" }, { "dimension": "error_consistency", "identifier": "search_engine_drops_operation_context_on_io_errors", "summary": "Search engine returns raw IO/JSON errors without operation context at key boundaries.", "related_files": [ "internal/search/engine.go", "internal/indexer/indexer.go" ], "evidence": [ "internal/search/engine.go returns bare errors at several boundaries (e.g., MkdirAll/listDocFiles/os.ReadFile/json.Unmarshal paths).", "internal/indexer/indexer.go wraps errors with explicit operation strings (`failed to generate embeddings`, `failed to add to vector store`), improving traceability." ], "suggestion": "Wrap engine boundary errors with operation-specific context (`fmt.Errorf(\"ensure index metadata: %w\", err)`, etc.) consistently across Rebuild/EnsureIndexed/Search.", "confidence": "medium", "impact_scope": "subsystem", "fix_scope": "multi_file_refactor" }, { "dimension": "error_consistency", "identifier": "test_coverage_detector_mixes_silent_skip_and_hard_failure", "summary": "Coverage detector silently skips some environment failures but fails hard on others.", "related_files": [ "internal/quality/plugins/go/analyzers/test_coverage.go", "internal/quality/scanner.go" ], "evidence": [ "internal/quality/plugins/go/analyzers/test_coverage.go:39-41 returns `nil, nil` if `go` is unavailable; lines 50-51 also return `nil, nil` when profile is missing.", "The same detector returns hard errors for command execution failures (`failed to run test coverage`) and parse failures, yielding mixed failure contracts.", "internal/quality/scanner.go aggregates detector errors, so silent `nil,nil` prevents scanner-level visibility for some failure modes." ], "suggestion": "Standardize detector contract: either return explicit typed 'skipped' metadata/finding for non-actionable environment gaps, or return wrapped errors consistently so scanner can report them predictably.", "confidence": "high", "impact_scope": "subsystem", "fix_scope": "architectural_change" }, { "dimension": "error_consistency", "identifier": "plugin_registration_uses_panic_while_cli_paths_return_errors", "summary": "Plugin init panics on registration failure instead of using returned error flow.", "related_files": [ "internal/quality/plugins/go/plugin.go", "cmd/root.go" ], "evidence": [ "internal/quality/plugins/go/plugin.go:360-363 panics in `init()` when registration fails.", "cmd/root.go:41-45 follows controlled error propagation (`Execute` prints error and exits), indicating a different process-level failure strategy." ], "suggestion": "Replace panic-based registration with explicit initialization returning errors (or a centralized startup validation step) so failures follow the same surfaced error path as other startup errors.", "confidence": "medium", "impact_scope": "subsystem", "fix_scope": "architectural_change" } ] }