Repository: bacalhau-project/bacalhau (language: python)

Issue:
Rename ListX responses to `Items`
Instead of having ListJob, ListJobExecutions,... return an array of `Jobs`, `Executions`,... , unify this to always return `Items` array along with `NextToken`

Preferably we should do this before announcing V1 API deprecation. Also would be nice to do this while maintaining backward compatibility with existing clients. Maybe we should explore adding bacalhau version as an http header, and return `Items` only for new versions? Up for discussion


Discussion / hints:
@frrist please prioritize this as we want to get it out for 1.4
Sorry, but I am not sure what the ask is here. Do we want to add struct tags to the listed results? e.g.
```go
type ListJobResultsResponse struct {
	BaseListResponse
	Results []*models.SpecConfig `json:"Items"`
}

type ListJobHistoryResponse struct {
	BaseListResponse
	History []*models.JobHistory `json:"Items"`
}

type ListJobsResponse struct {
	BaseListResponse
	Jobs []*models.Job `json:"Items"`
}
```
Or are we asking for a generic? e.g.
```go
type ListResponse[T any] struct {
	BaseListResponse
	Items []T
}
```
My initial thought is:
```
type ListJobResultsResponse struct {
	BaseListResponse
	Items []*models.SpecConfig
}

type ListJobHistoryResponse struct {
	BaseListResponse
	Items []*models.JobHistory
}

type ListJobsResponse struct {
	BaseListResponse
	Items []*models.Job
}
```

but generics may be a better idea. Keep in mind that I don't want to break backward compatibility with 1.3.x clients, as mentioned in the issue description 
To keep backwards compatibility with existing clients I think we'll need something like:
```go
type ListJobResultsResponse struct {
	BaseListResponse
	Results []*models.SpecConfig  // Deprecated
	Items   []*models.SpecConfig
}

type ListJobHistoryResponse struct {
	BaseListResponse
	History []*models.JobHistory  // Deprecated
	Items   []*models.JobHistory 
}

type ListJobsResponse struct {
	BaseListResponse
	Jobs  []*models.Job  // Deprecated
	Items []*models.Job 
}
```
After some amount of time we'll then need to remove the deprecated fields. wdyt?
We need the client to include the version in the header when making these requests to determine the field to populate. So if there isn't a version we populate both

