# Delete AGENTS-forbidden salvage paths

**Effort:** M · **Impact:** M · **Immediate roc UX:** yes

## Repro (wrong answers today)

Pick any of these; each is a silent lie rather than an honest miss.

### A — Text-token hover salvage

1. Hover a call / identifier where CIR offset matching is ambiguous or misses, but the **source token text** matches some other definition name in the module.
2. Observe hover showing a **type/docs for the wrong binding** (name match), not “no hover”.

**Code:** `src/lsp/syntax.zig` → `getTypeAtPosition` continues into `symbolAtOffset` + `findDefinitionByUnqualifiedName` after CIR paths fail (“Text-token fallback…”).

### B — Wrong-module `ModuleEnv`

1. Open a non-root module in a multi-module / package layout where `findModuleByPath` fails but a coordinator root still exists.
2. Trigger hover / completions / symbols.
3. Observe results drawn from **another** module’s `ModuleEnv` (root / “any coordinator package”), not null.

**Code:** `src/lsp/build_session.zig` → `getModuleEnv` after path lookup:

```zig
// Fallback: try to get the discovered root module by its package identity.
// Fallback: try to get a root module from any coordinator package.
```

### C — Same-text document highlights

1. Open a file with two unrelated identifiers that share spelling (or hover a name under parse stress).
2. When CIR highlights miss, handler falls back to `findHighlightsByToken`.
3. Observe every textual occurrence highlighted — including different bindings / noise — as if they were the same symbol.

**Code:** `src/lsp/handlers/document_highlight.zig` → after CIR miss, `findHighlightsByToken`.

## Why this is a red line

`AGENTS.md`: workarounds / fallbacks / heuristics are forbidden outside parse and error reporting. These paths **guess** when explicit CIR / path data is missing. Wrong answer > empty answer for editor trust.

## Goal

- Path-exact `ModuleEnv` or null — never substitute another module.
- CIR / region / pattern queries only for semantic features — never salvage by token text name.
- Parse-token scans only if framed as **parse/error-buffer UX** with a design.md-allowed role; default for highlight/hover is empty on miss.

## Fix shape

1. `getModuleEnv`: delete both fallback blocks; return null if `findModuleByPath` has no env.
2. `getTypeAtPosition`: delete `symbolAtOffset` salvage block (and remove `symbolAtOffset` if unused).
3. `document_highlight`: on CIR miss / error, return `[]` (or proper error per hand-off 03) — delete `findHighlightsByToken` path.
4. Grep `src/lsp` for `Fallback`, `fallback`, `for simplicity`, `any coordinator` — remove or justify under AGENTS with design.md text (prefer remove).
5. Tests that **pin the rejected side**: wrong-module must not appear; same-text highlight must not fire without CIR; hover name-match without CIR offset hit must be null.

## Acceptance

- [ ] No ModuleEnv returned for a path that wasn’t the built module for that URI.
- [ ] Hover without CIR hit → null (not another symbol with the same name).
- [ ] Document highlight without CIR → empty list.
- [ ] No new `RedirectRule`-style or heuristic recovery in LSP query paths.

## Out of scope

- Improving CIR offset precision so true hits increase (good follow-up; separate from deleting salvage).
- UTF-16 (hand-off 04) — do encoding first or together so “miss” isn’t caused by wrong columns.
