From 5b08e09d6f241ed7936563ccc226d9f777050c9b Mon Sep 17 00:00:00 2001 From: PJ Date: Sat, 15 Aug 2026 13:41:45 +0530 Subject: [PATCH] feat(spec): give state.lastAction an applied field Three states, not two: no action is a null lastAction, applied: true is an action the runner confirmed, applied: null is one it dispatched and never learned the fate of. --- pkg/spec/src/index.ts | 1 + pkg/spec/src/types.ts | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/pkg/spec/src/index.ts b/pkg/spec/src/index.ts index 4ac8c31..4f75729 100644 --- a/pkg/spec/src/index.ts +++ b/pkg/spec/src/index.ts @@ -12,6 +12,7 @@ export type { InputTextAction, Key, KnownAttrSelectors, + LastAction, LogEntry, Point, PressKeyAction, diff --git a/pkg/spec/src/types.ts b/pkg/spec/src/types.ts index f748d83..c28fd05 100644 --- a/pkg/spec/src/types.ts +++ b/pkg/spec/src/types.ts @@ -102,10 +102,20 @@ export interface ExceptionRecord { unixMillis?: number; } +/** + * The previous step's action as the runner reports it. `applied` is true when + * the runner saw the dispatch succeed and null when the apply call failed with + * the gesture possibly already delivered: an RPC deadline can fire after the + * tap landed. Null is unknown, not "it did not happen" (`state.lastAction` is + * itself null for that), so a property attributing an effect to this action + * has to decline unless `applied` is true. + */ +export type LastAction = Action & { applied: true | null }; + export interface State { snapshots: Snapshots; ax: AccessibilityTree; - lastAction: Action | null; + lastAction: LastAction | null; time: number; logs: readonly LogEntry[]; exceptions: readonly ExceptionRecord[];