Fix patch:
diff --git a/cmd/cli/job/describe.go b/cmd/cli/job/describe.go
index b5347727ea..5c3a2209cd 100644
--- a/cmd/cli/job/describe.go
+++ b/cmd/cli/job/describe.go
@@ -102,7 +102,7 @@ func (o *DescribeOptions) run(cmd *cobra.Command, args []string, api client.API)
 	var executions []*models.Execution
 	if response.Executions != nil {
 		// TODO: #520 rename Executions.Executions to Executions.Items
-		executions = response.Executions.Executions
+		executions = response.Executions.Items
 	}
 	// Show most relevant execution first: sort by time DESC
 	slices.SortFunc(executions, func(a, b *models.Execution) int {
@@ -111,7 +111,7 @@ func (o *DescribeOptions) run(cmd *cobra.Command, args []string, api client.API)
 
 	var history []*models.JobHistory
 	if response.History != nil {
-		history = response.History.History
+		history = response.History.Items
 	}
 
 	o.printHeaderData(cmd, job)
diff --git a/cmd/cli/job/executions.go b/cmd/cli/job/executions.go
index da9c4f8b32..3a337299bf 100644
--- a/cmd/cli/job/executions.go
+++ b/cmd/cli/job/executions.go
@@ -150,7 +150,7 @@ func (o *ExecutionOptions) run(cmd *cobra.Command, args []string, api client.API
 		return err
 	}
 
-	if err = output.Output(cmd, executionColumns, o.OutputOptions, response.Executions); err != nil {
+	if err = output.Output(cmd, executionColumns, o.OutputOptions, response.Items); err != nil {
 		return fmt.Errorf("failed to output: %w", err)
 	}
 
diff --git a/cmd/cli/job/history.go b/cmd/cli/job/history.go
index ffa224540e..8fc9507aa5 100644
--- a/cmd/cli/job/history.go
+++ b/cmd/cli/job/history.go
@@ -188,7 +188,7 @@ func (o *HistoryOptions) run(cmd *cobra.Command, args []string, api client.API)
 		return err
 	}
 
-	if err = output.Output(cmd, historyColumns, o.OutputOptions, response.History); err != nil {
+	if err = output.Output(cmd, historyColumns, o.OutputOptions, response.Items); err != nil {
 		return fmt.Errorf("failed to output: %w", err)
 	}
 
diff --git a/cmd/cli/job/list.go b/cmd/cli/job/list.go
index 61b11af016..d72e7f14a0 100644
--- a/cmd/cli/job/list.go
+++ b/cmd/cli/job/list.go
@@ -150,7 +150,7 @@ func (o *ListOptions) run(cmd *cobra.Command, api client.API) error {
 		return fmt.Errorf("failed request: %w", err)
 	}
 
-	if err = output.Output(cmd, listColumns, o.OutputOptions, response.Jobs); err != nil {
+	if err = output.Output(cmd, listColumns, o.OutputOptions, response.Items); err != nil {
 		return fmt.Errorf("failed to output: %w", err)
 	}
 
diff --git a/cmd/util/download.go b/cmd/util/download.go
index 36ee59b604..c20d3d4fde 100644
--- a/cmd/util/download.go
+++ b/cmd/util/download.go
@@ -36,7 +36,7 @@ func DownloadResultsHandler(
 		Fatal(cmd, fmt.Errorf("could not get results for job %s: %w", jobID, err), 1)
 	}
 
-	if len(response.Results) == 0 {
+	if len(response.Items) == 0 {
 		// No results doesn't mean error, so we should print out a message and return nil
 		cmd.Println("No results found")
 		cmd.Println("You can check the logged output of the job using the logs command.")
@@ -50,11 +50,11 @@ func DownloadResultsHandler(
 	}
 
 	// check if we don't support downloading the results
-	for _, result := range response.Results {
+	for _, result := range response.Items {
 		if !downloaderProvider.Has(ctx, result.Type) {
 			cmd.PrintErrln(
 				"No supported downloader found for the published results. You will have to download the results differently.")
-			b, err := json.MarshalIndent(response.Results, "", "    ")
+			b, err := json.MarshalIndent(response.Items, "", "    ")
 			if err != nil {
 				return err
 			}
@@ -70,7 +70,7 @@ func DownloadResultsHandler(
 
 	err = downloader.DownloadResults(
 		ctx,
-		response.Results,
+		response.Items,
 		downloaderProvider,
 		(*downloader.DownloaderSettings)(processedDownloadSettings),
 	)
diff --git a/cmd/util/printer/print.go b/cmd/util/printer/print.go
index 1d3ea65417..4719e7c419 100644
--- a/cmd/util/printer/print.go
+++ b/cmd/util/printer/print.go
@@ -90,7 +90,7 @@ func PrintJobExecution(
 			return fmt.Errorf("failed getting job history: %w", err)
 		}
 
-		historySummary := summariseHistoryEvents(history.History)
+		historySummary := summariseHistoryEvents(history.Items)
 		if len(historySummary) > 0 {
 			for _, event := range historySummary {
 				printEvent(cmd, event)
@@ -107,7 +107,7 @@ func PrintJobExecution(
 		if err != nil {
 			return fmt.Errorf("failed getting job executions: %w", err)
 		}
-		summary := summariseExecutions(executions.Executions)
+		summary := summariseExecutions(executions.Items)
 		if len(summary) > 0 {
 			cmd.Println("\nJob Results By Node:")
 			for message, runs := range summary {
diff --git a/pkg/publicapi/apimodels/helpers.go b/pkg/publicapi/apimodels/helpers.go
new file mode 100644
index 0000000000..d161a45d2a
--- /dev/null
+++ b/pkg/publicapi/apimodels/helpers.go
@@ -0,0 +1,23 @@
+package apimodels
+
+import (
+	"net/http"
+
+	"github.com/Masterminds/semver"
+
+	"github.com/bacalhau-project/bacalhau/pkg/version"
+)
+
+// GetClientVersion extracts the client version from the `X-Bacalhau-Git-Version` header in the request.
+// If the header is present and the version string can be parsed, it returns the parsed version.
+// If the header is missing or the version string cannot be parsed, it returns version.Unknown.
+func GetClientVersion(req *http.Request) *semver.Version {
+	if clientVerStr := req.Header.Get(HTTPHeaderBacalhauGitVersion); clientVerStr != "" {
+		clientVersion, err := semver.NewVersion(clientVerStr)
+		if err != nil {
+			return version.Unknown
+		}
+		return clientVersion
+	}
+	return version.Unknown
+}
diff --git a/pkg/publicapi/apimodels/job.go b/pkg/publicapi/apimodels/job.go
index 24de5431e9..69eec677fd 100644
--- a/pkg/publicapi/apimodels/job.go
+++ b/pkg/publicapi/apimodels/job.go
@@ -3,8 +3,9 @@ package apimodels
 import (
 	"strconv"
 
-	"github.com/bacalhau-project/bacalhau/pkg/models"
 	"k8s.io/apimachinery/pkg/labels"
+
+	"github.com/bacalhau-project/bacalhau/pkg/models"
 )
 
 type PutJobRequest struct {
@@ -89,7 +90,9 @@ func (o *ListJobsRequest) ToHTTPRequest() *HTTPRequest {
 
 type ListJobsResponse struct {
 	BaseListResponse
-	Jobs []*models.Job `json:"Jobs"`
+	// Deprecated, use Items
+	Jobs  []*models.Job
+	Items []*models.Job
 }
 
 // Normalize is used to canonicalize fields in the ListJobsResponse.
@@ -98,6 +101,9 @@ func (r *ListJobsResponse) Normalize() {
 	for _, job := range r.Jobs {
 		job.Normalize()
 	}
+	for _, job := range r.Items {
+		job.Normalize()
+	}
 }
 
 type ListJobHistoryRequest struct {
@@ -130,7 +136,9 @@ func (o *ListJobHistoryRequest) ToHTTPRequest() *HTTPRequest {
 
 type ListJobHistoryResponse struct {
 	BaseListResponse
+	// Deprecated: use Items
 	History []*models.JobHistory
+	Items   []*models.JobHistory
 }
 
 type ListJobExecutionsRequest struct {
@@ -140,7 +148,9 @@ type ListJobExecutionsRequest struct {
 
 type ListJobExecutionsResponse struct {
 	BaseListResponse
+	// Deprecated: use Items
 	Executions []*models.Execution
+	Items      []*models.Execution
 }
 
 type ListJobResultsRequest struct {
@@ -150,7 +160,9 @@ type ListJobResultsRequest struct {
 
 type ListJobResultsResponse struct {
 	BaseListResponse
+	// Deprecated: use Items
 	Results []*models.SpecConfig
+	Items   []*models.SpecConfig
 }
 
 type StopJobRequest struct {
diff --git a/pkg/publicapi/endpoint/orchestrator/job.go b/pkg/publicapi/endpoint/orchestrator/job.go
index f3502c2286..dc83b85e00 100644
--- a/pkg/publicapi/endpoint/orchestrator/job.go
+++ b/pkg/publicapi/endpoint/orchestrator/job.go
@@ -5,7 +5,7 @@ import (
 	"net/http"
 	"strings"
 
-	"github.com/bacalhau-project/bacalhau/pkg/lib/concurrency"
+	"github.com/Masterminds/semver"
 	"github.com/gorilla/websocket"
 	"github.com/labstack/echo/v4"
 	"github.com/rs/zerolog/log"
@@ -13,11 +13,13 @@ import (
 	"golang.org/x/exp/slices"
 
 	"github.com/bacalhau-project/bacalhau/pkg/jobstore"
+	"github.com/bacalhau-project/bacalhau/pkg/lib/concurrency"
 	"github.com/bacalhau-project/bacalhau/pkg/models"
 	"github.com/bacalhau-project/bacalhau/pkg/orchestrator"
 	"github.com/bacalhau-project/bacalhau/pkg/publicapi"
 	"github.com/bacalhau-project/bacalhau/pkg/publicapi/apimodels"
 	"github.com/bacalhau-project/bacalhau/pkg/util"
+	"github.com/bacalhau-project/bacalhau/pkg/version"
 )
 
 // godoc for Orchestrator PutJob
@@ -69,7 +71,7 @@ func (e *Endpoint) putJob(c echo.Context) error {
 // @Failure		400	{object}	string
 // @Failure		500	{object}	string
 // @Router			/api/v1/orchestrator/jobs [get]
-func (e *Endpoint) getJob(c echo.Context) error {
+func (e *Endpoint) getJob(c echo.Context) error { //nolint: gocyclo
 	ctx := c.Request().Context()
 	jobID := c.Param("id")
 	var args apimodels.GetJobRequest
@@ -97,10 +99,15 @@ func (e *Endpoint) getJob(c echo.Context) error {
 				return err
 			}
 			response.History = &apimodels.ListJobHistoryResponse{
-				History: make([]*models.JobHistory, len(history)),
+				Items: make([]*models.JobHistory, len(history)),
 			}
 			for i := range history {
-				response.History.History[i] = &history[i]
+				response.History.Items[i] = &history[i]
+			}
+			// migrate to old response if required
+			if listResponseRequiresMigration(apimodels.GetClientVersion(c.Request())) {
+				response.History.History = response.History.Items //nolint: staticcheck
+				response.History.Items = make([]*models.JobHistory, 0)
 			}
 		case "executions":
 			// ignore if user requested executions twice
@@ -114,13 +121,19 @@ func (e *Endpoint) getJob(c echo.Context) error {
 				return err
 			}
 			response.Executions = &apimodels.ListJobExecutionsResponse{
-				Executions: make([]*models.Execution, len(executions)),
+				Items: make([]*models.Execution, len(executions)),
 			}
 			for i := range executions {
-				response.Executions.Executions[i] = &executions[i]
+				response.Executions.Items[i] = &executions[i]
+			}
+			// migrate to old response if required
+			if listResponseRequiresMigration(apimodels.GetClientVersion(c.Request())) {
+				response.Executions.Executions = response.Executions.Items //nolint: staticcheck
+				response.Executions.Items = make([]*models.Execution, 0)
 			}
 		}
 	}
+
 	return c.JSON(http.StatusOK, response)
 }
 
@@ -209,7 +222,7 @@ func (e *Endpoint) listJobs(c echo.Context) error {
 	}
 
 	res := &apimodels.ListJobsResponse{
-		Jobs: lo.Map[models.Job, *models.Job](response.Jobs, func(item models.Job, _ int) *models.Job {
+		Items: lo.Map[models.Job, *models.Job](response.Jobs, func(item models.Job, _ int) *models.Job {
 			return &item
 		}),
 		BaseListResponse: apimodels.BaseListResponse{
@@ -217,6 +230,13 @@ func (e *Endpoint) listJobs(c echo.Context) error {
 		},
 	}
 
+	// migrate to old response if required
+	if listResponseRequiresMigration(apimodels.GetClientVersion(c.Request())) {
+		res.Jobs = res.Items
+		res.Items = make([]*models.Job, 0)
+		res.Normalize()
+	}
+
 	return c.JSON(http.StatusOK, res)
 }
 
@@ -298,10 +318,17 @@ func (e *Endpoint) jobHistory(c echo.Context) error {
 		return err
 	}
 	res := &apimodels.ListJobHistoryResponse{
-		History: make([]*models.JobHistory, len(history)),
+		Items: make([]*models.JobHistory, len(history)),
 	}
 	for i := range history {
-		res.History[i] = &history[i]
+		res.Items[i] = &history[i]
+	}
+
+	// migrate to old response if required
+	if listResponseRequiresMigration(apimodels.GetClientVersion(c.Request())) {
+		res.History = res.Items //nolint: staticcheck
+		res.Items = make([]*models.JobHistory, 0)
+		res.Normalize()
 	}
 
 	return c.JSON(http.StatusOK, res)
@@ -384,10 +411,17 @@ func (e *Endpoint) jobExecutions(c echo.Context) error {
 
 	// prepare result
 	res := &apimodels.ListJobExecutionsResponse{
-		Executions: make([]*models.Execution, len(executions)),
+		Items: make([]*models.Execution, len(executions)),
 	}
 	for i := range executions {
-		res.Executions[i] = &executions[i]
+		res.Items[i] = &executions[i]
+	}
+
+	// migrate to old response if required
+	if listResponseRequiresMigration(apimodels.GetClientVersion(c.Request())) {
+		res.Executions = res.Items //nolint: staticcheck
+		res.Items = make([]*models.Execution, 0)
+		res.Normalize()
 	}
 
 	return c.JSON(http.StatusOK, res)
@@ -428,9 +462,15 @@ func (e *Endpoint) jobResults(c echo.Context) error {
 		return err
 	}
 
-	return publicapi.UnescapedJSON(c, http.StatusOK, &apimodels.ListJobResultsResponse{
-		Results: resp.Results,
-	})
+	result := &apimodels.ListJobResultsResponse{Items: resp.Results}
+	// migrate to old response if required
+	if listResponseRequiresMigration(apimodels.GetClientVersion(c.Request())) {
+		result.Results = result.Items //nolint: staticcheck
+		result.Items = make([]*models.SpecConfig, 0)
+		result.Normalize()
+	}
+
+	return publicapi.UnescapedJSON(c, http.StatusOK, result)
 }
 
 // godoc for Orchestrator JobLogs
@@ -498,3 +538,15 @@ func (e *Endpoint) logsWS(c echo.Context, ws *websocket.Conn) error {
 	}
 	return nil
 }
+
+// listResponseRequiresMigration determines if the response to the request needs
+// to be migrated based on the client version. It returns true if the client
+// version is less than or equal to version.V1_3_2 without a pre-release version,
+// or if the client version is not development, or is unknown.
+// Otherwise, it returns false.
+func listResponseRequiresMigration(clientVersion *semver.Version) bool {
+	return !(clientVersion.GreaterThan(version.V1_3_2) ||
+		(clientVersion.Equal(version.V1_3_2) && clientVersion.Prerelease() != "") ||
+		clientVersion.Equal(version.Development) ||
+		clientVersion.Equal(version.Unknown))
+}
diff --git a/pkg/version/version.go b/pkg/version/version.go
index 77fbead493..aeae1da90a 100644
--- a/pkg/version/version.go
+++ b/pkg/version/version.go
@@ -19,6 +19,13 @@ import (
 )
 
 const DevelopmentGitVersion = "v0.0.0-xxxxxxx"
+const UnknownGitVersion = "v0.0.0"
+
+var (
+	Development = semver.MustParse(DevelopmentGitVersion)
+	Unknown     = semver.MustParse(UnknownGitVersion)
+	V1_3_2      = semver.MustParse("v1.3.2") //nolint: stylecheck
+)
 
 var (
 	// GITVERSION is the Git tag that Bacalhau was built from. This is expected to be populated via the `ldflags` flag,


Test patch:
diff --git a/cmd/cli/docker/docker_run_test.go b/cmd/cli/docker/docker_run_test.go
index 2a54543e89..19a93cc7ea 100644
--- a/cmd/cli/docker/docker_run_test.go
+++ b/cmd/cli/docker/docker_run_test.go
@@ -366,8 +366,8 @@ func (s *DockerRunSuite) TestTruncateReturn() {
 			})
 			s.Require().NoError(err)
 
-			s.Len(info.Executions.Executions, 1)
-			s.Len(info.Executions.Executions[0].RunOutput.STDOUT, int(tc.expectedLength.Bytes()))
+			s.Len(info.Executions.Items, 1)
+			s.Len(info.Executions.Items[0].RunOutput.STDOUT, int(tc.expectedLength.Bytes()))
 		})
 	}
 }
@@ -490,9 +490,9 @@ func (s *DockerRunSuite) TestRun_InvalidImage() {
 	// expected message we may consider adjusting the retry policy for this specific
 	// test. Alternatively, we could reduce the complexity and assert the job
 	// simply failed which is the expected behaviour for an invalid image
-	s.Require().Len(info.Executions.Executions, 2)
-	s.Contains(info.Executions.Executions[0].ComputeState.Message, `Could not inspect image "@" - could be due to repo/image not existing`)
-	s.Contains(info.Executions.Executions[1].ComputeState.Message, `Could not inspect image "@" - could be due to repo/image not existing`)
+	s.Require().Len(info.Executions.Items, 2)
+	s.Contains(info.Executions.Items[0].ComputeState.Message, `Could not inspect image "@" - could be due to repo/image not existing`)
+	s.Contains(info.Executions.Items[1].ComputeState.Message, `Could not inspect image "@" - could be due to repo/image not existing`)
 }
 
 func (s *DockerRunSuite) TestRun_Timeout_DefaultValue() {
@@ -541,9 +541,9 @@ func (s *DockerRunSuite) TestRun_NoPublisher() {
 	s.Require().NoError(err)
 	s.T().Log(info)
 
-	s.Require().Len(info.Executions.Executions, 1)
+	s.Require().Len(info.Executions.Items, 1)
 
-	exec := info.Executions.Executions[0]
+	exec := info.Executions.Items[0]
 	s.Require().Empty(exec.PublishedResult)
 
 }
@@ -561,9 +561,9 @@ func (s *DockerRunSuite) TestRun_LocalPublisher() {
 	s.Require().NoError(err)
 	s.T().Log(info)
 
-	s.Require().Len(info.Executions.Executions, 1)
+	s.Require().Len(info.Executions.Items, 1)
 
-	exec := info.Executions.Executions[0]
+	exec := info.Executions.Items[0]
 	result := exec.PublishedResult
 	s.Require().Equal(models.StorageSourceURL, result.Type)
 
diff --git a/cmd/cli/wasm/wasm_run_test.go b/cmd/cli/wasm/wasm_run_test.go
index c6bfffb8a0..1f40315c3a 100644
--- a/cmd/cli/wasm/wasm_run_test.go
+++ b/cmd/cli/wasm/wasm_run_test.go
@@ -58,7 +58,7 @@ func (s *WasmRunSuite) TestNoPublisher() {
 	s.Require().NoError(err)
 	s.T().Log(info)
 
-	exec := info.Executions.Executions
+	exec := info.Executions.Items
 	s.Require().Len(exec, 1)
 
 	result := exec[0].PublishedResult
@@ -83,7 +83,7 @@ func (s *WasmRunSuite) TestLocalPublisher() {
 
 	s.Require().Equal(models.PublisherLocal, job.Task().Publisher.Type, "Expected a local publisher")
 
-	exec := info.Executions.Executions
+	exec := info.Executions.Items
 	s.Require().Len(exec, 1)
 
 	result := exec[0].PublishedResult
diff --git a/pkg/publicapi/endpoint/orchestrator/migrate_list_resp_test.go b/pkg/publicapi/endpoint/orchestrator/migrate_list_resp_test.go
new file mode 100644
index 0000000000..ffca7c7995
--- /dev/null
+++ b/pkg/publicapi/endpoint/orchestrator/migrate_list_resp_test.go
@@ -0,0 +1,59 @@
+//go:build unit || !integration
+
+package orchestrator
+
+import (
+	"testing"
+
+	"github.com/Masterminds/semver"
+
+	"github.com/bacalhau-project/bacalhau/pkg/version"
+)
+
+func TestListResponseRequiresMigration(t *testing.T) {
+	tests := []struct {
+		name     string
+		version  *semver.Version
+		expected bool
+	}{
+		{
+			name:     "version less than 1.3.2",
+			version:  semver.MustParse("1.2.0"),
+			expected: true,
+		},
+		{
+			name:     "version equal to 1.3.2",
+			version:  version.V1_3_2,
+			expected: true,
+		},
+		{
+			name:     "development version",
+			version:  version.Development,
+			expected: false,
+		},
+		{
+			name:     "unknown version",
+			version:  version.Unknown,
+			expected: false,
+		},
+		{
+			name:     "version greater than 1.3.2",
+			version:  semver.MustParse("1.4.0"),
+			expected: false,
+		},
+		{
+			name:     "version equal to 1.3.2 with prerelease",
+			version:  semver.MustParse("v1.3.2-alpha"),
+			expected: true,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			result := listResponseRequiresMigration(tt.version)
+			if result != tt.expected {
+				t.Errorf("listResponseRequiresMigration(%v) = %v; want %v", tt.version, result, tt.expected)
+			}
+		})
+	}
+}
diff --git a/pkg/publicapi/test/job_test.go b/pkg/publicapi/test/job_test.go
index 528bcf459d..659af57b5a 100644
--- a/pkg/publicapi/test/job_test.go
+++ b/pkg/publicapi/test/job_test.go
@@ -30,10 +30,10 @@ func (s *ServerSuite) TestJobOperations() {
 	listResponse, err := s.client.Jobs().List(ctx, &apimodels.ListJobsRequest{})
 	s.Require().NoError(err)
 	s.Require().NotNil(listResponse)
-	s.Require().NotEmpty(listResponse.Jobs)
+	s.Require().NotEmpty(listResponse.Items)
 
 	found := false
-	for _, j := range listResponse.Jobs {
+	for _, j := range listResponse.Items {
 		if j.ID == putResponse.JobID {
 			found = true
 			break
@@ -59,8 +59,8 @@ func (s *ServerSuite) TestJobOperations() {
 	historyResponse, err := s.client.Jobs().History(ctx, &apimodels.ListJobHistoryRequest{JobID: putResponse.JobID})
 	s.Require().NoError(err)
 	s.Require().NotNil(historyResponse)
-	s.Require().NotEmpty(historyResponse.History)
-	for _, h := range historyResponse.History {
+	s.Require().NotEmpty(historyResponse.Items)
+	for _, h := range historyResponse.Items {
 		s.Require().Equal(putResponse.JobID, h.JobID)
 	}
 
@@ -69,13 +69,13 @@ func (s *ServerSuite) TestJobOperations() {
 		JobID})
 	s.Require().NoError(err)
 	s.Require().NotNil(executionsResponse)
-	s.Require().NotEmpty(executionsResponse.Executions)
+	s.Require().NotEmpty(executionsResponse.Items)
 
 	// list results
 	resultsResponse, err := s.client.Jobs().Results(ctx, &apimodels.ListJobResultsRequest{JobID: putResponse.JobID})
 	s.Require().NoError(err)
 	s.Require().NotNil(resultsResponse)
-	s.Require().Empty(resultsResponse.Results, "expected no results as we did not specify a publisher")
+	s.Require().Empty(resultsResponse.Items, "expected no results as we did not specify a publisher")
 
 	// stop the job should fail as it is already complete
 	_, err = s.client.Jobs().Stop(ctx, &apimodels.StopJobRequest{JobID: putResponse.JobID})
diff --git a/pkg/test/devstack/oversubscription_test.go b/pkg/test/devstack/oversubscription_test.go
index 7ee32afcf5..5c711c9a23 100644
--- a/pkg/test/devstack/oversubscription_test.go
+++ b/pkg/test/devstack/oversubscription_test.go
@@ -179,7 +179,7 @@ func (s *OverSubscriptionTestSuite) getJobStates() []models.JobStateType {
 	jobStates := make([]models.JobStateType, 0)
 	res, err := s.client.Jobs().List(context.Background(), &apimodels.ListJobsRequest{})
 	s.Require().NoError(err)
-	for _, j := range res.Jobs {
+	for _, j := range res.Items {
 		jobStates = append(jobStates, j.State.StateType)
 	}
 	return jobStates
diff --git a/pkg/test/scenario/suite.go b/pkg/test/scenario/suite.go
index 98190fa02c..5a92a353be 100644
--- a/pkg/test/scenario/suite.go
+++ b/pkg/test/scenario/suite.go
@@ -194,7 +194,7 @@ func (s *ScenarioRunner) RunScenario(scenario Scenario) string {
 			models.StorageSourceURL: http.NewHTTPDownloader(),
 		})
 
-		err = downloader.DownloadResults(s.Ctx, results.Results, downloaderProvider, downloaderSettings)
+		err = downloader.DownloadResults(s.Ctx, results.Items, downloaderProvider, downloaderSettings)
 		s.Require().NoError(err)
 
 		err = scenario.ResultsChecker(resultsDir)