Skip to content

fix(rust): the toolchain's children are told where the toolchain is - #9

Merged
CesarManzoCode merged 1 commit into
mainfrom
claude/rust-analyzer-semantic-resolution-vneio1
Sep 5, 2026
Merged

fix(rust): the toolchain's children are told where the toolchain is#9
CesarManzoCode merged 1 commit into
mainfrom
claude/rust-analyzer-semantic-resolution-vneio1

Conversation

@CesarManzoCode

Copy link
Copy Markdown
Owner

The VM closed the previous cause: inside Thalyx, cargo 1.90.0 from: thalyx and rust-analyzer 1.90.0 from: thalyx. And the machine still could not resolve a name. context('lantern/src/lib.rs') found LanternRegistry; context('LanternRegistry') answered resolution: nothing, entries: [], and a rename at the identifier's own physical position — 8:12, not the outline's guess — answered No references found at position.

Reproduced here with an environment holding exactly what Thalyx hands over and nothing else, and the cause is in the server's own log:

ERROR FetchWorkspaceError: rust-analyzer failed to load workspace:
  Failed to run `cargo metadata …`: No such file or directory (os error 2)
WARN  failed to get rustc cfgs e=unable to fetch cfgs via `… "rustc" …`
  Caused by: No such file or directory (os error 2)

rust-analyzer is not a program Thalyx runs; it is a program that runs programs. It spells cargo metadata, cargo locate-project, cargo --version and rustc --print cfg as bare names, which the kernel resolves through PATH and nothing else — and Thalyx, which finds every tool by absolute path and goes on doing so, had never given its children one. With no crate graph there is no semantics; syntax survives because syntax needs no subprocess, which is exactly the shape the machine showed.

The change is one variable. toolchain::environment now hands a managed toolchain a PATH built by Thalyx out of one directory, its own bin: nothing inherited, no /usr/bin, no ~/.cargo, no ~/.rustup. Measured — adding it and nothing else turned workspace/symbol, definition and rename from empty to correct in the same fixture. CARGO, RUSTC and RUST_SRC_PATH are deliberately not set: PATH alone was sufficient, and a variable added because Rust usually has it is a variable nobody can remove later. An installed toolchain gets its bin in front of the inherited PATH rather than instead of it, which is also what sudo's secure_path had been costing verify.sh.

Two instrument defects came with it, and both were worse than the bug.

dev/verify-agent-rust.sh printed PROVEN context('LanternRegistry') came from rust-analyzer about {source: "rust-analyzer", resolution: "nothing", entries: []}. source says who answered; it has never said that the answer resolved anything. PROVEN now needs all three: rust-analyzer answered, resolution is one, and the entries carry exactly the declaration asked about, with the handle a rename would take.

And the control written to demonstrate the defect resolved the symbol anyway. rust-analyzer looks for cargo in three places — $CARGO, PATH, $CARGO_HOME/bin — and a rustup machine has the third one full. Inside Thalyx CARGO_HOME is /state/cargo and has no bin, so the control was modelling a developer's laptop rather than the guest. It models the guest now.

Separately, the outline placed a documented struct at its doc comment: with hierarchicalDocumentSymbolSupport: false each entry carries one range and rust-analyzer fills it with the whole item, so LanternRegistry came back at 3:1 instead of 8:12. The hierarchical answer carries selectionRange, which is the identifier. Not the blocker — 8:12 failed too — but a position a rename by handle would have used. The server's real answer is captured verbatim in tests/samples/document-symbol-hierarchical.json, rule 6.

Proven in the container, with env_clear and only Thalyx's pairs, over dev/rust-corpus: without PATH the outline finds the struct and every name resolves to nothing; with it, Resolution::One at lantern/src/lib.rs:8:12, uses in the other crate, and a real rename across two files. And the chain below — cargo invoked as a bare name with an empty environment compiles the workspace, so it found its rustc the same way.

Confinement is untouched on purpose. The VM reported analyzer_confined=false because the kernel is attached but observing, and the provider fell back to an ordinary process inside Thalyx and the semantics failed anyway. One cause at a time.

Claude-Session: https://claude.ai/code/session_01S4ij9nSjMTiCT6sd8DuBgQ

