Skip to content

Implement LPP rename and edit validation in opy-provider #403

Description

@e54-bot

Readiness: needs-decision. The LPP contract and the Wright consumer path already exist; only the initial set of renameable symbol kinds (see "Decision needed") is open. Confirming the proposed default makes this ready-for-implementation.

Goal

opy-provider implements LPP lpp/rename and lpp/validateEdits for OPY projects, so Wright can offer validated semantic source edits for OPY without implementing OPY edit semantics itself.

Context

  • LPP v1 already specifies both methods: docs/spec/symbols-and-edits.md §15 (lpp/rename) and §16 (lpp/validateEdits, including the normative edit-application rules in §16.3). Refusal codes are provider-defined strings (docs/spec/errors-and-versioning.md §18.4), so no protocol change is needed.
  • opy-provider currently declares rename: false and editValidation: false (as well as symbols, definition, and references) in lpp/initialize (crates/opy-provider/src/main.rs), and its tests assert rename == false.
  • opy_rs::tooling::SemanticModel already indexes program-scope symbols (Global, Player, Subroutine, Def, Constant, Macro) with declaration and resolved reference locations. Rename should build on this owner model rather than on textual matching.
  • Wright already consumes these capabilities: ToolRequest::ProviderRename / provider edit validation in wright-driver call lpp/rename, then lpp/validateEdits on each edited document, then lpp/check over the edited project, and refuse explicitly on any failure (crates/wright-driver/src/provider_edit.rs). That path currently always ends in capability-unavailable for OPY. Wire provider-driven mutation through Wright product surfaces wright#156 wires the same capability through the Wright CLI and LSP once it exists here.

Scope

  • lpp/rename for the symbol kinds agreed below, across every document in the request's documents set (entry plus included files).
  • lpp/validateEdits for OPY documents per LPP §16.3: bounds, sorting, overlap detection with original-order indices, application, then parse/semantic validation.
  • Declare rename: true and editValidation: true in lpp/initialize only once both are implemented.
  • Refuse with LPP refusals, never partial or best-effort edits:
    • rename.noSymbolAtPosition when no symbol is at the position;
    • rename.invalidName for names that are not valid OPY identifiers, including reserved words;
    • rename.nameCollision when the new name collides with an existing symbol in the same scope or with a name the OPY resolver would bind first;
    • rename.requiresDocument when a reference lives in a project file that was not sent;
    • a provider-defined code, for example rename.unsupportedSymbolKind, for symbol kinds outside the agreed scope.

Decision needed

Which symbol kinds are renameable in the first release?

Proposed default: Global, Player, and Subroutine. Def, Constant, and Macro refuse with rename.unsupportedSymbolKind until their reference sites are proven to map exactly to authored text. Macro bodies and expansion sites are the main risk: a rename must never produce edits at preprocessed or expanded positions that do not correspond 1:1 to authored source.

Constraints

  • Edits are exact authored-source ranges. No whole-file regeneration and no serialized AST/IR (LPP §15). Unaffected source, comments, and trivia stay byte-identical.
  • If any reference location of the symbol cannot be mapped to an exact authored range (for example it comes from macro expansion or preprocessing), refuse the rename. Do not drop that reference.
  • lpp/validateEdits receives a single document with no project context. When that document is an included fragment, validation must not report a false syntaxError for names that only resolve across files. Cross-file semantic validation is Wright's follow-up lpp/check over the edited project.
  • check and compile must agree about whether the edited project is clean, as the existing tooling contract already requires.

Non-goals

Acceptance criteria

  • lpp/initialize declares rename: true and editValidation: true. The existing capability assertions are updated to match.
  • Renaming each in-scope symbol kind in a multi-file project (entry plus an included file) returns non-overlapping edits per document, sorted by range.start, that echo each document's version and cover the declaration and every reference. After the edits are applied, lpp/check is clean and bytes outside the edited ranges are unchanged.
  • After a rename, compiled Workshop output equals the pre-rename output with only the renamed identifier changed.
  • Each refusal (noSymbolAtPosition, invalidName, nameCollision, requiresDocument, unsupported kind) is covered by a test and returns no edits.
  • A symbol with at least one reference produced by macro expansion or preprocessing is refused rather than partially renamed.
  • lpp/validateEdits returns rangeOutOfBounds and overlappingEdits with the correct original-order failingEditIndex, returns syntaxError for edits that break the document, returns valid: true with the echoed version for clean edits, and does not report syntaxError for a clean included fragment that references cross-file symbols.
  • The LPP conformance runner's protocol scope still passes against opy-provider.
  • Ablation: replacing the rename edit generation with a result that skips one reference makes the coverage test fail.

Dependencies / ownership

Activity

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions