language server: a rename checks the files of its name once #172

Closed
opened 2026-10-08 01:20:48 +00:00 by orion · 4 comments
Collaborator

Context

LANGUAGE-SERVER.md section 15, fourth bullet: a rename of a name many files have checks all of them twice - before the edits and after - which takes seconds. Split from #10.

Depends on #171. Both change how the server holds a ModuleRun and its pending work in server.trb; start this one after #171 is merged.

Goal

A rename checks each file of its name once: the check after the edits. The facts of the check before the edits (ModuleFacts of compiler/src/language-server/rename.trb: what every name resolves to, and every problem) come from what the server already knows, instead of a second ModuleRun over the same files.

Design record points (pinned)

  • Section 10: a rename is checked before it is made - the files it could touch (the old name or the new one as a word) are checked before the edits and after them, the facts compared with the places moved, and the rename answered only where they agree; a file that has the old name and a problem before refuses it. Behaviour is unchanged: the same refusals with the same reasons, the same edits. Only where the "before" comes from changes.
  • Section 5: a file's check depends on its own text and on the interfaces it sees; a body change that leaves the interface alone checks that body and nothing that imports it. The same fact says when a kept "before" is still true.
  • Sections 2 and 3: the rename is a RequestJob that takes steps and can be cancelled.

Design (inside the record, no owner question)

  • The server keeps ModuleFacts per file, taken when the workspace check finishes a module (and when a rename or a references search checks a file), with the text it was taken from and the project's generation: the count that grows where the front is built from scratch (outline change, closed document, watched file changed on disk, the 200th run) and where a body change alters what other bodies see (bodyFactsOf, section 7).
  • A rename reuses a file's kept facts only if the file's text is the one in the rename's tree and the generation is the one the facts were taken in. A file without valid facts is checked before the edits as today. The after check is always run.
  • A change of a file drops that file's facts at once.
  • Memory: the facts hold three integers per resolved name. The PR measures them for the compiler's own workspace and, if they are large, bounds the kept set (for example to the files that have a word at all; least recently used otherwise) and says so in the record. Bounding must not change an answer, only how often the before check runs.

