From b65b8373e623ae041831a9de92f55f21b225068a Mon Sep 17 00:00:00 2001 From: PJ Date: Mon, 13 Jul 2026 08:21:49 +0530 Subject: [PATCH] fix(verifier): label editable fields by hint, not the typed value an editable field's own text is its transient content; prefer the hint so the field is named by purpose and the label stays stable. --- internal/verifier/llm.go | 7 +++++++ internal/verifier/llm_test.go | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/internal/verifier/llm.go b/internal/verifier/llm.go index f5d2dc8..fd4280e 100644 --- a/internal/verifier/llm.go +++ b/internal/verifier/llm.go @@ -581,6 +581,13 @@ func buildNodeIndex(tree *hierarchy.Tree) map[*hierarchy.Element]*hierarchy.Node // case that fixes empty-text Compose buttons whose word lives on a child), then // its class as a last resort. func visibleLabel(element *hierarchy.Element, nodeIndex map[*hierarchy.Element]*hierarchy.Node) string { + // An editable field's own text is the transient typed value ("1"); its hint + // names its purpose ("Amount") and stays stable, so prefer the hint there. + if element.Editable { + if hint := element.Attributes["hintText"]; hint != "" { + return truncateLabel(hint) + } + } if element.Text != "" { return truncateLabel(element.Text) } diff --git a/internal/verifier/llm_test.go b/internal/verifier/llm_test.go index 0fcdbbb..a1a7510 100644 --- a/internal/verifier/llm_test.go +++ b/internal/verifier/llm_test.go @@ -100,6 +100,25 @@ func TestCandidatesTypingExposesInputType(t *testing.T) { } } +func TestCandidatesLabelsEditableFieldByHintNotTypedValue(t *testing.T) { + // A field already showing "99" must still be labeled by its purpose (the + // hint), not by its transient content, so the description stays stable. + tree := `{ + "attributes": {"bounds": "[0,0,400,800]"}, + "children": [ + {"attributes": {"resource-id": "Amt", "class": "EditText", "hintText": "Amount", "text": "99", "bounds": "[0,0,400,100]"}, "enabled": true, "children": []} + ] + }` + v := enumVerifier(t, "{kind:'builtin', verb:'typing'}", tree) + candidates := v.Candidates() + if hasCandidate(candidates, `Type into "99" (number)`) || hasCandidate(candidates, `Type into "99"`) { + t.Errorf("editable field labeled by its typed value: %v", descriptions(candidates)) + } + if !hasCandidate(candidates, `Type into "Amount" (number)`) { + t.Errorf("want the field labeled by its hint, got %v", descriptions(candidates)) + } +} + func TestCandidatesFoldsGesturesIntoDirectionalScrolls(t *testing.T) { v := enumVerifier(t, "{kind:'weighted', branches:[[1,{kind:'builtin',verb:'scrolls'}],[1,{kind:'builtin',verb:'swipes'}]]}",