From 53245fc589da09d804177bccbf5c926134aa17c7 Mon Sep 17 00:00:00 2001 From: PJ Date: Sat, 15 Aug 2026 13:33:49 +0530 Subject: [PATCH] fix(verifier): report whether the last action was confirmed applied Both hosts get applied: true when the runner saw the dispatch succeed and applied: null when it could not, so an unconfirmed action stops arriving at the spec as no action at all. --- internal/verifier/marshal.go | 16 ++++++++++++++-- internal/verifier/types.go | 5 +++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/internal/verifier/marshal.go b/internal/verifier/marshal.go index f9604b5..212f4a3 100644 --- a/internal/verifier/marshal.go +++ b/internal/verifier/marshal.go @@ -344,7 +344,19 @@ func lastActionFields(action *Action) []actionField { point := func(x, y int) []actionField { return []actionField{{key: "x", value: x}, {key: "y", value: y}} } - fields := []actionField{{key: "kind", value: string(action.Kind)}} + // An action whose apply call failed is not an action that did not happen: + // the dispatch may have landed before the error. That is unknown, and + // unknown is null here for the same reason every other absence in the spec + // surface is, so a property decides for itself instead of being handed a + // "nothing happened" the runner cannot vouch for. + var applied any + if action.Applied { + applied = true + } + fields := []actionField{ + {key: "kind", value: string(action.Kind)}, + {key: "applied", value: applied}, + } if action.On != "" { fields = append(fields, actionField{key: "on", value: action.On}) } @@ -397,7 +409,7 @@ func objectFromFields(runtime *goja.Runtime, fields []actionField) *goja.Object // has no Go-side state object to read: the runner pushes this JSON into the // page before each extractor evaluation. A nil action encodes as JSON null, // the same value the goja host reports on the first step of a run and after a -// step whose action was never applied. +// step whose action was never dispatched. func EncodeLastAction(action *Action) json.RawMessage { if action == nil { return json.RawMessage("null") diff --git a/internal/verifier/types.go b/internal/verifier/types.go index 5b35eb7..125703b 100644 --- a/internal/verifier/types.go +++ b/internal/verifier/types.go @@ -33,6 +33,11 @@ type Action struct { // Direction is the scroll direction for ActionKindScroll: one of "up", // "down", "left", "right". Empty for every other kind. Direction string + // Applied is meaningful only on the action a step reports to the spec as + // state.lastAction: true when the runner saw the dispatch succeed, false + // when the apply call failed and nothing can say whether the action + // reached the app. The spec is told which of the two it is. + Applied bool } // LogEntry mirrors a logcat line captured between steps.