diff --git a/internal/runner/llm_source.go b/internal/runner/llm_source.go index e7f1afb..ac0c172 100644 --- a/internal/runner/llm_source.go +++ b/internal/runner/llm_source.go @@ -302,7 +302,14 @@ func describeAction(action verifier.Action) string { case verifier.ActionKindInputText: return fmt.Sprintf("InputText %s = %q", actionTarget(action), action.Text) case verifier.ActionKindScroll: - return fmt.Sprintf("Scroll %s %s", action.Direction, action.On) + // A builtin gesture carries endpoints rather than a selector, so name the + // container by where the drag starts; that is what tells two scrollable + // regions apart in the recent-action memory. + target := action.On + if target == "" { + target = fmt.Sprintf("(%d,%d)", action.FromX, action.FromY) + } + return fmt.Sprintf("Scroll %s %s", action.Direction, target) case verifier.ActionKindSwipe: // Coordinates make a repeated identical swipe recognizable in the // prompt's recent-action memory. diff --git a/internal/runner/llm_source_test.go b/internal/runner/llm_source_test.go index 057f583..f3372b1 100644 --- a/internal/runner/llm_source_test.go +++ b/internal/runner/llm_source_test.go @@ -62,6 +62,20 @@ func TestActionForCandidatePassesNonTypingThrough(t *testing.T) { } } +func TestDescribeActionNamesGesturesByOrigin(t *testing.T) { + builtin := verifier.Action{ + Kind: verifier.ActionKindScroll, Direction: "down", + FromX: 200, FromY: 500, ToX: 200, ToY: 340, + } + if got := describeAction(builtin); got != "Scroll down (200,500)" { + t.Errorf("builtin gesture described as %q, want the drag origin", got) + } + authored := verifier.Action{Kind: verifier.ActionKindScroll, Direction: "up", On: "id:List"} + if got := describeAction(authored); got != "Scroll up id:List" { + t.Errorf("authored scroll described as %q, want its selector", got) + } +} + func TestActionForCandidateUsesModelText(t *testing.T) { source := &llmSource{} candidate := verifier.ActionCandidate{