ID |
|
|---|---|
Status |
Backlog |
Bucket |
architecture |
Priority |
2 |
Theme |
lsp |
Created |
2026-08-11 |
Updated |
2026-08-13 |
LSP argMapping completions and diagnostics at the @routine coordinate
LspVocabulary.CanonicalOverlay.overlay() keys Behavior.ArgMappingBinding on the SchemaCoordinate.InputField("ExternalCodeReference", "argMapping") coordinate only. @routine’s `argMapping is a SchemaCoordinate.DirectiveArg, and the overlay names no @routine coordinate at all, so @routine(argMapping:) gets no completions and no diagnostics: an author gets editor help on @service and silence on @routine. Add the SchemaCoordinate.DirectiveArg("routine", "argMapping") coordinate bound to Behavior.ArgMappingBinding.
The design was worked out and reviewed as part of roadmap/unify-argmapping-resolution-seam.md, and lifted out of it at that item’s Spec review to keep the seam work inside one module. It is independently observable and depends on nothing that item lands, so it can proceed in either order. Three observations from the current code:
-
ArgMappingCompletions.leftCandidatesgoes throughArgMappingSupport.resolveMethodand returns an empty list when no Java method resolves, so at a@routinecoordinate it degrades to silence rather than to wrong answers. It needs the routine’s IN parameter names from the catalog instead. Do not do this by branching on the coordinate.Behavior.ArgMappingBindingis a data-free marker, so a coordinate branch would re-derive, at two sites that must agree and nothing binds (leftCandidatesandDiagnostics.resolveParameterNames), a fact the overlay already knows when it registers the entry. Instead give the behaviour the fact:ArgMappingBinding(TargetSource source)with a sealedTargetSource.{ReflectedMethod(SchemaCoordinate classNameCoord), RoutineParams(SchemaCoordinate nameCoord)}. Both consumers switch on the carried variant and a third target set becomes a compile error at both. The exemplar is the sibling overlay entryBehavior.MethodNameBinding(ecrClassName), which already carries the coordinate its resolution depends on. The data-freecase Behavior.ArgMappingBinding ignored ->arms inCompletions,DefinitionsandHoverskeep compiling unchanged. -
Note that this is where the "named target set" abstraction that the seam item rejects for the classifier does pay. In the LSP both sides genuinely are "a name set resolved from a sibling directive argument", one axis with two arms. In the classifier they are not, because the two sides are discovered at different times by different mechanisms. Same words, different fact, so the same abstraction is right in one module and wrong in the other.
-
ArgMappingCompletions.rightCandidatesis already generic overTypeContext.fieldArgumentNames, so it needs nothing. It deliberately returns nothing once the token contains a., with the comment "Dot-path expansion into nested input fields is not modelled; offer nothing rather than a misleading flat list". That "offer nothing" note is now narrower than it reads, and the narrowing is worth stating because the two arms after a dot have different answers available: -
The input-object arm (a dot opening an input object into its fields) is still unanswerable and stays uniform across directives; improving it needs a nested-input-field projection in the LSP snapshot, which is its own item.
-
The node-id arm (a dot opening an
IDcarrying@nodeId(typeName:)into that node type’s key columns, the shape the key-column projection shipped) is answerable fromintent_resolved_node_key_columntoday, and needs no new capture:graphitron_argument_node_idandgraphitron_field_node_idalready carrynode_type_refat both coordinates. What is missing is only the consumer,rightCandidatesreturning nothing the moment a dot appears. So the editor is silent on a spelling the build now both accepts and rejects with a candidate list, which is the asymmetry to close. -
Diagnostics.validateArgMappingGraphqlArgalready validates the head segment only and already flags just the head span. It becomes reachable at@routinefor free once the overlay coordinate exists.
Tests: ArgMappingCompletionsTest and ArgMappingDiagnosticsTest gain @routine cases, mirroring the @service behaviour those files already pin: left-hand completions offer the routine’s IN parameter names, and a typo’d head segment underlines the head span only.
A small adjacent follow-up rides the same completions surface: ArgMappingSigil admits $session as an argMapping RHS at the @service site (binding the parameter to the <sessionState> mount’s returned handle), but right-hand completions never offer it. Offering the admitted sigil literal alongside the field argument names, at admitted sites only, is one more entry in an existing list rather than a new mechanism; the sigil owner (ArgMappingSigil) is where the admitted-site predicate already lives, so the completions arm should consult it rather than re-declare it. Named here because the session-identity spec that deferred it deletes at Done.