Acceptance criteria

  • After the workspace check finished, a rename of a name that ten files hold word-wise runs the check before the edits for none of them and the check after them for each of them once; a test counts module checks (a counter or the run's timings) over a workspace of at least ten small modules.
  • Differential test: for every rename scenario of the existing tests (the refused ones - shadowing local, collision, member takeover, a problem before the rename - and the accepted ones, field renames with labels), the answer with kept facts equals the answer with the facts dropped.
  • Stale facts are not used: a file edited after the workspace check (open document change, and a change on disk) is checked before the edits again, with a test for each.
  • An interface change of a module drops the kept facts (generation bump); a rename right after it checks before and after as today, with a test.
  • $/cancelRequest in either phase still stops the rename.
  • The existing rename tests and tests/lsp/*.expected pass unchanged.
  • The rename of a name many files have is timed on the compiler's own workspace (a name used in the most files, for example a parameter-free helper) on a binary built by the forge CI (not a gate), before and after the PR; the numbers and the memory cost of the kept facts are written into section 10 and the fourth bullet of section 15 is removed.
  • If the docs change reaches skills/, it is regenerated.

Seed

No. Existing syntax; no native, no flag.

Size and commits

One PR, one or two Conventional Commits: perf(lsp): take the facts before a rename from the check the workspace made, and optionally docs(lsp): measure a rename of a name many files have. Tier A in the forge CI.

Implementer

opus / high (language server core).

Collisions

Touches server.trb (RenameSearch, renameBefore, the workspace check's publishing), workspace.trb, rename.trb. #171 changes the same server code: this issue starts after it. No overlap with the running #6, #7, #9.

## Context [LANGUAGE-SERVER.md section 15, fourth bullet](https://git.torb.dev/torbscript/language/src/commit/068e52da9182672d56447e775c6705661eca5af2/docs/design/LANGUAGE-SERVER.md#L407): a rename of a name many files have checks all of them twice - before the edits and after - which takes seconds. Split from #10. **Depends on #171.** Both change how the server holds a `ModuleRun` and its pending work in `server.trb`; start this one after #171 is merged. ## Goal A rename checks each file of its name once: the check after the edits. The facts of the check before the edits (`ModuleFacts` of `compiler/src/language-server/rename.trb`: what every name resolves to, and every problem) come from what the server already knows, instead of a second `ModuleRun` over the same files. ## Design record points (pinned) - Section 10: a rename is checked before it is made - the files it could touch (the old name or the new one as a word) are checked before the edits and after them, the facts compared with the places moved, and the rename answered only where they agree; a file that has the old name and a problem before refuses it. **Behaviour is unchanged**: the same refusals with the same reasons, the same edits. Only where the "before" comes from changes. - Section 5: a file's check depends on its own text and on the interfaces it sees; a body change that leaves the interface alone checks that body and nothing that imports it. The same fact says when a kept "before" is still true. - Sections 2 and 3: the rename is a `RequestJob` that takes steps and can be cancelled. ## Design (inside the record, no owner question) - The server keeps `ModuleFacts` per file, taken when the workspace check finishes a module (and when a rename or a references search checks a file), with the text it was taken from and the project's generation: the count that grows where the front is built from scratch (outline change, closed document, watched file changed on disk, the 200th run) and where a body change alters what other bodies see (`bodyFactsOf`, section 7). - A rename reuses a file's kept facts only if the file's text is the one in the rename's tree and the generation is the one the facts were taken in. A file without valid facts is checked before the edits as today. The after check is always run. - A change of a file drops that file's facts at once. - Memory: the facts hold three integers per resolved name. The PR measures them for the compiler's own workspace and, if they are large, bounds the kept set (for example to the files that have a word at all; least recently used otherwise) and says so in the record. Bounding must not change an answer, only how often the before check runs. ## Acceptance criteria - [ ] After the workspace check finished, a rename of a name that ten files hold word-wise runs the check before the edits for none of them and the check after them for each of them once; a test counts module checks (a counter or the run's timings) over a workspace of at least ten small modules. - [ ] Differential test: for every rename scenario of the existing tests (the refused ones - shadowing local, collision, member takeover, a problem before the rename - and the accepted ones, field renames with labels), the answer with kept facts equals the answer with the facts dropped. - [ ] Stale facts are not used: a file edited after the workspace check (open document change, and a change on disk) is checked before the edits again, with a test for each. - [ ] An interface change of a module drops the kept facts (generation bump); a rename right after it checks before and after as today, with a test. - [ ] `$/cancelRequest` in either phase still stops the rename. - [ ] The existing rename tests and `tests/lsp/*.expected` pass unchanged. - [ ] The rename of a name many files have is timed on the compiler's own workspace (a name used in the most files, for example a parameter-free helper) on a binary built by the forge CI (not a gate), before and after the PR; the numbers and the memory cost of the kept facts are written into section 10 and the fourth bullet of section 15 is removed. - [ ] If the docs change reaches `skills/`, it is regenerated. ## Seed No. Existing syntax; no native, no flag. ## Size and commits One PR, one or two Conventional Commits: `perf(lsp): take the facts before a rename from the check the workspace made`, and optionally `docs(lsp): measure a rename of a name many files have`. Tier A in the forge CI. ## Implementer opus / high (language server core). ## Collisions Touches `server.trb` (`RenameSearch`, `renameBefore`, the workspace check's publishing), `workspace.trb`, `rename.trb`. #171 changes the same server code: this issue starts after it. No overlap with the running #6, #7, #9.
Author
Collaborator

[loop:torbscript] refine: split from #10 and made ready (acceptance criteria, pinned records, seed: no). Implementer: opus/high. Depends on #171: start only after it is merged (same server.trb code), next: implement

[loop:torbscript] refine: split from #10 and made ready (acceptance criteria, pinned records, seed: no). Implementer: opus/high. Depends on #171: start only after it is merged (same server.trb code), next: implement
Author
Collaborator

[loop:torbscript] claim implement by session:loop-torbscript-20261008 until 2026-10-08T21:10:00Z

[loop:torbscript] claim implement by session:loop-torbscript-20261008 until 2026-10-08T21:10:00Z
argus closed this issue 2026-10-08 14:22:57 +00:00
Author
Collaborator

[loop:torbscript] implement: PR #195 open, CI green (https://git.torb.dev/torbscript/language/actions/runs/275), next: review

[loop:torbscript] implement: PR https://git.torb.dev/torbscript/language/pulls/195 open, CI green (https://git.torb.dev/torbscript/language/actions/runs/275), next: review
Author
Collaborator

[loop:torbscript] implement: correction - argus already reviewed and merged #195 (head 3272b13d, both commits, CI green), so review is done.

[loop:torbscript] implement: correction - argus already reviewed and merged https://git.torb.dev/torbscript/language/pulls/195 (head 3272b13d, both commits, CI green), so review is done.
Sign in to join this conversation.
No labels
loop
ready
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
torbscript/language#172
No description provided.