fix(manifest): a configured source_dirs must survive a manifest discovery failure, and an in-repo includeBuild must be judged by its path - #724
Merged
Conversation
…-manifest-discovery-failure-and-an-in-repo-includebuild-must-be-judged-by-its
…fest-discovery-failure-and-an-in-repo-includebuild-must-be-judged-by-its verification
… fix Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DgYAvsQM6P9fKxDotnDuzP
0xLeif
requested review from
0xGaspar,
Kyntrin and
tofu-ux
and removed request for
a team
August 27, 2026 15:11
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #723. 6.0 release blocker — a real adopter cannot use any v6 candidate at all.
The report, confirmed across the whole line
Reproduced locally before fixing:
Two defects; the second is the one that matters
A —
includeBuildwas rejected on the token prefix, never the path.src/manifest.rsdecided ontoken.starts_with("include")and never looked at the argument, so an in-repo composite build was refused identically to one escaping the repository. Every fixture in the guarding test used"../outside", so the ordinary case was never covered.Now judged by argument: a literal path beneath the root parses and contributes no module; escapes, interpolation, dynamic expressions, multiple arguments and trailing config blocks keep failing closed, and the error now names the argument.
B — a discovery failure overrode an explicitly configured
source_dirsand aborted coverage. This is why setting it did not help them. Other call sites degrade (config.rsusesunwrap_or_else,validator.rs:430falls back to a scan); coverage propagated with?.Discovery exists to infer what the user did not state. When the user has stated it, a failure to infer must not veto it. It is now a notice rendered beside the coverage figures — deliberately non-gating, since gating would put the adopter back where they started, and unlike a shrunken denominator a notice cannot inflate a percentage.
B is the more valuable fix: it removes the whole class. No unreadable manifest, in any ecosystem, can override an explicit declaration again.
Verified against the reported case, not just unit tests
Same fixture, this build:
Zero
Gradle/manifest/mutatorhits remain in either output. The remaining exit 1 is--stricttreating unfilled-scaffold warnings as errors — correct behaviour on a fixture whose specs were never written, not the reported bug.Tests, and which fail against main
All four fail on current
main, verified by disabling both fixes in place and re-running so each failed with its own message rather than a shared compile error:gradle_settings_accept_an_in_repo_include_buildgradle_settings_still_refuse_an_escaping_or_dynamic_include_build— honest label: its refusals pass unfixed too; what fails is the diagnostic, which previously said the same thing about an escape and a valid buildconfigured_source_dirs_survive_a_manifest_that_cannot_be_parsedunsafe_gradle_discovery_degrades_over_stated_source_dirs_without_escapingThe precedence test asserts both halves in one test — stated
source_dirscompletes with a notice; the same tree with the flag off is still fatal — so it cannot pass against a change that merely stopped failing. Its manifest is malformed rather than unsupported, so fixing A cannot make it vacuous.Two things found on the way
Six existing integration tests were asserting the wrong case. Every
gradle_*_is_inconclusive_for_coverage_gating_commandsfixture built onsetup_minimal_project, which statessourceDirs, so all six were exercising the configured path while using the exit code as a proxy for safety. Each now clears it and still asserts the fail-closed contract on an inferred list, and the new integration test checks the safety properties directly — no byte outside the root disclosed, nothing generated from rejected discovery.A first-cut bug in the fix itself: judging
includeBuildby argument left its position unjudged, soif (x) { includeBuild("vendor/s") }was refused on one line and accepted across three. Settled by accepting both — a composite build contributes no module whether or not its branch runs — deliberately asymmetric withinclude, which stays refused when conditional.cargo clippy -- -D warningsclean,change checkexit 0,change audit --strictclean, 2389 unit + 406 integration.🤖 Generated with Claude Code
https://claude.ai/code/session_01DgYAvsQM6P9fKxDotnDuzP