From 3d6f21ff9b874b9a09d243db19ff07d43c95ce47 Mon Sep 17 00:00:00 2001 From: Teakowa Date: Sun, 11 Oct 2026 04:44:21 +0800 Subject: [PATCH] feat(protocol): add canonical id resolution via lpp/resolveIds LPP 1.6 adds the optional resolveIds capability: a project-independent, bounded, deterministic map from canonical Workshop ids (calls, and enum members grouped by domain) to the language's spellings. An id with no spelling is omitted, never guessed, and a request over 1024 ids is rejected rather than truncated. The mock provider maps a small fixed table for x-demo-lang. Fixtures cover mapping and omission, the bound, the version gate, the absent capability, an invalid language, and invalid params. ADR-0006 records the decision. Fixes #55 --- README.md | 2 +- conformance/README.md | 7 +- .../fixtures/v1/62-resolve-ids-mapping.json | 12 + ...63-resolve-ids-capability-unavailable.json | 12 + .../v1/64-resolve-ids-version-gate.json | 10 + .../v1/65-resolve-ids-invalid-language.json | 10 + .../v1/66-resolve-ids-invalid-params.json | 14 + .../fixtures/v1/67-resolve-ids-bound.json | 3147 +++++++++++++++++ conformance/fixtures/v1/sessions/1.6.json | 30 + conformance/mock-provider/src/methods.rs | 32 +- conformance/mock-provider/src/puzzle.rs | 2 + .../mock-provider/src/puzzle/spellings.rs | 43 + conformance/mock-provider/src/puzzle/tests.rs | 21 + conformance/mock-provider/src/server.rs | 3 +- conformance/mock-provider/src/wire.rs | 12 +- conformance/runner/src/matcher.rs | 2 + docs/adr/0006-canonical-id-resolution.md | 82 + docs/adr/README.md | 1 + docs/spec/README.md | 3 +- docs/spec/conformance.md | 4 +- docs/spec/errors-and-versioning.md | 7 +- docs/spec/project-loading.md | 7 +- docs/spec/resolve-ids.md | 87 + 23 files changed, 3537 insertions(+), 13 deletions(-) create mode 100644 conformance/fixtures/v1/62-resolve-ids-mapping.json create mode 100644 conformance/fixtures/v1/63-resolve-ids-capability-unavailable.json create mode 100644 conformance/fixtures/v1/64-resolve-ids-version-gate.json create mode 100644 conformance/fixtures/v1/65-resolve-ids-invalid-language.json create mode 100644 conformance/fixtures/v1/66-resolve-ids-invalid-params.json create mode 100644 conformance/fixtures/v1/67-resolve-ids-bound.json create mode 100644 conformance/fixtures/v1/sessions/1.6.json create mode 100644 conformance/mock-provider/src/puzzle/spellings.rs create mode 100644 docs/adr/0006-canonical-id-resolution.md create mode 100644 docs/spec/resolve-ids.md diff --git a/README.md b/README.md index 3f9eb19..3f00389 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ its frontend, compiler, reconstruction, or Workshop integration internally. ## Status -- Protocol versions: **1.0**, additive **1.1** file-entry loading, additive **1.2** directory targets, and additive **1.3** source identity for entry-based compilation, and additive **1.4** artifact format negotiation for `lpp/compile`, and additive **1.5** name lookup via `lpp/lookup` (specified in [`docs/spec/README.md`](docs/spec/README.md)). +- Protocol versions: **1.0**, additive **1.1** file-entry loading, additive **1.2** directory targets, and additive **1.3** source identity for entry-based compilation, and additive **1.4** artifact format negotiation for `lpp/compile`, and additive **1.5** name lookup via `lpp/lookup`, and additive **1.6** canonical id resolution via `lpp/resolveIds` (specified in [`docs/spec/README.md`](docs/spec/README.md)). - Repository state: initial published contract and conformance suite. - Wright is a client/consumer of the protocol; LPP is not a dependency from the language implementation back into Wright tooling internals. diff --git a/conformance/README.md b/conformance/README.md index 6668af5..9ba5e92 100644 --- a/conformance/README.md +++ b/conformance/README.md @@ -1,6 +1,6 @@ # LPP v1 Conformance Suite -This directory contains the test suite and fixtures for the Language Provider Protocol v1 wire contract, including the LPP 1.1 file-entry, LPP 1.2 directory-target project-loading, LPP 1.3 source-identity, LPP 1.4 artifact-format negotiation, and LPP 1.5 name-lookup revisions (see [`../docs/spec/README.md`](../docs/spec/README.md)). +This directory contains the test suite and fixtures for the Language Provider Protocol v1 wire contract, including the LPP 1.1 file-entry, LPP 1.2 directory-target project-loading, LPP 1.3 source-identity, LPP 1.4 artifact-format negotiation, LPP 1.5 name-lookup, and LPP 1.6 canonical-id-resolution revisions (see [`../docs/spec/README.md`](../docs/spec/README.md)). ## Layout @@ -12,7 +12,7 @@ mock-provider/ Reference provider for the "x-demo-lang" equation DSL (Ru runner/ Conformance runner that replays fixtures against any provider binary ``` -* **Fixtures** (`fixtures/v1/`): one JSON file per scenario. Each scenario defines a session with request/response steps, optional CLI flags, and the expected exit code. Responses are compared after JSON parsing so key order does not matter. The directory contains LPP 1.0, LPP 1.1, LPP 1.2, LPP 1.3, LPP 1.4, and LPP 1.5 scenarios. `fixtures/v1/sessions/` holds the standard initialize/shutdown handshake once per protocol version; a scenario whose steps don't themselves exercise the handshake sets `"session": ""` and the runner splices those steps around its own. +* **Fixtures** (`fixtures/v1/`): one JSON file per scenario. Each scenario defines a session with request/response steps, optional CLI flags, and the expected exit code. Responses are compared after JSON parsing so key order does not matter. The directory contains LPP 1.0, LPP 1.1, LPP 1.2, LPP 1.3, LPP 1.4, LPP 1.5, and LPP 1.6 scenarios. `fixtures/v1/sessions/` holds the standard initialize/shutdown handshake once per protocol version; a scenario whose steps don't themselves exercise the handshake sets `"session": ""` and the runner splices those steps around its own. * **Mock provider** (`mock-provider/`): a small Rust binary implementing the full LPP v1 surface for a demonstration language distinct from OPY and OSTW. It runs over stdio so clients (like the Wright LPP client in wrightkit/wright#142) can test against it directly. * **Runner** (`runner/`): spawns a fresh provider process per scenario, feeds requests over stdin, validates stdout responses against expectations, and checks the process exit code. Expected responses compare verbatim except at leaves a fixture marks provider-supplied (see the scenario format below). @@ -154,6 +154,9 @@ Semantics exercised by the fixtures: and `start` settings, and the arithmetic operators, which form the `x-demo:enum/operator` enum domain — returned as ranked entries with callable, enum-domain, parameter, and setting facts. +* **resolveIds**: a fixed table that spells `applyImpulse` and + `setStatusEffect` as `shove` and `afflict` and `Status`/`STUNNED` as + `stunned`; every other id is unmapped and omitted. The mock provider binary accepts `--without ,...` to disable capabilities at runtime, which the capability-negotiation fixtures use. A diff --git a/conformance/fixtures/v1/62-resolve-ids-mapping.json b/conformance/fixtures/v1/62-resolve-ids-mapping.json new file mode 100644 index 0000000..4afa39b --- /dev/null +++ b/conformance/fixtures/v1/62-resolve-ids-mapping.json @@ -0,0 +1,12 @@ +{ + "name": "resolve-ids-mapping", + "description": "resolveIds maps requested canonical ids to the language's spellings: calls by id, enum members grouped by domain. Ids the language does not map, and domains with no mapped member, are omitted rather than reported.", + "scope": "semantics", + "session": "1.6", + "providerArgs": ["--protocol-version", "1.6"], + "steps": [ + {"request":{"id":2,"method":"lpp/resolveIds","params":{"languageId":"x-demo-lang","calls":["applyImpulse","setStatusEffect"],"enums":{"Status":["STUNNED"]}}},"expectResponse":{"result":{"calls":{"applyImpulse":"shove","setStatusEffect":"afflict"},"enums":{"Status":{"STUNNED":"stunned"}}}}}, + {"request":{"id":3,"method":"lpp/resolveIds","params":{"languageId":"x-demo-lang","calls":["applyImpulse","loweredOnlyConstruct"],"enums":{"Status":["STUNNED","UNMAPPED_MEMBER"],"UnmappedDomain":["ANY"]}}},"expectResponse":{"result":{"calls":{"applyImpulse":"shove"},"enums":{"Status":{"STUNNED":"stunned"}}}}}, + {"request":{"id":4,"method":"lpp/resolveIds","params":{"languageId":"x-demo-lang"}},"expectResponse":{"result":{"calls":{},"enums":{}}}} + ] +} diff --git a/conformance/fixtures/v1/63-resolve-ids-capability-unavailable.json b/conformance/fixtures/v1/63-resolve-ids-capability-unavailable.json new file mode 100644 index 0000000..f60844f --- /dev/null +++ b/conformance/fixtures/v1/63-resolve-ids-capability-unavailable.json @@ -0,0 +1,12 @@ +{ + "name": "resolve-ids-capability-unavailable", + "description": "A 1.6 provider may decline resolveIds independently: it advertises resolveIds false and answers lpp/resolveIds with capabilityUnavailable while lookup keeps working.", + "scope": "protocol", + "providerArgs": ["--protocol-version", "1.6", "--without", "resolveIds"], + "steps": [ + {"request":{"id":1,"method":"lpp/initialize","params":{"protocolVersion":"1.6"}},"expectResponse":{"result":{"protocolVersion":"1.6","serverInfo":{"name":{"$provider":"nonEmptyString"},"version":{"$provider":"nonEmptyString"}},"languages":{"$provider":"languageList"},"capabilities":{"check":true,"compile":true,"reconstruct":true,"symbols":true,"definition":true,"references":true,"rename":true,"editValidation":true,"projectLoading":true,"sourceIdentity":true,"lookup":true,"resolveIds":false}}}}, + {"request":{"id":2,"method":"lpp/resolveIds","params":{"languageId":"x-demo-lang","calls":["applyImpulse"]}},"expectResponse":{"error":{"code":-32000,"message":{"$provider":"nonEmptyString"},"data":{"lpp":{"kind":"capabilityUnavailable","details":{"capability":"resolveIds","method":"lpp/resolveIds"}}}}}}, + {"request":{"id":3,"method":"lpp/lookup","params":{"languageId":"x-demo-lang","query":"multiply","kind":"operator"}},"expectResponse":{"result":{"entries":[{"identity":"x-demo:operator/multiply","kind":"operator","spelling":"*","displayName":"multiply","callable":{"receiver":"integer","parameters":[{"name":"arg","type":"integer","required":true}]}}]}}}, + {"request":{"id":4,"method":"lpp/shutdown","params":{}},"expectResponse":{"result":null}} + ] +} diff --git a/conformance/fixtures/v1/64-resolve-ids-version-gate.json b/conformance/fixtures/v1/64-resolve-ids-version-gate.json new file mode 100644 index 0000000..187937f --- /dev/null +++ b/conformance/fixtures/v1/64-resolve-ids-version-gate.json @@ -0,0 +1,10 @@ +{ + "name": "resolve-ids-version-gate", + "description": "lpp/resolveIds exists only in LPP 1.6 sessions: a 1.5 provider does not advertise it and answers the method with capabilityUnavailable.", + "scope": "protocol", + "session": "1.5", + "providerArgs": ["--protocol-version", "1.5"], + "steps": [ + {"request":{"id":2,"method":"lpp/resolveIds","params":{"languageId":"x-demo-lang","calls":["applyImpulse"]}},"expectResponse":{"error":{"code":-32000,"message":{"$provider":"nonEmptyString"},"data":{"lpp":{"kind":"capabilityUnavailable","details":{"capability":"resolveIds","method":"lpp/resolveIds"}}}}}} + ] +} diff --git a/conformance/fixtures/v1/65-resolve-ids-invalid-language.json b/conformance/fixtures/v1/65-resolve-ids-invalid-language.json new file mode 100644 index 0000000..1454e6a --- /dev/null +++ b/conformance/fixtures/v1/65-resolve-ids-invalid-language.json @@ -0,0 +1,10 @@ +{ + "name": "resolve-ids-invalid-language", + "description": "A languageId the provider does not serve is refused with invalidLanguage.", + "scope": "protocol", + "session": "1.6", + "providerArgs": ["--protocol-version", "1.6"], + "steps": [ + {"request":{"id":2,"method":"lpp/resolveIds","params":{"languageId":"not-a-language","calls":["applyImpulse"]}},"expectResponse":{"error":{"code":-32000,"message":{"$provider":"nonEmptyString"},"data":{"lpp":{"kind":"invalidLanguage","details":{"languageId":"not-a-language"}}}}}} + ] +} diff --git a/conformance/fixtures/v1/66-resolve-ids-invalid-params.json b/conformance/fixtures/v1/66-resolve-ids-invalid-params.json new file mode 100644 index 0000000..ac4e84a --- /dev/null +++ b/conformance/fixtures/v1/66-resolve-ids-invalid-params.json @@ -0,0 +1,14 @@ +{ + "name": "resolve-ids-invalid-params", + "description": "Malformed resolveIds params are rejected with -32602: a missing languageId, wrong element types, and wrong container types.", + "scope": "protocol", + "session": "1.6", + "providerArgs": ["--protocol-version", "1.6"], + "steps": [ + {"request":{"id":2,"method":"lpp/resolveIds","params":{"calls":["applyImpulse"]}},"expectResponse":{"error":{"code":-32602,"message":{"$provider":"nonEmptyString"}}}}, + {"request":{"id":3,"method":"lpp/resolveIds","params":{"languageId":"x-demo-lang","calls":[1]}},"expectResponse":{"error":{"code":-32602,"message":{"$provider":"nonEmptyString"}}}}, + {"request":{"id":4,"method":"lpp/resolveIds","params":{"languageId":"x-demo-lang","calls":"applyImpulse"}},"expectResponse":{"error":{"code":-32602,"message":{"$provider":"nonEmptyString"}}}}, + {"request":{"id":5,"method":"lpp/resolveIds","params":{"languageId":"x-demo-lang","enums":["Status"]}},"expectResponse":{"error":{"code":-32602,"message":{"$provider":"nonEmptyString"}}}}, + {"request":{"id":6,"method":"lpp/resolveIds","params":{"languageId":"x-demo-lang","enums":{"Status":"STUNNED"}}},"expectResponse":{"error":{"code":-32602,"message":{"$provider":"nonEmptyString"}}}} + ] +} diff --git a/conformance/fixtures/v1/67-resolve-ids-bound.json b/conformance/fixtures/v1/67-resolve-ids-bound.json new file mode 100644 index 0000000..6b0e933 --- /dev/null +++ b/conformance/fixtures/v1/67-resolve-ids-bound.json @@ -0,0 +1,3147 @@ +{ + "name": "resolve-ids-bound", + "description": "A request may carry at most 1024 ids, counting calls and enum members together with duplicates. Exactly 1024 is served; 1025, including a split across calls and enum members, is rejected with -32602 rather than truncated.", + "scope": "protocol", + "session": "1.6", + "providerArgs": [ + "--protocol-version", + "1.6" + ], + "steps": [ + { + "request": { + "id": 2, + "method": "lpp/resolveIds", + "params": { + "languageId": "x-demo-lang", + "calls": [ + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse" + ] + } + }, + "expectResponse": { + "result": { + "calls": { + "applyImpulse": "shove" + }, + "enums": {} + } + } + }, + { + "request": { + "id": 3, + "method": "lpp/resolveIds", + "params": { + "languageId": "x-demo-lang", + "calls": [ + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse" + ] + } + }, + "expectResponse": { + "error": { + "code": -32602, + "message": { + "$provider": "nonEmptyString" + } + } + } + }, + { + "request": { + "id": 4, + "method": "lpp/resolveIds", + "params": { + "languageId": "x-demo-lang", + "calls": [ + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse", + "applyImpulse" + ], + "enums": { + "Status": [ + "STUNNED", + "STUNNED", + "STUNNED", + "STUNNED", + "STUNNED", + "STUNNED", + "STUNNED", + "STUNNED", + "STUNNED", + "STUNNED", + "STUNNED", + "STUNNED", + "STUNNED", + "STUNNED", + "STUNNED", + "STUNNED", + "STUNNED", + "STUNNED", + "STUNNED", + "STUNNED", + "STUNNED", + "STUNNED", + "STUNNED", + "STUNNED", + "STUNNED" + ] + } + } + }, + "expectResponse": { + "error": { + "code": -32602, + "message": { + "$provider": "nonEmptyString" + } + } + } + } + ] +} diff --git a/conformance/fixtures/v1/sessions/1.6.json b/conformance/fixtures/v1/sessions/1.6.json new file mode 100644 index 0000000..f2c7142 --- /dev/null +++ b/conformance/fixtures/v1/sessions/1.6.json @@ -0,0 +1,30 @@ +{ + "initialize": { + "request": { "id": "init", "method": "lpp/initialize", "params": { "protocolVersion": "1.6" } }, + "expectResponse": { + "result": { + "protocolVersion": "1.6", + "serverInfo": { "name": { "$provider": "nonEmptyString" }, "version": { "$provider": "nonEmptyString" } }, + "languages": { "$provider": "languageList" }, + "capabilities": { + "check": { "$provider": "boolean" }, + "compile": { "$provider": "boolean" }, + "reconstruct": { "$provider": "boolean" }, + "symbols": { "$provider": "boolean" }, + "definition": { "$provider": "boolean" }, + "references": { "$provider": "boolean" }, + "rename": { "$provider": "boolean" }, + "editValidation": { "$provider": "boolean" }, + "projectLoading": { "$provider": "boolean" }, + "sourceIdentity": { "$provider": "boolean" }, + "lookup": { "$provider": "boolean" }, + "resolveIds": { "$provider": "boolean" } + } + } + } + }, + "shutdown": { + "request": { "id": "shutdown", "method": "lpp/shutdown", "params": {} }, + "expectResponse": { "result": null } + } +} diff --git a/conformance/mock-provider/src/methods.rs b/conformance/mock-provider/src/methods.rs index d57e196..4ed1e82 100644 --- a/conformance/mock-provider/src/methods.rs +++ b/conformance/mock-provider/src/methods.rs @@ -21,7 +21,7 @@ use crate::rpc::{HandlerError, parse_params}; use crate::server::{LANGUAGE_ID, Server}; use crate::wire::{ DocsParams, Document, LookupParams, PositionParams, ReconstructParams, ReferencesParams, - RenameParams, ValidateEditsParams, + RenameParams, ResolveIdsParams, ValidateEditsParams, }; /// A dispatchable `lpp/*` method: wire name, gating capability, handler. @@ -79,6 +79,11 @@ pub(crate) const METHODS: &[Method] = &[ capability: "lookup", handler: Server::lookup, }, + Method { + name: "lpp/resolveIds", + capability: "resolveIds", + handler: Server::resolve_ids, + }, ]; impl Server { @@ -344,8 +349,33 @@ impl Server { })?; Ok(json!({ "entries": entries })) } + + fn resolve_ids(&self, params: Value) -> Result { + let params: ResolveIdsParams = parse_params(params)?; + if params.language_id != LANGUAGE_ID { + return Err(HandlerError::lpp( + "invalidLanguage", + json!({ "languageId": params.language_id }), + format!( + "language '{}' is not served by this provider", + params.language_id + ), + )); + } + let calls = params.calls.unwrap_or_default(); + let enums = params.enums.unwrap_or_default(); + let total = calls.len() + enums.values().map(Vec::len).sum::(); + if total > MAX_RESOLVE_IDS { + return Err(HandlerError::invalid_params()); + } + Ok(puzzle::resolve_ids(&calls, &enums)) + } } +/// The most ids (calls plus enum members, duplicates counted) one +/// `lpp/resolveIds` request may carry. +const MAX_RESOLVE_IDS: usize = 1024; + /// The provider-side bound applied when a request omits `limit`. const DEFAULT_LOOKUP_LIMIT: u32 = 20; diff --git a/conformance/mock-provider/src/puzzle.rs b/conformance/mock-provider/src/puzzle.rs index b4049be..f59c98c 100644 --- a/conformance/mock-provider/src/puzzle.rs +++ b/conformance/mock-provider/src/puzzle.rs @@ -10,6 +10,7 @@ mod catalog; mod edits; mod lex; mod parse; +mod spellings; mod symbols; mod text; @@ -20,6 +21,7 @@ pub(crate) use artifact::{ pub(crate) use catalog::{LookupScope, lookup}; pub(crate) use edits::{EditValidation, validate_edits}; pub(crate) use parse::parse_document; +pub(crate) use spellings::resolve_ids; pub(crate) use symbols::{Symbol, is_valid_identifier}; pub(crate) use text::{Position, Range, SourceText}; diff --git a/conformance/mock-provider/src/puzzle/spellings.rs b/conformance/mock-provider/src/puzzle/spellings.rs new file mode 100644 index 0000000..150f359 --- /dev/null +++ b/conformance/mock-provider/src/puzzle/spellings.rs @@ -0,0 +1,43 @@ +//! The canonical-id to `x-demo-lang` spelling table served by +//! `lpp/resolveIds`. +//! +//! The ids are the Workshop ids the protocol fixtures use. The demo language +//! maps only a few of them, with spellings unlike OverPy's, so a client cannot +//! pass by assuming spelling equals id. Every other id is unmapped and is +//! omitted from the result. + +use std::collections::BTreeMap; + +use serde_json::{Map, Value, json}; + +const CALLS: &[(&str, &str)] = &[("applyImpulse", "shove"), ("setStatusEffect", "afflict")]; + +const ENUM_MEMBERS: &[(&str, &str, &str)] = &[("Status", "STUNNED", "stunned")]; + +/// The result for the requested ids: only mapped ids, with `enums` grouped by +/// domain and a domain omitted when none of its members map. +pub(crate) fn resolve_ids(calls: &[String], enums: &BTreeMap>) -> Value { + let calls: Map = calls + .iter() + .filter_map(|id| { + let (_, spelling) = CALLS.iter().find(|(known, _)| known == id)?; + Some((id.clone(), json!(spelling))) + }) + .collect(); + let mut domains = Map::new(); + for (domain, members) in enums { + let mapped: Map = members + .iter() + .filter_map(|member| { + let (_, _, spelling) = ENUM_MEMBERS + .iter() + .find(|(d, m, _)| d == domain && m == member)?; + Some((member.clone(), json!(spelling))) + }) + .collect(); + if !mapped.is_empty() { + domains.insert(domain.clone(), Value::Object(mapped)); + } + } + json!({ "calls": calls, "enums": domains }) +} diff --git a/conformance/mock-provider/src/puzzle/tests.rs b/conformance/mock-provider/src/puzzle/tests.rs index 19e5ec8..f2c091d 100644 --- a/conformance/mock-provider/src/puzzle/tests.rs +++ b/conformance/mock-provider/src/puzzle/tests.rs @@ -334,3 +334,24 @@ fn identifier_rules_match_the_lexer() { assert!(!is_valid_identifier("")); assert!(!is_valid_identifier("a-b")); } + +#[test] +fn resolve_ids_omits_unmapped_ids_and_empty_domains() { + use super::spellings::resolve_ids; + use std::collections::BTreeMap; + let enums = BTreeMap::from([ + ( + "Status".to_string(), + vec!["STUNNED".into(), "HASTED".into()], + ), + ("Team".to_string(), vec!["ALL".into()]), + ]); + let result = resolve_ids(&["applyImpulse".into(), "noSuchCall".into()], &enums); + assert_eq!( + result, + serde_json::json!({ + "calls": { "applyImpulse": "shove" }, + "enums": { "Status": { "STUNNED": "stunned" } } + }) + ); +} diff --git a/conformance/mock-provider/src/server.rs b/conformance/mock-provider/src/server.rs index c5351ef..f1bbabd 100644 --- a/conformance/mock-provider/src/server.rs +++ b/conformance/mock-provider/src/server.rs @@ -12,7 +12,7 @@ use crate::rpc::{lpp_error, ok, parse_params, std_error}; use crate::wire::InitParams; /// Protocol versions accepted by `--protocol-version`. -pub(crate) const PROTOCOL_VERSIONS: [&str; 6] = ["1.0", "1.1", "1.2", "1.3", "1.4", "1.5"]; +pub(crate) const PROTOCOL_VERSIONS: [&str; 7] = ["1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6"]; pub(crate) const DEFAULT_PROTOCOL_VERSION: &str = PROTOCOL_VERSIONS[0]; pub(crate) const LANGUAGE_ID: &str = "x-demo-lang"; @@ -33,6 +33,7 @@ const CAPABILITIES: &[(&str, u32)] = &[ ("projectLoading", 1), ("sourceIdentity", 3), ("lookup", 5), + ("resolveIds", 6), ]; fn minor_of(version: &str) -> Option { diff --git a/conformance/mock-provider/src/wire.rs b/conformance/mock-provider/src/wire.rs index ffed3af..19347a4 100644 --- a/conformance/mock-provider/src/wire.rs +++ b/conformance/mock-provider/src/wire.rs @@ -1,7 +1,7 @@ //! Wire parameter shapes for the LPP v1 methods the mock provider serves. //! Field names follow the spec's camelCase JSON keys via serde. -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap}; use serde::{Deserialize, Serialize}; @@ -113,6 +113,16 @@ pub(crate) struct LookupParams { pub limit: Option, } +/// `lpp/resolveIds` params; element types are enforced by deserialization +/// and the total bound by the handler. +#[derive(Deserialize)] +#[serde(rename_all = "camelCase")] +pub(crate) struct ResolveIdsParams { + pub language_id: String, + pub calls: Option>, + pub enums: Option>>, +} + #[derive(Deserialize)] #[serde(rename_all = "camelCase")] pub(crate) struct ValidateEditsParams { diff --git a/conformance/runner/src/matcher.rs b/conformance/runner/src/matcher.rs index 52f8dce..387afb4 100644 --- a/conformance/runner/src/matcher.rs +++ b/conformance/runner/src/matcher.rs @@ -44,6 +44,7 @@ const CAPABILITY_IDS: &[&str] = &[ "projectLoading", "sourceIdentity", "lookup", + "resolveIds", ]; /// The capability ids a negotiated protocol version declares. @@ -53,6 +54,7 @@ fn declared_capability_ids(root: &Value) -> Option<&'static [&'static str]> { "1.1" | "1.2" => 9, "1.3" | "1.4" => 10, "1.5" => 11, + "1.6" => 12, _ => return None, }; Some(&CAPABILITY_IDS[..count]) diff --git a/docs/adr/0006-canonical-id-resolution.md b/docs/adr/0006-canonical-id-resolution.md new file mode 100644 index 0000000..57d7fab --- /dev/null +++ b/docs/adr/0006-canonical-id-resolution.md @@ -0,0 +1,82 @@ +# ADR 0006: Canonical Id Resolution via `lpp/resolveIds` + +- Status: Accepted +- Decision date: 2026-10-11 (UTC) +- Scope: LPP 1.6 `lpp/resolveIds` requests + +## Context + +Wright is adding structured rule content that names actions, values, +operators, and enum members by canonical Workshop id, such as `applyImpulse` +and `Status`/`STUNNED` (`wrightkit/wright#615`, ADR-0024 in that repository). +For an OverPy project the result must also carry the OverPy spelling of each +id that occurs in the content. Wright must not invent spellings or translate +names itself, so the provider has to supply them. + +`lpp/lookup` (LPP 1.5, ADR 0005) cannot do this. It resolves free text, and +the `identity` it issues is opaque to the client, so there is no path from a +canonical id to a spelling. + +## Decision + +LPP 1.6 adds `lpp/resolveIds` behind the optional `resolveIds` capability. + +- The request carries `languageId`, optional `calls` (an array of canonical + ids for actions, values, and operators), and optional `enums` (enum + members grouped by canonical domain id). +- The result has the same shape: `calls` maps id to spelling, and `enums` + maps domain to member to spelling. It contains only requested ids that the + language spells. +- An id with no spelling is omitted: no error, no placeholder, no guess. A + domain with no spelled member is omitted. +- A request holds at most 1024 ids in total, duplicates counted. A larger + request is rejected with `-32602` and is never truncated. +- A request needs no loaded project, as with `lpp/lookup`. +- LPP treats canonical ids as opaque strings. The Workshop ecosystem owns + the vocabulary; LPP defines none. +- A session that did not negotiate the capability, including one on an + earlier version, is answered with `capabilityUnavailable`. + +## Consequences + +- Version `"1.6"` is added as an additive minor version. Sessions on 1.5 and + earlier are unaffected. +- A provider advertises `resolveIds` only when it fully implements the + method. Wright reports the names as unavailable when it is absent. +- An id the provider does not know is treated as unmapped, so a newer client + vocabulary does not fail against an older provider. +- Conformance fixtures cover mapping, omission, the bound, the version gate, + the absent capability, an invalid language, and invalid params. The mock + provider maps a small fixed table for `x-demo-lang` with spellings unlike + the ids. +- `opy-rs` implements the capability from its own mapping from Workshop names + to OverPy spellings (`wrightkit/opy-rs#515`). + +## Alternatives considered + +### A canonical-id selector on `lpp/lookup` + +Rejected. `lookup` is a ranked, limited free-text search with opaque +identities. Adding an exact-id mode would give one method two semantics and +need rules for combining the modes. + +### A flat array of `{kind, id}` entries + +Rejected. It leaves room for id categories nobody has asked for. A new +category can be added later as an optional field under the minor-version +rules. + +### A provider-declared maximum + +Rejected. Callers send only the ids occurring in a bounded result, so a fixed +bound serves them, and a negotiated maximum adds a field with no consumer. + +### Reporting unmapped ids as an error or an `unmapped` list + +Rejected. A missing key already says "no spelling", and a guessed or +placeholder spelling would break the rule that spellings are not invented. + +### Truncating an oversized request + +Rejected. A client would read a missing key as "no spelling" when the +provider had only not looked. diff --git a/docs/adr/README.md b/docs/adr/README.md index bc82e82..0310c08 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -20,6 +20,7 @@ material process or wire-boundary decision. | [0003](0003-owner-selected-source-identity.md) | Owner-selected source identity for entry compilation | Accepted | 2026-09-13 | 2026-09-14 | [PR #34](https://github.com/wrightkit/language-provider-protocol/pull/34) | | [0004](0004-artifact-format-negotiation.md) | Client-stated artifact format negotiation for `lpp/compile` | Accepted | 2026-09-24 | 2026-09-24 | [Issue #39](https://github.com/wrightkit/language-provider-protocol/issues/39), [workshop-rs#271](https://github.com/wrightkit/workshop-rs/issues/271) | | [0005](0005-name-lookup.md) | Provider-owned name lookup via `lpp/lookup` | Accepted | 2026-10-05 | 2026-10-05 | [Issue #45](https://github.com/wrightkit/language-provider-protocol/issues/45), [wright#482](https://github.com/wrightkit/wright/issues/482) | +| [0006](0006-canonical-id-resolution.md) | Provider-owned canonical id resolution via `lpp/resolveIds` | Accepted | 2026-10-11 | 2026-10-11 | [Issue #55](https://github.com/wrightkit/language-provider-protocol/issues/55) | ## Post-baseline audit diff --git a/docs/spec/README.md b/docs/spec/README.md index c6d54d5..97904a5 100644 --- a/docs/spec/README.md +++ b/docs/spec/README.md @@ -2,7 +2,7 @@ | | | | --- | --- | -| Protocol versions | `1.0`, `1.1`, `1.2`, `1.3`, `1.4`, `1.5` | +| Protocol versions | `1.0`, `1.1`, `1.2`, `1.3`, `1.4`, `1.5`, `1.6` | | Status | Normative for protocol major version 1 | | Transport | JSON-RPC 2.0 over stdio, newline-delimited framing | | Conformance | `conformance/fixtures/v1/` + `conformance/runner` + `conformance/mock-provider` | @@ -26,6 +26,7 @@ Section numbering remains stable across files. - [Errors and protocol evolution](errors-and-versioning.md) — sections 18–19 - [Conformance and appendices](conformance.md) — section 20 and appendices - [Name lookup](name-lookup.md) — section 21 +- [Canonical id resolution](resolve-ids.md) — section 22 Read only the sections relevant to the implementation task. The files together form one versioned protocol contract. diff --git a/docs/spec/conformance.md b/docs/spec/conformance.md index 3a87d55..b5ec173 100644 --- a/docs/spec/conformance.md +++ b/docs/spec/conformance.md @@ -16,7 +16,8 @@ contract: scenario's `session` field. The same directory covers LPP 1.0, its LPP 1.1 file-entry revision, its LPP 1.2 directory-target revision, its LPP 1.3 source-identity revision, its LPP 1.4 artifact-format negotiation - revision, and its LPP 1.5 name-lookup revision. + revision, its LPP 1.5 name-lookup revision, and its LPP 1.6 + canonical-id-resolution revision. * `conformance/runner/`: a runner that replays fixtures against any provider binary and compares responses. * `conformance/mock-provider/`: the reference provider for the demonstration @@ -88,6 +89,7 @@ Methods: | `lpp/rename` | `rename` | `{ documents, positionDocumentUri, position, newName, projectRoot? }` | `{ edits: [{ documentUri, version, textEdits }] }` | | `lpp/validateEdits` | `editValidation` | `{ document, edits }` | `{ valid, version, reason?, failingEditIndex? }` | | `lpp/lookup` | `lookup` (LPP 1.5) | `{ languageId, query?, kind?, within?, locale?, limit? }` | `{ entries: [{ identity, kind, spelling, displayName, callable?, enum?, parameter?, setting? }] }` | +| `lpp/resolveIds` | `resolveIds` (LPP 1.6) | `{ languageId, calls?, enums? }` | `{ calls, enums }` | Types: `Position`, `Range`, `TextEdit`, `Document`, `DocumentSet`, `ProjectEntry`, `Diagnostic`, `Location`, `Symbol`, `WorkshopArtifact` (see diff --git a/docs/spec/errors-and-versioning.md b/docs/spec/errors-and-versioning.md index e92dc89..ce2c7c6 100644 --- a/docs/spec/errors-and-versioning.md +++ b/docs/spec/errors-and-versioning.md @@ -82,7 +82,8 @@ clients MUST NOT parse `message`. optional `sourceIdentity` capability for entry-based compile results, and LPP 1.4 adds `acceptedArtifactFormats` artifact format negotiation to `lpp/compile`. LPP 1.5 adds the optional `lookup` capability and the - `lpp/lookup` method. + `lpp/lookup` method, and LPP 1.6 adds the optional `resolveIds` + capability and the `lpp/resolveIds` method. * `MAJOR` changes are breaking: message shapes, method semantics, or framing may change. A breaking change always produces a new MAJOR version, and clients and providers speaking different MAJOR versions are never expected @@ -111,7 +112,9 @@ clients MUST NOT parse `message`. request `"1.3"` or later and require `sourceIdentity: true` in the result capabilities. Clients that send `acceptedArtifactFormats` MUST request `"1.4"` or later. Clients that need name lookup MUST request `"1.5"` or - later and require `lookup: true` in the result capabilities. + later and require `lookup: true` in the result capabilities. Clients that + need canonical id resolution MUST request `"1.6"` or later and require + `resolveIds: true`. * A provider MUST support at least one of the versions it lists in `supportedProtocolVersions`. diff --git a/docs/spec/project-loading.md b/docs/spec/project-loading.md index 547f6fa..db816be 100644 --- a/docs/spec/project-loading.md +++ b/docs/spec/project-loading.md @@ -23,7 +23,7 @@ Initialization and capability negotiation. The client MUST send | Field | Type | Description | | --- | --- | --- | -| `protocolVersion` | string | The protocol version the client wants to speak: `"1.0"`, `"1.1"`, `"1.2"`, `"1.3"`, `"1.4"`, or `"1.5"`. | +| `protocolVersion` | string | The protocol version the client wants to speak: `"1.0"`, `"1.1"`, `"1.2"`, `"1.3"`, `"1.4"`, `"1.5"`, or `"1.6"`. | | `clientInfo` | object, OPTIONAL | `{ "name": string, "version": string }` identifying the client. | ### 7.2 Result @@ -50,10 +50,10 @@ Initialization and capability negotiation. The client MUST send | Field | Type | Description | | --- | --- | --- | -| `protocolVersion` | string | The protocol version the provider will speak: `"1.0"`, `"1.1"`, `"1.2"`, `"1.3"`, `"1.4"`, or `"1.5"`. | +| `protocolVersion` | string | The protocol version the provider will speak: `"1.0"`, `"1.1"`, `"1.2"`, `"1.3"`, `"1.4"`, `"1.5"`, or `"1.6"`. | | `serverInfo` | object | `{ "name": string, "version": string }` identifying the provider. | | `languages` | array | One entry per source language the provider serves. | -| `capabilities` | object | The capabilities the provider advertises, as one boolean field per capability id. The object itself is required; its keys are drawn from the capability ids declared for the negotiated version (Section 7.3): LPP 1.0 declares the eight listed below, LPP 1.1 adds `projectLoading`, LPP 1.3 adds `sourceIdentity`, and LPP 1.5 adds `lookup`. A provider MAY advertise any subset — an absent id means not offered, equivalent to `false`. | +| `capabilities` | object | The capabilities the provider advertises, as one boolean field per capability id. The object itself is required; its keys are drawn from the capability ids declared for the negotiated version (Section 7.3): LPP 1.0 declares the eight listed below, LPP 1.1 adds `projectLoading`, LPP 1.3 adds `sourceIdentity`, and LPP 1.5 adds `lookup`, and LPP 1.6 adds `resolveIds`. A provider MAY advertise any subset — an absent id means not offered, equivalent to `false`. | Each language entry: `{ "id": string, "extensions": [string] }`. `extensions` is the list of file extensions the provider associates with the language, @@ -78,6 +78,7 @@ extension. | `projectLoading` | `lpp/check`, `lpp/compile` | Accept a client-selected entry or directory target and load its filesystem-backed source project. LPP 1.1 and later. | | `sourceIdentity` | `lpp/compile` | Return the provider-selected primary source identity for an entry-based compile result. LPP 1.3 and later. | | `lookup` | `lpp/lookup` | Resolve free-text name guesses to language spellings and signature facts. LPP 1.5 and later. | +| `resolveIds` | `lpp/resolveIds` | Map canonical Workshop ids to language spellings. LPP 1.6 and later. | * The provider MUST set each capability to `true` only if it fully implements the corresponding method(s). diff --git a/docs/spec/resolve-ids.md b/docs/spec/resolve-ids.md new file mode 100644 index 0000000..fa4423b --- /dev/null +++ b/docs/spec/resolve-ids.md @@ -0,0 +1,87 @@ +# LPP v1 — Canonical id resolution + +[← LPP v1 specification index](README.md) + +## 22. lpp/resolveIds (LPP 1.6) + +Map a set of canonical Workshop ids to the provider's language spellings: +the reverse direction of `lpp/lookup`, which resolves free text and issues +opaque identities. A client that holds canonical ids, for example the ids in a +rule's content, uses `lpp/resolveIds` to learn how the language writes each +one. The provider owns the spellings; the client MUST NOT derive or guess +them. + +The canonical ids are owned by the Workshop ecosystem, not by LPP. LPP treats +each id as an opaque string and defines no id vocabulary. + +`lpp/resolveIds` is available only in a session that negotiated protocol +version `"1.6"` or later and whose provider advertised +`capabilities.resolveIds: true`. A request in any other session MUST be +answered with an LPP error of kind `capabilityUnavailable`, including a session +that negotiated an earlier version (see +[Section 7.3](project-loading.md#73-capability-negotiation)). + +### 22.1 Request + +```json +{ + "jsonrpc": "2.0", + "id": 12, + "method": "lpp/resolveIds", + "params": { + "languageId": "x-demo-lang", + "calls": ["applyImpulse", "setStatusEffect"], + "enums": { "Status": ["STUNNED"] } + } +} +``` + +| Field | Type | Description | +| --- | --- | --- | +| `languageId` | string | REQUIRED. The language to resolve for. It MUST be a language id advertised in `lpp/initialize`; a language the provider does not serve MUST produce an LPP error of kind `invalidLanguage`. | +| `calls` | array of string | OPTIONAL. Canonical ids of actions, values, and operators. Absent is equivalent to `[]`. | +| `enums` | object | OPTIONAL. Enum members grouped by canonical domain id: each key is a domain id and each value is an array of canonical member ids. Absent is equivalent to `{}`. | + +* The total number of ids, `calls` plus every `enums` member array, counting + duplicates, MUST NOT exceed **1024**. A request over the bound MUST be + rejected with JSON-RPC `-32602`; a provider MUST NOT truncate. A client with + more ids sends several requests. +* A `params` value that does not match this schema MUST be rejected with + `-32602`, including a missing `languageId` or a wrong element or container + type. +* A request carries no `documents` or `entry`: the provider MUST answer from + its language vocabulary alone and MUST NOT require a loaded project. + +### 22.2 Result + +```json +{ + "calls": { "applyImpulse": "shove", "setStatusEffect": "afflict" }, + "enums": { "Status": { "STUNNED": "stunned" } } +} +``` + +| Field | Type | Description | +| --- | --- | --- | +| `calls` | object | REQUIRED. Maps each requested call id the language spells to its spelling. | +| `enums` | object | REQUIRED. Maps a domain id to an object that maps each requested member id the language spells to its spelling. | + +* A spelling is the bare text the client would write in the language, as in + `lpp/lookup`; it is never a rendered signature. Its format is + provider-defined. +* **Omission:** an id the language has no spelling for, whether it is unknown + to the provider or exists only after lowering, MUST be omitted. A provider + MUST NOT report it as an error, return a placeholder, or guess a spelling. + A domain none of whose requested members is spelled MUST be omitted. A + client treats an absent key as "no spelling". +* The result contains only requested ids, so it is bounded by the request. +* Results MUST be deterministic: the same request against the same provider + version MUST return the same result. Key order carries no meaning. +* A request with no ids produces `{ "calls": {}, "enums": {} }`. + +### 22.3 Failure behavior + +* Capability not negotiated, including a session that negotiated a version + earlier than 1.6: LPP error of kind `capabilityUnavailable`. +* `languageId` not served by the provider: LPP error of kind `invalidLanguage`. +* Invalid `params`, or more than 1024 ids: JSON-RPC `-32602`.