Skip to content

Cargo build-cache invalidation reads .cargo/config.toml where cargo reads .cargo/config, so it cleans the wrong target dir #1832

Open

Description

[agent] Filed by the scheduled architecture audit (audit-core). Register: register.

Kind: bug (with a duplication root cause). Register ID: A01.

Problem

The cargo config chain is read in two places, and the two copies prefer different files when a .cargo/ directory holds both config and config.toml:

  • utils/cargo_build_cache.rs#L151-L183 ConfigDirs::read tries ["config.toml", "config"], so config.toml wins.
  • formats/cargo/source_replacement.rs#L110-L142```` config_layer_paths tries `["config", "config.toml"]`. Its doc comment says this matches cargo ("cargo prefers the legacy extensionless file when both exist"). It also skips `$CARGO_HOME` when an ancestor already named that directory.

The two copies have drifted on two more points. For the $CARGO_HOME base, ConfigDirs::read falls back to unwrap_or_default() and config_layer_paths to unwrap_or(home). And only config_layer_paths checks whether an ancestor already named $CARGO_HOME.

Proof (executed on main @ b291caa). I added a scratch test in a throwaway worktree. It makes ws/.cargo/config with target-dir = "legacy" and ws/.cargo/config.toml with target-dir = "modern":

AUDIT build_dirs=["/tmp/.tmp2e21zC/ws/modern"] cargo_layers=[("/tmp/.tmp2e21zC/ws/.cargo/config", "/tmp/.tmp2e21zC/ws")]

Cargo builds into legacy/. So invalidate_project (called from apply and rollback) removes fingerprints under modern/, and the stale fingerprints that cargo actually uses survive. The next cargo build then links the unpatched code, which is the failure this module exists to prevent.

Proposed change

  • Build ConfigDirs::read on config_layer_paths(cwd, cargo_home, Path::is_file). Keep only the [build] target-dir/build-dir extraction, and delete its own ancestor walk and file pick. This is about −15 lines.
  • Optionally, move config_layer_paths to a neutral home such as formats/cargo/config.rs, since it is now shared by the source-replacement reader and the build-cache cleaner.

Size: 1–2 files, about +5/−20.

Acceptance criteria

  • A unit test in cargo_build_cache.rs covers the case above: both files exist, and the build dirs resolve to the extensionless file's target-dir.
  • build_dirs_honours_env_config_and_workspace_root still passes.
  • The source-replacement tests are unchanged.

Activity

  1. added
    bugSomething isn't working
    arch-auditFiled by a scheduled architecture audit routine (see the architecture review discussion)
    on Oct 29, 2026
  2. mikolalysenko commented on Oct 29, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Claiming this for the architecture refactor routine (top structural candidate, score 7; A02 is blocked by #1829 touching workspace_globs.rs). Branch: arch-refactor/1832-cargo-config-chain. Claim-ID: 2026-10-29T18:56:14Z-a1c832


    Generated by Claude Code

  3. added a commit that references this issue on Oct 29, 2026
    099c132
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent:claimedagent:triagedarch-auditFiled by a scheduled architecture audit routine (see the architecture review discussion)bugSomething isn't workingpriority:p2

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions