internal/workflow: order sub-workflow names from highest level to lowest

Deeply nested workflows are rare, but do come up: combined minor
Go release workflows (e.g., for 1.24 and 1.23) have a sub-workflow
per Go release, with further nested sub-workflows per release target.

It's seemingly more logical to have the top-level sub-workflow name at
at the first position, the second-level sub-workflow name at the second
position, and so on. We ended up with the inverse order, which leads to
task names like "linux-arm64: Go 1.24: Check distpacks match" instead of
task names like "Go 1.24: linux-arm64: Check distpacks match". Flip 'em.

Change-Id: I833e34e66c3eaee4b40c5d9450875a15ddf3d2f7
Reviewed-on: https://go-review.googlesource.com/c/build/+/670477
Reviewed-by: Carlos Amedee <carlos@golang.org>
Auto-Submit: Dmitri Shuralyov <dmitshur@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
diff --git a/internal/workflow/workflow.go b/internal/workflow/workflow.go
index 2032eca..f658287 100644
--- a/internal/workflow/workflow.go
+++ b/internal/workflow/workflow.go
@@ -79,7 +79,7 @@
 
 func (d *Definition) Sub(name string) *Definition {
 	return &Definition{
-		namePrefix:      name + ": " + d.namePrefix,
+		namePrefix:      d.namePrefix + name + ": ",
 		definitionState: d.definitionState,
 	}
 }
diff --git a/internal/workflow/workflow_test.go b/internal/workflow/workflow_test.go
index 24c74e3..1ec64f6 100644
--- a/internal/workflow/workflow_test.go
+++ b/internal/workflow/workflow_test.go
@@ -8,7 +8,9 @@
 	"context"
 	"errors"
 	"fmt"
+	"maps"
 	"reflect"
+	"slices"
 	"strings"
 	"sync/atomic"
 	"testing"
@@ -95,17 +97,23 @@
 	}
 
 	wd := wf.New(wf.ACL{})
-	sub1 := wd.Sub("sub1")
+	topSub := wd.Sub("top-sub")
+	sub1 := topSub.Sub("sub1")
 	g1 := wf.Task0(sub1, "Greeting", hi)
-	sub2 := wd.Sub("sub2")
+	sub2 := topSub.Sub("sub2")
 	g2 := wf.Task0(sub2, "Greeting", hi)
 	wf.Output(wd, "result", wf.Task2(wd, "Concatenate", concat, g1, g2))
 
+	storage := &mapListener{Listener: &verboseListener{t}}
 	w := startWorkflow(t, wd, nil)
-	outputs := runWorkflow(t, w, nil)
+	outputs := runWorkflow(t, w, storage)
 	if got, want := outputs["result"], "hi hi"; got != want {
 		t.Errorf("result = %q, want %q", got, want)
 	}
+	const wantTaskID = "top-sub: sub1: Greeting"
+	if _, ok := storage.states[w.ID][wantTaskID]; !ok {
+		t.Errorf("task ID %q doesn't exist, have: %q", wantTaskID, slices.Sorted(maps.Keys(storage.states[w.ID])))
+	}
 }
 
 func TestSplitJoin(t *testing.T) {