Skip to content

Log a WARN instead of silently dropping invalid ScopeKnownError config - #355

Draft
rubberduck203 wants to merge 2 commits into
mainfrom
fix/344-hard-fail-invalid-known-error
Draft

Log a WARN instead of silently dropping invalid ScopeKnownError config#355
rubberduck203 wants to merge 2 commits into
mainfrom
fix/344-hard-fail-invalid-known-error

Conversation

@rubberduck203

@rubberduck203 rubberduck203 commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #344. Config::new (now FoundConfig::new) converted each raw parsed
config document into its typed model via try_into() and silently discarded
the Err case with zero logging — a ScopeKnownError using a reserved
capture group name, or shipping a broken {{ }} fix template, would just
vanish with no signal, and the tool would report "No known errors found" as
if the config didn't exist at all.

The issue thread initially discussed making a ScopeKnownError conversion
failure a hard failure that aborts config loading entirely, since a
recognized-but-invalid known error can never work as written. After
implementing that, we reconsidered: aborting the whole config load meant a
single broken known-error file anywhere in a fleet-wide shared .scope
directory would disable known-error matching (and scope-intercept's
auto-fix) for every unrelated known error too, and would block
scope doctor/list/report outright with exit code 2 — too large a blast
radius for one bad file.

So the final behavior: every kind (ScopeKnownError, ScopeDoctorGroup,
etc.) now logs a warn!(target: "user", ...) naming the file and the cause
when it fails to convert, and is dropped — the config load itself always
succeeds, same as before #344, just no longer silently. This preserves the
existing tolerant philosophy from #68/PR #69 uniformly across all kinds,
while finally giving the "at minimum, log it" signal the issue asked for.

Also fixed along the way, since silence had been hiding it:

  • ParsedConfig::try_from (src/shared/models/internal/mod.rs) used
    if let Ok(Some(known)) = ...known_type(...), silently swallowing real
    deserialization errors (e.g. a missing required field) behind a generic,
    typo'd "Error was know a known type" message. Real errors now propagate
    via ?, so the new warn logs actually show the useful underlying cause.
  • scope.rs's config-load error log used {} instead of {:#}, which for
    a .context()-wrapped anyhow error prints only the outermost message and
    drops the real cause. Fixed for the "unable to get a working dir" path
    that can still fail there.

Test plan

  • cargo test — full suite passes, including 2 new unit tests in
    src/shared/config_load.rs (via a shared found_config_from_files
    test helper) covering: a bad known error warning-and-dropping while a
    valid known error in the same directory still loads, and the same for
    a bad doctor group alongside a valid one.
  • cargo clippy --all-targets -- -D warnings clean
  • cargo fmt --check clean
  • Manually reproduced the issue's MVCE against scope-intercept: a
    broken known-error file now logs
    WARN Unable to load ScopeKnownError/bad-reserved from <path> because known error '...' has a pattern with a capture group named 'captures', which is reserved for template substitution, while a second, valid
    known error in the same directory still matches and reports correctly.

🤖 Generated with Claude Code

…ing it

Config::new (now FoundConfig::new) discarded any raw config document that
failed to convert into its typed model, with zero logging. A ScopeKnownError
using a reserved capture group name, or shipping a broken fix template,
would silently never register, giving false confidence scope was watching
for it.

ScopeKnownError conversion failures now abort config loading with a
diagnosable error naming the file and cause (scope exits 2; scope-intercept
falls back to an empty config after logging the error). Other kinds, chiefly
ScopeDoctorGroup, keep the existing tolerant behavior from #68/PR #69 but now
actually warn instead of failing silently — including a ScopeKnownError from
an apiVersion this binary doesn't recognize, which is treated the same as
any other not-yet-understood config rather than a hard failure.

Also fixes ParsedConfig::try_from silently swallowing real deserialization
errors behind a generic, typo'd message, and scope.rs's error log dropping
the underlying cause by using Display instead of the alternate/chained form.

Fixes #344
Revisited the design from the previous commit after further discussion: a
recognized-but-invalid ScopeKnownError now warns and is dropped, the same as
any other kind, rather than aborting the entire config load. Aborting the
whole load meant a single broken known-error file anywhere in a fleet-wide
shared config directory would silently disable known-error matching (and
scope-intercept's auto-fix) for every unrelated known error too, and would
block scope doctor/list/report outright — too large a blast radius for one
bad file.

This also removes the hand-rolled kind/apiVersion matching that only existed
to special-case ScopeKnownError, and consolidates the four config-load tests
onto a shared found_config_from_files test helper.
@rubberduck203 rubberduck203 changed the title Hard-fail on invalid ScopeKnownError config instead of silently dropping it Log a WARN instead of silently dropping invalid ScopeKnownError config Jul 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Known-error/fix config errors are silently dropped at load time instead of failing loudly

1 participant