refactor(trace): rename Step.Action to Step.NextAction

The trace step's action field is the action chosen FOR THE NEXT iteration
based on observing this step's hierarchy, not the action that produced
this step. Rename Step.Action to Step.NextAction and the JSON tag to
next_action to make causality explicit at the data level.
This commit is contained in:
pj committed 2026-05-31 15:39:32 +05:30
1 parent 8d29b2906f
commit 4ee3d97cff
2 files changed
+11 -10

No files matched your search

+2 -1
View File
@@ -17,7 +17,8 @@ type Step struct {
Timestamp time.Time `json:"timestamp"`
Screen string `json:"screen,omitempty"`
Snapshots map[string]json.RawMessage `json:"snapshots,omitempty"`
Action *Action `json:"action,omitempty"`
// NextAction is the action chosen for the next iteration based on observing this step.
NextAction *Action `json:"next_action,omitempty"`
Exceptions []Exception `json:"exceptions,omitempty"`
Violations []string `json:"violations,omitempty"`
Hierarchy *hierarchy.Tree `json:"hierarchy,omitempty"`
+9 -9
View File
@@ -102,7 +102,7 @@ func TestWriteStep_HierarchyAndResidualsRoundTrip(t *testing.T) {
step := Step{
Index: 1,
Timestamp: time.Now().UTC(),
Action: &Action{
NextAction: &Action{
Kind: "tap",
Selector: "id:next",
ResolvedBounds: &BoundsRecord{X: 10, Y: 20, Width: 100, Height: 50},
@@ -120,14 +120,14 @@ func TestWriteStep_HierarchyAndResidualsRoundTrip(t *testing.T) {
if err := json.Unmarshal(body, &got); err != nil {
t.Fatalf("bad jsonl: %v\n%s", err, body)
}
if got.Action.Selector != "id:next" {
t.Errorf("selector = %q", got.Action.Selector)
if got.NextAction.Selector != "id:next" {
t.Errorf("selector = %q", got.NextAction.Selector)
}
if got.Action.ResolvedBounds == nil || got.Action.ResolvedBounds.Width != 100 {
t.Errorf("resolved_bounds round-trip wrong: %+v", got.Action.ResolvedBounds)
if got.NextAction.ResolvedBounds == nil || got.NextAction.ResolvedBounds.Width != 100 {
t.Errorf("resolved_bounds round-trip wrong: %+v", got.NextAction.ResolvedBounds)
}
if got.Action.TapPoint == nil || got.Action.TapPoint.X != 60 {
t.Errorf("tap_point round-trip wrong: %+v", got.Action.TapPoint)
if got.NextAction.TapPoint == nil || got.NextAction.TapPoint.X != 60 {
t.Errorf("tap_point round-trip wrong: %+v", got.NextAction.TapPoint)
}
if string(got.Residuals["prop1"]) != `{"op":"true"}` {
t.Errorf("residuals round-trip wrong: %s", got.Residuals["prop1"])
@@ -162,7 +162,7 @@ func TestWriteStep_AppendsOneJsonLine(t *testing.T) {
Snapshots: map[string]json.RawMessage{
"ledger.balance": json.RawMessage(`1500`),
},
Action: &Action{Kind: "tap", X: 100, Y: 200},
NextAction: &Action{Kind: "tap", X: 100, Y: 200},
Violations: []string{"ledgerBalanceMatchesTxns"},
}
if err := writer.WriteStep(step); err != nil {
@@ -177,7 +177,7 @@ func TestWriteStep_AppendsOneJsonLine(t *testing.T) {
if err := json.Unmarshal([]byte(lines[0]), &got); err != nil {
t.Fatalf("invalid JSONL line: %v\n%s", err, lines[0])
}
if got.Index != 1 || got.Screen != "customer_ledger" || got.Action.X != 100 || got.Violations[0] != "ledgerBalanceMatchesTxns" {
if got.Index != 1 || got.Screen != "customer_ledger" || got.NextAction.X != 100 || got.Violations[0] != "ledgerBalanceMatchesTxns" {
t.Errorf("step round-trip wrong: %+v", got)
}
}