From bdf1d301e05919cff613eedb1a3ce3f771d45532 Mon Sep 17 00:00:00 2001 From: Stephan Renatus Date: Tue, 21 Jul 2026 11:07:16 +0200 Subject: [PATCH] server/failtracer: skip self-referential undefined-ref hints The compile-time fail hints used a fuzzy match against the ref's top-level segment to suggest typo fixes (e.g. input.frut -> input.fruit). levenshtein.ClosestStrings returns the exact match itself when the top-level segment already matches a declared unknown, so any failure caused by a missing/undefined sub-field (rather than a misspelled top-level name) produced a hint suggesting the exact same ref back, e.g. "input.resource.heading undefined, did you mean input.resource.heading?". Skip the hint entirely in that case, since the fuzzy matcher has no visibility into sub-fields and suggesting the ref unchanged is a no-op. Signed-off-by: Stephan Renatus --- v1/server/failtracer/failtracer.go | 7 +++++++ v1/server/failtracer/hints_test.go | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/v1/server/failtracer/failtracer.go b/v1/server/failtracer/failtracer.go index 08a205dd60..47b4a604d8 100644 --- a/v1/server/failtracer/failtracer.go +++ b/v1/server/failtracer/failtracer.go @@ -85,6 +85,13 @@ func (b *failTracer) Hints(unknowns []ast.Ref) []Hint { continue } miss := string(tblPart) + if slices.Contains(candidates, miss) { + // The top-level segment is already a declared unknown, so the + // failure comes from something deeper in the ref that this + // fuzzy match can't see. Suggesting the ref itself as a "fix" + // would be a no-op, so skip it. + continue + } rs := ref[1:].String() if _, ok := seenRefs[rs]; ok { continue diff --git a/v1/server/failtracer/hints_test.go b/v1/server/failtracer/hints_test.go index b299c013d3..6f9ae7e803 100644 --- a/v1/server/failtracer/hints_test.go +++ b/v1/server/failtracer/hints_test.go @@ -84,6 +84,14 @@ func TestHints(t *testing.T) { {Message: "input.fruit.colour undefined, did you mean input.fruits.colour?"}, }, }, + { + note: "top-level ref already correct, no self-referential hint", + evts: []topdown.Event{ + evtFromExpr(`__local1__ = input.resource.heading`), + }, + unknowns: []string{"input.resource"}, + exp: nil, + }, { note: "same typo, multiple fail events", evts: []topdown.Event{