The VM closed the previous cause: inside Thalyx, `cargo 1.90.0 from: thalyx`
and `rust-analyzer 1.90.0 from: thalyx`. And the machine still could not
resolve a name. `context('lantern/src/lib.rs')` found `LanternRegistry`;
`context('LanternRegistry')` answered `resolution: nothing, entries: []`, and
a rename at the identifier's own physical position — 8:12, not the outline's
guess — answered `No references found at position`.

Reproduced here with an environment holding exactly what Thalyx hands over and
nothing else, and the cause is in the server's own log:

    ERROR FetchWorkspaceError: rust-analyzer failed to load workspace:
      Failed to run `cargo metadata …`: No such file or directory (os error 2)
    WARN  failed to get rustc cfgs e=unable to fetch cfgs via `… "rustc" …`
      Caused by: No such file or directory (os error 2)

rust-analyzer is not a program Thalyx runs; it is a program that runs
programs. It spells `cargo metadata`, `cargo locate-project`, `cargo --version`
and `rustc --print cfg` as bare names, which the kernel resolves through PATH
and nothing else — and Thalyx, which finds every tool by absolute path and goes
on doing so, had never given its children one. With no crate graph there is no
semantics; syntax survives because syntax needs no subprocess, which is exactly
the shape the machine showed.

The change is one variable. `toolchain::environment` now hands a managed
toolchain a PATH built by Thalyx out of one directory, its own `bin`: nothing
inherited, no /usr/bin, no ~/.cargo, no ~/.rustup. Measured — adding it and
nothing else turned workspace/symbol, definition and rename from empty to
correct in the same fixture. CARGO, RUSTC and RUST_SRC_PATH are deliberately
not set: PATH alone was sufficient, and a variable added because Rust usually
has it is a variable nobody can remove later. An installed toolchain gets its
`bin` in front of the inherited PATH rather than instead of it, which is also
what sudo's secure_path had been costing verify.sh.

Two instrument defects came with it, and both were worse than the bug.

`dev/verify-agent-rust.sh` printed `PROVEN context('LanternRegistry') came from
rust-analyzer` about `{source: "rust-analyzer", resolution: "nothing",
entries: []}`. `source` says who answered; it has never said that the answer
resolved anything. PROVEN now needs all three: rust-analyzer answered,
resolution is `one`, and the entries carry exactly the declaration asked about,
with the handle a rename would take.

And the control written to demonstrate the defect resolved the symbol anyway.
rust-analyzer looks for cargo in three places — $CARGO, PATH, $CARGO_HOME/bin —
and a rustup machine has the third one full. Inside Thalyx CARGO_HOME is
<store>/state/cargo and has no bin, so the control was modelling a developer's
laptop rather than the guest. It models the guest now.

Separately, the outline placed a documented struct at its doc comment: with
`hierarchicalDocumentSymbolSupport: false` each entry carries one range and
rust-analyzer fills it with the whole item, so `LanternRegistry` came back at
3:1 instead of 8:12. The hierarchical answer carries `selectionRange`, which is
the identifier. Not the blocker — 8:12 failed too — but a position a rename by
handle would have used. The server's real answer is captured verbatim in
tests/samples/document-symbol-hierarchical.json, rule 6.

Proven in the container, with env_clear and only Thalyx's pairs, over
dev/rust-corpus: without PATH the outline finds the struct and every name
resolves to nothing; with it, Resolution::One at lantern/src/lib.rs:8:12, uses
in the other crate, and a real rename across two files. And the chain below —
`cargo` invoked as a bare name with an empty environment compiles the workspace,
so it found its rustc the same way.

Confinement is untouched on purpose. The VM reported analyzer_confined=false
because the kernel is attached but observing, and the provider fell back to an
ordinary process inside Thalyx and the semantics failed anyway. One cause at a
time.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S4ij9nSjMTiCT6sd8DuBgQ
@CesarManzoCode
CesarManzoCode merged commit b7ba71b into main Sep 5, 2026
1 check failed
@CesarManzoCode
CesarManzoCode deleted the claude/rust-analyzer-semantic-resolution-vneio1 branch September 5, 2026 03:01
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.

2 participants