Fix: file-read fail-loud for config + deps (unreadable-but-present files silently degraded)#325
Fix: file-read fail-loud for config + deps (unreadable-but-present files silently degraded)#3250xLeif wants to merge 1 commit into
Conversation
…iles no longer silently degrade Audit Batch 3 (config & deps half) — three "a file that EXISTS but can't be read must fail loud, not silently degrade" defects: - **[medium] Unreadable config silently reverts to defaults.** load_toml_config / load_json_config mapped a read failure to SpecSyncConfig::default() with no signal, downgrading enforcement (strict→warn, exit 1→0) on a config that was present but not valid UTF-8. Now, since callers reach these only after an `.exists()` check, a None on a still-existing file warns loudly (naming the file) before falling back. Same for the optional local override (config.local.toml). - **[low] deps drops an unreadable source's imports.** check_undeclared_imports did `Err(_) => continue`, so a non-UTF-8 declared source contributed no imports and `deps --strict` could pass while hiding undeclared-import violations. Now pushes a hard error (mirrors validator.rs's source-read policy); cmd_deps exits 1. - **[medium] deps drops an unreadable spec from the graph.** build_dep_graph did `Err(_) => continue`, silently removing the node — defeating cycle and missing-dependency detection for that module. Refactored into an internal build_dep_graph_checked that also returns read-failure messages; validate_deps extends report.errors with them (build_dep_graph keeps its signature for the non-gating visualization / topological-order callers). cmd_deps exits 1. Reproduced: non-UTF-8 config → loud "exists but could not be read" warning (was silent); non-UTF-8 declared source → deps error + exit 1 (was exit 0); non-UTF-8 spec → deps error + exit 1 (was exit 0, node silently dropped). Tests: 3 integration regressions (deps unreadable source, deps unreadable spec, config unreadable warning). Documented as config spec invariant #9 and deps spec invariant #7. 750 unit + 180 integration, fmt / clippy / self-check 100%. (The schema-discovery fail-open — build_schema / get_schema_table_names silently skipping unreadable migration files — is the same theme but needs signature changes across schema.rs + validator.rs + check; it ships as its own follow-up PR.) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KDJxU4R8hUEuq1Y5jzft5m
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
There was a problem hiding this comment.
Code Review
This pull request updates the configuration and dependency validation logic to fail loudly when files exist but cannot be read (e.g., due to invalid UTF-8), rather than silently skipping them or reverting to defaults. Specifically, it updates the specifications, modifies the configuration loaders to emit warnings, updates the dependency graph builder and import checker to collect and report errors, and adds integration tests to cover these scenarios. There are no review comments, and I have no feedback to provide.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
There was a problem hiding this comment.
✅ Corvin says...
_
<(^\ .oO(Caw! ^v^)
|/(\
\(\\
" "\\
"Caw! Found a shiny new spec!"
CI Summary
| Check | Status |
|---|---|
| Validate action.yml | ✅ Passed |
| Dependency Audit | ✅ Passed |
| Code Coverage | ✅ Passed |
| Format Check | ✅ Passed |
| Docs Site | ✅ Passed |
| Spec Validation | ✅ Passed |
| Tests (build, test, clippy) | ✅ Passed |
| VS Code Extension | ✅ Passed |
📋 Spec Validation Details
✅ SpecSync: Passed
| Metric | Value |
|---|---|
| Specs checked | 60 |
| Passed | 60 |
| Errors | 0 |
| Warnings | 0 |
| File coverage | 100% (76/76) |
| LOC coverage | 100% (38512/38512) |
Generated by specsync · Run specsync check --format github to reproduce
Powered by corvid-pet
|
Adversarial review: READY_WITH_NITS, 93 — no defects found.
Non-blocking nit (point 6): the config warning is stderr-only and CI gates on exit code, so an unreadable enforcement config downgrades to defaults and still exits 0. This is consistent with the pre-existing JSON-parse-error branch (also warn+default), so it ships as-is; escalating an unreadable config to a hard non-zero exit for gating commands is noted as a candidate future hardening. |
Kyntrin
left a comment
There was a problem hiding this comment.
Thanks for the focused regression coverage here. The code change looks directionally right and CI is green, but the spec updates need to be completed before merge.
Requested changes:
-
specs/deps/deps.spec.mdnow has a new invariant saying unreadable declared source/spec files are hard errors, but the Error Cases table still saysSource file unreadable | Skipped during import extraction. That contradicts the new behavior invalidate_deps/cmd_deps; please update the Error Cases row to match the hard-error behavior, and add an unreadable-spec row if you want the table to cover both new cases. -
Both changed specs add new behavioral contract, but neither spec was version-bumped or given a Change Log entry. Per this repo's AGENTS.md workflow, after spec changes we should increment the spec
versionfield and add a dated Change Log entry. Please updatespecs/config/config.spec.mdandspecs/deps/deps.spec.mdaccordingly.
Non-blocking note: specs/config/config.spec.md could also make the Error Cases table more explicit that unreadable config files now warn loudly before falling back to defaults. I’m not blocking on the existing fallback wording as long as the version/changelog update lands, but tightening it would prevent future ambiguity.
Validation I ran locally: cargo run --quiet -- check --strict passed with 60 specs checked, 60 passed.
Audit Batch 3 (config & deps half) — three defects of the same shape: a file that exists but can't be read as UTF-8 was silently degraded instead of failing loud.
Fixed
load_toml_config/load_json_configmapped a read failure toSpecSyncConfig::default()with no signal, downgrading enforcement (strict→warn, exit 1→0) on a config that was present but not valid UTF-8. Callers reach these only after an.exists()check, so aNoneon a still-existing file now warns loudly (naming the file) before falling back. Same for the optional local override (config.local.toml). An absent config stays silent (expected).depsdrops an unreadable source's imports.check_undeclared_importsdidErr(_) => continue, so a non-UTF-8 declared source contributed no imports anddeps --strictcould pass while hiding undeclared-import violations. Now a hard error (mirrorsvalidator.rs's source-read policy);cmd_depsexits 1.depsdrops an unreadable spec from the graph.build_dep_graphdidErr(_) => continue, silently removing the node — defeating cycle and missing-dependency detection for that module. Refactored into an internalbuild_dep_graph_checkedthat also returns read-failure messages;validate_depsextendsreport.errors.build_dep_graphkeeps its signature for the non-gating visualization / topological-order callers.Reproduced
exists but could not be readwarning (was silent);depserror + exit 1 (was exit 0);depserror + exit 1 (was exit 0, node silently dropped).Tests
3 integration regressions + config spec invariant #9 + deps spec invariant #7. 750 unit + 180 integration, fmt / clippy / self-check 100%.
Scope note
The schema-discovery fail-open (
build_schema/get_schema_table_namessilently skipping unreadable migration files, weakening DB-column validation) is the same theme but needs signature changes acrossschema.rs+validator.rs+ the check command — it ships as its own follow-up PR to keep this one focused.Part of the post-v4.7.1 audit sweep (Batch 3).
🤖 Generated with Claude Code