Repository: kubernetes-sigs/kueue

Issue:
"Nominate Worker Clusters with Incremental Dispatcher" is constantly logged for all workloads at V3
**What happened**:

This log line is constantly logged for all workloads: "Nominate Worker Clusters with Incremental Dispatcher"

**What you expected to happen**:

Log this line only for: MultiKueue workload which is QuotaReserved (and not Finished etc)

**How to reproduce it (as minimally and precisely as possible)**:


Just see our e2e logs (not for MultiKueue even), eg:

https://storage.googleapis.com/kubernetes-ci-logs/pr-logs/pull/kubernetes-sigs_kueue/7318/pull-kueue-test-e2e-main-1-34/1980552609731186688/artifacts/run-test-e2e-singlecluster-1.34.0/kind-worker2/pods/kueue-system_kueue-controller-manager-74948d5f78-8jhm2_9cd4181b-f4d6-4f03-b951-1eecff8060b6/manager/0.log


**Anything else we need to know?**:

```
2025-10-21T08:49:55.133092469Z stderr F 2025-10-21T08:49:55.132883577Z	LEVEL(-3)	workloaddispatcher/incrementaldispatcher.go:77	Nominate Worker Clusters with Incremental Dispatcher	{"controller": "multikueue_incremental_dispatcher", "controllerGroup": "kueue.x-k8s.io", "controllerKind": "Workload", "Workload": {"name":"job-admission-checked-job-42f2a","namespace":"e2e-metrics-qtdfr"}, "namespace": "e2e-metrics-qtdfr", "name": "job-admission-checked-job-42f2a", "reconcileID": "b8d97723-347d-4740-bee5-f61c4382e49f"}
2025-10-21T08:49:55.133127589Z stderr F 2025-10-21T08:49:55.132932997Z	LEVEL(-3)	workloaddispatcher/incrementaldispatcher.go:80	Not a Incremental Dispatcher, skip the reconciliation	{"controller": "multikueue_incremental_dispatcher", "controllerGroup": "kueue.x-k8s.io", "controllerKind": "Workload", "Workload": {"name":"job-admission-checked-job-42f2a","namespace":"e2e-metrics-qtdfr"}, "namespace": "e2e-metrics-qtdfr", "name": "job-admission-checked-job-42f2a", "reconcileID": "b8d97723-347d-4740-bee5-f61c4382e49f", "dispatcherName": "kueue.x-k8s.io/multikueue-dispatcher-all-at-once"}
```

Hints from issue comments:
@mimowo: cc @mszadkow @mszadkow: /assign@mszadkow: /unassign@mszadkow: /assign

Solution patch:
diff --git a/apis/kueue/v1beta1/workload_conversion.go b/apis/kueue/v1beta1/workload_conversion.go
index 729b7f863..b32330e80 100644
--- a/apis/kueue/v1beta1/workload_conversion.go
+++ b/apis/kueue/v1beta1/workload_conversion.go
@@ -21,6 +21,7 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/conversion"
 
 	"sigs.k8s.io/kueue/apis/kueue/v1beta2"
+	"sigs.k8s.io/kueue/pkg/util/tas"
 )
 
 //lint:file-ignore ST1003 "generated Convert_* calls below use underscores"
@@ -69,3 +70,32 @@ func Convert_v1beta2_WorkloadSpec_To_v1beta1_WorkloadSpec(in *v1beta2.WorkloadSp
 	}
 	return autoConvert_v1beta2_WorkloadSpec_To_v1beta1_WorkloadSpec(in, out, s)
 }
+
+func Convert_v1beta1_TopologyAssignment_To_v1beta2_TopologyAssignment(in *TopologyAssignment, out *v1beta2.TopologyAssignment, s conversionapi.Scope) error {
+	ta := &tas.TopologyAssignment{
+		Levels:  in.Levels,
+		Domains: make([]tas.TopologyDomainAssignment, 0, len(in.Domains)),
+	}
+	for _, domain := range in.Domains {
+		ta.Domains = append(ta.Domains, tas.TopologyDomainAssignment{
+			Values: domain.Values,
+			Count:  domain.Count,
+		})
+	}
+	v2 := tas.V1Beta2From(ta)
+	out.Levels = v2.Levels
+	out.Slices = v2.Slices
+	return nil
+}
+
+func Convert_v1beta2_TopologyAssignment_To_v1beta1_TopologyAssignment(in *v1beta2.TopologyAssignment, out *TopologyAssignment, s conversionapi.Scope) error {
+	out.Levels = in.Levels
+	out.Domains = make([]TopologyDomainAssignment, 0, tas.TotalDomainCount(in))
+	for req := range tas.InternalSeqFrom(in) {
+		out.Domains = append(out.Domains, TopologyDomainAssignment{
+			Values: req.Values,
+			Count:  req.Count,
+		})
+	}
+	return nil
+}
diff --git a/apis/kueue/v1beta1/zz_generated.conversion.go b/apis/kueue/v1beta1/zz_generated.conversion.go
index 3ae4e0220..ee4b57db6 100644
--- a/apis/kueue/v1beta1/zz_generated.conversion.go
+++ b/apis/kueue/v1beta1/zz_generated.conversion.go
@@ -618,26 +618,6 @@ func RegisterConversions(s *runtime.Scheme) error {
 	}); err != nil {
 		return err
 	}
-	if err := s.AddGeneratedConversionFunc((*TopologyAssignment)(nil), (*v1beta2.TopologyAssignment)(nil), func(a, b interface{}, scope conversion.Scope) error {
-		return Convert_v1beta1_TopologyAssignment_To_v1beta2_TopologyAssignment(a.(*TopologyAssignment), b.(*v1beta2.TopologyAssignment), scope)
-	}); err != nil {
-		return err
-	}
-	if err := s.AddGeneratedConversionFunc((*v1beta2.TopologyAssignment)(nil), (*TopologyAssignment)(nil), func(a, b interface{}, scope conversion.Scope) error {
-		return Convert_v1beta2_TopologyAssignment_To_v1beta1_TopologyAssignment(a.(*v1beta2.TopologyAssignment), b.(*TopologyAssignment), scope)
-	}); err != nil {
-		return err
-	}
-	if err := s.AddGeneratedConversionFunc((*TopologyDomainAssignment)(nil), (*v1beta2.TopologyDomainAssignment)(nil), func(a, b interface{}, scope conversion.Scope) error {
-		return Convert_v1beta1_TopologyDomainAssignment_To_v1beta2_TopologyDomainAssignment(a.(*TopologyDomainAssignment), b.(*v1beta2.TopologyDomainAssignment), scope)
-	}); err != nil {
-		return err
-	}
-	if err := s.AddGeneratedConversionFunc((*v1beta2.TopologyDomainAssignment)(nil), (*TopologyDomainAssignment)(nil), func(a, b interface{}, scope conversion.Scope) error {
-		return Convert_v1beta2_TopologyDomainAssignment_To_v1beta1_TopologyDomainAssignment(a.(*v1beta2.TopologyDomainAssignment), b.(*TopologyDomainAssignment), scope)
-	}); err != nil {
-		return err
-	}
 	if err := s.AddGeneratedConversionFunc((*TopologyInfo)(nil), (*v1beta2.TopologyInfo)(nil), func(a, b interface{}, scope conversion.Scope) error {
 		return Convert_v1beta1_TopologyInfo_To_v1beta2_TopologyInfo(a.(*TopologyInfo), b.(*v1beta2.TopologyInfo), scope)
 	}); err != nil {
@@ -758,6 +738,11 @@ func RegisterConversions(s *runtime.Scheme) error {
 	}); err != nil {
 		return err
 	}
+	if err := s.AddConversionFunc((*TopologyAssignment)(nil), (*v1beta2.TopologyAssignment)(nil), func(a, b interface{}, scope conversion.Scope) error {
+		return Convert_v1beta1_TopologyAssignment_To_v1beta2_TopologyAssignment(a.(*TopologyAssignment), b.(*v1beta2.TopologyAssignment), scope)
+	}); err != nil {
+		return err
+	}
 	if err := s.AddConversionFunc((*WorkloadSpec)(nil), (*v1beta2.WorkloadSpec)(nil), func(a, b interface{}, scope conversion.Scope) error {
 		return Convert_v1beta1_WorkloadSpec_To_v1beta2_WorkloadSpec(a.(*WorkloadSpec), b.(*v1beta2.WorkloadSpec), scope)
 	}); err != nil {
@@ -778,6 +763,11 @@ func RegisterConversions(s *runtime.Scheme) error {
 	}); err != nil {
 		return err
 	}
+	if err := s.AddConversionFunc((*v1beta2.TopologyAssignment)(nil), (*TopologyAssignment)(nil), func(a, b interface{}, scope conversion.Scope) error {
+		return Convert_v1beta2_TopologyAssignment_To_v1beta1_TopologyAssignment(a.(*v1beta2.TopologyAssignment), b.(*TopologyAssignment), scope)
+	}); err != nil {
+		return err
+	}
 	if err := s.AddConversionFunc((*v1beta2.WorkloadSpec)(nil), (*WorkloadSpec)(nil), func(a, b interface{}, scope conversion.Scope) error {
 		return Convert_v1beta2_WorkloadSpec_To_v1beta1_WorkloadSpec(a.(*v1beta2.WorkloadSpec), b.(*WorkloadSpec), scope)
 	}); err != nil {
@@ -793,7 +783,17 @@ func RegisterConversions(s *runtime.Scheme) error {
 
 func autoConvert_v1beta1_Admission_To_v1beta2_Admission(in *Admission, out *v1beta2.Admission, s conversion.Scope) error {
 	out.ClusterQueue = v1beta2.ClusterQueueReference(in.ClusterQueue)
-	out.PodSetAssignments = *(*[]v1beta2.PodSetAssignment)(unsafe.Pointer(&in.PodSetAssignments))
+	if in.PodSetAssignments != nil {
+		in, out := &in.PodSetAssignments, &out.PodSetAssignments
+		*out = make([]v1beta2.PodSetAssignment, len(*in))
+		for i := range *in {
+			if err := Convert_v1beta1_PodSetAssignment_To_v1beta2_PodSetAssignment(&(*in)[i], &(*out)[i], s); err != nil {
+				return err
+			}
+		}
+	} else {
+		out.PodSetAssignments = nil
+	}
 	return nil
 }
 
@@ -804,7 +804,17 @@ func Convert_v1beta1_Admission_To_v1beta2_Admission(in *Admission, out *v1beta2.
 
 func autoConvert_v1beta2_Admission_To_v1beta1_Admission(in *v1beta2.Admission, out *Admission, s conversion.Scope) error {
 	out.ClusterQueue = ClusterQueueReference(in.ClusterQueue)
-	out.PodSetAssignments = *(*[]PodSetAssignment)(unsafe.Pointer(&in.PodSetAssignments))
+	if in.PodSetAssignments != nil {
+		in, out := &in.PodSetAssignments, &out.PodSetAssignments
+		*out = make([]PodSetAssignment, len(*in))
+		for i := range *in {
+			if err := Convert_v1beta2_PodSetAssignment_To_v1beta1_PodSetAssignment(&(*in)[i], &(*out)[i], s); err != nil {
+				return err
+			}
+		}
+	} else {
+		out.PodSetAssignments = nil
+	}
 	return nil
 }
 
@@ -1830,7 +1840,15 @@ func autoConvert_v1beta1_PodSetAssignment_To_v1beta2_PodSetAssignment(in *PodSet
 	out.Flavors = *(*map[corev1.ResourceName]v1beta2.ResourceFlavorReference)(unsafe.Pointer(&in.Flavors))
 	out.ResourceUsage = *(*corev1.ResourceList)(unsafe.Pointer(&in.ResourceUsage))
 	out.Count = (*int32)(unsafe.Pointer(in.Count))
-	out.TopologyAssignment = (*v1beta2.TopologyAssignment)(unsafe.Pointer(in.TopologyAssignment))
+	if in.TopologyAssignment != nil {
+		in, out := &in.TopologyAssignment, &out.TopologyAssignment
+		*out = new(v1beta2.TopologyAssignment)
+		if err := Convert_v1beta1_TopologyAssignment_To_v1beta2_TopologyAssignment(*in, *out, s); err != nil {
+			return err
+		}
+	} else {
+		out.TopologyAssignment = nil
+	}
 	out.DelayedTopologyRequest = (*v1beta2.DelayedTopologyRequestState)(unsafe.Pointer(in.DelayedTopologyRequest))
 	return nil
 }
@@ -1845,7 +1863,15 @@ func autoConvert_v1beta2_PodSetAssignment_To_v1beta1_PodSetAssignment(in *v1beta
 	out.Flavors = *(*map[corev1.ResourceName]ResourceFlavorReference)(unsafe.Pointer(&in.Flavors))
 	out.ResourceUsage = *(*corev1.ResourceList)(unsafe.Pointer(&in.ResourceUsage))
 	out.Count = (*int32)(unsafe.Pointer(in.Count))
-	out.TopologyAssignment = (*TopologyAssignment)(unsafe.Pointer(in.TopologyAssignment))
+	if in.TopologyAssignment != nil {
+		in, out := &in.TopologyAssignment, &out.TopologyAssignment
+		*out = new(TopologyAssignment)
+		if err := Convert_v1beta2_TopologyAssignment_To_v1beta1_TopologyAssignment(*in, *out, s); err != nil {
+			return err
+		}
+	} else {
+		out.TopologyAssignment = nil
+	}
 	out.DelayedTopologyRequest = (*DelayedTopologyRequestState)(unsafe.Pointer(in.DelayedTopologyRequest))
 	return nil
 }
@@ -2323,48 +2349,16 @@ func Convert_v1beta2_Topology_To_v1beta1_Topology(in *v1beta2.Topology, out *Top
 
 func autoConvert_v1beta1_TopologyAssignment_To_v1beta2_TopologyAssignment(in *TopologyAssignment, out *v1beta2.TopologyAssignment, s conversion.Scope) error {
 	out.Levels = *(*[]string)(unsafe.Pointer(&in.Levels))
-	out.Domains = *(*[]v1beta2.TopologyDomainAssignment)(unsafe.Pointer(&in.Domains))
+	// WARNING: in.Domains requires manual conversion: does not exist in peer-type
 	return nil
 }
 
-// Convert_v1beta1_TopologyAssignment_To_v1beta2_TopologyAssignment is an autogenerated conversion function.
-func Convert_v1beta1_TopologyAssignment_To_v1beta2_TopologyAssignment(in *TopologyAssignment, out *v1beta2.TopologyAssignment, s conversion.Scope) error {
-	return autoConvert_v1beta1_TopologyAssignment_To_v1beta2_TopologyAssignment(in, out, s)
-}
-
 func autoConvert_v1beta2_TopologyAssignment_To_v1beta1_TopologyAssignment(in *v1beta2.TopologyAssignment, out *TopologyAssignment, s conversion.Scope) error {
 	out.Levels = *(*[]string)(unsafe.Pointer(&in.Levels))
-	out.Domains = *(*[]TopologyDomainAssignment)(unsafe.Pointer(&in.Domains))
+	// WARNING: in.Slices requires manual conversion: does not exist in peer-type
 	return nil
 }
 
-// Convert_v1beta2_TopologyAssignment_To_v1beta1_TopologyAssignment is an autogenerated conversion function.
-func Convert_v1beta2_TopologyAssignment_To_v1beta1_TopologyAssignment(in *v1beta2.TopologyAssignment, out *TopologyAssignment, s conversion.Scope) error {
-	return autoConvert_v1beta2_TopologyAssignment_To_v1beta1_TopologyAssignment(in, out, s)
-}
-
-func autoConvert_v1beta1_TopologyDomainAssignment_To_v1beta2_TopologyDomainAssignment(in *TopologyDomainAssignment, out *v1beta2.TopologyDomainAssignment, s conversion.Scope) error {
-	out.Values = *(*[]string)(unsafe.Pointer(&in.Values))
-	out.Count = in.Count
-	return nil
-}
-
-// Convert_v1beta1_TopologyDomainAssignment_To_v1beta2_TopologyDomainAssignment is an autogenerated conversion function.
-func Convert_v1beta1_TopologyDomainAssignment_To_v1beta2_TopologyDomainAssignment(in *TopologyDomainAssignment, out *v1beta2.TopologyDomainAssignment, s conversion.Scope) error {
-	return autoConvert_v1beta1_TopologyDomainAssignment_To_v1beta2_TopologyDomainAssignment(in, out, s)
-}
-
-func autoConvert_v1beta2_TopologyDomainAssignment_To_v1beta1_TopologyDomainAssignment(in *v1beta2.TopologyDomainAssignment, out *TopologyDomainAssignment, s conversion.Scope) error {
-	out.Values = *(*[]string)(unsafe.Pointer(&in.Values))
-	out.Count = in.Count
-	return nil
-}
-
-// Convert_v1beta2_TopologyDomainAssignment_To_v1beta1_TopologyDomainAssignment is an autogenerated conversion function.
-func Convert_v1beta2_TopologyDomainAssignment_To_v1beta1_TopologyDomainAssignment(in *v1beta2.TopologyDomainAssignment, out *TopologyDomainAssignment, s conversion.Scope) error {
-	return autoConvert_v1beta2_TopologyDomainAssignment_To_v1beta1_TopologyDomainAssignment(in, out, s)
-}
-
 func autoConvert_v1beta1_TopologyInfo_To_v1beta2_TopologyInfo(in *TopologyInfo, out *v1beta2.TopologyInfo, s conversion.Scope) error {
 	out.Name = v1beta2.TopologyReference(in.Name)
 	out.Levels = *(*[]string)(unsafe.Pointer(&in.Levels))
@@ -2636,7 +2630,15 @@ func autoConvert_v1beta2_WorkloadSpec_To_v1beta1_WorkloadSpec(in *v1beta2.Worklo
 
 func autoConvert_v1beta1_WorkloadStatus_To_v1beta2_WorkloadStatus(in *WorkloadStatus, out *v1beta2.WorkloadStatus, s conversion.Scope) error {
 	out.Conditions = *(*[]v1.Condition)(unsafe.Pointer(&in.Conditions))
-	out.Admission = (*v1beta2.Admission)(unsafe.Pointer(in.Admission))
+	if in.Admission != nil {
+		in, out := &in.Admission, &out.Admission
+		*out = new(v1beta2.Admission)
+		if err := Convert_v1beta1_Admission_To_v1beta2_Admission(*in, *out, s); err != nil {
+			return err
+		}
+	} else {
+		out.Admission = nil
+	}
 	out.RequeueState = (*v1beta2.RequeueState)(unsafe.Pointer(in.RequeueState))
 	out.ReclaimablePods = *(*[]v1beta2.ReclaimablePod)(unsafe.Pointer(&in.ReclaimablePods))
 	out.AdmissionChecks = *(*[]v1beta2.AdmissionCheckState)(unsafe.Pointer(&in.AdmissionChecks))
@@ -2651,7 +2653,15 @@ func autoConvert_v1beta1_WorkloadStatus_To_v1beta2_WorkloadStatus(in *WorkloadSt
 
 func autoConvert_v1beta2_WorkloadStatus_To_v1beta1_WorkloadStatus(in *v1beta2.WorkloadStatus, out *WorkloadStatus, s conversion.Scope) error {
 	out.Conditions = *(*[]v1.Condition)(unsafe.Pointer(&in.Conditions))
-	out.Admission = (*Admission)(unsafe.Pointer(in.Admission))
+	if in.Admission != nil {
+		in, out := &in.Admission, &out.Admission
+		*out = new(Admission)
+		if err := Convert_v1beta2_Admission_To_v1beta1_Admission(*in, *out, s); err != nil {
+			return err
+		}
+	} else {
+		out.Admission = nil
+	}
 	out.RequeueState = (*RequeueState)(unsafe.Pointer(in.RequeueState))
 	out.ReclaimablePods = *(*[]ReclaimablePod)(unsafe.Pointer(&in.ReclaimablePods))
 	out.AdmissionChecks = *(*[]AdmissionCheckState)(unsafe.Pointer(&in.AdmissionChecks))
diff --git a/apis/kueue/v1beta2/workload_types.go b/apis/kueue/v1beta2/workload_types.go
index 825eea6a6..ca9ad1023 100644
--- a/apis/kueue/v1beta2/workload_types.go
+++ b/apis/kueue/v1beta2/workload_types.go
@@ -278,46 +278,113 @@ type PodSetAssignment struct {
 	// topology domains corresponding to the lowest level of the topology.
 	// The assignment specifies the number of Pods to be scheduled per topology
 	// domain and specifies the node selectors for each topology domain, in the
-	// following way: the node selector keys are specified by the levels field
-	// (same for all domains), and the corresponding node selector value is
-	// specified by the domains.values subfield. If the TopologySpec.Levels field contains
-	// "kubernetes.io/hostname" label, topologyAssignment will contain data only for
-	// this label, and omit higher levels in the topology
+	// following way:
+	// * `levels` specifies the node selector keys (same for all domains).
+	//   - If the TopologySpec.Levels field contains "kubernetes.io/hostname" label,
+	//     topologyAssignment will contain data only for this label,
+	//     and omit higher levels in the topology.
+	// * `slices` specifies the node selector values and pod counts for all domains
+	//   (which may be partitioned into separate slices).
+	//   - The node selector values are arranged first by topology level, only then by domain.
+	//     (This allows "optimizing" similar values; see below).
+	// * The format of `slices` supports the following variations
+	//   (aimed to optimize the total bytesize for very large number of domains; see examples below):
+	//   - When all node selector values (at a given topology level, in a given slice)
+	//     share a common prefix and/or suffix, these may be stored
+	//     in dedicated `commonPrefix`/`commonSuffix` fields.
+	//     If so, the array of `roots` will only store the remaining parts of these strings.
+	//   - When all node selector values (at a given topology level, in a given slice)
+	//     are identical, this may be represented by `universal` value.
+	//   - When all pod counts (in a given slice) are identical,
+	//     this may be represented by `universal` pod count.
+	//
+	// Example 1:
+	//
+	// The following represents an assignment in which:
+	// * 4 Pods are to be scheduled on nodes matching the node selector:
+	//   - cloud.provider.com/topology-block: block-1
+	//   - cloud.provider.com/topology-rack: rack-1
+	// * 2 Pods are to be scheduled on nodes matching the node selector:
+	//   - cloud.provider.com/topology-block: block-1
+	//   - cloud.provider.com/topology-rack: rack-2
 	//
-	// Example:
+	// topologyAssignment:
+	//   levels:
+	//   - cloud.provider.com/topology-block
+	//   - cloud.provider.com/topology-rack
+	//   slices:
+	//   - domainCount: 2
+	//     valuesPerLevel:
+	//     - individual:
+	//         roots: [block-1, block-1]
+	//     - individual:
+	//         roots: [rack-1, rack-2]
+	//     podCounts:
+	//       individual: [4, 2]
+	//
+	// Example 2:
+	//
+	// The following is equivalent to Example 1 - but using extracted prefix and universalValue.
 	//
 	// topologyAssignment:
 	//   levels:
 	//   - cloud.provider.com/topology-block
 	//   - cloud.provider.com/topology-rack
-	//   domains:
-	//   - values: [block-1, rack-1]
-	//     count: 4
-	//   - values: [block-1, rack-2]
-	//     count: 2
-	//
-	// Here:
-	// - 4 Pods are to be scheduled on nodes matching the node selector:
-	//   cloud.provider.com/topology-block: block-1
-	//   cloud.provider.com/topology-rack: rack-1
-	// - 2 Pods are to be scheduled on nodes matching the node selector:
-	//   cloud.provider.com/topology-block: block-1
-	//   cloud.provider.com/topology-rack: rack-2
-	//
-	// Example:
-	// Below there is an equivalent of the above example assuming, Topology
-	// object defines kubernetes.io/hostname as the lowest level in topology.
-	// Hence we omit higher level of topologies, since the hostname label
-	// is sufficient to explicitly identify a proper node.
+	//   slices:
+	//   - domainCount: 2
+	//     valuesPerLevel:
+	//     - universal: block-1
+	//     - individual:
+	//         prefix: rack-
+	// 		   roots: [1, 2]
+	//     podCounts:
+	//       individual: [4, 2]
+	//
+	// Example 3:
+	//
+	// Now suppose that:
+	// - the Topology object defines kubernetes.io/hostname as the lowest level
+	//   (and hence, in the topologyAssignment, we omit all other levels
+	//   since the hostname label suffices to explicitly identify a proper node),
+	// - we assign 1 Pod per each node,
+	// - the node naming scheme is `block-{blockId}-rack-{rackId}-node-{nodeId}`.
+	// Then, using the "extraction of commons", the assignment from Examples 1-2 would look as follows:
+	//
+	// topologyAssignment:
+	//   levels:
+	//   - kubernetes.io/hostname
+	//   slices:
+	//   - domainCount: 6
+	//     valuesPerLevel:
+	//     - individual:
+	//         prefix: block-1-rack-
+	// 		   roots: [1-node-1, 1-node-2, 1-node-3, 1-node-4, 2-node-1, 2-node-2]
+	//     podCounts:
+	//       universal: 1
+	//
+	// Example 4:
+	//
+	// By using multiple slices, we can afford even longer common prefixes.
+	// The assignment from Example 3 can be alternatively represented as follows:
 	//
 	// topologyAssignment:
 	//   levels:
 	//   - kubernetes.io/hostname
-	//   domains:
-	//   - values: [hostname-1]
-	//     count: 4
-	//   - values: [hostname-2]
-	//     count: 2
+	//   slices:
+	//   - domainCount: 4
+	//     valuesPerLevel:
+	//     - individual:
+	//         prefix: block-1-rack-1-node-
+	// 		   roots: [1, 2, 3, 4]
+	//     podCounts:
+	//       universal: 1
+	//   - domainCount: 2
+	//     valuesPerLevel:
+	//     - individual:
+	//         prefix: block-1-rack-2-node-
+	// 		   roots: [1, 2]
+	//     podCounts:
+	//       universal: 1
 	//
 	// +optional
 	TopologyAssignment *TopologyAssignment `json:"topologyAssignment,omitempty"`
@@ -347,6 +414,7 @@ const (
 	DelayedTopologyRequestStateReady DelayedTopologyRequestState = "Ready"
 )
 
+// +kubebuilder:validation:XValidation:rule="self.slices.all(x, size(x.valuesPerLevel) == size(self.levels))", message="valuesPerLevel must have the same length as the number of levels in this TopologyAssignment"
 type TopologyAssignment struct {
 	// levels is an ordered list of keys denoting the levels of the assigned
 	// topology (i.e. node label keys), from the highest to the lowest level of
@@ -359,33 +427,90 @@ type TopologyAssignment struct {
 	// +kubebuilder:validation:items:MaxLength=317
 	Levels []string `json:"levels,omitempty"`
 
-	// domains is a list of topology assignments split by topology domains at
-	// the lowest level of the topology.
-	//
+	// slices represent topology assignments for subsets of pods of a workload.
+	// The full assignment is obtained as a union of all slices.
 	// +required
 	// +listType=atomic
-	// +kubebuilder:validation:MaxItems=100000
-	Domains []TopologyDomainAssignment `json:"domains,omitempty"`
+	// +kubebuilder:validation:MaxItems=1000
+	Slices []TopologyAssignmentSlice `json:"slices,omitempty"`
 }
 
-type TopologyDomainAssignment struct {
-	// values is an ordered list of node selector values describing a topology
-	// domain. The values correspond to the consecutive topology levels, from
-	// the highest to the lowest.
-	//
+// +kubebuilder:validation:XValidation:rule="!has(self.podCounts.individual) || size(self.podCounts.individual) == self.domainCount", message="podCounts.individual must have length equal to domainCount"
+// +kubebuilder:validation:XValidation:rule="self.valuesPerLevel.all(x, !has(x.individual) || size(x.individual.roots) == self.domainCount)", message="valuesPerLevel.individual, if set, must have roots of length equal to domainCount of this TopologyAssignmentSlice"
+type TopologyAssignmentSlice struct {
+	// domainCount is the number of domains covered by this slice.
+	// +required
+	// +kubebuilder:validation:Minimum=1
+	DomainCount int32 `json:"domainCount,omitempty"`
+
+	// valuesPerLevel has one entry for each of the Levels specified in the TopologyAssignment.
+	// The entry corresponding to a particular level specifies the placement of pods at that level.
 	// +required
 	// +listType=atomic
 	// +kubebuilder:validation:MinItems=1
 	// +kubebuilder:validation:MaxItems=16
-	// +kubebuilder:validation:items:MaxLength=63
-	Values []string `json:"values,omitempty"`
+	ValuesPerLevel []TopologyAssignmentSliceLevelValues `json:"valuesPerLevel,omitempty"`
 
-	// count indicates the number of Pods to be scheduled in the topology
-	// domain indicated by the values field.
-	//
+	// podCounts specifies the number of pods allocated per each domain.
+	// +required
+	PodCounts TopologyAssignmentSlicePodCounts `json:"podCounts,omitempty"`
+}
+
+// +kubebuilder:validation:ExactlyOneOf=universal;individual
+type TopologyAssignmentSliceLevelValues struct {
+	// universal - if set - specifies a single topology placement value (at a particular topology level)
+	// that applies to all pods in the current TopologyAssignmentSlice.
+	// Exactly one of universal, individual must be set.
+	// +optional
+	// +kubebuilder:validation:MaxLength=63
+	Universal *string `json:"universal,omitempty"`
+
+	// individual - if set - specifies multiple topology placement values (at a particular topology level)
+	// that apply to the pods in the current TopologyAssignmentSlice.
+	// Exactly one of universal, individual must be set.
+	// +optional
+	Individual *TopologyAssignmentSliceLevelIndividualValues `json:"individual,omitempty"`
+}
+
+type TopologyAssignmentSliceLevelIndividualValues struct {
+	// commonPrefix specifies a common prefix for all values in this slice assignment.
+	// It must be either nil pointer or a non-empty string.
+	// +optional
+	// +kubebuilder:validation:MaxLength=63
+	CommonPrefix *string `json:"commonPrefix,omitempty"`
+	// commonSuffix specifies a common suffix for all values in this slice assignment.
+	// It must be either nil pointer or a non-empty string.
+	// +optional
+	// +kubebuilder:validation:MaxLength=63
+	CommonSuffix *string `json:"commonSuffix,omitempty"`
+
+	// roots specifies the values in this assignment (excluding commonPrefix and commonSuffix, if non-empty).
+	// Its length must be equal to the "domainCount" field of the TopologyAssignmentSlice.
 	// +required
+	// +listType=atomic
+	// +kubebuilder:validation:MinItems=1
+	// +kubebuilder:validation:MaxItems=100000
+	// +kubebuilder:validation:items:MaxLength=63
+	Roots []string `json:"roots,omitempty"`
+}
+
+// +kubebuilder:validation:ExactlyOneOf=universal;individual
+type TopologyAssignmentSlicePodCounts struct {
+	// universal - if set - specifies the number of pods allocated in every domain in this slice.
+	// Exactly one of universal, individual must be set.
+	// +optional
 	// +kubebuilder:validation:Minimum=1
-	Count int32 `json:"count,omitempty"`
+	Universal *int32 `json:"universal,omitempty"`
+
+	// individual - if set - specifies the number of pods allocated in each domain in this slice.
+	// If set, its length must be equal to the "domainCount" field of the TopologyAssignmentSlice.
+	// Exactly one of universal, individual must be set.
+	// +optional
+	// +listType=atomic
+	// +kubebuilder:validation:MinItems=1
+	// +kubebuilder:validation:MaxItems=100000
+	// +kubebuilder:validation:items:Minimum=1
+	Individual []int32 `json:"individual,omitempty"`
 }
 
 // +kubebuilder:validation:XValidation:rule="has(self.minCount) ? self.minCount <= self.count : true", message="minCount should be positive and less or equal to count"
diff --git a/apis/kueue/v1beta2/zz_generated.deepcopy.go b/apis/kueue/v1beta2/zz_generated.deepcopy.go
index 77a57cd69..9b82dc8b6 100644
--- a/apis/kueue/v1beta2/zz_generated.deepcopy.go
+++ b/apis/kueue/v1beta2/zz_generated.deepcopy.go
@@ -1659,9 +1659,9 @@ func (in *TopologyAssignment) DeepCopyInto(out *TopologyAssignment) {
 		*out = make([]string, len(*in))
 		copy(*out, *in)
 	}
-	if in.Domains != nil {
-		in, out := &in.Domains, &out.Domains
-		*out = make([]TopologyDomainAssignment, len(*in))
+	if in.Slices != nil {
+		in, out := &in.Slices, &out.Slices
+		*out = make([]TopologyAssignmentSlice, len(*in))
 		for i := range *in {
 			(*in)[i].DeepCopyInto(&(*out)[i])
 		}
@@ -1679,21 +1679,104 @@ func (in *TopologyAssignment) DeepCopy() *TopologyAssignment {
 }
 
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *TopologyDomainAssignment) DeepCopyInto(out *TopologyDomainAssignment) {
+func (in *TopologyAssignmentSlice) DeepCopyInto(out *TopologyAssignmentSlice) {
 	*out = *in
-	if in.Values != nil {
-		in, out := &in.Values, &out.Values
+	if in.ValuesPerLevel != nil {
+		in, out := &in.ValuesPerLevel, &out.ValuesPerLevel
+		*out = make([]TopologyAssignmentSliceLevelValues, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+	in.PodCounts.DeepCopyInto(&out.PodCounts)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TopologyAssignmentSlice.
+func (in *TopologyAssignmentSlice) DeepCopy() *TopologyAssignmentSlice {
+	if in == nil {
+		return nil
+	}
+	out := new(TopologyAssignmentSlice)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *TopologyAssignmentSliceLevelIndividualValues) DeepCopyInto(out *TopologyAssignmentSliceLevelIndividualValues) {
+	*out = *in
+	if in.CommonPrefix != nil {
+		in, out := &in.CommonPrefix, &out.CommonPrefix
+		*out = new(string)
+		**out = **in
+	}
+	if in.CommonSuffix != nil {
+		in, out := &in.CommonSuffix, &out.CommonSuffix
+		*out = new(string)
+		**out = **in
+	}
+	if in.Roots != nil {
+		in, out := &in.Roots, &out.Roots
 		*out = make([]string, len(*in))
 		copy(*out, *in)
 	}
 }
 
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TopologyDomainAssignment.
-func (in *TopologyDomainAssignment) DeepCopy() *TopologyDomainAssignment {
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TopologyAssignmentSliceLevelIndividualValues.
+func (in *TopologyAssignmentSliceLevelIndividualValues) DeepCopy() *TopologyAssignmentSliceLevelIndividualValues {
+	if in == nil {
+		return nil
+	}
+	out := new(TopologyAssignmentSliceLevelIndividualValues)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *TopologyAssignmentSliceLevelValues) DeepCopyInto(out *TopologyAssignmentSliceLevelValues) {
+	*out = *in
+	if in.Universal != nil {
+		in, out := &in.Universal, &out.Universal
+		*out = new(string)
+		**out = **in
+	}
+	if in.Individual != nil {
+		in, out := &in.Individual, &out.Individual
+		*out = new(TopologyAssignmentSliceLevelIndividualValues)
+		(*in).DeepCopyInto(*out)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TopologyAssignmentSliceLevelValues.
+func (in *TopologyAssignmentSliceLevelValues) DeepCopy() *TopologyAssignmentSliceLevelValues {
+	if in == nil {
+		return nil
+	}
+	out := new(TopologyAssignmentSliceLevelValues)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *TopologyAssignmentSlicePodCounts) DeepCopyInto(out *TopologyAssignmentSlicePodCounts) {
+	*out = *in
+	if in.Universal != nil {
+		in, out := &in.Universal, &out.Universal
+		*out = new(int32)
+		**out = **in
+	}
+	if in.Individual != nil {
+		in, out := &in.Individual, &out.Individual
+		*out = make([]int32, len(*in))
+		copy(*out, *in)
+	}
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TopologyAssignmentSlicePodCounts.
+func (in *TopologyAssignmentSlicePodCounts) DeepCopy() *TopologyAssignmentSlicePodCounts {
 	if in == nil {
 		return nil
 	}
-	out := new(TopologyDomainAssignment)
+	out := new(TopologyAssignmentSlicePodCounts)
 	in.DeepCopyInto(out)
 	return out
 }
diff --git a/charts/kueue/templates/crd/kueue.x-k8s.io_workloads.yaml b/charts/kueue/templates/crd/kueue.x-k8s.io_workloads.yaml
index aba263826..97ebb2267 100644
--- a/charts/kueue/templates/crd/kueue.x-k8s.io_workloads.yaml
+++ b/charts/kueue/templates/crd/kueue.x-k8s.io_workloads.yaml
@@ -17251,100 +17251,131 @@ spec:
                               This field will not change in case of quota reclaim.
                             type: object
                           topologyAssignment:
-                            description: |-
-                              topologyAssignment indicates the topology assignment divided into
-                              topology domains corresponding to the lowest level of the topology.
-                              The assignment specifies the number of Pods to be scheduled per topology
-                              domain and specifies the node selectors for each topology domain, in the
-                              following way: the node selector keys are specified by the levels field
-                              (same for all domains), and the corresponding node selector value is
-                              specified by the domains.values subfield. If the TopologySpec.Levels field contains
-                              "kubernetes.io/hostname" label, topologyAssignment will contain data only for
-                              this label, and omit higher levels in the topology
-
-                              Example:
-
-                              topologyAssignment:
-                                levels:
-                                - cloud.provider.com/topology-block
-                                - cloud.provider.com/topology-rack
-                                domains:
-                                - values: [block-1, rack-1]
-                                  count: 4
-                                - values: [block-1, rack-2]
-                                  count: 2
-
-                              Here:
-                              - 4 Pods are to be scheduled on nodes matching the node selector:
-                                cloud.provider.com/topology-block: block-1
-                                cloud.provider.com/topology-rack: rack-1
-                              - 2 Pods are to be scheduled on nodes matching the node selector:
-                                cloud.provider.com/topology-block: block-1
-                                cloud.provider.com/topology-rack: rack-2
-
-                              Example:
-                              Below there is an equivalent of the above example assuming, Topology
-                              object defines kubernetes.io/hostname as the lowest level in topology.
-                              Hence we omit higher level of topologies, since the hostname label
-                              is sufficient to explicitly identify a proper node.
-
-                              topologyAssignment:
-                                levels:
-                                - kubernetes.io/hostname
-                                domains:
-                                - values: [hostname-1]
-                                  count: 4
-                                - values: [hostname-2]
-                                  count: 2
+                            description: "topologyAssignment indicates the topology assignment divided into\ntopology domains corresponding to the lowest level of the topology.\nThe assignment specifies the number of Pods to be scheduled per topology\ndomain and specifies the node selectors for each topology domain, in the\nfollowing way:\n* `levels` specifies the node selector keys (same for all domains).\n  - If the TopologySpec.Levels field contains \"kubernetes.io/hostname\" label,\n    topologyAssignment will contain data only for this label,\n    and omit higher levels in the topology.\n* `slices` specifies the node selector values and pod counts for all domains\n  (which may be partitioned into separate slices).\n  - The node selector values are arranged first by topology level, only then by domain.\n    (This allows \"optimizing\" similar values; see below).\n* The format of `slices` supports the following variations\n  (aimed to optimize the total bytesize for very large number of domains; see examples below):\n  - When all node selector values (at a given topology level, in a given slice)\n    share a common prefix and/or suffix, these may be stored\n    in dedicated `commonPrefix`/`commonSuffix` fields.\n    If so, the array of `roots` will only store the remaining parts of these strings.\n  - When all node selector values (at a given topology level, in a given slice)\n    are identical, this may be represented by `universal` value.\n  - When all pod counts (in a given slice) are identical,\n    this may be represented by `universal` pod count.\n\nExample 1:\n\nThe following represents an assignment in which:\n* 4 Pods are to be scheduled on nodes matching the node selector:\n  - cloud.provider.com/topology-block: block-1\n  - cloud.provider.com/topology-rack: rack-1\n* 2 Pods are to be scheduled on nodes matching the node selector:\n  - cloud.provider.com/topology-block: block-1\n  - cloud.provider.com/topology-rack: rack-2\n\ntopologyAssignment:\n  levels:\n  - cloud.provider.com/topology-block\n  - cloud.provider.com/topology-rack\n  slices:\n  - domainCount: 2\n    valuesPerLevel:\n    - individual:\n        roots: [block-1, block-1]\n    - individual:\n        roots: [rack-1, rack-2]\n    podCounts:\n      individual: [4, 2]\n\nExample 2:\n\nThe following is equivalent to Example 1 - but using extracted prefix and universalValue.\n\ntopologyAssignment:\n  levels:\n  - cloud.provider.com/topology-block\n  - cloud.provider.com/topology-rack\n  slices:\n  - domainCount: 2\n    valuesPerLevel:\n    - universal: block-1\n    - individual:\n        prefix: rack-\n\t\t   roots: [1, 2]\n    podCounts:\n      individual: [4, 2]\n\nExample 3:\n\nNow suppose that:\n- the Topology object defines kubernetes.io/hostname as the lowest level\n  (and hence, in the topologyAssignment, we omit all other levels\n  since the hostname label suffices to explicitly identify a proper node),\n- we assign 1 Pod per each node,\n- the node naming scheme is `block-{blockId}-rack-{rackId}-node-{nodeId}`.\nThen, using the \"extraction of commons\", the assignment from Examples 1-2 would look as follows:\n\ntopologyAssignment:\n  levels:\n  - kubernetes.io/hostname\n  slices:\n  - domainCount: 6\n    valuesPerLevel:\n    - individual:\n        prefix: block-1-rack-\n\t\t   roots: [1-node-1, 1-node-2, 1-node-3, 1-node-4, 2-node-1, 2-node-2]\n    podCounts:\n      universal: 1\n\nExample 4:\n\nBy using multiple slices, we can afford even longer common prefixes.\nThe assignment from Example 3 can be alternatively represented as follows:\n\ntopologyAssignment:\n  levels:\n  - kubernetes.io/hostname\n  slices:\n  - domainCount: 4\n    valuesPerLevel:\n    - individual:\n        prefix: block-1-rack-1-node-\n\t\t   roots: [1, 2, 3, 4]\n    podCounts:\n      universal: 1\n  - domainCount: 2\n    valuesPerLevel:\n    - individual:\n        prefix: block-1-rack-2-node-\n\t\t   roots: [1, 2]\n    podCounts:\n      universal: 1"
                             properties:
-                              domains:
+                              levels:
                                 description: |-
-                                  domains is a list of topology assignments split by topology domains at
-                                  the lowest level of the topology.
+                                  levels is an ordered list of keys denoting the levels of the assigned
+                                  topology (i.e. node label keys), from the highest to the lowest level of
+                                  the topology.
+                                items:
+                                  maxLength: 317
+                                  type: string
+                                maxItems: 16
+                                minItems: 1
+                                type: array
+                                x-kubernetes-list-type: atomic
+                              slices:
+                                description: |-
+                                  slices represent topology assignments for subsets of pods of a workload.
+                                  The full assignment is obtained as a union of all slices.
                                 items:
                                   properties:
-                                    count:
-                                      description: |-
-                                        count indicates the number of Pods to be scheduled in the topology
-                                        domain indicated by the values field.
+                                    domainCount:
+                                      description: domainCount is the number of domains covered by this slice.
                                       format: int32
                                       minimum: 1
                                       type: integer
-                                    values:
+                                    podCounts:
+                                      description: podCounts specifies the number of pods allocated per each domain.
+                                      properties:
+                                        individual:
+                                          description: |-
+                                            individual - if set - specifies the number of pods allocated in each domain in this slice.
+                                            If set, its length must be equal to the "domainCount" field of the TopologyAssignmentSlice.
+                                            Exactly one of universal, individual must be set.
+                                          items:
+                                            format: int32
+                                            minimum: 1
+                                            type: integer
+                                          maxItems: 100000
+                                          minItems: 1
+                                          type: array
+                                          x-kubernetes-list-type: atomic
+                                        universal:
+                                          description: |-
+                                            universal - if set - specifies the number of pods allocated in every domain in this slice.
+                                            Exactly one of universal, individual must be set.
+                                          format: int32
+                                          minimum: 1
+                                          type: integer
+                                      type: object
+                                      x-kubernetes-validations:
+                                        - message: exactly one of the fields in [universal individual] must be set
+                                          rule: '[has(self.universal),has(self.individual)].filter(x,x==true).size() == 1'
+                                    valuesPerLevel:
                                       description: |-
-                                        values is an ordered list of node selector values describing a topology
-                                        domain. The values correspond to the consecutive topology levels, from
-                                        the highest to the lowest.
+                                        valuesPerLevel has one entry for each of the Levels specified in the TopologyAssignment.
+                                        The entry corresponding to a particular level specifies the placement of pods at that level.
                                       items:
-                                        maxLength: 63
-                                        type: string
+                                        properties:
+                                          individual:
+                                            description: |-
+                                              individual - if set - specifies multiple topology placement values (at a particular topology level)
+                                              that apply to the pods in the current TopologyAssignmentSlice.
+                                              Exactly one of universal, individual must be set.
+                                            properties:
+                                              commonPrefix:
+                                                description: |-
+                                                  commonPrefix specifies a common prefix for all values in this slice assignment.
+                                                  It must be either nil pointer or a non-empty string.
+                                                maxLength: 63
+                                                type: string
+                                              commonSuffix:
+                                                description: |-
+                                                  commonSuffix specifies a common suffix for all values in this slice assignment.
+                                                  It must be either nil pointer or a non-empty string.
+                                                maxLength: 63
+                                                type: string
+                                              roots:
+                                                description: |-
+                                                  roots specifies the values in this assignment (excluding commonPrefix and commonSuffix, if non-empty).
+                                                  Its length must be equal to the "domainCount" field of the TopologyAssignmentSlice.
+                                                items:
+                                                  maxLength: 63
+                                                  type: string
+                                                maxItems: 100000
+                                                minItems: 1
+                                                type: array
+                                                x-kubernetes-list-type: atomic
+                                            required:
+                                              - roots
+                                            type: object
+                                          universal:
+                                            description: |-
+                                              universal - if set - specifies a single topology placement value (at a particular topology level)
+                                              that applies to all pods in the current TopologyAssignmentSlice.
+                                              Exactly one of universal, individual must be set.
+                                            maxLength: 63
+                                            type: string
+                                        type: object
+                                        x-kubernetes-validations:
+                                          - message: exactly one of the fields in [universal individual] must be set
+                                            rule: '[has(self.universal),has(self.individual)].filter(x,x==true).size() == 1'
                                       maxItems: 16
                                       minItems: 1
                                       type: array
                                       x-kubernetes-list-type: atomic
                                   required:
-                                    - count
-                                    - values
+                                    - domainCount
+                                    - podCounts
+                                    - valuesPerLevel
                                   type: object
-                                maxItems: 100000
-                                type: array
-                                x-kubernetes-list-type: atomic
-                              levels:
-                                description: |-
-                                  levels is an ordered list of keys denoting the levels of the assigned
-                                  topology (i.e. node label keys), from the highest to the lowest level of
-                                  the topology.
-                                items:
-                                  maxLength: 317
-                                  type: string
-                                maxItems: 16
-                                minItems: 1
+                                  x-kubernetes-validations:
+                                    - message: podCounts.individual must have length equal to domainCount
+                                      rule: '!has(self.podCounts.individual) || size(self.podCounts.individual) == self.domainCount'
+                                    - message: valuesPerLevel.individual, if set, must have roots of length equal to domainCount of this TopologyAssignmentSlice
+                                      rule: self.valuesPerLevel.all(x, !has(x.individual) || size(x.individual.roots) == self.domainCount)
+                                maxItems: 1000
                                 type: array
                                 x-kubernetes-list-type: atomic
                             required:
-                              - domains
                               - levels
+                              - slices
                             type: object
+                            x-kubernetes-validations:
+                              - message: valuesPerLevel must have the same length as the number of levels in this TopologyAssignment
+                                rule: self.slices.all(x, size(x.valuesPerLevel) == size(self.levels))
                         type: object
                       maxItems: 8
                       type: array
diff --git a/client-go/applyconfiguration/kueue/v1beta2/topologyassignment.go b/client-go/applyconfiguration/kueue/v1beta2/topologyassignment.go
index 969bbd294..226b0ba01 100644
--- a/client-go/applyconfiguration/kueue/v1beta2/topologyassignment.go
+++ b/client-go/applyconfiguration/kueue/v1beta2/topologyassignment.go
@@ -20,8 +20,8 @@ package v1beta2
 // TopologyAssignmentApplyConfiguration represents a declarative configuration of the TopologyAssignment type for use
 // with apply.
 type TopologyAssignmentApplyConfiguration struct {
-	Levels  []string                                     `json:"levels,omitempty"`
-	Domains []TopologyDomainAssignmentApplyConfiguration `json:"domains,omitempty"`
+	Levels []string                                    `json:"levels,omitempty"`
+	Slices []TopologyAssignmentSliceApplyConfiguration `json:"slices,omitempty"`
 }
 
 // TopologyAssignmentApplyConfiguration constructs a declarative configuration of the TopologyAssignment type for use with
@@ -40,15 +40,15 @@ func (b *TopologyAssignmentApplyConfiguration) WithLevels(values ...string) *Top
 	return b
 }
 
-// WithDomains adds the given value to the Domains field in the declarative configuration
+// WithSlices adds the given value to the Slices field in the declarative configuration
 // and returns the receiver, so that objects can be build by chaining "With" function invocations.
-// If called multiple times, values provided by each call will be appended to the Domains field.
-func (b *TopologyAssignmentApplyConfiguration) WithDomains(values ...*TopologyDomainAssignmentApplyConfiguration) *TopologyAssignmentApplyConfiguration {
+// If called multiple times, values provided by each call will be appended to the Slices field.
+func (b *TopologyAssignmentApplyConfiguration) WithSlices(values ...*TopologyAssignmentSliceApplyConfiguration) *TopologyAssignmentApplyConfiguration {
 	for i := range values {
 		if values[i] == nil {
-			panic("nil value passed to WithDomains")
+			panic("nil value passed to WithSlices")
 		}
-		b.Domains = append(b.Domains, *values[i])
+		b.Slices = append(b.Slices, *values[i])
 	}
 	return b
 }
diff --git a/client-go/applyconfiguration/kueue/v1beta2/topologyassignmentslice.go b/client-go/applyconfiguration/kueue/v1beta2/topologyassignmentslice.go
new file mode 100644
index 000000000..cc065891d
--- /dev/null
+++ b/client-go/applyconfiguration/kueue/v1beta2/topologyassignmentslice.go
@@ -0,0 +1,61 @@
+/*
+Copyright The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+// Code generated by applyconfiguration-gen. DO NOT EDIT.
+
+package v1beta2
+
+// TopologyAssignmentSliceApplyConfiguration represents a declarative configuration of the TopologyAssignmentSlice type for use
+// with apply.
+type TopologyAssignmentSliceApplyConfiguration struct {
+	DomainCount    *int32                                                 `json:"domainCount,omitempty"`
+	ValuesPerLevel []TopologyAssignmentSliceLevelValuesApplyConfiguration `json:"valuesPerLevel,omitempty"`
+	PodCounts      *TopologyAssignmentSlicePodCountsApplyConfiguration    `json:"podCounts,omitempty"`
+}
+
+// TopologyAssignmentSliceApplyConfiguration constructs a declarative configuration of the TopologyAssignmentSlice type for use with
+// apply.
+func TopologyAssignmentSlice() *TopologyAssignmentSliceApplyConfiguration {
+	return &TopologyAssignmentSliceApplyConfiguration{}
+}
+
+// WithDomainCount sets the DomainCount field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the DomainCount field is set to the value of the last call.
+func (b *TopologyAssignmentSliceApplyConfiguration) WithDomainCount(value int32) *TopologyAssignmentSliceApplyConfiguration {
+	b.DomainCount = &value
+	return b
+}
+
+// WithValuesPerLevel adds the given value to the ValuesPerLevel field in the declarative configuration
+// and returns the receiver, so that objects can be build by chaining "With" function invocations.
+// If called multiple times, values provided by each call will be appended to the ValuesPerLevel field.
+func (b *TopologyAssignmentSliceApplyConfiguration) WithValuesPerLevel(values ...*TopologyAssignmentSliceLevelValuesApplyConfiguration) *TopologyAssignmentSliceApplyConfiguration {
+	for i := range values {
+		if values[i] == nil {
+			panic("nil value passed to WithValuesPerLevel")
+		}
+		b.ValuesPerLevel = append(b.ValuesPerLevel, *values[i])
+	}
+	return b
+}
+
+// WithPodCounts sets the PodCounts field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the PodCounts field is set to the value of the last call.
+func (b *TopologyAssignmentSliceApplyConfiguration) WithPodCounts(value *TopologyAssignmentSlicePodCountsApplyConfiguration) *TopologyAssignmentSliceApplyConfiguration {
+	b.PodCounts = value
+	return b
+}
diff --git a/client-go/applyconfiguration/kueue/v1beta2/topologyassignmentslicelevelindividualvalues.go b/client-go/applyconfiguration/kueue/v1beta2/topologyassignmentslicelevelindividualvalues.go
new file mode 100644
index 000000000..ce4789e0a
--- /dev/null
+++ b/client-go/applyconfiguration/kueue/v1beta2/topologyassignmentslicelevelindividualvalues.go
@@ -0,0 +1,58 @@
+/*
+Copyright The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+// Code generated by applyconfiguration-gen. DO NOT EDIT.
+
+package v1beta2
+
+// TopologyAssignmentSliceLevelIndividualValuesApplyConfiguration represents a declarative configuration of the TopologyAssignmentSliceLevelIndividualValues type for use
+// with apply.
+type TopologyAssignmentSliceLevelIndividualValuesApplyConfiguration struct {
+	CommonPrefix *string  `json:"commonPrefix,omitempty"`
+	CommonSuffix *string  `json:"commonSuffix,omitempty"`
+	Roots        []string `json:"roots,omitempty"`
+}
+
+// TopologyAssignmentSliceLevelIndividualValuesApplyConfiguration constructs a declarative configuration of the TopologyAssignmentSliceLevelIndividualValues type for use with
+// apply.
+func TopologyAssignmentSliceLevelIndividualValues() *TopologyAssignmentSliceLevelIndividualValuesApplyConfiguration {
+	return &TopologyAssignmentSliceLevelIndividualValuesApplyConfiguration{}
+}
+
+// WithCommonPrefix sets the CommonPrefix field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the CommonPrefix field is set to the value of the last call.
+func (b *TopologyAssignmentSliceLevelIndividualValuesApplyConfiguration) WithCommonPrefix(value string) *TopologyAssignmentSliceLevelIndividualValuesApplyConfiguration {
+	b.CommonPrefix = &value
+	return b
+}
+
+// WithCommonSuffix sets the CommonSuffix field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the CommonSuffix field is set to the value of the last call.
+func (b *TopologyAssignmentSliceLevelIndividualValuesApplyConfiguration) WithCommonSuffix(value string) *TopologyAssignmentSliceLevelIndividualValuesApplyConfiguration {
+	b.CommonSuffix = &value
+	return b
+}
+
+// WithRoots adds the given value to the Roots field in the declarative configuration
+// and returns the receiver, so that objects can be build by chaining "With" function invocations.
+// If called multiple times, values provided by each call will be appended to the Roots field.
+func (b *TopologyAssignmentSliceLevelIndividualValuesApplyConfiguration) WithRoots(values ...string) *TopologyAssignmentSliceLevelIndividualValuesApplyConfiguration {
+	for i := range values {
+		b.Roots = append(b.Roots, values[i])
+	}
+	return b
+}
diff --git a/client-go/applyconfiguration/kueue/v1beta2/topologyassignmentslicelevelvalues.go b/client-go/applyconfiguration/kueue/v1beta2/topologyassignmentslicelevelvalues.go
new file mode 100644
index 000000000..2af4ee272
--- /dev/null
+++ b/client-go/applyconfiguration/kueue/v1beta2/topologyassignmentslicelevelvalues.go
@@ -0,0 +1,47 @@
+/*
+Copyright The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+// Code generated by applyconfiguration-gen. DO NOT EDIT.
+
+package v1beta2
+
+// TopologyAssignmentSliceLevelValuesApplyConfiguration represents a declarative configuration of the TopologyAssignmentSliceLevelValues type for use
+// with apply.
+type TopologyAssignmentSliceLevelValuesApplyConfiguration struct {
+	Universal  *string                                                         `json:"universal,omitempty"`
+	Individual *TopologyAssignmentSliceLevelIndividualValuesApplyConfiguration `json:"individual,omitempty"`
+}
+
+// TopologyAssignmentSliceLevelValuesApplyConfiguration constructs a declarative configuration of the TopologyAssignmentSliceLevelValues type for use with
+// apply.
+func TopologyAssignmentSliceLevelValues() *TopologyAssignmentSliceLevelValuesApplyConfiguration {
+	return &TopologyAssignmentSliceLevelValuesApplyConfiguration{}
+}
+
+// WithUniversal sets the Universal field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the Universal field is set to the value of the last call.
+func (b *TopologyAssignmentSliceLevelValuesApplyConfiguration) WithUniversal(value string) *TopologyAssignmentSliceLevelValuesApplyConfiguration {
+	b.Universal = &value
+	return b
+}
+
+// WithIndividual sets the Individual field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the Individual field is set to the value of the last call.
+func (b *TopologyAssignmentSliceLevelValuesApplyConfiguration) WithIndividual(value *TopologyAssignmentSliceLevelIndividualValuesApplyConfiguration) *TopologyAssignmentSliceLevelValuesApplyConfiguration {
+	b.Individual = value
+	return b
+}
diff --git a/client-go/applyconfiguration/kueue/v1beta2/topologyassignmentslicepodcounts.go b/client-go/applyconfiguration/kueue/v1beta2/topologyassignmentslicepodcounts.go
new file mode 100644
index 000000000..f46ab96a6
--- /dev/null
+++ b/client-go/applyconfiguration/kueue/v1beta2/topologyassignmentslicepodcounts.go
@@ -0,0 +1,49 @@
+/*
+Copyright The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+// Code generated by applyconfiguration-gen. DO NOT EDIT.
+
+package v1beta2
+
+// TopologyAssignmentSlicePodCountsApplyConfiguration represents a declarative configuration of the TopologyAssignmentSlicePodCounts type for use
+// with apply.
+type TopologyAssignmentSlicePodCountsApplyConfiguration struct {
+	Universal  *int32  `json:"universal,omitempty"`
+	Individual []int32 `json:"individual,omitempty"`
+}
+
+// TopologyAssignmentSlicePodCountsApplyConfiguration constructs a declarative configuration of the TopologyAssignmentSlicePodCounts type for use with
+// apply.
+func TopologyAssignmentSlicePodCounts() *TopologyAssignmentSlicePodCountsApplyConfiguration {
+	return &TopologyAssignmentSlicePodCountsApplyConfiguration{}
+}
+
+// WithUniversal sets the Universal field in the declarative configuration to the given value
+// and returns the receiver, so that objects can be built by chaining "With" function invocations.
+// If called multiple times, the Universal field is set to the value of the last call.
+func (b *TopologyAssignmentSlicePodCountsApplyConfiguration) WithUniversal(value int32) *TopologyAssignmentSlicePodCountsApplyConfiguration {
+	b.Universal = &value
+	return b
+}
+
+// WithIndividual adds the given value to the Individual field in the declarative configuration
+// and returns the receiver, so that objects can be build by chaining "With" function invocations.
+// If called multiple times, values provided by each call will be appended to the Individual field.
+func (b *TopologyAssignmentSlicePodCountsApplyConfiguration) WithIndividual(values ...int32) *TopologyAssignmentSlicePodCountsApplyConfiguration {
+	for i := range values {
+		b.Individual = append(b.Individual, values[i])
+	}
+	return b
+}
diff --git a/client-go/applyconfiguration/kueue/v1beta2/topologydomainassignment.go b/client-go/applyconfiguration/kueue/v1beta2/topologydomainassignment.go
deleted file mode 100644
index 32d97305f..000000000
--- a/client-go/applyconfiguration/kueue/v1beta2/topologydomainassignment.go
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
-Copyright The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-// Code generated by applyconfiguration-gen. DO NOT EDIT.
-
-package v1beta2
-
-// TopologyDomainAssignmentApplyConfiguration represents a declarative configuration of the TopologyDomainAssignment type for use
-// with apply.
-type TopologyDomainAssignmentApplyConfiguration struct {
-	Values []string `json:"values,omitempty"`
-	Count  *int32   `json:"count,omitempty"`
-}
-
-// TopologyDomainAssignmentApplyConfiguration constructs a declarative configuration of the TopologyDomainAssignment type for use with
-// apply.
-func TopologyDomainAssignment() *TopologyDomainAssignmentApplyConfiguration {
-	return &TopologyDomainAssignmentApplyConfiguration{}
-}
-
-// WithValues adds the given value to the Values field in the declarative configuration
-// and returns the receiver, so that objects can be build by chaining "With" function invocations.
-// If called multiple times, values provided by each call will be appended to the Values field.
-func (b *TopologyDomainAssignmentApplyConfiguration) WithValues(values ...string) *TopologyDomainAssignmentApplyConfiguration {
-	for i := range values {
-		b.Values = append(b.Values, values[i])
-	}
-	return b
-}
-
-// WithCount sets the Count field in the declarative configuration to the given value
-// and returns the receiver, so that objects can be built by chaining "With" function invocations.
-// If called multiple times, the Count field is set to the value of the last call.
-func (b *TopologyDomainAssignmentApplyConfiguration) WithCount(value int32) *TopologyDomainAssignmentApplyConfiguration {
-	b.Count = &value
-	return b
-}
diff --git a/client-go/applyconfiguration/utils.go b/client-go/applyconfiguration/utils.go
index 162c4b523..4a50fa25e 100644
--- a/client-go/applyconfiguration/utils.go
+++ b/client-go/applyconfiguration/utils.go
@@ -283,8 +283,14 @@ func ForKind(kind schema.GroupVersionKind) interface{} {
 		return &kueuev1beta2.TopologyApplyConfiguration{}
 	case v1beta2.SchemeGroupVersion.WithKind("TopologyAssignment"):
 		return &kueuev1beta2.TopologyAssignmentApplyConfiguration{}
-	case v1beta2.SchemeGroupVersion.WithKind("TopologyDomainAssignment"):
-		return &kueuev1beta2.TopologyDomainAssignmentApplyConfiguration{}
+	case v1beta2.SchemeGroupVersion.WithKind("TopologyAssignmentSlice"):
+		return &kueuev1beta2.TopologyAssignmentSliceApplyConfiguration{}
+	case v1beta2.SchemeGroupVersion.WithKind("TopologyAssignmentSliceLevelIndividualValues"):
+		return &kueuev1beta2.TopologyAssignmentSliceLevelIndividualValuesApplyConfiguration{}
+	case v1beta2.SchemeGroupVersion.WithKind("TopologyAssignmentSliceLevelValues"):
+		return &kueuev1beta2.TopologyAssignmentSliceLevelValuesApplyConfiguration{}
+	case v1beta2.SchemeGroupVersion.WithKind("TopologyAssignmentSlicePodCounts"):
+		return &kueuev1beta2.TopologyAssignmentSlicePodCountsApplyConfiguration{}
 	case v1beta2.SchemeGroupVersion.WithKind("TopologyLevel"):
 		return &kueuev1beta2.TopologyLevelApplyConfiguration{}
 	case v1beta2.SchemeGroupVersion.WithKind("TopologySpec"):
diff --git a/cmd/kueue/main.go b/cmd/kueue/main.go
index 6cb775687..676387b36 100644
--- a/cmd/kueue/main.go
+++ b/cmd/kueue/main.go
@@ -380,7 +380,7 @@ func setupControllers(ctx context.Context, mgr ctrl.Manager, cCache *schdcache.C
 			return fmt.Errorf("could not setup MultiKueue controller: %w", err)
 		}
 
-		if failedDispatcher, err := dispatcher.SetupControllers(mgr, cfg, ptr.Deref(cfg.MultiKueue.DispatcherName, configapi.MultiKueueDispatcherModeAllAtOnce)); err != nil {
+		if failedDispatcher, err := dispatcher.SetupControllers(mgr, cfg); err != nil {
 			return fmt.Errorf("could not setup Dispatcher controller %q for MultiKueue: %w", failedDispatcher, err)
 		}
 	}
diff --git a/config/components/crd/bases/kueue.x-k8s.io_workloads.yaml b/config/components/crd/bases/kueue.x-k8s.io_workloads.yaml
index 5dfd7860f..2d4a9b04f 100644
--- a/config/components/crd/bases/kueue.x-k8s.io_workloads.yaml
+++ b/config/components/crd/bases/kueue.x-k8s.io_workloads.yaml
@@ -18250,100 +18250,209 @@ spec:
                             This field will not change in case of quota reclaim.
                           type: object
                         topologyAssignment:
-                          description: |-
-                            topologyAssignment indicates the topology assignment divided into
-                            topology domains corresponding to the lowest level of the topology.
-                            The assignment specifies the number of Pods to be scheduled per topology
-                            domain and specifies the node selectors for each topology domain, in the
-                            following way: the node selector keys are specified by the levels field
-                            (same for all domains), and the corresponding node selector value is
-                            specified by the domains.values subfield. If the TopologySpec.Levels field contains
-                            "kubernetes.io/hostname" label, topologyAssignment will contain data only for
-                            this label, and omit higher levels in the topology
-
-                            Example:
-
-                            topologyAssignment:
-                              levels:
-                              - cloud.provider.com/topology-block
-                              - cloud.provider.com/topology-rack
-                              domains:
-                              - values: [block-1, rack-1]
-                                count: 4
-                              - values: [block-1, rack-2]
-                                count: 2
-
-                            Here:
-                            - 4 Pods are to be scheduled on nodes matching the node selector:
-                              cloud.provider.com/topology-block: block-1
-                              cloud.provider.com/topology-rack: rack-1
-                            - 2 Pods are to be scheduled on nodes matching the node selector:
-                              cloud.provider.com/topology-block: block-1
-                              cloud.provider.com/topology-rack: rack-2
-
-                            Example:
-                            Below there is an equivalent of the above example assuming, Topology
-                            object defines kubernetes.io/hostname as the lowest level in topology.
-                            Hence we omit higher level of topologies, since the hostname label
-                            is sufficient to explicitly identify a proper node.
-
-                            topologyAssignment:
-                              levels:
-                              - kubernetes.io/hostname
-                              domains:
-                              - values: [hostname-1]
-                                count: 4
-                              - values: [hostname-2]
-                                count: 2
+                          description: "topologyAssignment indicates the topology
+                            assignment divided into\ntopology domains corresponding
+                            to the lowest level of the topology.\nThe assignment specifies
+                            the number of Pods to be scheduled per topology\ndomain
+                            and specifies the node selectors for each topology domain,
+                            in the\nfollowing way:\n* `levels` specifies the node
+                            selector keys (same for all domains).\n  - If the TopologySpec.Levels
+                            field contains \"kubernetes.io/hostname\" label,\n    topologyAssignment
+                            will contain data only for this label,\n    and omit higher
+                            levels in the topology.\n* `slices` specifies the node
+                            selector values and pod counts for all domains\n  (which
+                            may be partitioned into separate slices).\n  - The node
+                            selector values are arranged first by topology level,
+                            only then by domain.\n    (This allows \"optimizing\"
+                            similar values; see below).\n* The format of `slices`
+                            supports the following variations\n  (aimed to optimize
+                            the total bytesize for very large number of domains; see
+                            examples below):\n  - When all node selector values (at
+                            a given topology level, in a given slice)\n    share a
+                            common prefix and/or suffix, these may be stored\n    in
+                            dedicated `commonPrefix`/`commonSuffix` fields.\n    If
+                            so, the array of `roots` will only store the remaining
+                            parts of these strings.\n  - When all node selector values
+                            (at a given topology level, in a given slice)\n    are
+                            identical, this may be represented by `universal` value.\n
+                            \ - When all pod counts (in a given slice) are identical,\n
+                            \   this may be represented by `universal` pod count.\n\nExample
+                            1:\n\nThe following represents an assignment in which:\n*
+                            4 Pods are to be scheduled on nodes matching the node
+                            selector:\n  - cloud.provider.com/topology-block: block-1\n
+                            \ - cloud.provider.com/topology-rack: rack-1\n* 2 Pods
+                            are to be scheduled on nodes matching the node selector:\n
+                            \ - cloud.provider.com/topology-block: block-1\n  - cloud.provider.com/topology-rack:
+                            rack-2\n\ntopologyAssignment:\n  levels:\n  - cloud.provider.com/topology-block\n
+                            \ - cloud.provider.com/topology-rack\n  slices:\n  - domainCount:
+                            2\n    valuesPerLevel:\n    - individual:\n        roots:
+                            [block-1, block-1]\n    - individual:\n        roots:
+                            [rack-1, rack-2]\n    podCounts:\n      individual: [4,
+                            2]\n\nExample 2:\n\nThe following is equivalent to Example
+                            1 - but using extracted prefix and universalValue.\n\ntopologyAssignment:\n
+                            \ levels:\n  - cloud.provider.com/topology-block\n  -
+                            cloud.provider.com/topology-rack\n  slices:\n  - domainCount:
+                            2\n    valuesPerLevel:\n    - universal: block-1\n    -
+                            individual:\n        prefix: rack-\n\t\t   roots: [1,
+                            2]\n    podCounts:\n      individual: [4, 2]\n\nExample
+                            3:\n\nNow suppose that:\n- the Topology object defines
+                            kubernetes.io/hostname as the lowest level\n  (and hence,
+                            in the topologyAssignment, we omit all other levels\n
+                            \ since the hostname label suffices to explicitly identify
+                            a proper node),\n- we assign 1 Pod per each node,\n- the
+                            node naming scheme is `block-{blockId}-rack-{rackId}-node-{nodeId}`.\nThen,
+                            using the \"extraction of commons\", the assignment from
+                            Examples 1-2 would look as follows:\n\ntopologyAssignment:\n
+                            \ levels:\n  - kubernetes.io/hostname\n  slices:\n  -
+                            domainCount: 6\n    valuesPerLevel:\n    - individual:\n
+                            \       prefix: block-1-rack-\n\t\t   roots: [1-node-1,
+                            1-node-2, 1-node-3, 1-node-4, 2-node-1, 2-node-2]\n    podCounts:\n
+                            \     universal: 1\n\nExample 4:\n\nBy using multiple
+                            slices, we can afford even longer common prefixes.\nThe
+                            assignment from Example 3 can be alternatively represented
+                            as follows:\n\ntopologyAssignment:\n  levels:\n  - kubernetes.io/hostname\n
+                            \ slices:\n  - domainCount: 4\n    valuesPerLevel:\n    -
+                            individual:\n        prefix: block-1-rack-1-node-\n\t\t
+                            \  roots: [1, 2, 3, 4]\n    podCounts:\n      universal:
+                            1\n  - domainCount: 2\n    valuesPerLevel:\n    - individual:\n
+                            \       prefix: block-1-rack-2-node-\n\t\t   roots: [1,
+                            2]\n    podCounts:\n      universal: 1"
                           properties:
-                            domains:
+                            levels:
                               description: |-
-                                domains is a list of topology assignments split by topology domains at
-                                the lowest level of the topology.
+                                levels is an ordered list of keys denoting the levels of the assigned
+                                topology (i.e. node label keys), from the highest to the lowest level of
+                                the topology.
+                              items:
+                                maxLength: 317
+                                type: string
+                              maxItems: 16
+                              minItems: 1
+                              type: array
+                              x-kubernetes-list-type: atomic
+                            slices:
+                              description: |-
+                                slices represent topology assignments for subsets of pods of a workload.
+                                The full assignment is obtained as a union of all slices.
                               items:
                                 properties:
-                                  count:
-                                    description: |-
-                                      count indicates the number of Pods to be scheduled in the topology
-                                      domain indicated by the values field.
+                                  domainCount:
+                                    description: domainCount is the number of domains
+                                      covered by this slice.
                                     format: int32
                                     minimum: 1
                                     type: integer
-                                  values:
+                                  podCounts:
+                                    description: podCounts specifies the number of
+                                      pods allocated per each domain.
+                                    properties:
+                                      individual:
+                                        description: |-
+                                          individual - if set - specifies the number of pods allocated in each domain in this slice.
+                                          If set, its length must be equal to the "domainCount" field of the TopologyAssignmentSlice.
+                                          Exactly one of universal, individual must be set.
+                                        items:
+                                          format: int32
+                                          minimum: 1
+                                          type: integer
+                                        maxItems: 100000
+                                        minItems: 1
+                                        type: array
+                                        x-kubernetes-list-type: atomic
+                                      universal:
+                                        description: |-
+                                          universal - if set - specifies the number of pods allocated in every domain in this slice.
+                                          Exactly one of universal, individual must be set.
+                                        format: int32
+                                        minimum: 1
+                                        type: integer
+                                    type: object
+                                    x-kubernetes-validations:
+                                    - message: exactly one of the fields in [universal
+                                        individual] must be set
+                                      rule: '[has(self.universal),has(self.individual)].filter(x,x==true).size()
+                                        == 1'
+                                  valuesPerLevel:
                                     description: |-
-                                      values is an ordered list of node selector values describing a topology
-                                      domain. The values correspond to the consecutive topology levels, from
-                                      the highest to the lowest.
+                                      valuesPerLevel has one entry for each of the Levels specified in the TopologyAssignment.
+                                      The entry corresponding to a particular level specifies the placement of pods at that level.
                                     items:
-                                      maxLength: 63
-                                      type: string
+                                      properties:
+                                        individual:
+                                          description: |-
+                                            individual - if set - specifies multiple topology placement values (at a particular topology level)
+                                            that apply to the pods in the current TopologyAssignmentSlice.
+                                            Exactly one of universal, individual must be set.
+                                          properties:
+                                            commonPrefix:
+                                              description: |-
+                                                commonPrefix specifies a common prefix for all values in this slice assignment.
+                                                It must be either nil pointer or a non-empty string.
+                                              maxLength: 63
+                                              type: string
+                                            commonSuffix:
+                                              description: |-
+                                                commonSuffix specifies a common suffix for all values in this slice assignment.
+                                                It must be either nil pointer or a non-empty string.
+                                              maxLength: 63
+                                              type: string
+                                            roots:
+                                              description: |-
+                                                roots specifies the values in this assignment (excluding commonPrefix and commonSuffix, if non-empty).
+                                                Its length must be equal to the "domainCount" field of the TopologyAssignmentSlice.
+                                              items:
+                                                maxLength: 63
+                                                type: string
+                                              maxItems: 100000
+                                              minItems: 1
+                                              type: array
+                                              x-kubernetes-list-type: atomic
+                                          required:
+                                          - roots
+                                          type: object
+                                        universal:
+                                          description: |-
+                                            universal - if set - specifies a single topology placement value (at a particular topology level)
+                                            that applies to all pods in the current TopologyAssignmentSlice.
+                                            Exactly one of universal, individual must be set.
+                                          maxLength: 63
+                                          type: string
+                                      type: object
+                                      x-kubernetes-validations:
+                                      - message: exactly one of the fields in [universal
+                                          individual] must be set
+                                        rule: '[has(self.universal),has(self.individual)].filter(x,x==true).size()
+                                          == 1'
                                     maxItems: 16
                                     minItems: 1
                                     type: array
                                     x-kubernetes-list-type: atomic
                                 required:
-                                - count
-                                - values
+                                - domainCount
+                                - podCounts
+                                - valuesPerLevel
                                 type: object
-                              maxItems: 100000
-                              type: array
-                              x-kubernetes-list-type: atomic
-                            levels:
-                              description: |-
-                                levels is an ordered list of keys denoting the levels of the assigned
-                                topology (i.e. node label keys), from the highest to the lowest level of
-                                the topology.
-                              items:
-                                maxLength: 317
-                                type: string
-                              maxItems: 16
-                              minItems: 1
+                                x-kubernetes-validations:
+                                - message: podCounts.individual must have length equal
+                                    to domainCount
+                                  rule: '!has(self.podCounts.individual) || size(self.podCounts.individual)
+                                    == self.domainCount'
+                                - message: valuesPerLevel.individual, if set, must
+                                    have roots of length equal to domainCount of this
+                                    TopologyAssignmentSlice
+                                  rule: self.valuesPerLevel.all(x, !has(x.individual)
+                                    || size(x.individual.roots) == self.domainCount)
+                              maxItems: 1000
                               type: array
                               x-kubernetes-list-type: atomic
                           required:
-                          - domains
                           - levels
+                          - slices
                           type: object
+                          x-kubernetes-validations:
+                          - message: valuesPerLevel must have the same length as the
+                              number of levels in this TopologyAssignment
+                            rule: self.slices.all(x, size(x.valuesPerLevel) == size(self.levels))
                       type: object
                     maxItems: 8
                     type: array
diff --git a/keps/2724-topology-aware-scheduling/README.md b/keps/2724-topology-aware-scheduling/README.md
index d8baa1d23..8dd3cdf7d 100644
--- a/keps/2724-topology-aware-scheduling/README.md
+++ b/keps/2724-topology-aware-scheduling/README.md
@@ -32,6 +32,9 @@
   - [Validation](#validation)
     - [PodSet Slice size validation](#podset-slice-size-validation)
   - [Internal APIs](#internal-apis)
+    - [Topology assignment representation](#topology-assignment-representation)
+      - [Until v1beta1](#until-v1beta1)
+      - [Since v1beta2](#since-v1beta2)
     - [Node failures](#node-failures)
       - [Until v0.13](#until-v013)
       - [Since v0.14](#since-v014)
@@ -72,6 +75,7 @@
   - [Drop dedicated TAS label](#drop-dedicated-tas-label)
   - [MostFreeCapacity algorithm](#mostfreecapacity-algorithm)
     - [Example](#example-3)
+  - [TopologyAssignmentSlices as separate CRD instances](#topologyassignmentslices-as-separate-crd-instances)
 <!-- /toc -->
 
 ## Summary
@@ -819,55 +823,49 @@ at each topology level to the specific subset of nodes.
 type PodSetAssignment struct {
   ...
 
-  // topologyAssignment indicates the topology assignment divided into
-  // topology domains corresponding to the lowest level of the topology.
-  // The assignment specifies the number of Pods to be scheduled per topology
-  // domain and specifies the node selectors for each topology domain, in the
-  // following way: the node selector keys are specified by the levels field
-  // (same for all domains), and the corresponding node selector value is
-  // specified by the domains.values subfield. If the TopologySpec.Levels field contains
-  // "kubernetes.io/hostname" label, topologyAssignment will contain data only for
-  // this label, and omit higher levels in the topology
-  //
-  // Example:
-  //
-  // topologyAssignment:
-  //   levels:
-  //   - cloud.provider.com/topology-block
-  //   - cloud.provider.com/topology-rack
-  //   domains:
-  //   - values: [block-1, rack-1]
-  //     count: 4
-  //   - values: [block-1, rack-2]
-  //     count: 2
-  //
-  // Here:
-  // - 4 Pods are to be scheduled on nodes matching the node selector:
-  //   cloud.provider.com/topology-block: block-1
-  //   cloud.provider.com/topology-rack: rack-1
-  // - 2 Pods are to be scheduled on nodes matching the node selector:
-  //   cloud.provider.com/topology-block: block-1
-  //   cloud.provider.com/topology-rack: rack-2
-  //
-  // Example:
-	// Below there is an equivalent of the above example assuming, Topology
-	// object defines kubernetes.io/hostname as the lowest level in topology.
-	// Hence we omit higher level of topologies, since the hostname label
-	// is sufficient to explicitly identify a proper node.
-  //
-  // topologyAssignment:
-  //   levels:
-  //   - kubernetes.io/hostname
-  //   domains:
-  //   - values: [hostname-1]
-  //     count: 4
-  //   - values: [hostname-2]
-  //     count: 2
-  //
   // +optional
   TopologyAssignment *TopologyAssignment `json:"topologyAssignment,omitempty"`
-}
+```
+
+The format of `TopologyAssignment` depends on the API version; see details [below](#topology-assignment-representation).
+
+Kueue uses the `kueue.x-k8s.io/topology` scheduling gate to delay the
+`nodeSelector` assignment, because different pods in the same PodSet may have
+different values:
+
+```golang
+const (
+  // TopologySchedulingGate is used to delay scheduling of a Pod until the
+  // nodeSelectors corresponding to the assigned topology domain are injected
+  // into the Pod.
+  TopologySchedulingGate = "kueue.x-k8s.io/topology"
+
+  // WorkloadAnnotation is an annotation set on the Job's PodTemplate to
+  // indicate the name of the admitted Workload corresponding to the Job. The
+  // annotation is set when starting the Job, and removed on stopping the Job.
+  WorkloadAnnotation = "kueue.x-k8s.io/workload"
+
+  // TASLabel is a label set on the Job's PodTemplate to indicate that the
+  // PodSet is admitted using TopologyAwareScheduling, and all Pods created
+  // from the Job's PodTemplate also have the label.
+  TASLabel = "kueue.x-k8s.io/tas"
+)
+```
+
+#### Topology assignment representation
+
+`TopologyAssignment` indicates the topology assignment divided into topology domains corresponding to the lowest level of the topology. The assignment specifies the number of Pods to be scheduled per topology domain and the node selectors for each topology domain, in the following way:
+
+- the node selector keys are specified by the `Levels` field (same for all domains),
+- the corresponding node selector values - and the Pod counts - are specified by the other field (`Domains` until v1beta1 or `Slices` since v1beta2).
 
+If the `Levels` field contains `kubernetes.io/hostname` label, the `TopologyAssignment` will contain data only for this label, and omit higher levels in the topology.
+
+##### Until v1beta1
+
+In the older format, each domain assignment is represented by a single entry in the `Domains` list. 
+
+```golang
 type TopologyAssignment struct {
   // levels is an ordered list of keys denoting the levels of the assigned
   // topology (i.e. node label keys), from the highest to the lowest level of
@@ -906,29 +904,204 @@ type TopologyDomainAssignment struct {
 }
 ```
 
-Kueue uses the `kueue.x-k8s.io/topology` scheduling gate to delay the
-`nodeSelector` assignment, because different pods in the same PodSet may have
-different values:
+Example:
+
+```yaml
+topologyAssignment:
+  levels:
+  - cloud.provider.com/topology-block
+  - cloud.provider.com/topology-rack
+  domains:
+  - values: [block-1, rack-1]
+    count: 4
+  - values: [block-1, rack-2]
+    count: 2
+```
+
+Here:
+- 4 Pods are to be scheduled on nodes matching the node selector:
+  ```
+  cloud.provider.com/topology-block: block-1
+  cloud.provider.com/topology-rack: rack-1
+  ```
+- 2 Pods are to be scheduled on nodes matching the node selector:
+  ```
+  cloud.provider.com/topology-block: block-1
+  cloud.provider.com/topology-rack: rack-2
+  ```
+
+Below there is an equivalent of the above example, assuming that the Topology
+object defines `kubernetes.io/hostname` as the lowest level in topology.
+Hence we omit higher topology levels, since the hostname label
+is sufficient to uniquely identify a particular node.
+
+```yaml
+topologyAssignment:
+  levels:
+  - kubernetes.io/hostname
+  domains:
+  - values: [hostname-1]
+    count: 4
+  - values: [hostname-2]
+    count: 2
+```
+
+##### Since v1beta2
+
+In v1beta2, the data format is reshaped, with the main goal of improving handling of huge workloads. The 3 main ideas here are:
+
+- splitting the whole assignment structure into slices,
+- broader use of "parallel lists" which should be "zipped together" to produce their meaning \
+  (just like a _single_ list `Levels` in the old format specified the topology levels used in _every_ domain of the assignment),
+- extracting common prefixes and suffixes of node names.
 
 ```golang
-const (
-  // TopologySchedulingGate is used to delay scheduling of a Pod until the
-  // nodeSelectors corresponding to the assigned topology domain are injected
-  // into the Pod.
-  TopologySchedulingGate = "kueue.x-k8s.io/topology"
+type TopologyAssignment struct {
+  // (same role & comments as in v1beta1)
+  Levels []string `json:"levels,omitempty"`
 
-  // WorkloadAnnotation is an annotation set on the Job's PodTemplate to
-  // indicate the name of the admitted Workload corresponding to the Job. The
-  // annotation is set when starting the Job, and removed on stopping the Job.
-  WorkloadAnnotation = "kueue.x-k8s.io/workload"
+  // slices represent topology assignments for subsets of pods of a workload.
+  // The full assignment is obtained as a union of all slices.
+  // +required
+  // +listType=atomic
+  // +kubebuilder:validation:MaxItems=1000
+  Slices []TopologyAssignmentSlice `json:"slices,omitempty"`
+}
 
-  // TASLabel is a label set on the Job's PodTemplate to indicate that the
-  // PodSet is admitted using TopologyAwareScheduling, and all Pods created
-  // from the Job's PodTemplate also have the label.
-  TASLabel = "kueue.x-k8s.io/tas"
-)
+// TopologyAssignmentSlice fully specifies the topology assignment for a subset of pods of a workload.
+type TopologyAssignmentSlice struct {
+  // domainCount is the number of domains covered by this slice.
+  // +required
+  // +kubebuilder:validation:Minimum=1
+  DomainCount int32 `json:"domainCount,omitempty"`
+
+  // valuesPerLevel has one entry for each of the Levels specified in the TopologyAssignment.
+  // The entry corresponding to a particular level specifies the placement of pods at that level.
+  // +required
+  // +listType=atomic
+  // +kubebuilder:validation:MinItems=1
+  // +kubebuilder:validation:MaxItems=16
+  ValuesPerLevel []TopologyAssignmentSliceLevelValues `json:"valuesPerLevel,omitempty"`
+
+  // podCounts specifies the number of pods allocated per each domain.
+  // +required
+  PodCounts TopologyAssignmentSlicePodCounts `json:"podCounts,omitempty"`
+}
+
+type TopologyAssignmentSliceLevelValues struct {
+  // universal, if set, specifies a single topology placement value (at a particular topology level)
+  // that applies to all pods in the current TopologyAssignmentSlice.
+  // Exactly one of universal, individual must be set.
+  // +optional
+  Universal *string `json:"universal,omitempty"`
+
+  // individual, if set, specifies multiple topology placement values (at a particular topology level)
+  // that apply to the pods in the current TopologyAssignmentSlice.
+  // Exactly one of universal, individual must be set.
+  // +optional
+  Individual *TopologyAssignmentSliceLevelIndividualValues `json:"individual,omitempty"`
+}
+
+type TopologyAssignmentSliceLevelIndividualValues struct {
+  // commonPrefix specifies a common prefix for all values in this slice assignment.
+  // It must be either nil pointer or a non-empty string.
+  // +optional
+  // +kubebuilder:validation:MaxLength=63
+  CommonPrefix *string `json:"commonPrefix,omitempty"`
+  // commonSuffix specifies a common suffix for all values in this slice assignment.
+  // It must be either nil pointer or a non-empty string.
+  // +optional
+  // +kubebuilder:validation:MaxLength=63
+  CommonSuffix *string `json:"commonSuffix,omitempty"`
+
+  // roots specifies the values in this assignment (excluding commonPrefix and commonSuffix, if non-empty).
+  // Its length must be equal to the "domainCount" field of the TopologyAssignmentSlice.
+  // +required
+  // +listType=atomic
+  // +kubebuilder:validation:MinItems=1
+  // +kubebuilder:validation:MaxItems=100000
+  // +kubebuilder:validation:items:MaxLength=63
+  Roots []string `json:"roots,omitempty"`
+}
+
+type TopologyAssignmentSlicePodCounts struct {
+  // universal, if set, specifies the number of pods allocated in every domain in this slice.
+  // Exactly one of universal, individual must be set.
+  // +optional
+  // +kubebuilder:validation:Minimum=1
+  Universal *int32 `json:"universal,omitempty"`
+
+  // individual, if set, specifies the number of pods allocated in each domain in this slice.
+  // If set, its length must be equal to the "domainCount" field of the TopologyAssignmentSlice.
+  // Exactly one of universal, individual must be set.
+  // +optional
+  // +listType=atomic
+  // +kubebuilder:validation:MinItems=1
+  // +kubebuilder:validation:MaxItems=100000
+  // +kubebuilder:validation:items:Minimum=1
+  Individual []int32 `json:"podCounts,omitempty"`
+}
+```
+
+The above mentioned cross-validity rules (mutually exclusive fields, equal lengths, etc.) will be all expressed as `kubebuilder:validation:XValidation` rules on the respective "smallest common container types".
+
+Example (representing the same assignment as in the first example for the [old format](#until-v1beta1)):
+
+```yaml
+topologyAssignment:
+  levels:
+  - cloud.provider.com/topology-block
+  - cloud.provider.com/topology-rack
+  slices:
+  - domainCount: 2
+    valuesPerLevel:
+    - universal: block-1
+    - individual:
+        commonPrefix: rack-
+        roots: [1, 2]
+    podCounts:
+      individual: [4, 2]
 ```
 
+The above example has one slice, specifying 2 domains on 2 topology levels. On the block level, all domains take the same value (`block-1`), which allows using `universal`. On the rack level, the values diverge (`rack-1`) vs. (`rack-2`) but they still share a relatively long common prefix. The new representation allows deduplicating characters between these.
+
+Multiple slices may be used e.g. for a host-level assignment when the nodes being assigned are split into multiple "node pools". The following example illustrates this for an assignment of 12 pods on 12 nodes (1 per 1), where the nodes come from 2 pools (of size 5 and 7 respectively), with node names looking like `pool-X-node-Y`:
+
+```yaml
+topologyAssignment:
+  levels: [kubernetes.io/hostname]
+  slices:
+  - domainCount: 5
+    valuesPerLevel:
+    - individual:
+        commonPrefix: pool-1-node-
+        roots: [1, 2, 3, 4, 5]
+    podCounts:
+      universal: 1
+  - domainCount: 7
+    valuesPerLevel:
+    - individual:
+        commonPrefix: pool-2-node-
+        roots: [1, 2, 3, 4, 5, 6, 7]
+    podCounts:
+      universal: 1
+```
+
+The main motivation behind the new format is the etcd size limit of 1.5MiB per single resource, which currently restricts the number of nodes that can participate in the assignment for a single workload. (For the v1beta1 format, and the real-life node naming schemes of main K8s vendors, the limit is around 20-30k). The new format helps addressing this problem in 2 time perspectives:
+
+- In the short term, it increases the number of nodes which can fit into 1 etcd entry.
+
+  - By just using a single slice, with extracting common prefix and suffix of all node names, our simulations (for some real-life node naming schemes) suggested a limit of around 60k nodes.
+  
+  - Multiple slices allow optimizing even further, if desired. \
+    Our simulations of more complex algorithms (e.g. heuristic pruning of prefix tree) allowed fitting over 100k nodes. \
+    (However, at that point we reached a tradeoff between bytesize, encoding time, and conceptual simplicity. Resolving that tradeoff is out of scope of this design; the important thing is that the proposed data format supports various specific algorithms).
+
+- In the long term, as the number of nodes grows, at some point we'll inevitably hit the 1.5MiB limit anyway. \
+  When this happens, we foresee a need to store the slices as separate CRD instances (see [description](#topologyassignmentslices-as-separate-crd-instances) in the "Alternatives" section). \
+  While the v1beta2 format does not yet do that, by introducing `Slices` we come much closer to this. \
+  Once there is a need, we can promote (some of) `Slices` to instances of a standalone CRD - but the appropriate type system is already there.
+
 #### Node failures
 
 Initially we plan to support node becoming not ready (as indicated in Node
@@ -1566,3 +1739,17 @@ becomes apparent:
 **Reasons for discarding/deferring**
 Due to code simplicity concerns and a lack of use cases for the algorithm,
 the decision was made to remove it in favor of `BestFit`.
+
+### TopologyAssignmentSlices as separate CRD instances
+
+In the [v1beta2 format](#since-v1beta2) for TopologyAssignment, we introduce TopologyAssignmentSlices embedded in the WorkloadStatus. This helps fitting larger workloads within a single etcd entry, but still hits a scalability limit.
+
+One way of going beyond that limit would be to extract the slices into separate instances of a dedicated CRD (analogously to how [EndpointSlice](https://github.com/kubernetes/kubernetes/blob/3b632270e9b866ee8bf62e89377ae95987671b49/pkg/apis/discovery/types.go#L24-L29) has been introduced in K8s core). This would, in practice, allow storing arbitrarily many nodes, though at some cost. (See "Reasons for deferring" below).
+
+For these reasons, if we choose to do it, we would likely extract only "excess" slices, so that the TAS assignment for smaller workloads can be still kept inside WorkloadStatus.
+
+**Reasons for discarding/deferring**
+
+- Decreased UX of the API (some info delegated to other objects).
+- Decreased performance of Kueue scheduler (need to do more etcd reads and writes). \
+  (In particular, even when we end up using slices in separate CRDs, the "compression capabilities" introduced in v1beta2 are going to improve performance by reducing the necessary number of such slices).
diff --git a/keps/2724-topology-aware-scheduling/kep.yaml b/keps/2724-topology-aware-scheduling/kep.yaml
index b06fa80b4..b577a631b 100644
--- a/keps/2724-topology-aware-scheduling/kep.yaml
+++ b/keps/2724-topology-aware-scheduling/kep.yaml
@@ -3,6 +3,7 @@ kep-number: 2724
 authors:
   - "@mimowo"
   - "@mwielgus"
+  - "@olekzabl"
   - "@pbundyra"
 status: provisional
 creation-date: 2023-07-30
diff --git a/pkg/cache/scheduler/tas_flavor_snapshot.go b/pkg/cache/scheduler/tas_flavor_snapshot.go
index 5fd4f24dc..8a9d7ea89 100644
--- a/pkg/cache/scheduler/tas_flavor_snapshot.go
+++ b/pkg/cache/scheduler/tas_flavor_snapshot.go
@@ -380,7 +380,7 @@ func (r TASAssignmentsResult) Failure() *FailureInfo {
 }
 
 type tasPodSetAssignmentResult struct {
-	TopologyAssignment *kueue.TopologyAssignment
+	TopologyAssignment *utiltas.TopologyAssignment
 	FailureReason      string
 }
 
@@ -462,7 +462,7 @@ func (s *TASFlavorSnapshot) FindTopologyAssignmentsForFlavor(flavorTASRequests F
 				}
 				// We deepCopy the existing TopologyAssignment, so if we delete unwanted domain,
 				// And there is no fit, we have the original newAssignment to retry with
-				newAssignment, replacementAssignment, reason := s.findReplacementAssignment(&tr, psa.TopologyAssignment.DeepCopy(), opts.workload, assumedUsage)
+				newAssignment, replacementAssignment, reason := s.findReplacementAssignment(&tr, utiltas.InternalFrom(psa.TopologyAssignment), opts.workload, assumedUsage)
 				result[tr.PodSet.Name] = tasPodSetAssignmentResult{TopologyAssignment: newAssignment, FailureReason: reason}
 				if reason != "" {
 					return result
@@ -508,7 +508,7 @@ func findLeaderAndWorkers(trs FlavorTASRequests) (*TASPodSetRequests, TASPodSetR
 // findReplacementAssignment finds the topology assignment for the replacement node
 // it return new corrected topologyAssignment, a replacement topologyAssignment used to patched the old, faulty one, and
 // reason if finding fails
-func (s *TASFlavorSnapshot) findReplacementAssignment(tr *TASPodSetRequests, existingAssignment *kueue.TopologyAssignment, wl *kueue.Workload, assumedUsage map[utiltas.TopologyDomainID]resources.Requests) (*kueue.TopologyAssignment, *kueue.TopologyAssignment, string) {
+func (s *TASFlavorSnapshot) findReplacementAssignment(tr *TASPodSetRequests, existingAssignment *utiltas.TopologyAssignment, wl *kueue.Workload, assumedUsage map[utiltas.TopologyDomainID]resources.Requests) (*utiltas.TopologyAssignment, *utiltas.TopologyAssignment, string) {
 	tr.Count = deleteDomain(existingAssignment, wl.Status.UnhealthyNodes[0].Name)
 	if isStale, staleDomain := s.IsTopologyAssignmentStale(existingAssignment); isStale {
 		return nil, nil, fmt.Sprintf("Cannot replace the node, because the existing topologyAssignment is invalid, as it contains the stale domain %v", staleDomain)
@@ -530,7 +530,7 @@ func (s *TASFlavorSnapshot) findReplacementAssignment(tr *TASPodSetRequests, exi
 	return newAssignment, replacementAssignment[tr.PodSet.Name], ""
 }
 
-func addAssumedUsage(assumedUsage map[utiltas.TopologyDomainID]resources.Requests, ta *kueue.TopologyAssignment, tr *TASPodSetRequests) {
+func addAssumedUsage(assumedUsage map[utiltas.TopologyDomainID]resources.Requests, ta *utiltas.TopologyAssignment, tr *TASPodSetRequests) {
 	for _, domain := range ta.Domains {
 		domainID := utiltas.DomainID(domain.Values)
 		if assumedUsage[domainID] == nil {
@@ -552,7 +552,7 @@ func findPSA(wl *kueue.Workload, psName kueue.PodSetReference) *kueue.PodSetAssi
 	return nil
 }
 
-func (s *TASFlavorSnapshot) requiredReplacementDomain(tr *TASPodSetRequests, ta *kueue.TopologyAssignment) utiltas.TopologyDomainID {
+func (s *TASFlavorSnapshot) requiredReplacementDomain(tr *TASPodSetRequests, ta *utiltas.TopologyAssignment) utiltas.TopologyDomainID {
 	key := s.levelKeyWithImpliedFallback(tr)
 	if key == nil {
 		return ""
@@ -590,7 +590,7 @@ func (s *TASFlavorSnapshot) requiredReplacementDomain(tr *TASPodSetRequests, ta
 // IsTopologyAssignmentStale indicates whether the topologyAssignment have Nodes
 // that don't exists in the snapshot. It may be cause e.g. by Node deletion, or change
 // in Node's NodeReady condition
-func (s *TASFlavorSnapshot) IsTopologyAssignmentStale(ta *kueue.TopologyAssignment) (bool, string) {
+func (s *TASFlavorSnapshot) IsTopologyAssignmentStale(ta *utiltas.TopologyAssignment) (bool, string) {
 	for _, domain := range ta.Domains {
 		if _, found := s.domains[utiltas.DomainID(domain.Values)]; !found {
 			return true, domain.Values[0]
@@ -600,9 +600,9 @@ func (s *TASFlavorSnapshot) IsTopologyAssignmentStale(ta *kueue.TopologyAssignme
 }
 
 // deleteDomain deletes the domain the has faulty node and returns number of affected pods by the node
-func deleteDomain(currentTopologyAssignment *kueue.TopologyAssignment, unhealthyNode string) int32 {
+func deleteDomain(currentTopologyAssignment *utiltas.TopologyAssignment, unhealthyNode string) int32 {
 	var noAffectedPods int32 = 0
-	updatedAssignment := make([]kueue.TopologyDomainAssignment, 0, len(currentTopologyAssignment.Domains))
+	updatedAssignment := make([]utiltas.TopologyDomainAssignment, 0, len(currentTopologyAssignment.Domains))
 	for _, domain := range currentTopologyAssignment.Domains {
 		if domain.Values[len(domain.Values)-1] == unhealthyNode {
 			noAffectedPods = domain.Count
@@ -614,7 +614,7 @@ func deleteDomain(currentTopologyAssignment *kueue.TopologyAssignment, unhealthy
 	return noAffectedPods
 }
 
-func (s *TASFlavorSnapshot) findIncompleteSliceDomain(tr *TASPodSetRequests, ta *kueue.TopologyAssignment, missingCount int32) utiltas.TopologyDomainID {
+func (s *TASFlavorSnapshot) findIncompleteSliceDomain(tr *TASPodSetRequests, ta *utiltas.TopologyAssignment, missingCount int32) utiltas.TopologyDomainID {
 	// this function assumes that all assignments are at the hostname level
 	sliceTopologyKey := s.sliceLevelKeyWithDefault(tr.PodSet.TopologyRequest, s.lowestLevel())
 	sliceLevelIdx, found := s.resolveLevelIdx(sliceTopologyKey)
@@ -665,7 +665,7 @@ func (s *TASFlavorSnapshot) findTopologyAssignment(
 	workersTasPodSetRequests TASPodSetRequests,
 	leaderTasPodSetRequests *TASPodSetRequests,
 	assumedUsage map[utiltas.TopologyDomainID]resources.Requests,
-	simulateEmpty bool, requiredReplacementDomain utiltas.TopologyDomainID) (map[kueue.PodSetReference]*kueue.TopologyAssignment, string) {
+	simulateEmpty bool, requiredReplacementDomain utiltas.TopologyDomainID) (map[kueue.PodSetReference]*utiltas.TopologyAssignment, string) {
 	requests := workersTasPodSetRequests.SinglePodRequests.Clone()
 	requests.Add(resources.Requests{corev1.ResourcePods: 1})
 
@@ -788,7 +788,7 @@ func (s *TASFlavorSnapshot) findTopologyAssignment(
 		}
 	}
 
-	assignments := make(map[kueue.PodSetReference]*kueue.TopologyAssignment)
+	assignments := make(map[kueue.PodSetReference]*utiltas.TopologyAssignment)
 
 	if leaderTasPodSetRequests != nil {
 		var leaderFitDomains []*domain
@@ -829,17 +829,17 @@ func getSliceSizeWithSinglePodAsDefault(podSetTopologyRequest *kueue.PodSetTopol
 }
 
 // Merges two topology assignments keeping the lexicographical order of levelValues
-func (s *TASFlavorSnapshot) mergeTopologyAssignments(a, b *kueue.TopologyAssignment) *kueue.TopologyAssignment {
+func (s *TASFlavorSnapshot) mergeTopologyAssignments(a, b *utiltas.TopologyAssignment) *utiltas.TopologyAssignment {
 	nodeLevel := len(s.levelKeys) - 1
-	sortedDomains := make([]kueue.TopologyDomainAssignment, 0, len(a.Domains)+len(b.Domains))
+	sortedDomains := make([]utiltas.TopologyDomainAssignment, 0, len(a.Domains)+len(b.Domains))
 	sortedDomains = append(sortedDomains, a.Domains...)
 	sortedDomains = append(sortedDomains, b.Domains...)
-	slices.SortFunc(sortedDomains, func(a, b kueue.TopologyDomainAssignment) int {
+	slices.SortFunc(sortedDomains, func(a, b utiltas.TopologyDomainAssignment) int {
 		aDomain := s.domainsPerLevel[nodeLevel][utiltas.DomainID(a.Values)]
 		bDomain := s.domainsPerLevel[nodeLevel][utiltas.DomainID(b.Values)]
 		return cmp.Compare(utiltas.DomainID(aDomain.levelValues), utiltas.DomainID(bDomain.levelValues))
 	})
-	mergedDomains := make([]kueue.TopologyDomainAssignment, 0, len(sortedDomains))
+	mergedDomains := make([]utiltas.TopologyDomainAssignment, 0, len(sortedDomains))
 	for _, domain := range sortedDomains {
 		if canMerge(mergedDomains, domain) {
 			mergedDomains[len(mergedDomains)-1].Count += domain.Count
@@ -847,13 +847,13 @@ func (s *TASFlavorSnapshot) mergeTopologyAssignments(a, b *kueue.TopologyAssignm
 			mergedDomains = append(mergedDomains, domain)
 		}
 	}
-	return &kueue.TopologyAssignment{
+	return &utiltas.TopologyAssignment{
 		Levels:  a.Levels,
 		Domains: mergedDomains,
 	}
 }
 
-func canMerge(mergedDomains []kueue.TopologyDomainAssignment, domain kueue.TopologyDomainAssignment) bool {
+func canMerge(mergedDomains []utiltas.TopologyDomainAssignment, domain utiltas.TopologyDomainAssignment) bool {
 	if len(mergedDomains) == 0 {
 		return false
 	}
@@ -1198,9 +1198,9 @@ func (s *TASFlavorSnapshot) updateCountsToMinimumGeneric(domains []*domain, coun
 }
 
 // buildTopologyAssignmentForLevels build TopologyAssignment for levels starting from levelIdx
-func (s *TASFlavorSnapshot) buildTopologyAssignmentForLevels(domains []*domain, levelIdx int) *kueue.TopologyAssignment {
-	assignment := &kueue.TopologyAssignment{
-		Domains: make([]kueue.TopologyDomainAssignment, 0),
+func (s *TASFlavorSnapshot) buildTopologyAssignmentForLevels(domains []*domain, levelIdx int) *utiltas.TopologyAssignment {
+	assignment := &utiltas.TopologyAssignment{
+		Domains: make([]utiltas.TopologyDomainAssignment, 0),
 	}
 	assignment.Levels = s.levelKeys[levelIdx:]
 	for _, domain := range domains {
@@ -1208,7 +1208,7 @@ func (s *TASFlavorSnapshot) buildTopologyAssignmentForLevels(domains []*domain,
 			// It may happen when PodSet count is 0.
 			continue
 		}
-		assignment.Domains = append(assignment.Domains, kueue.TopologyDomainAssignment{
+		assignment.Domains = append(assignment.Domains, utiltas.TopologyDomainAssignment{
 			Values: domain.levelValues[levelIdx:],
 			Count:  domain.state,
 		})
@@ -1216,7 +1216,7 @@ func (s *TASFlavorSnapshot) buildTopologyAssignmentForLevels(domains []*domain,
 	return assignment
 }
 
-func (s *TASFlavorSnapshot) buildAssignment(domains []*domain) *kueue.TopologyAssignment {
+func (s *TASFlavorSnapshot) buildAssignment(domains []*domain) *utiltas.TopologyAssignment {
 	// lex sort domains by their levelValues instead of IDs, as leaves' IDs can only contain the hostname
 	slices.SortFunc(domains, func(a, b *domain) int {
 		return slices.Compare(a.levelValues, b.levelValues)
diff --git a/pkg/controller/tas/node_failure_controller.go b/pkg/controller/tas/node_failure_controller.go
index 065b28520..7eba1d9e5 100644
--- a/pkg/controller/tas/node_failure_controller.go
+++ b/pkg/controller/tas/node_failure_controller.go
@@ -191,8 +191,8 @@ func (r *nodeFailureReconciler) getWorkloadsOnNode(ctx context.Context, nodeName
 			if !utiltas.IsLowestLevelHostname(topologyAssignment.Levels) {
 				continue
 			}
-			for _, domain := range topologyAssignment.Domains {
-				if nodeName == domain.Values[len(domain.Values)-1] {
+			for value := range utiltas.LowestLevelValues(topologyAssignment) {
+				if value == nodeName {
 					tasWorkloadsOnNode.Insert(types.NamespacedName{Name: wl.Name, Namespace: wl.Namespace})
 				}
 			}
diff --git a/pkg/controller/tas/topology_ungater.go b/pkg/controller/tas/topology_ungater.go
index 8a08092c7..16132c797 100644
--- a/pkg/controller/tas/topology_ungater.go
+++ b/pkg/controller/tas/topology_ungater.go
@@ -302,7 +302,7 @@ func podsToUngateInfo(
 	psa *kueue.PodSetAssignment,
 	podToUngateWithDomain []podWithDomain) []podWithUngateInfo {
 	domainIDToLabelValues := make(map[utiltas.TopologyDomainID][]string)
-	for _, psaDomain := range psa.TopologyAssignment.Domains {
+	for psaDomain := range utiltas.InternalSeqFrom(psa.TopologyAssignment) {
 		domainID := utiltas.DomainID(psaDomain.Values)
 		domainIDToLabelValues[domainID] = psaDomain.Values
 	}
@@ -335,13 +335,13 @@ func assignGatedPodsToDomainsByRanks(
 	psa *kueue.PodSetAssignment,
 	rankToGatedPod map[int]*corev1.Pod) []podWithDomain {
 	toUngate := make([]podWithDomain, 0)
-	totalCount := 0
-	for i := range psa.TopologyAssignment.Domains {
-		totalCount += int(psa.TopologyAssignment.Domains[i].Count)
+	totalPodCount := 0
+	for count := range utiltas.PodCounts(psa.TopologyAssignment) {
+		totalPodCount += int(count)
 	}
-	rankToDomainID := make([]utiltas.TopologyDomainID, totalCount)
+	rankToDomainID := make([]utiltas.TopologyDomainID, totalPodCount)
 	index := int32(0)
-	for _, domain := range psa.TopologyAssignment.Domains {
+	for domain := range utiltas.InternalSeqFrom(psa.TopologyAssignment) {
 		for s := range domain.Count {
 			rankToDomainID[index+s] = utiltas.DomainID(domain.Values)
 		}
@@ -378,7 +378,7 @@ func assignGatedPodsToDomainsGreedy(
 		"domainIDToUngatedCount", domainIDToUngatedCnt,
 		"levelKeys", levelKeys)
 	toUngate := make([]podWithDomain, 0)
-	for _, psaDomain := range psa.TopologyAssignment.Domains {
+	for psaDomain := range utiltas.InternalSeqFrom(psa.TopologyAssignment) {
 		domainID := utiltas.DomainID(psaDomain.Values)
 		ungatedInDomainCnt := domainIDToUngatedCnt[domainID]
 		remainingUngatedInDomain := max(psaDomain.Count-ungatedInDomainCnt, 0)
diff --git a/pkg/controller/workloaddispatcher/controllers.go b/pkg/controller/workloaddispatcher/controllers.go
index 12d2bb86e..c598567a8 100644
--- a/pkg/controller/workloaddispatcher/controllers.go
+++ b/pkg/controller/workloaddispatcher/controllers.go
@@ -23,13 +23,17 @@ import (
 	"sigs.k8s.io/kueue/pkg/util/admissioncheck"
 )
 
-func SetupControllers(mgr ctrl.Manager, cfg *configapi.Configuration, dispatcherName string) (string, error) {
+func SetupControllers(mgr ctrl.Manager, cfg *configapi.Configuration) (string, error) {
+	if *cfg.MultiKueue.DispatcherName != configapi.MultiKueueDispatcherModeIncremental {
+		return "", nil
+	}
+
 	helper, err := admissioncheck.NewMultiKueueStoreHelper(mgr.GetClient())
 	if err != nil {
 		return "", err
 	}
 
-	idRec := NewIncrementalDispatcherReconciler(mgr.GetClient(), helper, dispatcherName)
+	idRec := NewIncrementalDispatcherReconciler(mgr.GetClient(), helper)
 	err = idRec.SetupWithManager(mgr, cfg)
 	if err != nil {
 		return "multikueue-incremental-dispatcher", err
diff --git a/pkg/controller/workloaddispatcher/incrementaldispatcher.go b/pkg/controller/workloaddispatcher/incrementaldispatcher.go
index 0435ba90e..891de59de 100644
--- a/pkg/controller/workloaddispatcher/incrementaldispatcher.go
+++ b/pkg/controller/workloaddispatcher/incrementaldispatcher.go
@@ -49,7 +49,6 @@ type IncrementalDispatcherReconciler struct {
 	client          client.Client
 	helper          *admissioncheck.MultiKueueStoreHelper
 	clock           clock.Clock
-	dispatcherName  string
 	roundStartTimes *utilmaps.SyncMap[types.NamespacedName, time.Time]
 }
 
@@ -63,23 +62,16 @@ func (r *IncrementalDispatcherReconciler) SetupWithManager(mgr ctrl.Manager, cfg
 		Complete(core.WithLeadingManager(mgr, r, &kueue.Workload{}, cfg))
 }
 
-func NewIncrementalDispatcherReconciler(c client.Client, helper *admissioncheck.MultiKueueStoreHelper, dispatcherName string) *IncrementalDispatcherReconciler {
+func NewIncrementalDispatcherReconciler(c client.Client, helper *admissioncheck.MultiKueueStoreHelper) *IncrementalDispatcherReconciler {
 	return &IncrementalDispatcherReconciler{
 		client:          c,
 		helper:          helper,
 		clock:           realClock,
-		dispatcherName:  dispatcherName,
 		roundStartTimes: utilmaps.NewSyncMap[types.NamespacedName, time.Time](0),
 	}
 }
 func (r *IncrementalDispatcherReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
 	log := ctrl.LoggerFrom(ctx)
-
-	if r.dispatcherName != kueueconfig.MultiKueueDispatcherModeIncremental {
-		log.V(3).Info("Not a Incremental Dispatcher, skip the reconciliation", "dispatcherName", r.dispatcherName)
-		return reconcile.Result{}, nil
-	}
-
 	wl := &kueue.Workload{}
 	err := r.client.Get(ctx, req.NamespacedName, wl)
 	if err != nil {
diff --git a/pkg/scheduler/flavorassigner/flavorassigner.go b/pkg/scheduler/flavorassigner/flavorassigner.go
index 2306acc85..0bfc2ac07 100644
--- a/pkg/scheduler/flavorassigner/flavorassigner.go
+++ b/pkg/scheduler/flavorassigner/flavorassigner.go
@@ -41,6 +41,7 @@ import (
 	preemptioncommon "sigs.k8s.io/kueue/pkg/scheduler/preemption/common"
 	utilmaps "sigs.k8s.io/kueue/pkg/util/maps"
 	"sigs.k8s.io/kueue/pkg/util/orderedgroups"
+	"sigs.k8s.io/kueue/pkg/util/tas"
 	"sigs.k8s.io/kueue/pkg/workload"
 )
 
@@ -239,7 +240,7 @@ type PodSetAssignment struct {
 	Requests corev1.ResourceList
 	Count    int32
 
-	TopologyAssignment     *kueue.TopologyAssignment
+	TopologyAssignment     *tas.TopologyAssignment
 	DelayedTopologyRequest *kueue.DelayedTopologyRequestState
 }
 
@@ -287,7 +288,7 @@ func (psa *PodSetAssignment) toAPI() kueue.PodSetAssignment {
 		Flavors:                flavors,
 		ResourceUsage:          psa.Requests,
 		Count:                  ptr.To(psa.Count),
-		TopologyAssignment:     psa.TopologyAssignment.DeepCopy(),
+		TopologyAssignment:     tas.V1Beta2From(psa.TopologyAssignment),
 		DelayedTopologyRequest: psa.DelayedTopologyRequest,
 	}
 }
@@ -551,7 +552,7 @@ func (a *FlavorAssigner) assignFlavors(log logr.Logger, counts []int32) Assignme
 				psAssignment.DelayedTopologyRequest = ptr.To(*podSet.DelayedTopologyRequest)
 			}
 			if podSet.TopologyRequest != nil {
-				psAssignment.TopologyAssignment = a.wl.Obj.Status.Admission.PodSetAssignments[i].TopologyAssignment
+				psAssignment.TopologyAssignment = tas.InternalFrom(a.wl.Obj.Status.Admission.PodSetAssignments[i].TopologyAssignment)
 			}
 		}
 
diff --git a/pkg/scheduler/flavorassigner/tas_flavorassigner.go b/pkg/scheduler/flavorassigner/tas_flavorassigner.go
index 957207476..30881a174 100644
--- a/pkg/scheduler/flavorassigner/tas_flavorassigner.go
+++ b/pkg/scheduler/flavorassigner/tas_flavorassigner.go
@@ -25,6 +25,7 @@ import (
 
 	kueue "sigs.k8s.io/kueue/apis/kueue/v1beta2"
 	schdcache "sigs.k8s.io/kueue/pkg/cache/scheduler"
+	"sigs.k8s.io/kueue/pkg/util/tas"
 	"sigs.k8s.io/kueue/pkg/workload"
 )
 
@@ -57,7 +58,7 @@ func (a *Assignment) WorkloadsTopologyRequests(wl *workload.Info, cq *schdcache.
 }
 
 func (psa *PodSetAssignment) HasUnhealthyNode(wl *workload.Info) bool {
-	return workload.HasUnhealthyNodes(wl.Obj) && slices.ContainsFunc(psa.TopologyAssignment.Domains, func(domain kueue.TopologyDomainAssignment) bool {
+	return workload.HasUnhealthyNodes(wl.Obj) && slices.ContainsFunc(psa.TopologyAssignment.Domains, func(domain tas.TopologyDomainAssignment) bool {
 		return workload.HasUnhealthyNode(wl.Obj, domain.Values[len(domain.Values)-1])
 	})
 }
diff --git a/pkg/util/tas/tas_assignment.go b/pkg/util/tas/tas_assignment.go
new file mode 100644
index 000000000..985a940f2
--- /dev/null
+++ b/pkg/util/tas/tas_assignment.go
@@ -0,0 +1,257 @@
+/*
+Copyright The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package tas
+
+import (
+	"iter"
+	"slices"
+
+	"k8s.io/utils/ptr"
+
+	kueue "sigs.k8s.io/kueue/apis/kueue/v1beta2"
+)
+
+type TopologyAssignment struct {
+	Levels  []string
+	Domains []TopologyDomainAssignment
+}
+
+type TopologyDomainAssignment struct {
+	Values []string
+	Count  int32
+}
+
+func valueAtIndex(values kueue.TopologyAssignmentSliceLevelValues, idx int) string {
+	if univ := values.Universal; univ != nil {
+		return *univ
+	}
+	ind := values.Individual
+	prefix := ptr.Deref(ind.CommonPrefix, "")
+	suffix := ptr.Deref(ind.CommonSuffix, "")
+	return prefix + ind.Roots[idx] + suffix
+}
+
+func countAtIndex(slice kueue.TopologyAssignmentSlice, idx int) int32 {
+	if univ := slice.PodCounts.Universal; univ != nil {
+		return *univ
+	}
+	return slice.PodCounts.Individual[idx]
+}
+
+func valuesAtLevel(ta *kueue.TopologyAssignment, levelIdx int) iter.Seq[string] {
+	return func(yield func(string) bool) {
+		for _, slice := range ta.Slices {
+			values := slice.ValuesPerLevel[levelIdx]
+			for i := range int(slice.DomainCount) {
+				if !yield(valueAtIndex(values, i)) {
+					return
+				}
+			}
+		}
+	}
+}
+
+func LowestLevelValues(ta *kueue.TopologyAssignment) iter.Seq[string] {
+	if ta == nil {
+		return nil
+	}
+	return valuesAtLevel(ta, len(ta.Levels)-1)
+}
+
+func PodCounts(ta *kueue.TopologyAssignment) iter.Seq[int32] {
+	if ta == nil {
+		return nil
+	}
+	return func(yield func(int32) bool) {
+		for _, slice := range ta.Slices {
+			for i := range int(slice.DomainCount) {
+				if !yield(countAtIndex(slice, i)) {
+					return
+				}
+			}
+		}
+	}
+}
+
+func TotalDomainCount(ta *kueue.TopologyAssignment) int {
+	if ta == nil {
+		return 0
+	}
+	res := 0
+	for _, slice := range ta.Slices {
+		res += int(slice.DomainCount)
+	}
+	return res
+}
+
+func InternalSeqFrom(ta *kueue.TopologyAssignment) iter.Seq[TopologyDomainAssignment] {
+	if ta == nil {
+		return nil
+	}
+	return func(yield func(TopologyDomainAssignment) bool) {
+		for _, slice := range ta.Slices {
+			for i := range int(slice.DomainCount) {
+				req := TopologyDomainAssignment{
+					Count:  countAtIndex(slice, i),
+					Values: make([]string, 0, len(ta.Levels)),
+				}
+				for levelIdx := range ta.Levels {
+					req.Values = append(req.Values, valueAtIndex(slice.ValuesPerLevel[levelIdx], i))
+				}
+				if !yield(req) {
+					return
+				}
+			}
+		}
+	}
+}
+
+func InternalFrom(ta *kueue.TopologyAssignment) *TopologyAssignment {
+	if ta == nil {
+		return nil
+	}
+	return &TopologyAssignment{
+		Levels:  ta.Levels,
+		Domains: slices.Collect(InternalSeqFrom(ta)),
+	}
+}
+
+func fillSingleCompactSliceValues(
+	values *kueue.TopologyAssignmentSliceLevelValues,
+	inputProvider func() iter.Seq[string],
+) {
+	var prefix, suffix string
+	var maxLen, minLen, count int
+	for s := range inputProvider() {
+		count++
+		if count == 1 {
+			prefix = s
+			suffix = s
+			maxLen = len(s)
+			minLen = len(s)
+		} else {
+			n := len(s)
+			minLen = min(minLen, n)
+			maxLen = max(maxLen, n)
+			if n < len(prefix) {
+				prefix = prefix[:n]
+			}
+			if n < len(suffix) {
+				suffix = suffix[len(suffix)-n:]
+			}
+			for i := 0; i < len(prefix); i++ {
+				if s[i] != prefix[i] {
+					prefix = prefix[:i]
+					break
+				}
+			}
+			for i := 0; i < len(suffix); i++ {
+				if s[len(s)-1-i] != suffix[len(suffix)-1-i] {
+					suffix = suffix[len(suffix)-i:]
+					break
+				}
+			}
+		}
+	}
+
+	// All strings equal
+	if len(prefix) == maxLen {
+		values.Universal = &prefix
+		return
+	}
+
+	// Ensure that common prefix & suffix don't overlap.
+	// (Motivating example: {"ababa", "aba"})
+	if len(prefix)+len(suffix) > minLen {
+		prefix = prefix[:minLen-len(suffix)]
+	}
+
+	ind := &kueue.TopologyAssignmentSliceLevelIndividualValues{}
+	values.Individual = ind
+	if len(prefix) > 0 {
+		ind.CommonPrefix = &prefix
+	}
+	if len(suffix) > 0 {
+		ind.CommonSuffix = &suffix
+	}
+	values.Individual.Roots = make([]string, 0, count)
+	for s := range inputProvider() {
+		ind.Roots = append(ind.Roots, s[len(prefix):len(s)-len(suffix)])
+	}
+}
+
+// singleCompactSliceEncoding translates a v1beta1 TopologyAssignment
+// to a v1beta2 counterpart consisting of a single slice,
+// in which the "compressing options" (CommonPrefix, CommonSuffix,
+// Universal values for placement labels as well as Pod counts)
+// are used as much as possible.
+func singleCompactSliceEncoding(ta *TopologyAssignment) *kueue.TopologyAssignment {
+	n := len(ta.Domains)
+	if n == 0 {
+		return &kueue.TopologyAssignment{
+			Levels: ta.Levels,
+			Slices: []kueue.TopologyAssignmentSlice{},
+		}
+	}
+
+	levelCount := len(ta.Levels)
+	slice := &kueue.TopologyAssignmentSlice{
+		DomainCount:    int32(n),
+		ValuesPerLevel: make([]kueue.TopologyAssignmentSliceLevelValues, levelCount),
+	}
+
+	for i := range levelCount {
+		levelValuesProvider := func() iter.Seq[string] {
+			return func(yield func(string) bool) {
+				for j := range n {
+					if !yield(ta.Domains[j].Values[i]) {
+						return
+					}
+				}
+			}
+		}
+		fillSingleCompactSliceValues(&slice.ValuesPerLevel[i], levelValuesProvider)
+	}
+
+	podCounts := make([]int32, 0, n)
+	samePodCounts := true
+	for i := range n {
+		podCounts = append(podCounts, ta.Domains[i].Count)
+		if i > 0 && ta.Domains[i].Count != ta.Domains[i-1].Count {
+			samePodCounts = false
+		}
+	}
+	if samePodCounts {
+		slice.PodCounts.Universal = &podCounts[0]
+	} else {
+		slice.PodCounts.Individual = podCounts
+	}
+	return &kueue.TopologyAssignment{
+		Levels: ta.Levels,
+		Slices: []kueue.TopologyAssignmentSlice{*slice},
+	}
+}
+
+// V1Beta2From translates a v1beta1 TopologyAssignment into the v1beta2 format.
+// The choice of a specific v1beta2 representation is an implementation detail,
+// which may change in the future. (See KEP-2724).
+func V1Beta2From(ta *TopologyAssignment) *kueue.TopologyAssignment {
+	if ta == nil {
+		return nil
+	}
+	return singleCompactSliceEncoding(ta)
+}
diff --git a/pkg/workload/workload.go b/pkg/workload/workload.go
index 4375b16db..c2e95af32 100644
--- a/pkg/workload/workload.go
+++ b/pkg/workload/workload.go
@@ -51,6 +51,7 @@ import (
 	utilptr "sigs.k8s.io/kueue/pkg/util/ptr"
 	utilqueue "sigs.k8s.io/kueue/pkg/util/queue"
 	utilslices "sigs.k8s.io/kueue/pkg/util/slices"
+	"sigs.k8s.io/kueue/pkg/util/tas"
 	"sigs.k8s.io/kueue/pkg/util/wait"
 )
 
@@ -532,11 +533,11 @@ func totalRequestsFromAdmission(wl *kueue.Workload) []PodSetResources {
 			setRes.TopologyRequest = &TopologyRequest{
 				Levels: psa.TopologyAssignment.Levels,
 			}
-			for _, domain := range psa.TopologyAssignment.Domains {
+			for req := range tas.InternalSeqFrom(psa.TopologyAssignment) {
 				setRes.TopologyRequest.DomainRequests = append(setRes.TopologyRequest.DomainRequests, TopologyDomainRequests{
-					Values:            domain.Values,
+					Values:            req.Values,
 					SinglePodRequests: setRes.SinglePodRequests(),
-					Count:             domain.Count,
+					Count:             req.Count,
 				})
 			}
 		}
@@ -1182,8 +1183,8 @@ func HasTopologyAssignmentWithUnhealthyNode(w *kueue.Workload) bool {
 		if psa.TopologyAssignment == nil {
 			continue
 		}
-		for _, domain := range psa.TopologyAssignment.Domains {
-			if HasUnhealthyNode(w, domain.Values[len(domain.Values)-1]) {
+		for value := range tas.LowestLevelValues(psa.TopologyAssignment) {
+			if HasUnhealthyNode(w, value) {
 				return true
 			}
 		}
diff --git a/site/content/en/docs/reference/kueue.v1beta2.md b/site/content/en/docs/reference/kueue.v1beta2.md
index 4a061fcd5..05cc1e6ea 100644
--- a/site/content/en/docs/reference/kueue.v1beta2.md
+++ b/site/content/en/docs/reference/kueue.v1beta2.md
@@ -1912,46 +1912,144 @@ in that case spec.podSets[*].count value will be used.</p>
 topology domains corresponding to the lowest level of the topology.
 The assignment specifies the number of Pods to be scheduled per topology
 domain and specifies the node selectors for each topology domain, in the
-following way: the node selector keys are specified by the levels field
-(same for all domains), and the corresponding node selector value is
-specified by the domains.values subfield. If the TopologySpec.Levels field contains
-&quot;kubernetes.io/hostname&quot; label, topologyAssignment will contain data only for
-this label, and omit higher levels in the topology</p>
-<p>Example:</p>
+following way:</p>
+<ul>
+<li><code>levels</code> specifies the node selector keys (same for all domains).
+<ul>
+<li>If the TopologySpec.Levels field contains &quot;kubernetes.io/hostname&quot; label,
+topologyAssignment will contain data only for this label,
+and omit higher levels in the topology.</li>
+</ul>
+</li>
+<li><code>slices</code> specifies the node selector values and pod counts for all domains
+(which may be partitioned into separate slices).
+<ul>
+<li>The node selector values are arranged first by topology level, only then by domain.
+(This allows &quot;optimizing&quot; similar values; see below).</li>
+</ul>
+</li>
+<li>The format of <code>slices</code> supports the following variations
+(aimed to optimize the total bytesize for very large number of domains; see examples below):
+<ul>
+<li>When all node selector values (at a given topology level, in a given slice)
+share a common prefix and/or suffix, these may be stored
+in dedicated <code>commonPrefix</code>/<code>commonSuffix</code> fields.
+If so, the array of <code>roots</code> will only store the remaining parts of these strings.</li>
+<li>When all node selector values (at a given topology level, in a given slice)
+are identical, this may be represented by <code>universal</code> value.</li>
+<li>When all pod counts (in a given slice) are identical,
+this may be represented by <code>universal</code> pod count.</li>
+</ul>
+</li>
+</ul>
+<p>Example 1:</p>
+<p>The following represents an assignment in which:</p>
+<ul>
+<li>4 Pods are to be scheduled on nodes matching the node selector:
+<ul>
+<li>cloud.provider.com/topology-block: block-1</li>
+<li>cloud.provider.com/topology-rack: rack-1</li>
+</ul>
+</li>
+<li>2 Pods are to be scheduled on nodes matching the node selector:
+<ul>
+<li>cloud.provider.com/topology-block: block-1</li>
+<li>cloud.provider.com/topology-rack: rack-2</li>
+</ul>
+</li>
+</ul>
 <p>topologyAssignment:
 levels:</p>
 <ul>
 <li>cloud.provider.com/topology-block</li>
 <li>cloud.provider.com/topology-rack
-domains:</li>
-<li>values: [block-1, rack-1]
-count: 4</li>
-<li>values: [block-1, rack-2]
-count: 2</li>
+slices:</li>
+<li>domainCount: 2
+valuesPerLevel:
+<ul>
+<li>individual:
+roots: [block-1, block-1]</li>
+<li>individual:
+roots: [rack-1, rack-2]
+podCounts:
+individual: [4, 2]</li>
+</ul>
+</li>
 </ul>
-<p>Here:</p>
+<p>Example 2:</p>
+<p>The following is equivalent to Example 1 - but using extracted prefix and universalValue.</p>
+<p>topologyAssignment:
+levels:</p>
 <ul>
-<li>4 Pods are to be scheduled on nodes matching the node selector:
-cloud.provider.com/topology-block: block-1
-cloud.provider.com/topology-rack: rack-1</li>
-<li>2 Pods are to be scheduled on nodes matching the node selector:
-cloud.provider.com/topology-block: block-1
-cloud.provider.com/topology-rack: rack-2</li>
+<li>cloud.provider.com/topology-block</li>
+<li>cloud.provider.com/topology-rack
+slices:</li>
+<li>domainCount: 2
+valuesPerLevel:
+<ul>
+<li>universal: block-1</li>
+<li>individual:
+prefix: rack-
+roots: [1, 2]
+podCounts:
+individual: [4, 2]</li>
+</ul>
+</li>
+</ul>
+<p>Example 3:</p>
+<p>Now suppose that:</p>
+<ul>
+<li>the Topology object defines kubernetes.io/hostname as the lowest level
+(and hence, in the topologyAssignment, we omit all other levels
+since the hostname label suffices to explicitly identify a proper node),</li>
+<li>we assign 1 Pod per each node,</li>
+<li>the node naming scheme is <code>block-{blockId}-rack-{rackId}-node-{nodeId}</code>.
+Then, using the &quot;extraction of commons&quot;, the assignment from Examples 1-2 would look as follows:</li>
 </ul>
-<p>Example:
-Below there is an equivalent of the above example assuming, Topology
-object defines kubernetes.io/hostname as the lowest level in topology.
-Hence we omit higher level of topologies, since the hostname label
-is sufficient to explicitly identify a proper node.</p>
 <p>topologyAssignment:
 levels:</p>
 <ul>
 <li>kubernetes.io/hostname
-domains:</li>
-<li>values: [hostname-1]
-count: 4</li>
-<li>values: [hostname-2]
-count: 2</li>
+slices:</li>
+<li>domainCount: 6
+valuesPerLevel:
+<ul>
+<li>individual:
+prefix: block-1-rack-
+roots: [1-node-1, 1-node-2, 1-node-3, 1-node-4, 2-node-1, 2-node-2]
+podCounts:
+universal: 1</li>
+</ul>
+</li>
+</ul>
+<p>Example 4:</p>
+<p>By using multiple slices, we can afford even longer common prefixes.
+The assignment from Example 3 can be alternatively represented as follows:</p>
+<p>topologyAssignment:
+levels:</p>
+<ul>
+<li>kubernetes.io/hostname
+slices:</li>
+<li>domainCount: 4
+valuesPerLevel:
+<ul>
+<li>individual:
+prefix: block-1-rack-1-node-
+roots: [1, 2, 3, 4]
+podCounts:
+universal: 1</li>
+</ul>
+</li>
+<li>domainCount: 2
+valuesPerLevel:
+<ul>
+<li>individual:
+prefix: block-1-rack-2-node-
+roots: [1, 2]
+podCounts:
+universal: 1</li>
+</ul>
+</li>
 </ul>
 </td>
 </tr>
@@ -2859,18 +2957,18 @@ topology (i.e. node label keys), from the highest to the lowest level of
 the topology.</p>
 </td>
 </tr>
-<tr><td><code>domains</code> <B>[Required]</B><br/>
-<a href="#kueue-x-k8s-io-v1beta2-TopologyDomainAssignment"><code>[]TopologyDomainAssignment</code></a>
+<tr><td><code>slices</code> <B>[Required]</B><br/>
+<a href="#kueue-x-k8s-io-v1beta2-TopologyAssignmentSlice"><code>[]TopologyAssignmentSlice</code></a>
 </td>
 <td>
-   <p>domains is a list of topology assignments split by topology domains at
-the lowest level of the topology.</p>
+   <p>slices represent topology assignments for subsets of pods of a workload.
+The full assignment is obtained as a union of all slices.</p>
 </td>
 </tr>
 </tbody>
 </table>
 
-## `TopologyDomainAssignment`     {#kueue-x-k8s-io-v1beta2-TopologyDomainAssignment}
+## `TopologyAssignmentSlice`     {#kueue-x-k8s-io-v1beta2-TopologyAssignmentSlice}
     
 
 **Appears in:**
@@ -2884,21 +2982,136 @@ the lowest level of the topology.</p>
 <tbody>
     
   
-<tr><td><code>values</code> <B>[Required]</B><br/>
+<tr><td><code>domainCount</code> <B>[Required]</B><br/>
+<code>int32</code>
+</td>
+<td>
+   <p>domainCount is the number of domains covered by this slice.</p>
+</td>
+</tr>
+<tr><td><code>valuesPerLevel</code> <B>[Required]</B><br/>
+<a href="#kueue-x-k8s-io-v1beta2-TopologyAssignmentSliceLevelValues"><code>[]TopologyAssignmentSliceLevelValues</code></a>
+</td>
+<td>
+   <p>valuesPerLevel has one entry for each of the Levels specified in the TopologyAssignment.
+The entry corresponding to a particular level specifies the placement of pods at that level.</p>
+</td>
+</tr>
+<tr><td><code>podCounts</code> <B>[Required]</B><br/>
+<a href="#kueue-x-k8s-io-v1beta2-TopologyAssignmentSlicePodCounts"><code>TopologyAssignmentSlicePodCounts</code></a>
+</td>
+<td>
+   <p>podCounts specifies the number of pods allocated per each domain.</p>
+</td>
+</tr>
+</tbody>
+</table>
+
+## `TopologyAssignmentSliceLevelIndividualValues`     {#kueue-x-k8s-io-v1beta2-TopologyAssignmentSliceLevelIndividualValues}
+    
+
+**Appears in:**
+
+- [TopologyAssignmentSliceLevelValues](#kueue-x-k8s-io-v1beta2-TopologyAssignmentSliceLevelValues)
+
+
+
+<table class="table">
+<thead><tr><th width="30%">Field</th><th>Description</th></tr></thead>
+<tbody>
+    
+  
+<tr><td><code>commonPrefix</code><br/>
+<code>string</code>
+</td>
+<td>
+   <p>commonPrefix specifies a common prefix for all values in this slice assignment.
+It must be either nil pointer or a non-empty string.</p>
+</td>
+</tr>
+<tr><td><code>commonSuffix</code><br/>
+<code>string</code>
+</td>
+<td>
+   <p>commonSuffix specifies a common suffix for all values in this slice assignment.
+It must be either nil pointer or a non-empty string.</p>
+</td>
+</tr>
+<tr><td><code>roots</code> <B>[Required]</B><br/>
 <code>[]string</code>
 </td>
 <td>
-   <p>values is an ordered list of node selector values describing a topology
-domain. The values correspond to the consecutive topology levels, from
-the highest to the lowest.</p>
+   <p>roots specifies the values in this assignment (excluding commonPrefix and commonSuffix, if non-empty).
+Its length must be equal to the &quot;domainCount&quot; field of the TopologyAssignmentSlice.</p>
 </td>
 </tr>
-<tr><td><code>count</code> <B>[Required]</B><br/>
+</tbody>
+</table>
+
+## `TopologyAssignmentSliceLevelValues`     {#kueue-x-k8s-io-v1beta2-TopologyAssignmentSliceLevelValues}
+    
+
+**Appears in:**
+
+- [TopologyAssignmentSlice](#kueue-x-k8s-io-v1beta2-TopologyAssignmentSlice)
+
+
+
+<table class="table">
+<thead><tr><th width="30%">Field</th><th>Description</th></tr></thead>
+<tbody>
+    
+  
+<tr><td><code>universal</code><br/>
+<code>string</code>
+</td>
+<td>
+   <p>universal - if set - specifies a single topology placement value (at a particular topology level)
+that applies to all pods in the current TopologyAssignmentSlice.
+Exactly one of universal, individual must be set.</p>
+</td>
+</tr>
+<tr><td><code>individual</code><br/>
+<a href="#kueue-x-k8s-io-v1beta2-TopologyAssignmentSliceLevelIndividualValues"><code>TopologyAssignmentSliceLevelIndividualValues</code></a>
+</td>
+<td>
+   <p>individual - if set - specifies multiple topology placement values (at a particular topology level)
+that apply to the pods in the current TopologyAssignmentSlice.
+Exactly one of universal, individual must be set.</p>
+</td>
+</tr>
+</tbody>
+</table>
+
+## `TopologyAssignmentSlicePodCounts`     {#kueue-x-k8s-io-v1beta2-TopologyAssignmentSlicePodCounts}
+    
+
+**Appears in:**
+
+- [TopologyAssignmentSlice](#kueue-x-k8s-io-v1beta2-TopologyAssignmentSlice)
+
+
+
+<table class="table">
+<thead><tr><th width="30%">Field</th><th>Description</th></tr></thead>
+<tbody>
+    
+  
+<tr><td><code>universal</code><br/>
 <code>int32</code>
 </td>
 <td>
-   <p>count indicates the number of Pods to be scheduled in the topology
-domain indicated by the values field.</p>
+   <p>universal - if set - specifies the number of pods allocated in every domain in this slice.
+Exactly one of universal, individual must be set.</p>
+</td>
+</tr>
+<tr><td><code>individual</code><br/>
+<code>[]int32</code>
+</td>
+<td>
+   <p>individual - if set - specifies the number of pods allocated in each domain in this slice.
+If set, its length must be equal to the &quot;domainCount&quot; field of the TopologyAssignmentSlice.
+Exactly one of universal, individual must be set.</p>
 </td>
 </tr>
 </tbody>



Test patch:
diff --git a/apis/kueue/v1beta1/workload_conversion_test.go b/apis/kueue/v1beta1/workload_conversion_test.go
index e9b9bdd0a..94421acf5 100644
--- a/apis/kueue/v1beta1/workload_conversion_test.go
+++ b/apis/kueue/v1beta1/workload_conversion_test.go
@@ -148,6 +148,65 @@ func TestWorkloadConvertTo(t *testing.T) {
 				},
 			},
 		},
+		"with TopologyAssignment": {
+			input: &Workload{
+				ObjectMeta: defaultObjectMeta,
+				Status: WorkloadStatus{
+					Admission: &Admission{
+						PodSetAssignments: []PodSetAssignment{
+							{
+								TopologyAssignment: &TopologyAssignment{
+									Levels: []string{"a", "b"},
+									Domains: []TopologyDomainAssignment{
+										{
+											Values: []string{"a1", "b1"},
+											Count:  10,
+										},
+										{
+											Values: []string{"a1", "b2"},
+											Count:  20,
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+			expected: &v1beta2.Workload{
+				ObjectMeta: defaultObjectMeta,
+				Status: v1beta2.WorkloadStatus{
+					Admission: &v1beta2.Admission{
+						PodSetAssignments: []v1beta2.PodSetAssignment{
+							{
+								TopologyAssignment: &v1beta2.TopologyAssignment{
+									Levels: []string{"a", "b"},
+									Slices: []v1beta2.TopologyAssignmentSlice{
+										{
+											DomainCount: 2,
+											ValuesPerLevel: []v1beta2.TopologyAssignmentSliceLevelValues{
+												{
+													Universal: ptr.To("a1"),
+												},
+												{
+													Individual: &v1beta2.TopologyAssignmentSliceLevelIndividualValues{
+														CommonPrefix: ptr.To("b"),
+														Roots:        []string{"1", "2"},
+													},
+												},
+											},
+											PodCounts: v1beta2.TopologyAssignmentSlicePodCounts{
+												Individual: []int32{10, 20},
+											},
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
 	}
 
 	for name, tc := range testCases {
@@ -285,6 +344,149 @@ func TestWorkloadConvertFrom(t *testing.T) {
 				},
 			},
 		},
+		"with TopologyAssignment": {
+			input: &v1beta2.Workload{
+				ObjectMeta: defaultObjectMeta,
+				Status: v1beta2.WorkloadStatus{
+					Admission: &v1beta2.Admission{
+						PodSetAssignments: []v1beta2.PodSetAssignment{
+							{
+								TopologyAssignment: &v1beta2.TopologyAssignment{
+									Levels: []string{"a", "b"},
+									Slices: []v1beta2.TopologyAssignmentSlice{
+										{
+											DomainCount: 2,
+											ValuesPerLevel: []v1beta2.TopologyAssignmentSliceLevelValues{
+												{
+													Universal: ptr.To("a1"),
+												},
+												{
+													Individual: &v1beta2.TopologyAssignmentSliceLevelIndividualValues{
+														CommonPrefix: ptr.To("b"),
+														Roots:        []string{"1", "2"},
+													},
+												},
+											},
+											PodCounts: v1beta2.TopologyAssignmentSlicePodCounts{
+												Individual: []int32{10, 20},
+											},
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+			expected: &Workload{
+				ObjectMeta: defaultObjectMeta,
+				Status: WorkloadStatus{
+					Admission: &Admission{
+						PodSetAssignments: []PodSetAssignment{
+							{
+								TopologyAssignment: &TopologyAssignment{
+									Levels: []string{"a", "b"},
+									Domains: []TopologyDomainAssignment{
+										{
+											Values: []string{"a1", "b1"},
+											Count:  10,
+										},
+										{
+											Values: []string{"a1", "b2"},
+											Count:  20,
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+		"with TopologyAssignment, multiple slices": {
+			input: &v1beta2.Workload{
+				ObjectMeta: defaultObjectMeta,
+				Status: v1beta2.WorkloadStatus{
+					Admission: &v1beta2.Admission{
+						PodSetAssignments: []v1beta2.PodSetAssignment{
+							{
+								TopologyAssignment: &v1beta2.TopologyAssignment{
+									Levels: []string{"a", "b"},
+									Slices: []v1beta2.TopologyAssignmentSlice{
+										{
+											DomainCount: 2,
+											ValuesPerLevel: []v1beta2.TopologyAssignmentSliceLevelValues{
+												{
+													Universal: ptr.To("a1"),
+												},
+												{
+													Individual: &v1beta2.TopologyAssignmentSliceLevelIndividualValues{
+														CommonPrefix: ptr.To("b"),
+														Roots:        []string{"1", "2"},
+													},
+												},
+											},
+											PodCounts: v1beta2.TopologyAssignmentSlicePodCounts{
+												Individual: []int32{10, 20},
+											},
+										},
+										{
+											DomainCount: 2,
+											ValuesPerLevel: []v1beta2.TopologyAssignmentSliceLevelValues{
+												{
+													Universal: ptr.To("a2"),
+												},
+												{
+													Individual: &v1beta2.TopologyAssignmentSliceLevelIndividualValues{
+														Roots:        []string{"first", "second"},
+														CommonSuffix: ptr.To("-in-a2"),
+													},
+												},
+											},
+											PodCounts: v1beta2.TopologyAssignmentSlicePodCounts{
+												Universal: ptr.To(int32(50)),
+											},
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+			expected: &Workload{
+				ObjectMeta: defaultObjectMeta,
+				Status: WorkloadStatus{
+					Admission: &Admission{
+						PodSetAssignments: []PodSetAssignment{
+							{
+								TopologyAssignment: &TopologyAssignment{
+									Levels: []string{"a", "b"},
+									Domains: []TopologyDomainAssignment{
+										{
+											Values: []string{"a1", "b1"},
+											Count:  10,
+										},
+										{
+											Values: []string{"a1", "b2"},
+											Count:  20,
+										},
+										{
+											Values: []string{"a2", "first-in-a2"},
+											Count:  50,
+										},
+										{
+											Values: []string{"a2", "second-in-a2"},
+											Count:  50,
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
 	}
 
 	for name, tc := range testCases {
@@ -360,6 +562,32 @@ func TestWorkloadConversion_RoundTrip(t *testing.T) {
 				},
 			},
 		},
+		"Workload with TopologyAssignment": {
+			v1beta1Obj: &Workload{
+				ObjectMeta: defaultObjectMeta,
+				Status: WorkloadStatus{
+					Admission: &Admission{
+						PodSetAssignments: []PodSetAssignment{
+							{
+								TopologyAssignment: &TopologyAssignment{
+									Levels: []string{"a", "b"},
+									Domains: []TopologyDomainAssignment{
+										{
+											Values: []string{"a1", "b1"},
+											Count:  10,
+										},
+										{
+											Values: []string{"a1", "b2"},
+											Count:  20,
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
 	}
 
 	for name, tc := range testCases {
diff --git a/pkg/cache/scheduler/tas_cache_test.go b/pkg/cache/scheduler/tas_cache_test.go
index 586dcb972..a0bd663f9 100644
--- a/pkg/cache/scheduler/tas_cache_test.go
+++ b/pkg/cache/scheduler/tas_cache_test.go
@@ -30,6 +30,7 @@ import (
 	tasindexer "sigs.k8s.io/kueue/pkg/controller/tas/indexer"
 	"sigs.k8s.io/kueue/pkg/features"
 	"sigs.k8s.io/kueue/pkg/resources"
+	"sigs.k8s.io/kueue/pkg/util/tas"
 	utiltesting "sigs.k8s.io/kueue/pkg/util/testing"
 	testingnode "sigs.k8s.io/kueue/pkg/util/testingjobs/node"
 	testingpod "sigs.k8s.io/kueue/pkg/util/testingjobs/pod"
@@ -44,7 +45,7 @@ type PodSetTestCase struct {
 	tolerations     []corev1.Toleration
 	nodeSelector    map[string]string
 	podSetGroupName *string
-	wantAssignment  *kueue.TopologyAssignment
+	wantAssignment  *tas.TopologyAssignment
 	wantReason      string
 }
 
@@ -463,9 +464,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 4,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 1,
 							Values: []string{
@@ -543,9 +544,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 2,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 1,
 							Values: []string{
@@ -610,9 +611,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 2,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 2,
 							Values: []string{
@@ -634,9 +635,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 2,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 2,
 							Values: []string{
@@ -656,9 +657,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 6,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{Count: 1, Values: []string{"x1"}},
 						{Count: 1, Values: []string{"x3"}},
 						{Count: 1, Values: []string{"x5"}},
@@ -679,9 +680,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 6,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{Count: 1, Values: []string{"x1"}},
 						{Count: 1, Values: []string{"x3"}},
 						{Count: 1, Values: []string{"x5"}},
@@ -702,9 +703,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 1,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 1,
 							Values: []string{
@@ -726,9 +727,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 1,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 1,
 							Values: []string{
@@ -751,9 +752,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 1,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 1,
 							Values: []string{
@@ -776,9 +777,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 4,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 1,
 							Values: []string{
@@ -818,9 +819,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 1,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 1,
 							Values: []string{
@@ -843,9 +844,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 1,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 1,
 							Values: []string{
@@ -867,9 +868,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 1,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 1,
 							Values: []string{
@@ -892,9 +893,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 2,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 2,
 							Values: []string{
@@ -917,9 +918,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 2,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 2,
 							Values: []string{
@@ -957,9 +958,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 1,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 1,
 							Values: []string{
@@ -982,9 +983,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 1,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultTwoLevels,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 1,
 							Values: []string{
@@ -1007,9 +1008,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 1,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 1,
 							Values: []string{
@@ -1032,9 +1033,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 2,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultTwoLevels,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 2,
 							Values: []string{
@@ -1058,9 +1059,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 3,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultTwoLevels,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 3,
 							Values: []string{
@@ -1108,9 +1109,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 5,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: []string{tasBlockLabel},
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 1,
 							Values: []string{
@@ -1138,9 +1139,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 2,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultTwoLevels,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 2,
 							Values: []string{
@@ -1177,9 +1178,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 1,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 1,
 							Values: []string{
@@ -1202,9 +1203,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 2,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 1,
 							Values: []string{
@@ -1233,12 +1234,12 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 1,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: []string{
 						tasBlockLabel,
 						tasRackLabel,
 					},
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 1,
 							Values: []string{
@@ -1261,12 +1262,12 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 4,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: []string{
 						tasBlockLabel,
 						tasRackLabel,
 					},
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 1,
 							Values: []string{
@@ -1296,9 +1297,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 4,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultTwoLevels,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 1,
 							Values: []string{
@@ -1356,9 +1357,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceMemory: 1024,
 				},
 				count: 4,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultTwoLevels,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 4,
 							Values: []string{
@@ -1381,9 +1382,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 4,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultTwoLevels,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 1,
 							Values: []string{
@@ -1413,9 +1414,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 6,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultTwoLevels,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 1,
 							Values: []string{
@@ -1452,9 +1453,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 6,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultTwoLevels,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 1,
 							Values: []string{
@@ -1543,9 +1544,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 1,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 1,
 							Values: []string{
@@ -1612,9 +1613,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 600,
 				},
 				count: 1,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 1,
 							Values: []string{
@@ -1656,9 +1657,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 600,
 				},
 				count: 1,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 1,
 							Values: []string{
@@ -1768,9 +1769,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 600,
 				},
 				count: 1,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 1,
 							Values: []string{
@@ -1902,9 +1903,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 1,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 1,
 							Values: []string{
@@ -2061,9 +2062,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 1,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 1,
 							Values: []string{
@@ -2127,9 +2128,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 6,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 2,
 							Values: []string{
@@ -2212,9 +2213,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 12,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 4,
 							Values: []string{
@@ -2287,9 +2288,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 4,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 2,
 							Values: []string{
@@ -2396,9 +2397,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 4,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 1,
 							Values: []string{
@@ -2440,9 +2441,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 4,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 1,
 							Values: []string{
@@ -2515,9 +2516,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 6,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 2,
 							Values: []string{
@@ -2584,9 +2585,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 4,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 2,
 							Values: []string{
@@ -2675,9 +2676,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 8,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 2,
 							Values: []string{
@@ -2762,9 +2763,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 12,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 3,
 							Values: []string{
@@ -2827,9 +2828,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					"example.com/gpu": 1,
 				},
 				count: 25,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count:  13,
 							Values: []string{"x1"},
@@ -2892,9 +2893,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					"example.com/gpu": 1,
 				},
 				count: 23,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count:  12,
 							Values: []string{"x1"},
@@ -2960,9 +2961,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					"example.com/gpu": 1,
 				},
 				count: 25,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count:  15,
 							Values: []string{"x2"},
@@ -3036,9 +3037,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					"example.com/gpu": 1,
 				},
 				count: 22,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count:  11,
 							Values: []string{"x3"},
@@ -3112,9 +3113,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					"example.com/gpu": 1,
 				},
 				count: 25,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count:  14,
 							Values: []string{"x1"},
@@ -3190,9 +3191,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					"example.com/gpu": 1,
 				},
 				count: 25,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count:  15,
 							Values: []string{"x3"},
@@ -3285,9 +3286,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					"example.com/gpu": 1,
 				},
 				count: 20,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: []string{corev1.LabelHostname},
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count:  10,
 							Values: []string{"x3"},
@@ -3383,9 +3384,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					"example.com/gpu": 1,
 				},
 				count: 20,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: []string{corev1.LabelHostname},
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count:  10,
 							Values: []string{"x3"},
@@ -3471,9 +3472,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					"example.com/gpu": 1,
 				},
 				count: 20,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: []string{tasBlockLabel, tasSubBlockLabel, tasRackLabel},
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count:  10,
 							Values: []string{"b1", "sb2", "r3"},
@@ -3559,9 +3560,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					"example.com/gpu": 1,
 				},
 				count: 22,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count:  12,
 							Values: []string{"x2"},
@@ -3644,9 +3645,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					"example.com/gpu": 1,
 				},
 				count: 22,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count:  11,
 							Values: []string{"x3"},
@@ -3715,9 +3716,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					},
 					podSetGroupName: ptr.To("sameGroup"),
 					count:           1,
-					wantAssignment: &kueue.TopologyAssignment{
+					wantAssignment: &tas.TopologyAssignment{
 						Levels: defaultOneLevel,
-						Domains: []kueue.TopologyDomainAssignment{
+						Domains: []tas.TopologyDomainAssignment{
 							{
 								Count:  1,
 								Values: []string{"x3"},
@@ -3737,9 +3738,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					},
 					podSetGroupName: ptr.To("sameGroup"),
 					count:           25,
-					wantAssignment: &kueue.TopologyAssignment{
+					wantAssignment: &tas.TopologyAssignment{
 						Levels: defaultOneLevel,
-						Domains: []kueue.TopologyDomainAssignment{
+						Domains: []tas.TopologyDomainAssignment{
 							{
 								Count:  15,
 								Values: []string{"x2"},
@@ -3823,9 +3824,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					"example.com/gpu": 1,
 				},
 				count: 15,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count:  5,
 							Values: []string{"x3"},
@@ -3912,9 +3913,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					"example.com/gpu": 1,
 				},
 				count: 24,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count:  8,
 							Values: []string{"x1"},
@@ -3994,9 +3995,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					"example.com/gpu": 1,
 				},
 				count: 23,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count:  12,
 							Values: []string{"x1"},
@@ -4129,9 +4130,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					"example.com/gpu": 1,
 				},
 				count: 20,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count:  5,
 							Values: []string{"x1"},
@@ -4197,9 +4198,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					},
 					podSetGroupName: ptr.To("sameGroup"),
 					count:           1,
-					wantAssignment: &kueue.TopologyAssignment{
+					wantAssignment: &tas.TopologyAssignment{
 						Levels: defaultOneLevel,
-						Domains: []kueue.TopologyDomainAssignment{
+						Domains: []tas.TopologyDomainAssignment{
 							{
 								Count:  1,
 								Values: []string{"x1"},
@@ -4217,9 +4218,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					},
 					podSetGroupName: ptr.To("sameGroup"),
 					count:           10,
-					wantAssignment: &kueue.TopologyAssignment{
+					wantAssignment: &tas.TopologyAssignment{
 						Levels: defaultOneLevel,
-						Domains: []kueue.TopologyDomainAssignment{
+						Domains: []tas.TopologyDomainAssignment{
 							{
 								Count:  5,
 								Values: []string{"x1"},
@@ -4419,9 +4420,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 6,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 3,
 							Values: []string{
@@ -4534,9 +4535,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 6,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 2,
 							Values: []string{
@@ -4571,9 +4572,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 6,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 4,
 							Values: []string{
@@ -4602,9 +4603,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					corev1.ResourceCPU: 1000,
 				},
 				count: 4,
-				wantAssignment: &kueue.TopologyAssignment{
+				wantAssignment: &tas.TopologyAssignment{
 					Levels: defaultOneLevel,
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Count: 1,
 							Values: []string{
@@ -4665,9 +4666,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 						corev1.ResourceCPU: 1000,
 					},
 					count: 3,
-					wantAssignment: &kueue.TopologyAssignment{
+					wantAssignment: &tas.TopologyAssignment{
 						Levels: []string{tasBlockLabel},
-						Domains: []kueue.TopologyDomainAssignment{
+						Domains: []tas.TopologyDomainAssignment{
 							{
 								Count: 2,
 								Values: []string{
@@ -4692,9 +4693,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 						corev1.ResourceCPU: 1000,
 					},
 					count: 3,
-					wantAssignment: &kueue.TopologyAssignment{
+					wantAssignment: &tas.TopologyAssignment{
 						Levels: []string{tasBlockLabel},
-						Domains: []kueue.TopologyDomainAssignment{
+						Domains: []tas.TopologyDomainAssignment{
 							{
 								Count: 1,
 								Values: []string{
@@ -4755,9 +4756,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					},
 					podSetGroupName: ptr.To("sameGroup"),
 					count:           1,
-					wantAssignment: &kueue.TopologyAssignment{
+					wantAssignment: &tas.TopologyAssignment{
 						Levels: []string{tasBlockLabel},
-						Domains: []kueue.TopologyDomainAssignment{
+						Domains: []tas.TopologyDomainAssignment{
 							{
 								Count: 1,
 								Values: []string{
@@ -4778,9 +4779,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					},
 					podSetGroupName: ptr.To("sameGroup"),
 					count:           4,
-					wantAssignment: &kueue.TopologyAssignment{
+					wantAssignment: &tas.TopologyAssignment{
 						Levels: []string{tasBlockLabel},
-						Domains: []kueue.TopologyDomainAssignment{
+						Domains: []tas.TopologyDomainAssignment{
 							{
 								Count: 4,
 								Values: []string{
@@ -4833,9 +4834,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 						corev1.ResourceCPU: 1000,
 					},
 					count: 1,
-					wantAssignment: &kueue.TopologyAssignment{
+					wantAssignment: &tas.TopologyAssignment{
 						Levels: []string{tasBlockLabel},
-						Domains: []kueue.TopologyDomainAssignment{
+						Domains: []tas.TopologyDomainAssignment{
 							{
 								Count:  1,
 								Values: []string{"b1"},
@@ -4853,9 +4854,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 						"example.com/gpu":  2,
 					},
 					count: 4,
-					wantAssignment: &kueue.TopologyAssignment{
+					wantAssignment: &tas.TopologyAssignment{
 						Levels: []string{tasBlockLabel},
-						Domains: []kueue.TopologyDomainAssignment{
+						Domains: []tas.TopologyDomainAssignment{
 							{
 								Count:  4,
 								Values: []string{"b2"},
@@ -4950,9 +4951,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					},
 					podSetGroupName: ptr.To("sameGroup"),
 					count:           1,
-					wantAssignment: &kueue.TopologyAssignment{
+					wantAssignment: &tas.TopologyAssignment{
 						Levels: []string{tasBlockLabel},
-						Domains: []kueue.TopologyDomainAssignment{
+						Domains: []tas.TopologyDomainAssignment{
 							{
 								Count: 1,
 								Values: []string{
@@ -4973,9 +4974,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					},
 					podSetGroupName: ptr.To("sameGroup"),
 					count:           4,
-					wantAssignment: &kueue.TopologyAssignment{
+					wantAssignment: &tas.TopologyAssignment{
 						Levels: []string{tasBlockLabel},
-						Domains: []kueue.TopologyDomainAssignment{
+						Domains: []tas.TopologyDomainAssignment{
 							{
 								Count: 4,
 								Values: []string{
@@ -5124,9 +5125,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					},
 					podSetGroupName: ptr.To("sameGroup"),
 					count:           1,
-					wantAssignment: &kueue.TopologyAssignment{
+					wantAssignment: &tas.TopologyAssignment{
 						Levels: []string{corev1.LabelHostname},
-						Domains: []kueue.TopologyDomainAssignment{
+						Domains: []tas.TopologyDomainAssignment{
 							{
 								Count: 1,
 								Values: []string{
@@ -5147,9 +5148,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					},
 					podSetGroupName: ptr.To("sameGroup"),
 					count:           2,
-					wantAssignment: &kueue.TopologyAssignment{
+					wantAssignment: &tas.TopologyAssignment{
 						Levels: []string{corev1.LabelHostname},
-						Domains: []kueue.TopologyDomainAssignment{
+						Domains: []tas.TopologyDomainAssignment{
 							{
 								Count: 1,
 								Values: []string{
@@ -5277,9 +5278,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					},
 					podSetGroupName: ptr.To("sameGroup"),
 					count:           1,
-					wantAssignment: &kueue.TopologyAssignment{
+					wantAssignment: &tas.TopologyAssignment{
 						Levels: []string{corev1.LabelHostname},
-						Domains: []kueue.TopologyDomainAssignment{
+						Domains: []tas.TopologyDomainAssignment{
 							{
 								Count: 1,
 								Values: []string{
@@ -5300,9 +5301,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 					},
 					podSetGroupName: ptr.To("sameGroup"),
 					count:           2,
-					wantAssignment: &kueue.TopologyAssignment{
+					wantAssignment: &tas.TopologyAssignment{
 						Levels: []string{corev1.LabelHostname},
-						Domains: []kueue.TopologyDomainAssignment{
+						Domains: []tas.TopologyDomainAssignment{
 							{
 								Count: 1,
 								Values: []string{
@@ -5333,9 +5334,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 						corev1.ResourceCPU: 1000,
 					},
 					count: 2,
-					wantAssignment: &kueue.TopologyAssignment{
+					wantAssignment: &tas.TopologyAssignment{
 						Levels: defaultTwoLevels,
-						Domains: []kueue.TopologyDomainAssignment{
+						Domains: []tas.TopologyDomainAssignment{
 							{
 								Count:  2,
 								Values: []string{"b1", "r1"},
@@ -5352,9 +5353,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 						corev1.ResourceMemory: 1024,
 					},
 					count: 1,
-					wantAssignment: &kueue.TopologyAssignment{
+					wantAssignment: &tas.TopologyAssignment{
 						Levels: defaultTwoLevels,
-						Domains: []kueue.TopologyDomainAssignment{
+						Domains: []tas.TopologyDomainAssignment{
 							{
 								Count:  1,
 								Values: []string{"b1", "r1"},
@@ -5379,9 +5380,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 						corev1.ResourceCPU: 1000,
 					},
 					count: 9,
-					wantAssignment: &kueue.TopologyAssignment{
+					wantAssignment: &tas.TopologyAssignment{
 						Levels: []string{corev1.LabelHostname},
-						Domains: []kueue.TopologyDomainAssignment{
+						Domains: []tas.TopologyDomainAssignment{
 							{Count: 9, Values: []string{"x2"}},
 						},
 					},
@@ -5395,9 +5396,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 						corev1.ResourceCPU: 1000,
 					},
 					count: 2,
-					wantAssignment: &kueue.TopologyAssignment{
+					wantAssignment: &tas.TopologyAssignment{
 						Levels: []string{corev1.LabelHostname},
-						Domains: []kueue.TopologyDomainAssignment{
+						Domains: []tas.TopologyDomainAssignment{
 							{Count: 2, Values: []string{"x3"}},
 						},
 					},
@@ -5419,9 +5420,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 						corev1.ResourceCPU: 1000,
 					},
 					count: 1,
-					wantAssignment: &kueue.TopologyAssignment{
+					wantAssignment: &tas.TopologyAssignment{
 						Levels: defaultTwoLevels,
-						Domains: []kueue.TopologyDomainAssignment{
+						Domains: []tas.TopologyDomainAssignment{
 							{Count: 1, Values: []string{"b1", "r1"}},
 						},
 					},
@@ -5436,9 +5437,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 						corev1.ResourceCPU:    1000,
 					},
 					count: 1,
-					wantAssignment: &kueue.TopologyAssignment{
+					wantAssignment: &tas.TopologyAssignment{
 						Levels: defaultTwoLevels,
-						Domains: []kueue.TopologyDomainAssignment{
+						Domains: []tas.TopologyDomainAssignment{
 							{Count: 1, Values: []string{"b1", "r1"}},
 						},
 					},
@@ -5460,9 +5461,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 						corev1.ResourceCPU: 1000,
 					},
 					count: 10,
-					wantAssignment: &kueue.TopologyAssignment{
+					wantAssignment: &tas.TopologyAssignment{
 						Levels: defaultTwoLevels,
-						Domains: []kueue.TopologyDomainAssignment{
+						Domains: []tas.TopologyDomainAssignment{
 							{Count: 10, Values: []string{"b1", "r1"}},
 						},
 					},
@@ -5476,9 +5477,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 						corev1.ResourceCPU: 1000,
 					},
 					count: 2,
-					wantAssignment: &kueue.TopologyAssignment{
+					wantAssignment: &tas.TopologyAssignment{
 						Levels: defaultTwoLevels,
-						Domains: []kueue.TopologyDomainAssignment{
+						Domains: []tas.TopologyDomainAssignment{
 							{Count: 2, Values: []string{"b2", "r1"}},
 						},
 					},
@@ -5500,9 +5501,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 						corev1.ResourceCPU: 1000,
 					},
 					count: 8,
-					wantAssignment: &kueue.TopologyAssignment{
+					wantAssignment: &tas.TopologyAssignment{
 						Levels: []string{corev1.LabelHostname},
-						Domains: []kueue.TopologyDomainAssignment{
+						Domains: []tas.TopologyDomainAssignment{
 							{Count: 8, Values: []string{"x2"}},
 						},
 					},
@@ -5516,9 +5517,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 						corev1.ResourceCPU: 1000,
 					},
 					count: 2,
-					wantAssignment: &kueue.TopologyAssignment{
+					wantAssignment: &tas.TopologyAssignment{
 						Levels: []string{corev1.LabelHostname},
-						Domains: []kueue.TopologyDomainAssignment{
+						Domains: []tas.TopologyDomainAssignment{
 							{Count: 2, Values: []string{"x2"}},
 						},
 					},
@@ -5558,9 +5559,9 @@ func TestFindTopologyAssignments(t *testing.T) {
 						corev1.ResourceMemory: 1000,
 					},
 					count: 1,
-					wantAssignment: &kueue.TopologyAssignment{
+					wantAssignment: &tas.TopologyAssignment{
 						Levels: []string{corev1.LabelHostname},
-						Domains: []kueue.TopologyDomainAssignment{
+						Domains: []tas.TopologyDomainAssignment{
 							{Count: 1, Values: []string{"x1"}},
 						},
 					},
diff --git a/pkg/cache/scheduler/tas_flavor_snapshot_test.go b/pkg/cache/scheduler/tas_flavor_snapshot_test.go
index 48f08817b..97eb87175 100644
--- a/pkg/cache/scheduler/tas_flavor_snapshot_test.go
+++ b/pkg/cache/scheduler/tas_flavor_snapshot_test.go
@@ -26,6 +26,7 @@ import (
 
 	kueue "sigs.k8s.io/kueue/apis/kueue/v1beta2"
 	"sigs.k8s.io/kueue/pkg/resources"
+	"sigs.k8s.io/kueue/pkg/util/tas"
 	utiltesting "sigs.k8s.io/kueue/pkg/util/testing"
 	"sigs.k8s.io/kueue/pkg/util/testingjobs/node"
 )
@@ -80,14 +81,14 @@ func TestMergeTopologyAssignments(t *testing.T) {
 	levels := []string{"level-1", "level-2"}
 
 	cases := map[string]struct {
-		a    *kueue.TopologyAssignment
-		b    *kueue.TopologyAssignment
-		want kueue.TopologyAssignment
+		a    *tas.TopologyAssignment
+		b    *tas.TopologyAssignment
+		want tas.TopologyAssignment
 	}{
 		"topologies with different domains, all a before b": {
-			a: &kueue.TopologyAssignment{
+			a: &tas.TopologyAssignment{
 				Levels: []string{"level-1", "level-2"},
-				Domains: []kueue.TopologyDomainAssignment{
+				Domains: []tas.TopologyDomainAssignment{
 					{
 						Values: []string{"a", "b"},
 						Count:  1,
@@ -98,9 +99,9 @@ func TestMergeTopologyAssignments(t *testing.T) {
 					},
 				},
 			},
-			b: &kueue.TopologyAssignment{
+			b: &tas.TopologyAssignment{
 				Levels: []string{"level-1", "level-2"},
-				Domains: []kueue.TopologyDomainAssignment{
+				Domains: []tas.TopologyDomainAssignment{
 					{
 						Values: []string{"d", "e"},
 						Count:  1,
@@ -111,9 +112,9 @@ func TestMergeTopologyAssignments(t *testing.T) {
 					},
 				},
 			},
-			want: kueue.TopologyAssignment{
+			want: tas.TopologyAssignment{
 				Levels: []string{"level-1", "level-2"},
-				Domains: []kueue.TopologyDomainAssignment{
+				Domains: []tas.TopologyDomainAssignment{
 					{
 						Values: []string{"a", "b"},
 						Count:  1,
@@ -134,9 +135,9 @@ func TestMergeTopologyAssignments(t *testing.T) {
 			},
 		},
 		"topologies with different domains, all b before a": {
-			a: &kueue.TopologyAssignment{
+			a: &tas.TopologyAssignment{
 				Levels: []string{"level-1", "level-2"},
-				Domains: []kueue.TopologyDomainAssignment{
+				Domains: []tas.TopologyDomainAssignment{
 					{
 						Values: []string{"d", "e"},
 						Count:  1,
@@ -147,9 +148,9 @@ func TestMergeTopologyAssignments(t *testing.T) {
 					},
 				},
 			},
-			b: &kueue.TopologyAssignment{
+			b: &tas.TopologyAssignment{
 				Levels: []string{"level-1", "level-2"},
-				Domains: []kueue.TopologyDomainAssignment{
+				Domains: []tas.TopologyDomainAssignment{
 					{
 						Values: []string{"a", "b"},
 						Count:  1,
@@ -160,9 +161,9 @@ func TestMergeTopologyAssignments(t *testing.T) {
 					},
 				},
 			},
-			want: kueue.TopologyAssignment{
+			want: tas.TopologyAssignment{
 				Levels: []string{"level-1", "level-2"},
-				Domains: []kueue.TopologyDomainAssignment{
+				Domains: []tas.TopologyDomainAssignment{
 					{
 						Values: []string{"a", "b"},
 						Count:  1,
@@ -183,9 +184,9 @@ func TestMergeTopologyAssignments(t *testing.T) {
 			},
 		},
 		"topologies with different domains, mixed order": {
-			a: &kueue.TopologyAssignment{
+			a: &tas.TopologyAssignment{
 				Levels: []string{"level-1", "level-2"},
-				Domains: []kueue.TopologyDomainAssignment{
+				Domains: []tas.TopologyDomainAssignment{
 					{
 						Values: []string{"a", "c"},
 						Count:  1,
@@ -196,9 +197,9 @@ func TestMergeTopologyAssignments(t *testing.T) {
 					},
 				},
 			},
-			b: &kueue.TopologyAssignment{
+			b: &tas.TopologyAssignment{
 				Levels: []string{"level-1", "level-2"},
-				Domains: []kueue.TopologyDomainAssignment{
+				Domains: []tas.TopologyDomainAssignment{
 					{
 						Values: []string{"a", "b"},
 						Count:  1,
@@ -209,9 +210,9 @@ func TestMergeTopologyAssignments(t *testing.T) {
 					},
 				},
 			},
-			want: kueue.TopologyAssignment{
+			want: tas.TopologyAssignment{
 				Levels: []string{"level-1", "level-2"},
-				Domains: []kueue.TopologyDomainAssignment{
+				Domains: []tas.TopologyDomainAssignment{
 					{
 						Values: []string{"a", "b"},
 						Count:  1,
@@ -232,9 +233,9 @@ func TestMergeTopologyAssignments(t *testing.T) {
 			},
 		},
 		"topologies with different and the same domains, mixed order": {
-			a: &kueue.TopologyAssignment{
+			a: &tas.TopologyAssignment{
 				Levels: []string{"level-1", "level-2"},
-				Domains: []kueue.TopologyDomainAssignment{
+				Domains: []tas.TopologyDomainAssignment{
 					{
 						Values: []string{"a", "c"},
 						Count:  1,
@@ -245,9 +246,9 @@ func TestMergeTopologyAssignments(t *testing.T) {
 					},
 				},
 			},
-			b: &kueue.TopologyAssignment{
+			b: &tas.TopologyAssignment{
 				Levels: []string{"level-1", "level-2"},
-				Domains: []kueue.TopologyDomainAssignment{
+				Domains: []tas.TopologyDomainAssignment{
 					{
 						Values: []string{"a", "b"},
 						Count:  1,
@@ -258,9 +259,9 @@ func TestMergeTopologyAssignments(t *testing.T) {
 					},
 				},
 			},
-			want: kueue.TopologyAssignment{
+			want: tas.TopologyAssignment{
 				Levels: []string{"level-1", "level-2"},
-				Domains: []kueue.TopologyDomainAssignment{
+				Domains: []tas.TopologyDomainAssignment{
 					{
 						Values: []string{"a", "b"},
 						Count:  1,
@@ -277,13 +278,13 @@ func TestMergeTopologyAssignments(t *testing.T) {
 			},
 		},
 		"topology a with empty domains": {
-			a: &kueue.TopologyAssignment{
+			a: &tas.TopologyAssignment{
 				Levels:  []string{"level-1", "level-2"},
-				Domains: []kueue.TopologyDomainAssignment{},
+				Domains: []tas.TopologyDomainAssignment{},
 			},
-			b: &kueue.TopologyAssignment{
+			b: &tas.TopologyAssignment{
 				Levels: []string{"level-1", "level-2"},
-				Domains: []kueue.TopologyDomainAssignment{
+				Domains: []tas.TopologyDomainAssignment{
 					{
 						Values: []string{"a", "b"},
 						Count:  1,
@@ -294,9 +295,9 @@ func TestMergeTopologyAssignments(t *testing.T) {
 					},
 				},
 			},
-			want: kueue.TopologyAssignment{
+			want: tas.TopologyAssignment{
 				Levels: []string{"level-1", "level-2"},
-				Domains: []kueue.TopologyDomainAssignment{
+				Domains: []tas.TopologyDomainAssignment{
 					{
 						Values: []string{"a", "b"},
 						Count:  1,
@@ -309,9 +310,9 @@ func TestMergeTopologyAssignments(t *testing.T) {
 			},
 		},
 		"topology b with empty domain": {
-			a: &kueue.TopologyAssignment{
+			a: &tas.TopologyAssignment{
 				Levels: []string{"level-1", "level-2"},
-				Domains: []kueue.TopologyDomainAssignment{
+				Domains: []tas.TopologyDomainAssignment{
 					{
 						Values: []string{"a", "c"},
 						Count:  1,
@@ -322,13 +323,13 @@ func TestMergeTopologyAssignments(t *testing.T) {
 					},
 				},
 			},
-			b: &kueue.TopologyAssignment{
+			b: &tas.TopologyAssignment{
 				Levels:  []string{"level-1", "level-2"},
-				Domains: []kueue.TopologyDomainAssignment{},
+				Domains: []tas.TopologyDomainAssignment{},
 			},
-			want: kueue.TopologyAssignment{
+			want: tas.TopologyAssignment{
 				Levels: []string{"level-1", "level-2"},
-				Domains: []kueue.TopologyDomainAssignment{
+				Domains: []tas.TopologyDomainAssignment{
 					{
 						Values: []string{"a", "c"},
 						Count:  1,
diff --git a/pkg/controller/tas/topology_ungater_test.go b/pkg/controller/tas/topology_ungater_test.go
index 37532aec3..33ea8432f 100644
--- a/pkg/controller/tas/topology_ungater_test.go
+++ b/pkg/controller/tas/topology_ungater_test.go
@@ -40,6 +40,7 @@ import (
 	"sigs.k8s.io/kueue/pkg/constants"
 	"sigs.k8s.io/kueue/pkg/controller/tas/indexer"
 	utilpod "sigs.k8s.io/kueue/pkg/util/pod"
+	"sigs.k8s.io/kueue/pkg/util/tas"
 	utiltesting "sigs.k8s.io/kueue/pkg/util/testing"
 	utiltestingapi "sigs.k8s.io/kueue/pkg/util/testing/v1beta2"
 	testingpod "sigs.k8s.io/kueue/pkg/util/testingjobs/pod"
@@ -1715,9 +1716,9 @@ func TestReconcile(t *testing.T) {
 							PodSets(utiltestingapi.MakePodSetAssignment(kueue.DefaultPodSetName).
 								Assignment(corev1.ResourceCPU, "unit-test-flavor", "4").
 								Count(4).
-								TopologyAssignment(&kueue.TopologyAssignment{
+								TopologyAssignment(tas.V1Beta2From(&tas.TopologyAssignment{
 									Levels: defaultTestLevels,
-									Domains: []kueue.TopologyDomainAssignment{
+									Domains: []tas.TopologyDomainAssignment{
 										{
 											Count: 2,
 											Values: []string{
@@ -1740,7 +1741,7 @@ func TestReconcile(t *testing.T) {
 											},
 										},
 									},
-								}).
+								})).
 								Obj()).
 							Obj(),
 					).
diff --git a/pkg/controller/workloaddispatcher/incrementaldispatcher_test.go b/pkg/controller/workloaddispatcher/incrementaldispatcher_test.go
index 6caf9bb4a..8dbb0b0c1 100644
--- a/pkg/controller/workloaddispatcher/incrementaldispatcher_test.go
+++ b/pkg/controller/workloaddispatcher/incrementaldispatcher_test.go
@@ -35,7 +35,6 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client/fake"
 	"sigs.k8s.io/controller-runtime/pkg/client/interceptor"
 
-	kueueconfig "sigs.k8s.io/kueue/apis/config/v1beta2"
 	kueue "sigs.k8s.io/kueue/apis/kueue/v1beta2"
 	"sigs.k8s.io/kueue/pkg/util/admissioncheck"
 	utilmaps "sigs.k8s.io/kueue/pkg/util/maps"
@@ -51,57 +50,45 @@ func TestIncrementalDispatcherReconciler_Reconcile(t *testing.T) {
 	baseWorkload := utiltestingapi.MakeWorkload(workloadName, metav1.NamespaceDefault)
 
 	tests := map[string]struct {
-		dispatcherName string
 		workload       *kueue.Workload
 		mkAcState      *kueue.AdmissionCheckState
 		wantErr        error
 		remoteClusters []string
 		clusters       []kueue.MultiKueueCluster
 	}{
-		"dispatcher name mismatch": {
-			dispatcherName: "other",
-			workload:       baseWorkload.Clone().Obj(),
-		},
 		"workload not found": {
-			dispatcherName: kueueconfig.MultiKueueDispatcherModeIncremental,
-			workload:       nil,
-			wantErr:        apierrors.NewNotFound(schema.GroupResource{Group: kueue.GroupVersion.Group, Resource: "workloads"}, workloadName),
+			workload: nil,
+			wantErr:  apierrors.NewNotFound(schema.GroupResource{Group: kueue.GroupVersion.Group, Resource: "workloads"}, workloadName),
 		},
 		"workload deleted": {
-			dispatcherName: kueueconfig.MultiKueueDispatcherModeIncremental,
-			workload:       baseWorkload.Clone().DeletionTimestamp(now).Finalizers("kubernetes").Obj(),
+			workload: baseWorkload.Clone().DeletionTimestamp(now).Finalizers("kubernetes").Obj(),
 		},
 		"admission check nil": {
-			dispatcherName: kueueconfig.MultiKueueDispatcherModeIncremental,
-			workload:       baseWorkload.Clone().Obj(),
+			workload: baseWorkload.Clone().Obj(),
 		},
 		"admission check is rejected": {
-			dispatcherName: kueueconfig.MultiKueueDispatcherModeIncremental,
-			workload:       baseWorkload.Clone().Obj(),
+			workload: baseWorkload.Clone().Obj(),
 			mkAcState: &kueue.AdmissionCheckState{
 				Name:  "ac1",
 				State: kueue.CheckStateRejected,
 			},
 		},
 		"admission check is ready": {
-			dispatcherName: kueueconfig.MultiKueueDispatcherModeIncremental,
-			workload:       baseWorkload.Clone().Obj(),
+			workload: baseWorkload.Clone().Obj(),
 			mkAcState: &kueue.AdmissionCheckState{
 				Name:  "ac1",
 				State: kueue.CheckStateReady,
 			},
 		},
 		"already assigned to cluster": {
-			dispatcherName: kueueconfig.MultiKueueDispatcherModeIncremental,
-			workload:       baseWorkload.Clone().ClusterName("assigned").Obj(),
+			workload: baseWorkload.Clone().ClusterName("assigned").Obj(),
 			mkAcState: &kueue.AdmissionCheckState{
 				Name:  "ac1",
 				State: kueue.CheckStatePending,
 			},
 		},
 		"workload is already finished": {
-			dispatcherName: kueueconfig.MultiKueueDispatcherModeIncremental,
-			workload:       baseWorkload.Clone().Finished().Obj(),
+			workload: baseWorkload.Clone().Finished().Obj(),
 			mkAcState: &kueue.AdmissionCheckState{
 				Name:  "ac1",
 				State: kueue.CheckStatePending,
@@ -115,8 +102,7 @@ func TestIncrementalDispatcherReconciler_Reconcile(t *testing.T) {
 			},
 		},
 		"workload has quota reserved": {
-			dispatcherName: kueueconfig.MultiKueueDispatcherModeIncremental,
-			workload:       baseWorkload.Clone().Obj(),
+			workload: baseWorkload.Clone().Obj(),
 			mkAcState: &kueue.AdmissionCheckState{
 				Name:  "ac1",
 				State: kueue.CheckStatePending,
@@ -168,7 +154,6 @@ func TestIncrementalDispatcherReconciler_Reconcile(t *testing.T) {
 				client:          cl,
 				helper:          helper,
 				clock:           fakeClock,
-				dispatcherName:  tc.dispatcherName,
 				roundStartTimes: utilmaps.NewSyncMap[types.NamespacedName, time.Time](0),
 			}
 
diff --git a/pkg/podset/podset_test.go b/pkg/podset/podset_test.go
index db7e38992..e1bfb27e6 100644
--- a/pkg/podset/podset_test.go
+++ b/pkg/podset/podset_test.go
@@ -28,6 +28,7 @@ import (
 
 	kueue "sigs.k8s.io/kueue/apis/kueue/v1beta2"
 	"sigs.k8s.io/kueue/pkg/features"
+	"sigs.k8s.io/kueue/pkg/util/tas"
 	utiltesting "sigs.k8s.io/kueue/pkg/util/testing"
 	utiltestingapi "sigs.k8s.io/kueue/pkg/util/testing/v1beta2"
 )
@@ -174,15 +175,15 @@ func TestFromAssignment(t *testing.T) {
 				Flavors: map[corev1.ResourceName]kueue.ResourceFlavorReference{
 					corev1.ResourceCPU: kueue.ResourceFlavorReference(flavor1.Name),
 				},
-				TopologyAssignment: &kueue.TopologyAssignment{
+				TopologyAssignment: tas.V1Beta2From(&tas.TopologyAssignment{
 					Levels: []string{"cloud.com/rack"},
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Values: []string{"rack1"},
 							Count:  4,
 						},
 					},
-				},
+				}),
 			},
 			defaultCount: 4,
 			flavors:      []kueue.ResourceFlavor{*flavor1.DeepCopy()},
@@ -210,15 +211,15 @@ func TestFromAssignment(t *testing.T) {
 				Flavors: map[corev1.ResourceName]kueue.ResourceFlavorReference{
 					corev1.ResourceCPU: kueue.ResourceFlavorReference(flavor1.Name),
 				},
-				TopologyAssignment: &kueue.TopologyAssignment{
+				TopologyAssignment: tas.V1Beta2From(&tas.TopologyAssignment{
 					Levels: []string{"cloud.com/rack"},
-					Domains: []kueue.TopologyDomainAssignment{
+					Domains: []tas.TopologyDomainAssignment{
 						{
 							Values: []string{"rack1"},
 							Count:  4,
 						},
 					},
-				},
+				}),
 			},
 			defaultCount: 4,
 			flavors:      []kueue.ResourceFlavor{*flavor1.DeepCopy()},
diff --git a/pkg/util/tas/tas_assignment_test.go b/pkg/util/tas/tas_assignment_test.go
new file mode 100644
index 000000000..299abc52e
--- /dev/null
+++ b/pkg/util/tas/tas_assignment_test.go
@@ -0,0 +1,791 @@
+/*
+Copyright The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package tas
+
+import (
+	"slices"
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/google/go-cmp/cmp/cmpopts"
+	"k8s.io/utils/ptr"
+
+	kueue "sigs.k8s.io/kueue/apis/kueue/v1beta2"
+)
+
+type testCase struct {
+	name             string
+	internal         *TopologyAssignment
+	v1beta2          *kueue.TopologyAssignment
+	podCounts        []int32
+	totalDomainCount int
+}
+
+// bothWaysTestCases expect that internal <-> v1beta2 maps in both ways.
+var bothWaysTestCases = []testCase{
+	{
+		name: "empty",
+		internal: &TopologyAssignment{
+			Levels: []string{"a", "b"},
+		},
+		v1beta2: &kueue.TopologyAssignment{
+			Levels: []string{"a", "b"},
+			Slices: []kueue.TopologyAssignmentSlice{},
+		},
+		podCounts:        []int32{},
+		totalDomainCount: 0,
+	},
+	{
+		name: "one domain",
+		internal: &TopologyAssignment{
+			Levels: []string{"a", "b"},
+			Domains: []TopologyDomainAssignment{
+				{
+					Values: []string{"a1", "b1"},
+					Count:  1,
+				},
+			},
+		},
+		v1beta2: &kueue.TopologyAssignment{
+			Levels: []string{"a", "b"},
+			Slices: []kueue.TopologyAssignmentSlice{
+				{
+					DomainCount: 1,
+					PodCounts: kueue.TopologyAssignmentSlicePodCounts{
+						Universal: ptr.To(int32(1)),
+					},
+					ValuesPerLevel: []kueue.TopologyAssignmentSliceLevelValues{
+						{
+							Universal: ptr.To("a1"),
+						},
+						{
+							Universal: ptr.To("b1"),
+						},
+					},
+				},
+			},
+		},
+		podCounts:        []int32{1},
+		totalDomainCount: 1,
+	},
+	{
+		name: "multiple domains, same counts, no common prefix",
+		internal: &TopologyAssignment{
+			Levels: []string{"a", "b"},
+			Domains: []TopologyDomainAssignment{
+				{
+					Values: []string{"a1", "b1"},
+					Count:  1,
+				},
+				{
+					Values: []string{"a2", "b2"},
+					Count:  1,
+				},
+			},
+		},
+		v1beta2: &kueue.TopologyAssignment{
+			Levels: []string{"a", "b"},
+			Slices: []kueue.TopologyAssignmentSlice{
+				{
+					DomainCount: 2,
+					PodCounts: kueue.TopologyAssignmentSlicePodCounts{
+						Universal: ptr.To(int32(1)),
+					},
+					ValuesPerLevel: []kueue.TopologyAssignmentSliceLevelValues{
+						{
+							Individual: &kueue.TopologyAssignmentSliceLevelIndividualValues{
+								CommonPrefix: ptr.To("a"),
+								Roots:        []string{"1", "2"},
+							},
+						},
+						{
+							Individual: &kueue.TopologyAssignmentSliceLevelIndividualValues{
+								CommonPrefix: ptr.To("b"),
+								Roots:        []string{"1", "2"},
+							},
+						},
+					},
+				},
+			},
+		},
+		podCounts:        []int32{1, 1},
+		totalDomainCount: 2,
+	},
+	{
+		name: "multiple domains, different counts, common prefix and suffix",
+		internal: &TopologyAssignment{
+			Levels: []string{"a", "b"},
+			Domains: []TopologyDomainAssignment{
+				{
+					Values: []string{"p.a1.s", "p.b1.s"},
+					Count:  1,
+				},
+				{
+					Values: []string{"p.a2.s", "p.b2.s"},
+					Count:  2,
+				},
+			},
+		},
+		v1beta2: &kueue.TopologyAssignment{
+			Levels: []string{"a", "b"},
+			Slices: []kueue.TopologyAssignmentSlice{
+				{
+					DomainCount: 2,
+					PodCounts: kueue.TopologyAssignmentSlicePodCounts{
+						Individual: []int32{1, 2},
+					},
+					ValuesPerLevel: []kueue.TopologyAssignmentSliceLevelValues{
+						{
+							Individual: &kueue.TopologyAssignmentSliceLevelIndividualValues{
+								CommonPrefix: ptr.To("p.a"),
+								CommonSuffix: ptr.To(".s"),
+								Roots:        []string{"1", "2"},
+							},
+						},
+						{
+							Individual: &kueue.TopologyAssignmentSliceLevelIndividualValues{
+								CommonPrefix: ptr.To("p.b"),
+								CommonSuffix: ptr.To(".s"),
+								Roots:        []string{"1", "2"},
+							},
+						},
+					},
+				},
+			},
+		},
+		podCounts:        []int32{1, 2},
+		totalDomainCount: 2,
+	},
+	{
+		name: "multiple domains, universal value",
+		internal: &TopologyAssignment{
+			Levels: []string{"a", "b"},
+			Domains: []TopologyDomainAssignment{
+				{
+					Values: []string{"a1", "x"},
+					Count:  1,
+				},
+				{
+					Values: []string{"a1", "y"},
+					Count:  2,
+				},
+			},
+		},
+		v1beta2: &kueue.TopologyAssignment{
+			Levels: []string{"a", "b"},
+			Slices: []kueue.TopologyAssignmentSlice{
+				{
+					DomainCount: 2,
+					PodCounts: kueue.TopologyAssignmentSlicePodCounts{
+						Individual: []int32{1, 2},
+					},
+					ValuesPerLevel: []kueue.TopologyAssignmentSliceLevelValues{
+						{
+							Universal: ptr.To("a1"),
+						},
+						{
+							Individual: &kueue.TopologyAssignmentSliceLevelIndividualValues{
+								Roots: []string{"x", "y"},
+							},
+						},
+					},
+				},
+			},
+		},
+		podCounts:        []int32{1, 2},
+		totalDomainCount: 2,
+	},
+	{
+		name: "multiple domains, same counts, shrinking prefix",
+		internal: &TopologyAssignment{
+			Levels: []string{"a"},
+			Domains: []TopologyDomainAssignment{
+				{
+					Values: []string{"a123"},
+					Count:  1,
+				},
+				{
+					Values: []string{"a12"},
+					Count:  1,
+				},
+				{
+					Values: []string{"a1"},
+					Count:  1,
+				},
+				{
+					Values: []string{"a13"},
+					Count:  1,
+				},
+			},
+		},
+		v1beta2: &kueue.TopologyAssignment{
+			Levels: []string{"a"},
+			Slices: []kueue.TopologyAssignmentSlice{
+				{
+					DomainCount: 4,
+					PodCounts: kueue.TopologyAssignmentSlicePodCounts{
+						Universal: ptr.To(int32(1)),
+					},
+					ValuesPerLevel: []kueue.TopologyAssignmentSliceLevelValues{
+						{
+							Individual: &kueue.TopologyAssignmentSliceLevelIndividualValues{
+								CommonPrefix: ptr.To("a1"),
+								Roots:        []string{"23", "2", "", "3"},
+							},
+						},
+					},
+				},
+			},
+		},
+		podCounts:        []int32{1, 1, 1, 1},
+		totalDomainCount: 4,
+	},
+	{
+		name: "multiple domains, same counts, shrinking suffix",
+		internal: &TopologyAssignment{
+			Levels: []string{"a"},
+			Domains: []TopologyDomainAssignment{
+				{
+					Values: []string{"123b"},
+					Count:  1,
+				},
+				{
+					Values: []string{"23b"},
+					Count:  1,
+				},
+				{
+					Values: []string{"3b"},
+					Count:  1,
+				},
+				{
+					Values: []string{"13b"},
+					Count:  1,
+				},
+			},
+		},
+		v1beta2: &kueue.TopologyAssignment{
+			Levels: []string{"a"},
+			Slices: []kueue.TopologyAssignmentSlice{
+				{
+					DomainCount: 4,
+					PodCounts: kueue.TopologyAssignmentSlicePodCounts{
+						Universal: ptr.To(int32(1)),
+					},
+					ValuesPerLevel: []kueue.TopologyAssignmentSliceLevelValues{
+						{
+							Individual: &kueue.TopologyAssignmentSliceLevelIndividualValues{
+								CommonSuffix: ptr.To("3b"),
+								Roots:        []string{"12", "2", "", "1"},
+							},
+						},
+					},
+				},
+			},
+		},
+		podCounts:        []int32{1, 1, 1, 1},
+		totalDomainCount: 4,
+	},
+	{
+		name: "multiple domains, same counts, max prefix & suffix overlap partially",
+		internal: &TopologyAssignment{
+			Levels: []string{"a"},
+			Domains: []TopologyDomainAssignment{
+				// Max prefix: "abaca"
+				// Max suffix: "acada"
+				// They overlap - we must shrink them so that they don't.
+				// (The current implementation chooses to shrink the prefix: "abaca" -> "ab").
+				{
+					Values: []string{"abacacada"},
+					Count:  1,
+				},
+				{
+					Values: []string{"abacada"},
+					Count:  1,
+				},
+			},
+		},
+		v1beta2: &kueue.TopologyAssignment{
+			Levels: []string{"a"},
+			Slices: []kueue.TopologyAssignmentSlice{
+				{
+					DomainCount: 2,
+					PodCounts: kueue.TopologyAssignmentSlicePodCounts{
+						Universal: ptr.To(int32(1)),
+					},
+					ValuesPerLevel: []kueue.TopologyAssignmentSliceLevelValues{
+						{
+							Individual: &kueue.TopologyAssignmentSliceLevelIndividualValues{
+								CommonPrefix: ptr.To("ab"),
+								CommonSuffix: ptr.To("acada"),
+								Roots:        []string{"ac", ""},
+							},
+						},
+					},
+				},
+			},
+		},
+		podCounts:        []int32{1, 1},
+		totalDomainCount: 2,
+	},
+	{
+		name: "multiple domains, same counts, max prefix & suffix overlap fully, shrinking strings",
+		internal: &TopologyAssignment{
+			Levels: []string{"a"},
+			Domains: []TopologyDomainAssignment{
+				{
+					Values: []string{"ababa"},
+					Count:  1,
+				},
+				{
+					Values: []string{"aba"},
+					Count:  1,
+				},
+			},
+		},
+		v1beta2: &kueue.TopologyAssignment{
+			Levels: []string{"a"},
+			Slices: []kueue.TopologyAssignmentSlice{
+				{
+					DomainCount: 2,
+					PodCounts: kueue.TopologyAssignmentSlicePodCounts{
+						Universal: ptr.To(int32(1)),
+					},
+					ValuesPerLevel: []kueue.TopologyAssignmentSliceLevelValues{
+						// Prefix shrunk to "" -> it shouldn't be set at all.
+						{
+							Individual: &kueue.TopologyAssignmentSliceLevelIndividualValues{
+								CommonSuffix: ptr.To("aba"),
+								Roots:        []string{"ab", ""},
+							},
+						},
+					},
+				},
+			},
+		},
+		podCounts:        []int32{1, 1},
+		totalDomainCount: 2,
+	},
+	{
+		name: "multiple domains, same counts, max prefix & suffix overlap fully, growing strings",
+		internal: &TopologyAssignment{
+			Levels: []string{"a"},
+			Domains: []TopologyDomainAssignment{
+				{
+					Values: []string{"aba"},
+					Count:  1,
+				},
+				{
+					Values: []string{"ababa"},
+					Count:  1,
+				},
+			},
+		},
+		v1beta2: &kueue.TopologyAssignment{
+			Levels: []string{"a"},
+			Slices: []kueue.TopologyAssignmentSlice{
+				{
+					DomainCount: 2,
+					PodCounts: kueue.TopologyAssignmentSlicePodCounts{
+						Universal: ptr.To(int32(1)),
+					},
+					ValuesPerLevel: []kueue.TopologyAssignmentSliceLevelValues{
+						// Prefix shrunk to "" -> it shouldn't be set at all.
+						{
+							Individual: &kueue.TopologyAssignmentSliceLevelIndividualValues{
+								CommonSuffix: ptr.To("aba"),
+								Roots:        []string{"", "ab"},
+							},
+						},
+					},
+				},
+			},
+		},
+		podCounts:        []int32{1, 1},
+		totalDomainCount: 2,
+	},
+}
+
+// oneWayTestCases expect that v1beta2 -> internal (via InternalFrom).
+// (these v1beta2 values cannot be produced by V1Beta2From as of now - though this may change in the future)
+var oneWayTestCases = []testCase{
+	{
+		name: "multiple slices, no prefixes/suffixes or universal values",
+		internal: &TopologyAssignment{
+			Levels: []string{"a", "b"},
+			Domains: []TopologyDomainAssignment{
+				{
+					Values: []string{"a", "b"},
+					Count:  1,
+				},
+				{
+					Values: []string{"c", "d"},
+					Count:  2,
+				},
+				{
+					Values: []string{"e", "f"},
+					Count:  3,
+				},
+			},
+		},
+		v1beta2: &kueue.TopologyAssignment{
+			Levels: []string{"a", "b"},
+			Slices: []kueue.TopologyAssignmentSlice{
+				{
+					DomainCount: 1,
+					PodCounts: kueue.TopologyAssignmentSlicePodCounts{
+						Individual: []int32{1},
+					},
+					ValuesPerLevel: []kueue.TopologyAssignmentSliceLevelValues{
+						{
+							Individual: &kueue.TopologyAssignmentSliceLevelIndividualValues{
+								Roots: []string{"a"},
+							},
+						},
+						{
+							Individual: &kueue.TopologyAssignmentSliceLevelIndividualValues{
+								Roots: []string{"b"},
+							},
+						},
+					},
+				},
+				{
+					DomainCount: 2,
+					PodCounts: kueue.TopologyAssignmentSlicePodCounts{
+						Individual: []int32{2, 3},
+					},
+					ValuesPerLevel: []kueue.TopologyAssignmentSliceLevelValues{
+						{
+							Individual: &kueue.TopologyAssignmentSliceLevelIndividualValues{
+								Roots: []string{"c", "e"},
+							},
+						},
+						{
+							Individual: &kueue.TopologyAssignmentSliceLevelIndividualValues{
+								Roots: []string{"d", "f"},
+							},
+						},
+					},
+				},
+			},
+		},
+		podCounts:        []int32{1, 2, 3},
+		totalDomainCount: 3,
+	},
+	{
+		name: "multiple slices, prefixes, suffixes & universal values",
+		internal: &TopologyAssignment{
+			Levels: []string{"a", "b"},
+			Domains: []TopologyDomainAssignment{
+				{
+					Values: []string{"a1", "b1-s"},
+					Count:  2,
+				},
+				{
+					Values: []string{"a1", "b2-s"},
+					Count:  3,
+				},
+				{
+					Values: []string{"a2", "x-t"},
+					Count:  5,
+				},
+				{
+					Values: []string{"a3", "y-t"},
+					Count:  5,
+				},
+				{
+					Values: []string{"a4", "z-t"},
+					Count:  5,
+				},
+				{
+					Values: []string{"a10", "b10"},
+					Count:  10,
+				},
+				{
+					Values: []string{"a10", "b10"},
+					Count:  10,
+				},
+			},
+		},
+		v1beta2: &kueue.TopologyAssignment{
+			Levels: []string{"a", "b"},
+			Slices: []kueue.TopologyAssignmentSlice{
+				{
+					DomainCount: 2,
+					PodCounts: kueue.TopologyAssignmentSlicePodCounts{
+						Individual: []int32{2, 3},
+					},
+					ValuesPerLevel: []kueue.TopologyAssignmentSliceLevelValues{
+						{
+							Universal: ptr.To("a1"),
+						},
+						{
+							Individual: &kueue.TopologyAssignmentSliceLevelIndividualValues{
+								CommonPrefix: ptr.To("b"),
+								CommonSuffix: ptr.To("-s"),
+								Roots:        []string{"1", "2"},
+							},
+						},
+					},
+				},
+				{
+					DomainCount: 3,
+					PodCounts: kueue.TopologyAssignmentSlicePodCounts{
+						Universal: ptr.To(int32(5)),
+					},
+					ValuesPerLevel: []kueue.TopologyAssignmentSliceLevelValues{
+						{
+							Individual: &kueue.TopologyAssignmentSliceLevelIndividualValues{
+								CommonPrefix: ptr.To("a"),
+								Roots:        []string{"2", "3", "4"},
+							},
+						},
+						{
+							Individual: &kueue.TopologyAssignmentSliceLevelIndividualValues{
+								CommonSuffix: ptr.To("-t"),
+								Roots:        []string{"x", "y", "z"},
+							},
+						},
+					},
+				},
+				{
+					DomainCount: 2,
+					PodCounts: kueue.TopologyAssignmentSlicePodCounts{
+						Universal: ptr.To(int32(10)),
+					},
+					ValuesPerLevel: []kueue.TopologyAssignmentSliceLevelValues{
+						{
+							Universal: ptr.To("a10"),
+						},
+						{
+							Universal: ptr.To("b10"),
+						},
+					},
+				},
+			},
+		},
+		podCounts:        []int32{2, 3, 5, 5, 5, 10, 10},
+		totalDomainCount: 7,
+	},
+}
+
+var twoDomains = &kueue.TopologyAssignment{
+	Levels: []string{"a"},
+	Slices: []kueue.TopologyAssignmentSlice{
+		{
+			DomainCount: 2,
+			PodCounts: kueue.TopologyAssignmentSlicePodCounts{
+				Universal: ptr.To(int32(1)),
+			},
+			ValuesPerLevel: []kueue.TopologyAssignmentSliceLevelValues{
+				{
+					Universal: ptr.To("a1"),
+				},
+			},
+		},
+	},
+}
+
+func TestV1Beta2FromInternal(t *testing.T) {
+	for _, tc := range bothWaysTestCases {
+		t.Run(tc.name, func(t *testing.T) {
+			got := V1Beta2From(tc.internal)
+			if diff := cmp.Diff(tc.v1beta2, got, cmpopts.EquateEmpty()); diff != "" {
+				t.Errorf("unexpected result (-want,+got):\n%s", diff)
+			}
+		})
+	}
+}
+
+func TestV1Beta2FromInternal_forNil(t *testing.T) {
+	got := V1Beta2From(nil)
+	if got != nil {
+		t.Errorf("unexpected result for nil: %+v", got)
+	}
+}
+
+func TestInternalFromV1Beta2(t *testing.T) {
+	for _, tc := range slices.Concat(bothWaysTestCases, oneWayTestCases) {
+		t.Run(tc.name, func(t *testing.T) {
+			got := InternalFrom(tc.v1beta2)
+			if diff := cmp.Diff(tc.internal, got, cmpopts.EquateEmpty()); diff != "" {
+				t.Errorf("unexpected result (-want,+got):\n%s", diff)
+			}
+		})
+	}
+}
+
+func TestInternalFromV1Beta2_forNil(t *testing.T) {
+	got := InternalFrom(nil)
+	if got != nil {
+		t.Errorf("unexpected result for nil: %+v", got)
+	}
+}
+
+func TestInternalSeqFromV1Beta2(t *testing.T) {
+	for _, tc := range slices.Concat(bothWaysTestCases, oneWayTestCases) {
+		t.Run(tc.name, func(t *testing.T) {
+			seq := InternalSeqFrom(tc.v1beta2)
+			got := slices.Collect(seq)
+			want := tc.internal.Domains
+			if diff := cmp.Diff(want, got, cmpopts.EquateEmpty()); diff != "" {
+				t.Errorf("unexpected result (-want,+got):\n%s", diff)
+			}
+		})
+	}
+}
+
+func TestInternalSeqFromV1Beta2_forNil(t *testing.T) {
+	got := InternalSeqFrom(nil)
+	if got != nil {
+		t.Errorf("unexpected result for nil: %+v", got)
+	}
+}
+
+func TestInternalSeqFromV1Beta2_iteratorStops(t *testing.T) {
+	for range InternalSeqFrom(twoDomains) {
+		// Break the loop prematurely.
+		// If the iterator isn't smart enough to stop, this will panic.
+		break
+	}
+}
+
+func TestPodCounts(t *testing.T) {
+	for _, tc := range slices.Concat(bothWaysTestCases, oneWayTestCases) {
+		t.Run(tc.name, func(t *testing.T) {
+			seq := PodCounts(tc.v1beta2)
+			got := slices.Collect(seq)
+			want := tc.podCounts
+			if diff := cmp.Diff(want, got, cmpopts.EquateEmpty()); diff != "" {
+				t.Errorf("unexpected result (-want,+got):\n%s", diff)
+			}
+		})
+	}
+}
+
+func TestPodCounts_forNil(t *testing.T) {
+	got := PodCounts(nil)
+	if got != nil {
+		t.Errorf("unexpected result for nil: %+v", got)
+	}
+}
+
+func TestPodCounts_iteratorStops(t *testing.T) {
+	for range PodCounts(twoDomains) {
+		// Break the loop prematurely.
+		// If the iterator isn't smart enough to stop, this will panic.
+		break
+	}
+}
+
+func TestTotalDomainCount(t *testing.T) {
+	for _, tc := range slices.Concat(bothWaysTestCases, oneWayTestCases) {
+		t.Run(tc.name, func(t *testing.T) {
+			got := TotalDomainCount(tc.v1beta2)
+			if diff := cmp.Diff(tc.totalDomainCount, got); diff != "" {
+				t.Errorf("unexpected result (-want,+got):\n%s", diff)
+			}
+		})
+	}
+}
+
+func TestTotalDomainCount_forNil(t *testing.T) {
+	got := TotalDomainCount(nil)
+	if got != 0 {
+		t.Errorf("unexpected result for nil: %d", got)
+	}
+}
+
+func TestLowestLevel(t *testing.T) {
+	v1beta2 := &kueue.TopologyAssignment{
+		Levels: []string{"a", "b"},
+		Slices: []kueue.TopologyAssignmentSlice{
+			{
+				DomainCount: 2,
+				PodCounts: kueue.TopologyAssignmentSlicePodCounts{
+					Individual: []int32{2, 3},
+				},
+				ValuesPerLevel: []kueue.TopologyAssignmentSliceLevelValues{
+					{
+						Universal: ptr.To("a1"),
+					},
+					{
+						Individual: &kueue.TopologyAssignmentSliceLevelIndividualValues{
+							CommonPrefix: ptr.To("b"),
+							CommonSuffix: ptr.To("-s"),
+							Roots:        []string{"1", "2"},
+						},
+					},
+				},
+			},
+			{
+				DomainCount: 3,
+				PodCounts: kueue.TopologyAssignmentSlicePodCounts{
+					Universal: ptr.To(int32(5)),
+				},
+				ValuesPerLevel: []kueue.TopologyAssignmentSliceLevelValues{
+					{
+						Individual: &kueue.TopologyAssignmentSliceLevelIndividualValues{
+							CommonPrefix: ptr.To("a"),
+							Roots:        []string{"2", "3", "4"},
+						},
+					},
+					{
+						Individual: &kueue.TopologyAssignmentSliceLevelIndividualValues{
+							CommonSuffix: ptr.To("-t"),
+							Roots:        []string{"x", "y", "z"},
+						},
+					},
+				},
+			},
+			{
+				DomainCount: 2,
+				PodCounts: kueue.TopologyAssignmentSlicePodCounts{
+					Universal: ptr.To(int32(10)),
+				},
+				ValuesPerLevel: []kueue.TopologyAssignmentSliceLevelValues{
+					{
+						Universal: ptr.To("a10"),
+					},
+					{
+						Universal: ptr.To("b10"),
+					},
+				},
+			},
+		},
+	}
+	want := []string{"b1-s", "b2-s", "x-t", "y-t", "z-t", "b10", "b10"}
+	seq := LowestLevelValues(v1beta2)
+	got := slices.Collect(seq)
+	if diff := cmp.Diff(want, got, cmpopts.EquateEmpty()); diff != "" {
+		t.Errorf("unexpected result (-want,+got):\n%s", diff)
+	}
+}
+
+func TestLowestLevelValues_forNil(t *testing.T) {
+	got := LowestLevelValues(nil)
+	if got != nil {
+		t.Errorf("unexpected result for nil: %+v", got)
+	}
+}
+
+func TestLowestLevelValues_iteratorStops(t *testing.T) {
+	for range LowestLevelValues(twoDomains) {
+		// Break the loop prematurely.
+		// If the iterator isn't smart enough to stop, this will panic.
+		break
+	}
+}
diff --git a/pkg/util/testing/v1beta2/wrappers.go b/pkg/util/testing/v1beta2/wrappers.go
index 6c2198efd..53e1c3a56 100644
--- a/pkg/util/testing/v1beta2/wrappers.go
+++ b/pkg/util/testing/v1beta2/wrappers.go
@@ -32,6 +32,7 @@ import (
 
 	kueue "sigs.k8s.io/kueue/apis/kueue/v1beta2"
 	"sigs.k8s.io/kueue/pkg/controller/constants"
+	"sigs.k8s.io/kueue/pkg/util/tas"
 	utiltesting "sigs.k8s.io/kueue/pkg/util/testing"
 )
 
@@ -1196,29 +1197,29 @@ func (t *TopologyWrapper) Obj() *kueue.Topology {
 }
 
 type TopologyDomainAssignmentWrapper struct {
-	kueue.TopologyDomainAssignment
+	tas.TopologyDomainAssignment
 }
 
 func MakeTopologyDomainAssignment(values []string, count int32) *TopologyDomainAssignmentWrapper {
 	return &TopologyDomainAssignmentWrapper{
-		TopologyDomainAssignment: kueue.TopologyDomainAssignment{
+		TopologyDomainAssignment: tas.TopologyDomainAssignment{
 			Values: values,
 			Count:  count,
 		},
 	}
 }
 
-func (t *TopologyDomainAssignmentWrapper) Obj() kueue.TopologyDomainAssignment {
+func (t *TopologyDomainAssignmentWrapper) Obj() tas.TopologyDomainAssignment {
 	return t.TopologyDomainAssignment
 }
 
 type TopologyAssignmentWrapper struct {
-	kueue.TopologyAssignment
+	tas.TopologyAssignment
 }
 
 func MakeTopologyAssignment(levels []string) *TopologyAssignmentWrapper {
 	return &TopologyAssignmentWrapper{
-		TopologyAssignment: kueue.TopologyAssignment{
+		TopologyAssignment: tas.TopologyAssignment{
 			Levels: levels,
 		},
 	}
@@ -1229,18 +1230,18 @@ func (t *TopologyAssignmentWrapper) Levels(levels ...string) *TopologyAssignment
 	return t
 }
 
-func (t *TopologyAssignmentWrapper) Domains(domains ...kueue.TopologyDomainAssignment) *TopologyAssignmentWrapper {
+func (t *TopologyAssignmentWrapper) Domains(domains ...tas.TopologyDomainAssignment) *TopologyAssignmentWrapper {
 	t.TopologyAssignment.Domains = domains
 	return t
 }
 
-func (t *TopologyAssignmentWrapper) Domain(domain kueue.TopologyDomainAssignment) *TopologyAssignmentWrapper {
+func (t *TopologyAssignmentWrapper) Domain(domain tas.TopologyDomainAssignment) *TopologyAssignmentWrapper {
 	t.TopologyAssignment.Domains = append(t.TopologyAssignment.Domains, domain)
 	return t
 }
 
 func (t *TopologyAssignmentWrapper) Obj() *kueue.TopologyAssignment {
-	return &t.TopologyAssignment
+	return tas.V1Beta2From(&t.TopologyAssignment)
 }
 
 type PodSetAssignmentWrapper struct {
diff --git a/pkg/webhooks/workload_webhook_test.go b/pkg/webhooks/workload_webhook_test.go
index dab56c982..af3f3f615 100644
--- a/pkg/webhooks/workload_webhook_test.go
+++ b/pkg/webhooks/workload_webhook_test.go
@@ -29,6 +29,7 @@ import (
 
 	kueue "sigs.k8s.io/kueue/apis/kueue/v1beta2"
 	"sigs.k8s.io/kueue/pkg/features"
+	"sigs.k8s.io/kueue/pkg/util/tas"
 	utiltesting "sigs.k8s.io/kueue/pkg/util/testing"
 	utiltestingapi "sigs.k8s.io/kueue/pkg/util/testing/v1beta2"
 	"sigs.k8s.io/kueue/pkg/workload"
@@ -390,15 +391,15 @@ func TestValidateWorkloadUpdate(t *testing.T) {
 					utiltestingapi.MakeAdmission("cluster-queue").
 						PodSets(kueue.PodSetAssignment{
 							Name: "ps1",
-							TopologyAssignment: &kueue.TopologyAssignment{
+							TopologyAssignment: tas.V1Beta2From(&tas.TopologyAssignment{
 								Levels: []string{"level"},
-								Domains: []kueue.TopologyDomainAssignment{
+								Domains: []tas.TopologyDomainAssignment{
 									{
 										Values: []string{"abc"},
 										Count:  2,
 									},
 								},
-							},
+							}),
 						}).
 						Obj(),
 				).
@@ -411,15 +412,15 @@ func TestValidateWorkloadUpdate(t *testing.T) {
 					utiltestingapi.MakeAdmission("cluster-queue").
 						PodSets(kueue.PodSetAssignment{
 							Name: "ps1",
-							TopologyAssignment: &kueue.TopologyAssignment{
+							TopologyAssignment: tas.V1Beta2From(&tas.TopologyAssignment{
 								Levels: []string{"level"},
-								Domains: []kueue.TopologyDomainAssignment{
+								Domains: []tas.TopologyDomainAssignment{
 									{
 										Values: []string{"abc"},
 										Count:  3,
 									},
 								},
-							},
+							}),
 						}).
 						Obj(),
 				).
diff --git a/test/e2e/multikueue/tas_test.go b/test/e2e/multikueue/tas_test.go
index 938e528d7..87851ab07 100644
--- a/test/e2e/multikueue/tas_test.go
+++ b/test/e2e/multikueue/tas_test.go
@@ -34,6 +34,7 @@ import (
 	kueue "sigs.k8s.io/kueue/apis/kueue/v1beta2"
 	workloadjob "sigs.k8s.io/kueue/pkg/controller/jobs/job"
 	"sigs.k8s.io/kueue/pkg/util/admissioncheck"
+	"sigs.k8s.io/kueue/pkg/util/tas"
 	utiltesting "sigs.k8s.io/kueue/pkg/util/testing"
 	utiltestingapi "sigs.k8s.io/kueue/pkg/util/testing/v1beta2"
 	testingjob "sigs.k8s.io/kueue/pkg/util/testingjobs/job"
@@ -259,7 +260,7 @@ var _ = ginkgo.Describe("MultiKueue with TopologyAwareScheduling", func() {
 					g.Expect(workerWl.Status.Admission.PodSetAssignments).To(gomega.HaveLen(1))
 					g.Expect(workerWl.Status.Admission.PodSetAssignments[0].TopologyAssignment).NotTo(gomega.BeNil())
 					g.Expect(workerWl.Status.Admission.PodSetAssignments[0].TopologyAssignment.Levels).To(gomega.Equal([]string{corev1.LabelHostname}))
-					g.Expect(workerWl.Status.Admission.PodSetAssignments[0].TopologyAssignment.Domains).NotTo(gomega.BeEmpty())
+					g.Expect(tas.TotalDomainCount(workerWl.Status.Admission.PodSetAssignments[0].TopologyAssignment)).NotTo(gomega.BeZero())
 				}, util.LongTimeout, util.Interval).Should(gomega.Succeed())
 			})
 
diff --git a/test/e2e/singlecluster/tas_test.go b/test/e2e/singlecluster/tas_test.go
index e04cc768e..3e0ff1e35 100644
--- a/test/e2e/singlecluster/tas_test.go
+++ b/test/e2e/singlecluster/tas_test.go
@@ -34,6 +34,7 @@ import (
 	podcontroller "sigs.k8s.io/kueue/pkg/controller/jobs/pod"
 	podconstants "sigs.k8s.io/kueue/pkg/controller/jobs/pod/constants"
 	workloadtrainjob "sigs.k8s.io/kueue/pkg/controller/jobs/trainjob"
+	"sigs.k8s.io/kueue/pkg/util/tas"
 	utiltesting "sigs.k8s.io/kueue/pkg/util/testing"
 	utiltestingapi "sigs.k8s.io/kueue/pkg/util/testing/v1beta2"
 	testingjob "sigs.k8s.io/kueue/pkg/util/testingjobs/job"
@@ -119,11 +120,11 @@ var _ = ginkgo.Describe("TopologyAwareScheduling", func() {
 				}, util.LongTimeout, util.Interval).Should(gomega.Succeed())
 				gomega.Expect(createdWorkload.Status.Admission.PodSetAssignments).Should(gomega.HaveLen(1))
 				gomega.Expect(createdWorkload.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-					&kueue.TopologyAssignment{
+					tas.V1Beta2From(&tas.TopologyAssignment{
 						Levels: []string{
 							corev1.LabelHostname,
 						},
-						Domains: []kueue.TopologyDomainAssignment{
+						Domains: []tas.TopologyDomainAssignment{
 							{
 								Count: 1,
 								Values: []string{
@@ -131,7 +132,7 @@ var _ = ginkgo.Describe("TopologyAwareScheduling", func() {
 								},
 							},
 						},
-					},
+					}),
 				))
 			})
 
@@ -251,22 +252,22 @@ var _ = ginkgo.Describe("TopologyAwareScheduling", func() {
 				gomega.Expect(createdWorkload.Status.Admission).ShouldNot(gomega.BeNil())
 				gomega.Expect(createdWorkload.Status.Admission.PodSetAssignments).Should(gomega.HaveLen(2))
 				gomega.Expect(createdWorkload.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-					&kueue.TopologyAssignment{
+					tas.V1Beta2From(&tas.TopologyAssignment{
 						Levels: []string{corev1.LabelHostname},
-						Domains: []kueue.TopologyDomainAssignment{{
+						Domains: []tas.TopologyDomainAssignment{{
 							Count:  1,
 							Values: []string{"kind-worker"},
 						}},
-					},
+					}),
 				))
 				gomega.Expect(createdWorkload.Status.Admission.PodSetAssignments[1].TopologyAssignment).Should(gomega.BeComparableTo(
-					&kueue.TopologyAssignment{
+					tas.V1Beta2From(&tas.TopologyAssignment{
 						Levels: []string{corev1.LabelHostname},
-						Domains: []kueue.TopologyDomainAssignment{{
+						Domains: []tas.TopologyDomainAssignment{{
 							Count:  1,
 							Values: []string{"kind-worker"},
 						}},
-					},
+					}),
 				))
 			})
 
@@ -361,13 +362,13 @@ var _ = ginkgo.Describe("TopologyAwareScheduling", func() {
 				gomega.Expect(createdWorkload.Status.Admission).ShouldNot(gomega.BeNil())
 				gomega.Expect(createdWorkload.Status.Admission.PodSetAssignments).Should(gomega.HaveLen(1))
 				gomega.Expect(createdWorkload.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-					&kueue.TopologyAssignment{
+					tas.V1Beta2From(&tas.TopologyAssignment{
 						Levels: []string{corev1.LabelHostname},
-						Domains: []kueue.TopologyDomainAssignment{{
+						Domains: []tas.TopologyDomainAssignment{{
 							Count:  1,
 							Values: []string{"kind-worker"},
 						}},
-					},
+					}),
 				))
 			})
 
@@ -425,13 +426,13 @@ var _ = ginkgo.Describe("TopologyAwareScheduling", func() {
 				gomega.Expect(createdWorkload.Status.Admission).ShouldNot(gomega.BeNil())
 				gomega.Expect(createdWorkload.Status.Admission.PodSetAssignments).Should(gomega.HaveLen(1))
 				gomega.Expect(createdWorkload.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-					&kueue.TopologyAssignment{
+					tas.V1Beta2From(&tas.TopologyAssignment{
 						Levels: []string{corev1.LabelHostname},
-						Domains: []kueue.TopologyDomainAssignment{{
+						Domains: []tas.TopologyDomainAssignment{{
 							Count:  2,
 							Values: []string{"kind-worker"},
 						}},
-					},
+					}),
 				))
 			})
 
@@ -539,13 +540,13 @@ var _ = ginkgo.Describe("TopologyAwareScheduling", func() {
 				gomega.Expect(createdWorkload.Status.Admission).ShouldNot(gomega.BeNil())
 				gomega.Expect(createdWorkload.Status.Admission.PodSetAssignments).Should(gomega.HaveLen(1))
 				gomega.Expect(createdWorkload.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-					&kueue.TopologyAssignment{
+					tas.V1Beta2From(&tas.TopologyAssignment{
 						Levels: []string{corev1.LabelHostname},
-						Domains: []kueue.TopologyDomainAssignment{{
+						Domains: []tas.TopologyDomainAssignment{{
 							Count:  1,
 							Values: []string{"kind-worker"},
 						}},
-					},
+					}),
 				))
 			})
 
diff --git a/test/e2e/tas/hotswap_test.go b/test/e2e/tas/hotswap_test.go
index a8d56c728..b412ecf1a 100644
--- a/test/e2e/tas/hotswap_test.go
+++ b/test/e2e/tas/hotswap_test.go
@@ -31,6 +31,7 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
 	kueue "sigs.k8s.io/kueue/apis/kueue/v1beta2"
+	"sigs.k8s.io/kueue/pkg/util/tas"
 	utiltesting "sigs.k8s.io/kueue/pkg/util/testing"
 	utiltestingapi "sigs.k8s.io/kueue/pkg/util/testing/v1beta2"
 	testingjob "sigs.k8s.io/kueue/pkg/util/testingjobs/job"
@@ -292,9 +293,9 @@ func expectWorkloadTopologyAssignment(ctx context.Context, k8sClient client.Clie
 		topologyAssignment := wl.Status.Admission.PodSetAssignments[0].TopologyAssignment
 		g.Expect(topologyAssignment).NotTo(gomega.BeNil())
 		g.Expect(topologyAssignment.Levels).To(gomega.BeEquivalentTo([]string{corev1.LabelHostname}))
-		g.Expect(topologyAssignment.Domains).To(gomega.HaveLen(numPods))
+		g.Expect(tas.TotalDomainCount(topologyAssignment)).To(gomega.Equal(numPods))
 		chosenNodes := []string{}
-		for _, domain := range topologyAssignment.Domains {
+		for domain := range tas.InternalSeqFrom(topologyAssignment) {
 			g.Expect(domain.Count).To(gomega.Equal(int32(1)))
 			chosenNodes = append(chosenNodes, domain.Values...)
 		}
diff --git a/test/e2e/tas/job_test.go b/test/e2e/tas/job_test.go
index 27d01b210..d89e1a3ad 100644
--- a/test/e2e/tas/job_test.go
+++ b/test/e2e/tas/job_test.go
@@ -30,6 +30,7 @@ import (
 
 	kueue "sigs.k8s.io/kueue/apis/kueue/v1beta2"
 	workloadjob "sigs.k8s.io/kueue/pkg/controller/jobs/job"
+	"sigs.k8s.io/kueue/pkg/util/tas"
 	utiltesting "sigs.k8s.io/kueue/pkg/util/testing"
 	utiltestingapi "sigs.k8s.io/kueue/pkg/util/testing/v1beta2"
 	testingjob "sigs.k8s.io/kueue/pkg/util/testingjobs/job"
@@ -133,27 +134,24 @@ var _ = ginkgo.Describe("TopologyAwareScheduling for Job", func() {
 					g.Expect(createdWorkload.Status.Admission).ShouldNot(gomega.BeNil())
 				}, util.LongTimeout, util.Interval).Should(gomega.Succeed())
 				gomega.Expect(createdWorkload.Status.Admission.PodSetAssignments).Should(gomega.HaveLen(1))
-				gomega.Expect(createdWorkload.Status.Admission.PodSetAssignments[0].TopologyAssignment.Levels).Should(gomega.BeComparableTo(
-					[]string{
-						corev1.LabelHostname,
-					},
-				))
-				gomega.Expect(createdWorkload.Status.Admission.PodSetAssignments[0].TopologyAssignment.Domains).Should(gomega.BeComparableTo(
-					[]kueue.TopologyDomainAssignment{
-						{
-							Values: []string{"kind-worker"},
-							Count:  1,
+				gomega.Expect(createdWorkload.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
+					tas.V1Beta2From(&tas.TopologyAssignment{
+						Levels: []string{corev1.LabelHostname},
+						Domains: []tas.TopologyDomainAssignment{
+							{
+								Values: []string{"kind-worker"},
+								Count:  1,
+							},
+							{
+								Values: []string{"kind-worker2"},
+								Count:  1,
+							},
+							{
+								Values: []string{"kind-worker3"},
+								Count:  1,
+							},
 						},
-						{
-							Values: []string{"kind-worker2"},
-							Count:  1,
-						},
-						{
-							Values: []string{"kind-worker3"},
-							Count:  1,
-						},
-					},
-				))
+					})))
 			})
 			ginkgo.By(fmt.Sprintf("verify the workload %q gets finished", wlLookupKey), func() {
 				gomega.Eventually(func(g gomega.Gomega) {
@@ -183,27 +181,23 @@ var _ = ginkgo.Describe("TopologyAwareScheduling for Job", func() {
 					g.Expect(createdWorkload.Status.Admission).ShouldNot(gomega.BeNil())
 				}, util.LongTimeout, util.Interval).Should(gomega.Succeed())
 				gomega.Expect(createdWorkload.Status.Admission.PodSetAssignments).Should(gomega.HaveLen(1))
-				gomega.Expect(createdWorkload.Status.Admission.PodSetAssignments[0].TopologyAssignment.Levels).Should(gomega.BeComparableTo(
-					[]string{
-						corev1.LabelHostname,
-					},
-				))
-				gomega.Expect(createdWorkload.Status.Admission.PodSetAssignments[0].TopologyAssignment.Domains).Should(gomega.BeComparableTo(
-					[]kueue.TopologyDomainAssignment{
-						{
-							Values: []string{"kind-worker"},
-							Count:  1,
-						},
-						{
-							Values: []string{"kind-worker2"},
-							Count:  1,
-						},
-						{
-							Values: []string{"kind-worker3"},
-							Count:  1,
-						},
-					},
-				))
+				gomega.Expect(createdWorkload.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
+					tas.V1Beta2From(&tas.TopologyAssignment{
+						Levels: []string{corev1.LabelHostname},
+						Domains: []tas.TopologyDomainAssignment{
+							{
+								Values: []string{"kind-worker"},
+								Count:  1,
+							},
+							{
+								Values: []string{"kind-worker2"},
+								Count:  1,
+							},
+							{
+								Values: []string{"kind-worker3"},
+								Count:  1,
+							},
+						}})))
 			})
 
 			ginkgo.By(fmt.Sprintf("verify the workload %q gets finished", wlLookupKey), func() {
diff --git a/test/integration/multikueue/external_job_test.go b/test/integration/multikueue/external_job_test.go
index d1b3cf65e..e3903beef 100644
--- a/test/integration/multikueue/external_job_test.go
+++ b/test/integration/multikueue/external_job_test.go
@@ -136,7 +136,7 @@ var _ = ginkgo.Describe("MultiKueue", ginkgo.Ordered, ginkgo.ContinueOnFailure,
 				)
 				gomega.Expect(err).NotTo(gomega.HaveOccurred())
 
-				_, err = dispatcher.SetupControllers(mgr, configuration, config.MultiKueueDispatcherModeAllAtOnce)
+				_, err = dispatcher.SetupControllers(mgr, configuration)
 				gomega.Expect(err).NotTo(gomega.HaveOccurred())
 			})
 		})
diff --git a/test/integration/multikueue/suite_test.go b/test/integration/multikueue/suite_test.go
index 6f5345f9c..726a03e22 100644
--- a/test/integration/multikueue/suite_test.go
+++ b/test/integration/multikueue/suite_test.go
@@ -370,9 +370,13 @@ func managerAndMultiKueueSetup(
 	)
 	gomega.Expect(err).NotTo(gomega.HaveOccurred())
 
-	configuration := &config.Configuration{}
+	configuration := &config.Configuration{
+		MultiKueue: &config.MultiKueue{
+			DispatcherName: &dispatcherName,
+		},
+	}
 	mgr.GetScheme().Default(configuration)
-	_, err = dispatcher.SetupControllers(mgr, configuration, dispatcherName)
+	_, err = dispatcher.SetupControllers(mgr, configuration)
 	gomega.Expect(err).NotTo(gomega.HaveOccurred())
 }
 
diff --git a/test/integration/multikueue/tas/tas_test.go b/test/integration/multikueue/tas/tas_test.go
index e3a3baa47..78ebf3dc0 100644
--- a/test/integration/multikueue/tas/tas_test.go
+++ b/test/integration/multikueue/tas/tas_test.go
@@ -40,6 +40,7 @@ import (
 	"sigs.k8s.io/kueue/pkg/controller/admissionchecks/provisioning"
 	workloadjob "sigs.k8s.io/kueue/pkg/controller/jobs/job"
 	"sigs.k8s.io/kueue/pkg/features"
+	"sigs.k8s.io/kueue/pkg/util/tas"
 	utiltesting "sigs.k8s.io/kueue/pkg/util/testing"
 	utiltestingapi "sigs.k8s.io/kueue/pkg/util/testing/v1beta2"
 	testingjob "sigs.k8s.io/kueue/pkg/util/testingjobs/job"
@@ -350,10 +351,10 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 					g.Expect(wl.Status.Admission).ShouldNot(gomega.BeNil())
 					g.Expect(wl.Status.Admission.PodSetAssignments).Should(gomega.HaveLen(1))
 					g.Expect(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-						&kueue.TopologyAssignment{
+						tas.V1Beta2From(&tas.TopologyAssignment{
 							Levels:  []string{corev1.LabelHostname},
-							Domains: []kueue.TopologyDomainAssignment{{Count: 1, Values: []string{"host-1"}}},
-						},
+							Domains: []tas.TopologyDomainAssignment{{Count: 1, Values: []string{"host-1"}}},
+						}),
 					))
 				}, util.Timeout, util.Interval).Should(gomega.Succeed())
 			})
@@ -575,11 +576,11 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 					g.Expect(wl.Status.Admission).ShouldNot(gomega.BeNil())
 					g.Expect(wl.Status.Admission.PodSetAssignments).Should(gomega.HaveLen(1))
 					g.Expect(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-						&kueue.TopologyAssignment{
+						tas.V1Beta2From(&tas.TopologyAssignment{
 							Levels: []string{
 								corev1.LabelHostname,
 							},
-							Domains: []kueue.TopologyDomainAssignment{
+							Domains: []tas.TopologyDomainAssignment{
 								{
 									Count: 1,
 									Values: []string{
@@ -587,7 +588,7 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 									},
 								},
 							},
-						},
+						}),
 					))
 				}, util.Timeout, util.Interval).Should(gomega.Succeed())
 			})
diff --git a/test/integration/singlecluster/controller/jobs/appwrapper/appwrapper_controller_test.go b/test/integration/singlecluster/controller/jobs/appwrapper/appwrapper_controller_test.go
index 2011b69ad..fc51568d8 100644
--- a/test/integration/singlecluster/controller/jobs/appwrapper/appwrapper_controller_test.go
+++ b/test/integration/singlecluster/controller/jobs/appwrapper/appwrapper_controller_test.go
@@ -39,6 +39,7 @@ import (
 	"sigs.k8s.io/kueue/pkg/controller/constants"
 	"sigs.k8s.io/kueue/pkg/controller/jobframework"
 	workloadaw "sigs.k8s.io/kueue/pkg/controller/jobs/appwrapper"
+	"sigs.k8s.io/kueue/pkg/util/tas"
 	utiltesting "sigs.k8s.io/kueue/pkg/util/testing"
 	utiltestingapi "sigs.k8s.io/kueue/pkg/util/testing/v1beta2"
 	testingaw "sigs.k8s.io/kueue/pkg/util/testingjobs/appwrapper"
@@ -946,10 +947,10 @@ var _ = ginkgo.Describe("AppWrapper controller with TopologyAwareScheduling", gi
 				g.Expect(wl.Status.Admission).ShouldNot(gomega.BeNil())
 				g.Expect(wl.Status.Admission.PodSetAssignments).Should(gomega.HaveLen(1))
 				g.Expect(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-					&kueue.TopologyAssignment{
+					tas.V1Beta2From(&tas.TopologyAssignment{
 						Levels:  []string{tasBlockLabel},
-						Domains: []kueue.TopologyDomainAssignment{{Count: 1, Values: []string{"b1"}}},
-					},
+						Domains: []tas.TopologyDomainAssignment{{Count: 1, Values: []string{"b1"}}},
+					}),
 				))
 			}, util.Timeout, util.Interval).Should(gomega.Succeed())
 		})
diff --git a/test/integration/singlecluster/controller/jobs/jaxjob/jaxjob_controller_test.go b/test/integration/singlecluster/controller/jobs/jaxjob/jaxjob_controller_test.go
index ca5866111..67cf231e9 100644
--- a/test/integration/singlecluster/controller/jobs/jaxjob/jaxjob_controller_test.go
+++ b/test/integration/singlecluster/controller/jobs/jaxjob/jaxjob_controller_test.go
@@ -34,6 +34,7 @@ import (
 	"sigs.k8s.io/kueue/pkg/controller/jobframework"
 	workloadjaxjob "sigs.k8s.io/kueue/pkg/controller/jobs/kubeflow/jobs/jaxjob"
 	"sigs.k8s.io/kueue/pkg/controller/jobs/kubeflow/kubeflowjob"
+	"sigs.k8s.io/kueue/pkg/util/tas"
 	utiltesting "sigs.k8s.io/kueue/pkg/util/testing"
 	utiltestingapi "sigs.k8s.io/kueue/pkg/util/testing/v1beta2"
 	testingjaxjob "sigs.k8s.io/kueue/pkg/util/testingjobs/jaxjob"
@@ -674,16 +675,16 @@ var _ = ginkgo.Describe("JAXJob controller with TopologyAwareScheduling", ginkgo
 				g.Expect(wl.Status.Admission).ShouldNot(gomega.BeNil())
 				g.Expect(wl.Status.Admission.PodSetAssignments).Should(gomega.HaveLen(1))
 				g.Expect(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-					&kueue.TopologyAssignment{
+					tas.V1Beta2From(&tas.TopologyAssignment{
 						Levels:  []string{utiltesting.DefaultBlockTopologyLevel, utiltesting.DefaultRackTopologyLevel},
-						Domains: []kueue.TopologyDomainAssignment{{Count: 1, Values: []string{"b1", "r1"}}},
-					},
+						Domains: []tas.TopologyDomainAssignment{{Count: 1, Values: []string{"b1", "r1"}}},
+					}),
 				))
 				g.Expect(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-					&kueue.TopologyAssignment{
+					tas.V1Beta2From(&tas.TopologyAssignment{
 						Levels:  []string{utiltesting.DefaultBlockTopologyLevel, utiltesting.DefaultRackTopologyLevel},
-						Domains: []kueue.TopologyDomainAssignment{{Count: 1, Values: []string{"b1", "r1"}}},
-					},
+						Domains: []tas.TopologyDomainAssignment{{Count: 1, Values: []string{"b1", "r1"}}},
+					}),
 				))
 			}, util.Timeout, util.Interval).Should(gomega.Succeed())
 		})
diff --git a/test/integration/singlecluster/controller/jobs/job/job_controller_test.go b/test/integration/singlecluster/controller/jobs/job/job_controller_test.go
index c9c0097cd..a376dd344 100644
--- a/test/integration/singlecluster/controller/jobs/job/job_controller_test.go
+++ b/test/integration/singlecluster/controller/jobs/job/job_controller_test.go
@@ -45,6 +45,7 @@ import (
 	"sigs.k8s.io/kueue/pkg/controller/jobframework"
 	workloadjob "sigs.k8s.io/kueue/pkg/controller/jobs/job"
 	"sigs.k8s.io/kueue/pkg/features"
+	"sigs.k8s.io/kueue/pkg/util/tas"
 	utiltesting "sigs.k8s.io/kueue/pkg/util/testing"
 	utiltestingapi "sigs.k8s.io/kueue/pkg/util/testing/v1beta2"
 	testingjob "sigs.k8s.io/kueue/pkg/util/testingjobs/job"
@@ -3113,10 +3114,10 @@ var _ = ginkgo.Describe("Job controller with TopologyAwareScheduling", ginkgo.Or
 				g.Expect(wl.Status.Admission).ShouldNot(gomega.BeNil())
 				g.Expect(wl.Status.Admission.PodSetAssignments).Should(gomega.HaveLen(1))
 				g.Expect(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-					&kueue.TopologyAssignment{
+					tas.V1Beta2From(&tas.TopologyAssignment{
 						Levels:  []string{tasBlockLabel},
-						Domains: []kueue.TopologyDomainAssignment{{Count: 1, Values: []string{"b1"}}},
-					},
+						Domains: []tas.TopologyDomainAssignment{{Count: 1, Values: []string{"b1"}}},
+					}),
 				))
 			}, util.Timeout, util.Interval).Should(gomega.Succeed())
 		})
@@ -3165,10 +3166,10 @@ var _ = ginkgo.Describe("Job controller with TopologyAwareScheduling", ginkgo.Or
 				g.Expect(wl.Status.Admission).ShouldNot(gomega.BeNil())
 				g.Expect(wl.Status.Admission.PodSetAssignments).Should(gomega.HaveLen(1))
 				g.Expect(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-					&kueue.TopologyAssignment{
+					tas.V1Beta2From(&tas.TopologyAssignment{
 						Levels:  []string{tasBlockLabel},
-						Domains: []kueue.TopologyDomainAssignment{{Count: 1, Values: []string{"b1"}}},
-					},
+						Domains: []tas.TopologyDomainAssignment{{Count: 1, Values: []string{"b1"}}},
+					}),
 				))
 			}, util.Timeout, util.Interval).Should(gomega.Succeed())
 		})
diff --git a/test/integration/singlecluster/controller/jobs/jobset/jobset_controller_test.go b/test/integration/singlecluster/controller/jobs/jobset/jobset_controller_test.go
index 43b7d0550..42b295908 100644
--- a/test/integration/singlecluster/controller/jobs/jobset/jobset_controller_test.go
+++ b/test/integration/singlecluster/controller/jobs/jobset/jobset_controller_test.go
@@ -38,6 +38,7 @@ import (
 	"sigs.k8s.io/kueue/pkg/controller/constants"
 	"sigs.k8s.io/kueue/pkg/controller/jobframework"
 	workloadjobset "sigs.k8s.io/kueue/pkg/controller/jobs/jobset"
+	"sigs.k8s.io/kueue/pkg/util/tas"
 	utiltesting "sigs.k8s.io/kueue/pkg/util/testing"
 	utiltestingapi "sigs.k8s.io/kueue/pkg/util/testing/v1beta2"
 	testingjobset "sigs.k8s.io/kueue/pkg/util/testingjobs/jobset"
@@ -1281,16 +1282,16 @@ var _ = ginkgo.Describe("JobSet controller with TopologyAwareScheduling", ginkgo
 				g.Expect(wl.Status.Admission).ShouldNot(gomega.BeNil())
 				g.Expect(wl.Status.Admission.PodSetAssignments).Should(gomega.HaveLen(2))
 				g.Expect(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-					&kueue.TopologyAssignment{
+					tas.V1Beta2From(&tas.TopologyAssignment{
 						Levels:  []string{utiltesting.DefaultBlockTopologyLevel, utiltesting.DefaultRackTopologyLevel},
-						Domains: []kueue.TopologyDomainAssignment{{Count: 1, Values: []string{"b1", "r1"}}},
-					},
+						Domains: []tas.TopologyDomainAssignment{{Count: 1, Values: []string{"b1", "r1"}}},
+					}),
 				))
 				g.Expect(wl.Status.Admission.PodSetAssignments[1].TopologyAssignment).Should(gomega.BeComparableTo(
-					&kueue.TopologyAssignment{
+					tas.V1Beta2From(&tas.TopologyAssignment{
 						Levels:  []string{utiltesting.DefaultBlockTopologyLevel, utiltesting.DefaultRackTopologyLevel},
-						Domains: []kueue.TopologyDomainAssignment{{Count: 1, Values: []string{"b1", "r1"}}},
-					},
+						Domains: []tas.TopologyDomainAssignment{{Count: 1, Values: []string{"b1", "r1"}}},
+					}),
 				))
 			}, util.Timeout, util.Interval).Should(gomega.Succeed())
 		})
diff --git a/test/integration/singlecluster/controller/jobs/mpijob/mpijob_controller_test.go b/test/integration/singlecluster/controller/jobs/mpijob/mpijob_controller_test.go
index 7fd268284..c565fa4b1 100644
--- a/test/integration/singlecluster/controller/jobs/mpijob/mpijob_controller_test.go
+++ b/test/integration/singlecluster/controller/jobs/mpijob/mpijob_controller_test.go
@@ -37,6 +37,7 @@ import (
 	"sigs.k8s.io/kueue/pkg/controller/constants"
 	"sigs.k8s.io/kueue/pkg/controller/jobframework"
 	workloadmpijob "sigs.k8s.io/kueue/pkg/controller/jobs/mpijob"
+	"sigs.k8s.io/kueue/pkg/util/tas"
 	utiltesting "sigs.k8s.io/kueue/pkg/util/testing"
 	utiltestingapi "sigs.k8s.io/kueue/pkg/util/testing/v1beta2"
 	testingjob "sigs.k8s.io/kueue/pkg/util/testingjobs/job"
@@ -1012,16 +1013,16 @@ var _ = ginkgo.Describe("MPIJob controller with TopologyAwareScheduling", ginkgo
 				g.Expect(wl.Status.Admission).ShouldNot(gomega.BeNil())
 				g.Expect(wl.Status.Admission.PodSetAssignments).Should(gomega.HaveLen(2))
 				g.Expect(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-					&kueue.TopologyAssignment{
+					tas.V1Beta2From(&tas.TopologyAssignment{
 						Levels:  []string{utiltesting.DefaultBlockTopologyLevel, utiltesting.DefaultRackTopologyLevel},
-						Domains: []kueue.TopologyDomainAssignment{{Count: 1, Values: []string{"b1", "r1"}}},
-					},
+						Domains: []tas.TopologyDomainAssignment{{Count: 1, Values: []string{"b1", "r1"}}},
+					}),
 				))
 				g.Expect(wl.Status.Admission.PodSetAssignments[1].TopologyAssignment).Should(gomega.BeComparableTo(
-					&kueue.TopologyAssignment{
+					tas.V1Beta2From(&tas.TopologyAssignment{
 						Levels:  []string{utiltesting.DefaultBlockTopologyLevel, utiltesting.DefaultRackTopologyLevel},
-						Domains: []kueue.TopologyDomainAssignment{{Count: 1, Values: []string{"b1", "r1"}}},
-					},
+						Domains: []tas.TopologyDomainAssignment{{Count: 1, Values: []string{"b1", "r1"}}},
+					}),
 				))
 			}, util.Timeout, util.Interval).Should(gomega.Succeed())
 		})
diff --git a/test/integration/singlecluster/controller/jobs/paddlejob/paddlejob_controller_test.go b/test/integration/singlecluster/controller/jobs/paddlejob/paddlejob_controller_test.go
index b554f245f..8f0e633f9 100644
--- a/test/integration/singlecluster/controller/jobs/paddlejob/paddlejob_controller_test.go
+++ b/test/integration/singlecluster/controller/jobs/paddlejob/paddlejob_controller_test.go
@@ -32,6 +32,7 @@ import (
 	"sigs.k8s.io/kueue/pkg/controller/jobframework"
 	workloadpaddlejob "sigs.k8s.io/kueue/pkg/controller/jobs/kubeflow/jobs/paddlejob"
 	"sigs.k8s.io/kueue/pkg/controller/jobs/kubeflow/kubeflowjob"
+	"sigs.k8s.io/kueue/pkg/util/tas"
 	utiltesting "sigs.k8s.io/kueue/pkg/util/testing"
 	utiltestingapi "sigs.k8s.io/kueue/pkg/util/testing/v1beta2"
 	testingnode "sigs.k8s.io/kueue/pkg/util/testingjobs/node"
@@ -415,16 +416,16 @@ var _ = ginkgo.Describe("PaddleJob controller with TopologyAwareScheduling", fra
 				g.Expect(wl.Status.Admission).ShouldNot(gomega.BeNil())
 				g.Expect(wl.Status.Admission.PodSetAssignments).Should(gomega.HaveLen(2))
 				g.Expect(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-					&kueue.TopologyAssignment{
+					tas.V1Beta2From(&tas.TopologyAssignment{
 						Levels:  []string{utiltesting.DefaultBlockTopologyLevel, utiltesting.DefaultRackTopologyLevel},
-						Domains: []kueue.TopologyDomainAssignment{{Count: 1, Values: []string{"b1", "r1"}}},
-					},
+						Domains: []tas.TopologyDomainAssignment{{Count: 1, Values: []string{"b1", "r1"}}},
+					}),
 				))
 				g.Expect(wl.Status.Admission.PodSetAssignments[1].TopologyAssignment).Should(gomega.BeComparableTo(
-					&kueue.TopologyAssignment{
+					tas.V1Beta2From(&tas.TopologyAssignment{
 						Levels:  []string{utiltesting.DefaultBlockTopologyLevel, utiltesting.DefaultRackTopologyLevel},
-						Domains: []kueue.TopologyDomainAssignment{{Count: 1, Values: []string{"b1", "r1"}}},
-					},
+						Domains: []tas.TopologyDomainAssignment{{Count: 1, Values: []string{"b1", "r1"}}},
+					}),
 				))
 			}, util.Timeout, util.Interval).Should(gomega.Succeed())
 		})
diff --git a/test/integration/singlecluster/controller/jobs/pod/pod_controller_test.go b/test/integration/singlecluster/controller/jobs/pod/pod_controller_test.go
index 36f0ed51b..72c67603c 100644
--- a/test/integration/singlecluster/controller/jobs/pod/pod_controller_test.go
+++ b/test/integration/singlecluster/controller/jobs/pod/pod_controller_test.go
@@ -18,6 +18,7 @@ package pod
 
 import (
 	"fmt"
+	"slices"
 	"strconv"
 
 	"github.com/google/go-cmp/cmp"
@@ -39,6 +40,7 @@ import (
 	podcontroller "sigs.k8s.io/kueue/pkg/controller/jobs/pod"
 	podconstants "sigs.k8s.io/kueue/pkg/controller/jobs/pod/constants"
 	"sigs.k8s.io/kueue/pkg/features"
+	"sigs.k8s.io/kueue/pkg/util/tas"
 	utiltesting "sigs.k8s.io/kueue/pkg/util/testing"
 	utiltestingapi "sigs.k8s.io/kueue/pkg/util/testing/v1beta2"
 	testingjob "sigs.k8s.io/kueue/pkg/util/testingjobs/job"
@@ -2288,10 +2290,10 @@ var _ = ginkgo.Describe("Pod controller with TopologyAwareScheduling", ginkgo.Or
 				g.Expect(wl.Status.Admission).ShouldNot(gomega.BeNil())
 				g.Expect(wl.Status.Admission.PodSetAssignments).Should(gomega.HaveLen(1))
 				g.Expect(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-					&kueue.TopologyAssignment{
+					tas.V1Beta2From(&tas.TopologyAssignment{
 						Levels:  []string{tasBlockLabel},
-						Domains: []kueue.TopologyDomainAssignment{{Count: 1, Values: []string{"b1"}}},
-					},
+						Domains: []tas.TopologyDomainAssignment{{Count: 1, Values: []string{"b1"}}},
+					}),
 				))
 			}, util.Timeout, util.Interval).Should(gomega.Succeed())
 		})
@@ -2339,10 +2341,10 @@ var _ = ginkgo.Describe("Pod controller with TopologyAwareScheduling", ginkgo.Or
 				g.Expect(wl.Status.Admission).ShouldNot(gomega.BeNil())
 				g.Expect(wl.Status.Admission.PodSetAssignments).Should(gomega.HaveLen(1))
 				g.Expect(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-					&kueue.TopologyAssignment{
+					tas.V1Beta2From(&tas.TopologyAssignment{
 						Levels:  []string{tasBlockLabel},
-						Domains: []kueue.TopologyDomainAssignment{{Count: 2, Values: []string{"b1"}}},
-					},
+						Domains: []tas.TopologyDomainAssignment{{Count: 2, Values: []string{"b1"}}},
+					}),
 				))
 			}, util.Timeout, util.Interval).Should(gomega.Succeed())
 		})
@@ -2486,8 +2488,9 @@ var _ = ginkgo.Describe("Pod controller with TASReplaceNodeOnPodTermination", gi
 		ginkgo.By("verify the workload is admitted", func() {
 			util.ExpectWorkloadsToBeAdmitted(ctx, k8sClient, wl)
 			gomega.Expect(k8sClient.Get(ctx, wlKey, wl)).To(gomega.Succeed())
-			gomega.Expect(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment.Domains).To(gomega.HaveLen(1))
-			nodeName = wl.Status.Admission.PodSetAssignments[0].TopologyAssignment.Domains[0].Values[0]
+			nodeNames := slices.Collect(tas.LowestLevelValues(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment))
+			gomega.Expect(nodeNames).To(gomega.HaveLen(1))
+			nodeName = nodeNames[0]
 			gomega.Expect(nodeName).To(gomega.Or(gomega.Equal("x1"), gomega.Equal("x3")))
 		})
 
@@ -2531,8 +2534,9 @@ var _ = ginkgo.Describe("Pod controller with TASReplaceNodeOnPodTermination", gi
 		ginkgo.By("verify the workload is assigned a new node", func() {
 			gomega.Eventually(func(g gomega.Gomega) string {
 				gomega.Expect(k8sClient.Get(ctx, wlKey, wl)).To(gomega.Succeed())
-				gomega.Expect(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment.Domains).To(gomega.HaveLen(1))
-				return wl.Status.Admission.PodSetAssignments[0].TopologyAssignment.Domains[0].Values[0]
+				nodeNames := slices.Collect(tas.LowestLevelValues(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment))
+				gomega.Expect(nodeNames).To(gomega.HaveLen(1))
+				return nodeNames[0]
 			}, util.Timeout, util.Interval).ShouldNot(gomega.Equal(nodeName))
 		})
 	})
@@ -2568,8 +2572,9 @@ var _ = ginkgo.Describe("Pod controller with TASReplaceNodeOnPodTermination", gi
 		ginkgo.By("verify the workload is admitted", func() {
 			util.ExpectWorkloadsToBeAdmitted(ctx, k8sClient, wl)
 			gomega.Expect(k8sClient.Get(ctx, wlKey, wl)).To(gomega.Succeed())
-			gomega.Expect(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment.Domains).To(gomega.HaveLen(1))
-			nodeName = wl.Status.Admission.PodSetAssignments[0].TopologyAssignment.Domains[0].Values[0]
+			nodeNames := slices.Collect(tas.LowestLevelValues(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment))
+			gomega.Expect(nodeNames).To(gomega.HaveLen(1))
+			nodeName = nodeNames[0]
 			gomega.Expect(nodeName).To(gomega.Or(gomega.Equal("x1"), gomega.Equal("x3")))
 		})
 
@@ -2613,8 +2618,9 @@ var _ = ginkgo.Describe("Pod controller with TASReplaceNodeOnPodTermination", gi
 		ginkgo.By("verify the workload is assigned a new node", func() {
 			gomega.Eventually(func(g gomega.Gomega) string {
 				gomega.Expect(k8sClient.Get(ctx, wlKey, wl)).To(gomega.Succeed())
-				gomega.Expect(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment.Domains).To(gomega.HaveLen(1))
-				return wl.Status.Admission.PodSetAssignments[0].TopologyAssignment.Domains[0].Values[0]
+				nodeNames := slices.Collect(tas.LowestLevelValues(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment))
+				gomega.Expect(nodeNames).To(gomega.HaveLen(1))
+				return nodeNames[0]
 			}, util.Timeout, util.Interval).ShouldNot(gomega.Equal(nodeName))
 		})
 	})
diff --git a/test/integration/singlecluster/controller/jobs/pytorchjob/pytorchjob_controller_test.go b/test/integration/singlecluster/controller/jobs/pytorchjob/pytorchjob_controller_test.go
index 2cb35dedc..cf96631df 100644
--- a/test/integration/singlecluster/controller/jobs/pytorchjob/pytorchjob_controller_test.go
+++ b/test/integration/singlecluster/controller/jobs/pytorchjob/pytorchjob_controller_test.go
@@ -34,6 +34,7 @@ import (
 	"sigs.k8s.io/kueue/pkg/controller/jobframework"
 	workloadpytorchjob "sigs.k8s.io/kueue/pkg/controller/jobs/kubeflow/jobs/pytorchjob"
 	"sigs.k8s.io/kueue/pkg/controller/jobs/kubeflow/kubeflowjob"
+	"sigs.k8s.io/kueue/pkg/util/tas"
 	utiltesting "sigs.k8s.io/kueue/pkg/util/testing"
 	utiltestingapi "sigs.k8s.io/kueue/pkg/util/testing/v1beta2"
 	testingnode "sigs.k8s.io/kueue/pkg/util/testingjobs/node"
@@ -711,16 +712,16 @@ var _ = ginkgo.Describe("PyTorchJob controller with TopologyAwareScheduling", gi
 				g.Expect(wl.Status.Admission).ShouldNot(gomega.BeNil())
 				g.Expect(wl.Status.Admission.PodSetAssignments).Should(gomega.HaveLen(2))
 				g.Expect(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-					&kueue.TopologyAssignment{
+					tas.V1Beta2From(&tas.TopologyAssignment{
 						Levels:  []string{utiltesting.DefaultBlockTopologyLevel, utiltesting.DefaultRackTopologyLevel},
-						Domains: []kueue.TopologyDomainAssignment{{Count: 1, Values: []string{"b1", "r1"}}},
-					},
+						Domains: []tas.TopologyDomainAssignment{{Count: 1, Values: []string{"b1", "r1"}}},
+					}),
 				))
 				g.Expect(wl.Status.Admission.PodSetAssignments[1].TopologyAssignment).Should(gomega.BeComparableTo(
-					&kueue.TopologyAssignment{
+					tas.V1Beta2From(&tas.TopologyAssignment{
 						Levels:  []string{utiltesting.DefaultBlockTopologyLevel, utiltesting.DefaultRackTopologyLevel},
-						Domains: []kueue.TopologyDomainAssignment{{Count: 1, Values: []string{"b1", "r1"}}},
-					},
+						Domains: []tas.TopologyDomainAssignment{{Count: 1, Values: []string{"b1", "r1"}}},
+					}),
 				))
 			}, util.Timeout, util.Interval).Should(gomega.Succeed())
 		})
diff --git a/test/integration/singlecluster/controller/jobs/tfjob/tfjob_controller_test.go b/test/integration/singlecluster/controller/jobs/tfjob/tfjob_controller_test.go
index bfa13849e..8aa8afff2 100644
--- a/test/integration/singlecluster/controller/jobs/tfjob/tfjob_controller_test.go
+++ b/test/integration/singlecluster/controller/jobs/tfjob/tfjob_controller_test.go
@@ -32,6 +32,7 @@ import (
 	"sigs.k8s.io/kueue/pkg/controller/jobframework"
 	workloadtfjob "sigs.k8s.io/kueue/pkg/controller/jobs/kubeflow/jobs/tfjob"
 	"sigs.k8s.io/kueue/pkg/controller/jobs/kubeflow/kubeflowjob"
+	"sigs.k8s.io/kueue/pkg/util/tas"
 	utiltesting "sigs.k8s.io/kueue/pkg/util/testing"
 	utiltestingapi "sigs.k8s.io/kueue/pkg/util/testing/v1beta2"
 	testingnode "sigs.k8s.io/kueue/pkg/util/testingjobs/node"
@@ -445,22 +446,22 @@ var _ = ginkgo.Describe("TFJob controller with TopologyAwareScheduling", framewo
 				g.Expect(wl.Status.Admission).ShouldNot(gomega.BeNil())
 				g.Expect(wl.Status.Admission.PodSetAssignments).Should(gomega.HaveLen(3))
 				g.Expect(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-					&kueue.TopologyAssignment{
+					tas.V1Beta2From(&tas.TopologyAssignment{
 						Levels:  []string{utiltesting.DefaultBlockTopologyLevel, utiltesting.DefaultRackTopologyLevel},
-						Domains: []kueue.TopologyDomainAssignment{{Count: 1, Values: []string{"b1", "r1"}}},
-					},
+						Domains: []tas.TopologyDomainAssignment{{Count: 1, Values: []string{"b1", "r1"}}},
+					}),
 				))
 				g.Expect(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-					&kueue.TopologyAssignment{
+					tas.V1Beta2From(&tas.TopologyAssignment{
 						Levels:  []string{utiltesting.DefaultBlockTopologyLevel, utiltesting.DefaultRackTopologyLevel},
-						Domains: []kueue.TopologyDomainAssignment{{Count: 1, Values: []string{"b1", "r1"}}},
-					},
+						Domains: []tas.TopologyDomainAssignment{{Count: 1, Values: []string{"b1", "r1"}}},
+					}),
 				))
 				g.Expect(wl.Status.Admission.PodSetAssignments[1].TopologyAssignment).Should(gomega.BeComparableTo(
-					&kueue.TopologyAssignment{
+					tas.V1Beta2From(&tas.TopologyAssignment{
 						Levels:  []string{utiltesting.DefaultBlockTopologyLevel, utiltesting.DefaultRackTopologyLevel},
-						Domains: []kueue.TopologyDomainAssignment{{Count: 1, Values: []string{"b1", "r1"}}},
-					},
+						Domains: []tas.TopologyDomainAssignment{{Count: 1, Values: []string{"b1", "r1"}}},
+					}),
 				))
 			}, util.Timeout, util.Interval).Should(gomega.Succeed())
 		})
diff --git a/test/integration/singlecluster/controller/jobs/trainjob/trainjob_controller_test.go b/test/integration/singlecluster/controller/jobs/trainjob/trainjob_controller_test.go
index 4f2c9a827..f83e664c7 100644
--- a/test/integration/singlecluster/controller/jobs/trainjob/trainjob_controller_test.go
+++ b/test/integration/singlecluster/controller/jobs/trainjob/trainjob_controller_test.go
@@ -37,6 +37,7 @@ import (
 	"sigs.k8s.io/kueue/pkg/controller/constants"
 	"sigs.k8s.io/kueue/pkg/controller/jobframework"
 	workloadtrainjob "sigs.k8s.io/kueue/pkg/controller/jobs/trainjob"
+	"sigs.k8s.io/kueue/pkg/util/tas"
 	utiltesting "sigs.k8s.io/kueue/pkg/util/testing"
 	utiltestingapi "sigs.k8s.io/kueue/pkg/util/testing/v1beta2"
 	testingjobset "sigs.k8s.io/kueue/pkg/util/testingjobs/jobset"
@@ -711,16 +712,16 @@ var _ = ginkgo.Describe("TrainJob controller with TopologyAwareScheduling", gink
 				g.Expect(wl.Status.Admission).ShouldNot(gomega.BeNil())
 				g.Expect(wl.Status.Admission.PodSetAssignments).Should(gomega.HaveLen(2))
 				g.Expect(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-					&kueue.TopologyAssignment{
+					tas.V1Beta2From(&tas.TopologyAssignment{
 						Levels:  []string{utiltesting.DefaultBlockTopologyLevel, utiltesting.DefaultRackTopologyLevel},
-						Domains: []kueue.TopologyDomainAssignment{{Count: 1, Values: []string{"b1", "r1"}}},
-					},
+						Domains: []tas.TopologyDomainAssignment{{Count: 1, Values: []string{"b1", "r1"}}},
+					}),
 				))
 				g.Expect(wl.Status.Admission.PodSetAssignments[1].TopologyAssignment).Should(gomega.BeComparableTo(
-					&kueue.TopologyAssignment{
+					tas.V1Beta2From(&tas.TopologyAssignment{
 						Levels:  []string{utiltesting.DefaultBlockTopologyLevel, utiltesting.DefaultRackTopologyLevel},
-						Domains: []kueue.TopologyDomainAssignment{{Count: 1, Values: []string{"b1", "r1"}}},
-					},
+						Domains: []tas.TopologyDomainAssignment{{Count: 1, Values: []string{"b1", "r1"}}},
+					}),
 				))
 			}, util.Timeout, util.Interval).Should(gomega.Succeed())
 		})
diff --git a/test/integration/singlecluster/controller/jobs/xgboostjob/xgboostjob_controller_test.go b/test/integration/singlecluster/controller/jobs/xgboostjob/xgboostjob_controller_test.go
index 3a4b04ad9..25c5b89ee 100644
--- a/test/integration/singlecluster/controller/jobs/xgboostjob/xgboostjob_controller_test.go
+++ b/test/integration/singlecluster/controller/jobs/xgboostjob/xgboostjob_controller_test.go
@@ -32,6 +32,7 @@ import (
 	"sigs.k8s.io/kueue/pkg/controller/jobframework"
 	workloadxgboostjob "sigs.k8s.io/kueue/pkg/controller/jobs/kubeflow/jobs/xgboostjob"
 	"sigs.k8s.io/kueue/pkg/controller/jobs/kubeflow/kubeflowjob"
+	"sigs.k8s.io/kueue/pkg/util/tas"
 	utiltesting "sigs.k8s.io/kueue/pkg/util/testing"
 	utiltestingapi "sigs.k8s.io/kueue/pkg/util/testing/v1beta2"
 	testingnode "sigs.k8s.io/kueue/pkg/util/testingjobs/node"
@@ -412,16 +413,16 @@ var _ = ginkgo.Describe("XGBoostJob controller with TopologyAwareScheduling", fr
 				g.Expect(wl.Status.Admission).ShouldNot(gomega.BeNil())
 				g.Expect(wl.Status.Admission.PodSetAssignments).Should(gomega.HaveLen(2))
 				g.Expect(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-					&kueue.TopologyAssignment{
+					tas.V1Beta2From(&tas.TopologyAssignment{
 						Levels:  []string{utiltesting.DefaultBlockTopologyLevel, utiltesting.DefaultRackTopologyLevel},
-						Domains: []kueue.TopologyDomainAssignment{{Count: 1, Values: []string{"b1", "r1"}}},
-					},
+						Domains: []tas.TopologyDomainAssignment{{Count: 1, Values: []string{"b1", "r1"}}},
+					}),
 				))
 				g.Expect(wl.Status.Admission.PodSetAssignments[1].TopologyAssignment).Should(gomega.BeComparableTo(
-					&kueue.TopologyAssignment{
+					tas.V1Beta2From(&tas.TopologyAssignment{
 						Levels:  []string{utiltesting.DefaultBlockTopologyLevel, utiltesting.DefaultRackTopologyLevel},
-						Domains: []kueue.TopologyDomainAssignment{{Count: 1, Values: []string{"b1", "r1"}}},
-					},
+						Domains: []tas.TopologyDomainAssignment{{Count: 1, Values: []string{"b1", "r1"}}},
+					}),
 				))
 			}, util.Timeout, util.Interval).Should(gomega.Succeed())
 		})
diff --git a/test/integration/singlecluster/tas/tas_test.go b/test/integration/singlecluster/tas/tas_test.go
index fd606fc8a..a987800f9 100644
--- a/test/integration/singlecluster/tas/tas_test.go
+++ b/test/integration/singlecluster/tas/tas_test.go
@@ -339,12 +339,12 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 				ginkgo.By("verify admission for the workload1", func() {
 					gomega.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(wl1), wl1)).To(gomega.Succeed())
 					gomega.Expect(wl1.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-						&kueue.TopologyAssignment{
+						utiltas.V1Beta2From(&utiltas.TopologyAssignment{
 							Levels: []string{
 								utiltesting.DefaultBlockTopologyLevel,
 								utiltesting.DefaultRackTopologyLevel,
 							},
-							Domains: []kueue.TopologyDomainAssignment{
+							Domains: []utiltas.TopologyDomainAssignment{
 								{
 									Count: 1,
 									Values: []string{
@@ -360,7 +360,7 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 									},
 								},
 							},
-						},
+						}),
 					))
 				})
 
@@ -381,12 +381,12 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 				ginkgo.By("verify admission for the workload2", func() {
 					gomega.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(wl2), wl2)).To(gomega.Succeed())
 					gomega.Expect(wl2.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-						&kueue.TopologyAssignment{
+						utiltas.V1Beta2From(&utiltas.TopologyAssignment{
 							Levels: []string{
 								utiltesting.DefaultBlockTopologyLevel,
 								utiltesting.DefaultRackTopologyLevel,
 							},
-							Domains: []kueue.TopologyDomainAssignment{
+							Domains: []utiltas.TopologyDomainAssignment{
 								{
 									Count: 1,
 									Values: []string{
@@ -395,7 +395,7 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 									},
 								},
 							},
-						},
+						}),
 					))
 				})
 
@@ -416,12 +416,12 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 				ginkgo.By("verify admission for the wl3", func() {
 					gomega.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(wl3), wl3)).To(gomega.Succeed())
 					gomega.Expect(wl3.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-						&kueue.TopologyAssignment{
+						utiltas.V1Beta2From(&utiltas.TopologyAssignment{
 							Levels: []string{
 								utiltesting.DefaultBlockTopologyLevel,
 								utiltesting.DefaultRackTopologyLevel,
 							},
-							Domains: []kueue.TopologyDomainAssignment{
+							Domains: []utiltas.TopologyDomainAssignment{
 								{
 									Count: 1,
 									Values: []string{
@@ -430,7 +430,7 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 									},
 								},
 							},
-						},
+						}),
 					))
 				})
 
@@ -457,12 +457,12 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 				ginkgo.By("verify admission for the wl4", func() {
 					gomega.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(wl4), wl4)).To(gomega.Succeed())
 					gomega.Expect(wl4.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-						&kueue.TopologyAssignment{
+						utiltas.V1Beta2From(&utiltas.TopologyAssignment{
 							Levels: []string{
 								utiltesting.DefaultBlockTopologyLevel,
 								utiltesting.DefaultRackTopologyLevel,
 							},
-							Domains: []kueue.TopologyDomainAssignment{
+							Domains: []utiltas.TopologyDomainAssignment{
 								{
 									Count: 1,
 									Values: []string{
@@ -471,7 +471,7 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 									},
 								},
 							},
-						},
+						}),
 					))
 				})
 			})
@@ -604,13 +604,13 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 				ginkgo.By("verify admission for the workload", func() {
 					gomega.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(wl), wl)).To(gomega.Succeed())
 					gomega.Expect(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-						&kueue.TopologyAssignment{
+						utiltas.V1Beta2From(&utiltas.TopologyAssignment{
 							Levels: []string{utiltesting.DefaultBlockTopologyLevel, utiltesting.DefaultRackTopologyLevel},
-							Domains: []kueue.TopologyDomainAssignment{
+							Domains: []utiltas.TopologyDomainAssignment{
 								{Count: 1, Values: []string{"b1", "r1"}},
 								{Count: 1, Values: []string{"b1", "r2"}},
 							},
-						},
+						}),
 					))
 				})
 			})
@@ -673,13 +673,13 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 				ginkgo.By("verify admission for the workload", func() {
 					gomega.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(wl), wl)).To(gomega.Succeed())
 					gomega.Expect(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-						&kueue.TopologyAssignment{
+						utiltas.V1Beta2From(&utiltas.TopologyAssignment{
 							Levels: []string{utiltesting.DefaultBlockTopologyLevel, utiltesting.DefaultRackTopologyLevel},
-							Domains: []kueue.TopologyDomainAssignment{
+							Domains: []utiltas.TopologyDomainAssignment{
 								{Count: 1, Values: []string{"b1", "r1"}},
 								{Count: 1, Values: []string{"b1", "r2"}},
 							},
-						},
+						}),
 					))
 				})
 			})
@@ -837,13 +837,13 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 					util.ExpectWorkloadsToBeAdmitted(ctx, k8sClient, wl1)
 					gomega.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(wl1), wl1)).To(gomega.Succeed())
 					gomega.Expect(wl1.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-						&kueue.TopologyAssignment{
+						utiltas.V1Beta2From(&utiltas.TopologyAssignment{
 							Levels: []string{corev1.LabelHostname},
-							Domains: []kueue.TopologyDomainAssignment{
+							Domains: []utiltas.TopologyDomainAssignment{
 								{Count: 1, Values: []string{"x3"}},
 								{Count: 1, Values: []string{"x1"}},
 							},
-						},
+						}),
 					))
 				})
 
@@ -882,13 +882,13 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 					util.ExpectWorkloadsToBeAdmitted(ctx, k8sClient, wl1)
 					gomega.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(wl1), wl1)).To(gomega.Succeed())
 					gomega.Expect(wl1.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-						&kueue.TopologyAssignment{
+						utiltas.V1Beta2From(&utiltas.TopologyAssignment{
 							Levels: []string{corev1.LabelHostname},
-							Domains: []kueue.TopologyDomainAssignment{
+							Domains: []utiltas.TopologyDomainAssignment{
 								{Count: 1, Values: []string{"x3"}},
 								{Count: 1, Values: []string{"x1"}},
 							},
-						},
+						}),
 					))
 				})
 
@@ -902,13 +902,13 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 					gomega.Eventually(func(g gomega.Gomega) {
 						g.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(wl1), wl1)).To(gomega.Succeed())
 						g.Expect(wl1.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-							&kueue.TopologyAssignment{
+							utiltas.V1Beta2From(&utiltas.TopologyAssignment{
 								Levels: []string{corev1.LabelHostname},
-								Domains: []kueue.TopologyDomainAssignment{
+								Domains: []utiltas.TopologyDomainAssignment{
 									{Count: 1, Values: []string{"x1"}},
 									{Count: 1, Values: []string{"x4"}},
 								},
-							},
+							}),
 						))
 						g.Expect(wl1.Status.UnhealthyNodes).NotTo(gomega.ContainElement(kueue.UnhealthyNode{Name: nodeName}))
 					}, util.Timeout, util.Interval).Should(gomega.Succeed())
@@ -931,13 +931,13 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 					util.ExpectWorkloadsToBeAdmitted(ctx, k8sClient, wl1)
 					gomega.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(wl1), wl1)).To(gomega.Succeed())
 					gomega.Expect(wl1.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-						&kueue.TopologyAssignment{
+						utiltas.V1Beta2From(&utiltas.TopologyAssignment{
 							Levels: []string{corev1.LabelHostname},
-							Domains: []kueue.TopologyDomainAssignment{
+							Domains: []utiltas.TopologyDomainAssignment{
 								{Count: 1, Values: []string{"x3"}},
 								{Count: 1, Values: []string{"x1"}},
 							},
-						},
+						}),
 					))
 				})
 
@@ -956,13 +956,13 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 					gomega.Eventually(func(g gomega.Gomega) {
 						g.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(wl1), wl1)).To(gomega.Succeed())
 						g.Expect(wl1.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-							&kueue.TopologyAssignment{
+							utiltas.V1Beta2From(&utiltas.TopologyAssignment{
 								Levels: []string{corev1.LabelHostname},
-								Domains: []kueue.TopologyDomainAssignment{
+								Domains: []utiltas.TopologyDomainAssignment{
 									{Count: 1, Values: []string{"x1"}},
 									{Count: 1, Values: []string{"x4"}},
 								},
-							},
+							}),
 						))
 						gomega.Expect(wl1.Status.UnhealthyNodes).NotTo(gomega.ContainElement(kueue.UnhealthyNode{Name: nodeName}))
 					}, util.Timeout, util.Interval).Should(gomega.Succeed())
@@ -986,13 +986,13 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 					util.ExpectWorkloadsToBeAdmitted(ctx, k8sClient, wl1)
 					gomega.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(wl1), wl1)).To(gomega.Succeed())
 					gomega.Expect(wl1.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-						&kueue.TopologyAssignment{
+						utiltas.V1Beta2From(&utiltas.TopologyAssignment{
 							Levels: []string{corev1.LabelHostname},
-							Domains: []kueue.TopologyDomainAssignment{
+							Domains: []utiltas.TopologyDomainAssignment{
 								{Count: 1, Values: []string{"x3"}},
 								{Count: 1, Values: []string{"x1"}},
 							},
-						},
+						}),
 					))
 				})
 
@@ -1050,13 +1050,13 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 					util.ExpectWorkloadsToBeAdmitted(ctx, k8sClient, wl1)
 					gomega.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(wl1), wl1)).To(gomega.Succeed())
 					gomega.Expect(wl1.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-						&kueue.TopologyAssignment{
+						utiltas.V1Beta2From(&utiltas.TopologyAssignment{
 							Levels: []string{corev1.LabelHostname},
-							Domains: []kueue.TopologyDomainAssignment{
+							Domains: []utiltas.TopologyDomainAssignment{
 								{Count: 1, Values: []string{"x3"}},
 								{Count: 1, Values: []string{"x1"}},
 							},
-						},
+						}),
 					))
 				})
 
@@ -1104,13 +1104,13 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 					util.ExpectWorkloadsToBeAdmitted(ctx, k8sClient, wl1)
 					gomega.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(wl1), wl1)).To(gomega.Succeed())
 					gomega.Expect(wl1.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-						&kueue.TopologyAssignment{
+						utiltas.V1Beta2From(&utiltas.TopologyAssignment{
 							Levels: []string{corev1.LabelHostname},
-							Domains: []kueue.TopologyDomainAssignment{
+							Domains: []utiltas.TopologyDomainAssignment{
 								{Count: 1, Values: []string{"x3"}},
 								{Count: 1, Values: []string{"x1"}},
 							},
-						},
+						}),
 					))
 				})
 
@@ -1127,13 +1127,13 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 					util.ExpectWorkloadsToBeAdmitted(ctx, k8sClient, wl2)
 					gomega.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(wl2), wl2)).To(gomega.Succeed())
 					gomega.Expect(wl2.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-						&kueue.TopologyAssignment{
+						utiltas.V1Beta2From(&utiltas.TopologyAssignment{
 							Levels: []string{corev1.LabelHostname},
-							Domains: []kueue.TopologyDomainAssignment{
+							Domains: []utiltas.TopologyDomainAssignment{
 								{Count: 1, Values: []string{"x4"}},
 								{Count: 1, Values: []string{"x2"}},
 							},
-						},
+						}),
 					))
 				})
 
@@ -1152,13 +1152,13 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 					gomega.Consistently(func(g gomega.Gomega) {
 						g.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(wl1), wl1)).To(gomega.Succeed())
 						g.Expect(wl1.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-							&kueue.TopologyAssignment{
+							utiltas.V1Beta2From(&utiltas.TopologyAssignment{
 								Levels: []string{corev1.LabelHostname},
-								Domains: []kueue.TopologyDomainAssignment{
+								Domains: []utiltas.TopologyDomainAssignment{
 									{Count: 1, Values: []string{"x3"}},
 									{Count: 1, Values: []string{"x1"}},
 								},
-							},
+							}),
 						))
 					}, util.ConsistentDuration, util.ShortInterval).Should(gomega.Succeed())
 				})
@@ -1170,13 +1170,13 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 					gomega.Eventually(func(g gomega.Gomega) {
 						g.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(wl1), wl1)).To(gomega.Succeed())
 						g.Expect(wl1.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-							&kueue.TopologyAssignment{
+							utiltas.V1Beta2From(&utiltas.TopologyAssignment{
 								Levels: []string{corev1.LabelHostname},
-								Domains: []kueue.TopologyDomainAssignment{
+								Domains: []utiltas.TopologyDomainAssignment{
 									{Count: 1, Values: []string{"x1"}},
 									{Count: 1, Values: []string{"x4"}},
 								},
-							},
+							}),
 						))
 						g.Expect(wl1.Status.UnhealthyNodes).NotTo(gomega.ContainElement(kueue.UnhealthyNode{Name: nodeName}))
 					}, util.Timeout, util.Interval).Should(gomega.Succeed())
@@ -1202,13 +1202,13 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 					util.ExpectWorkloadsToBeAdmitted(ctx, k8sClient, wl1)
 					gomega.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(wl1), wl1)).To(gomega.Succeed())
 					gomega.Expect(wl1.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-						&kueue.TopologyAssignment{
+						utiltas.V1Beta2From(&utiltas.TopologyAssignment{
 							Levels: []string{corev1.LabelHostname},
-							Domains: []kueue.TopologyDomainAssignment{
+							Domains: []utiltas.TopologyDomainAssignment{
 								{Count: 1, Values: []string{node1Name}},
 								{Count: 1, Values: []string{node2Name}},
 							},
-						},
+						}),
 					))
 				})
 
@@ -1252,13 +1252,13 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 					util.ExpectWorkloadsToBeAdmitted(ctx, k8sClient, wl1)
 					gomega.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(wl1), wl1)).To(gomega.Succeed())
 					gomega.Expect(wl1.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-						&kueue.TopologyAssignment{
+						utiltas.V1Beta2From(&utiltas.TopologyAssignment{
 							Levels: []string{corev1.LabelHostname},
-							Domains: []kueue.TopologyDomainAssignment{
+							Domains: []utiltas.TopologyDomainAssignment{
 								{Count: 1, Values: []string{node1Name}},
 								{Count: 1, Values: []string{node2Name}},
 							},
-						},
+						}),
 					))
 				})
 
@@ -1401,13 +1401,13 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 					util.ExpectWorkloadsToBeAdmitted(ctx, k8sClient, wl1)
 					gomega.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(wl1), wl1)).To(gomega.Succeed())
 					gomega.Expect(wl1.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-						&kueue.TopologyAssignment{
+						utiltas.V1Beta2From(&utiltas.TopologyAssignment{
 							Levels: []string{corev1.LabelHostname},
-							Domains: []kueue.TopologyDomainAssignment{
+							Domains: []utiltas.TopologyDomainAssignment{
 								{Count: 1, Values: []string{"x1"}},
 								{Count: 1, Values: []string{"x3"}},
 							},
-						},
+						}),
 					))
 				})
 
@@ -1436,13 +1436,13 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 					util.ExpectWorkloadsToBeAdmitted(ctx, k8sClient, wl1)
 					gomega.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(wl1), wl1)).To(gomega.Succeed())
 					gomega.Expect(wl1.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-						&kueue.TopologyAssignment{
+						utiltas.V1Beta2From(&utiltas.TopologyAssignment{
 							Levels: []string{corev1.LabelHostname},
-							Domains: []kueue.TopologyDomainAssignment{
+							Domains: []utiltas.TopologyDomainAssignment{
 								{Count: 1, Values: []string{"x2"}},
 								{Count: 1, Values: []string{"x4"}},
 							},
-						},
+						}),
 					))
 				})
 			})
@@ -1560,13 +1560,13 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 					util.ExpectWorkloadsToBeAdmitted(ctx, k8sClient, wl1)
 					gomega.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(wl1), wl1)).To(gomega.Succeed())
 					gomega.Expect(wl1.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-						&kueue.TopologyAssignment{
+						utiltas.V1Beta2From(&utiltas.TopologyAssignment{
 							Levels: []string{corev1.LabelHostname},
-							Domains: []kueue.TopologyDomainAssignment{
+							Domains: []utiltas.TopologyDomainAssignment{
 								{Count: 8, Values: []string{"x1"}},
 								{Count: 8, Values: []string{"x2"}},
 							},
-						},
+						}),
 					))
 				})
 			})
@@ -1597,22 +1597,22 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 					util.ExpectWorkloadsToBeAdmitted(ctx, k8sClient, wl1)
 					gomega.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(wl1), wl1)).To(gomega.Succeed())
 					gomega.Expect(wl1.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-						&kueue.TopologyAssignment{
+						utiltas.V1Beta2From(&utiltas.TopologyAssignment{
 							Levels: []string{corev1.LabelHostname},
-							Domains: []kueue.TopologyDomainAssignment{
+							Domains: []utiltas.TopologyDomainAssignment{
 								{Count: 1, Values: []string{"x1"}},
 							},
-						},
+						}),
 					))
 					gomega.Expect(wl1.Status.Admission.PodSetAssignments[1].TopologyAssignment).Should(gomega.BeComparableTo(
-						&kueue.TopologyAssignment{
+						utiltas.V1Beta2From(&utiltas.TopologyAssignment{
 							Levels: []string{corev1.LabelHostname},
-							Domains: []kueue.TopologyDomainAssignment{
+							Domains: []utiltas.TopologyDomainAssignment{
 								{Count: 10, Values: []string{"x1"}},
 								{Count: 10, Values: []string{"x2"}},
 								{Count: 10, Values: []string{"x3"}},
 							},
-						},
+						}),
 					))
 				})
 			})
@@ -2290,11 +2290,11 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 						g.Expect(wl1.Status.Admission).ShouldNot(gomega.BeNil())
 						g.Expect(wl1.Status.Admission.PodSetAssignments).Should(gomega.HaveLen(1))
 						g.Expect(wl1.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeEquivalentTo(
-							&kueue.TopologyAssignment{
+							utiltas.V1Beta2From(&utiltas.TopologyAssignment{
 								Levels: []string{
 									corev1.LabelHostname,
 								},
-								Domains: []kueue.TopologyDomainAssignment{
+								Domains: []utiltas.TopologyDomainAssignment{
 									{
 										Count: 1,
 										Values: []string{
@@ -2302,7 +2302,7 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 										},
 									},
 								},
-							},
+							}),
 						))
 					}, util.Timeout, util.Interval).Should(gomega.Succeed())
 				})
@@ -2410,11 +2410,11 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 						g.Expect(wl1.Status.Admission).ShouldNot(gomega.BeNil())
 						g.Expect(wl1.Status.Admission.PodSetAssignments).Should(gomega.HaveLen(1))
 						g.Expect(wl1.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeEquivalentTo(
-							&kueue.TopologyAssignment{
+							utiltas.V1Beta2From(&utiltas.TopologyAssignment{
 								Levels: []string{
 									corev1.LabelHostname,
 								},
-								Domains: []kueue.TopologyDomainAssignment{
+								Domains: []utiltas.TopologyDomainAssignment{
 									{
 										Count: 1,
 										Values: []string{
@@ -2422,7 +2422,7 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 										},
 									},
 								},
-							},
+							}),
 						))
 					}, util.Timeout, util.Interval).Should(gomega.Succeed())
 				})
@@ -2533,11 +2533,11 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 						g.Expect(wl1.Status.Admission).ShouldNot(gomega.BeNil())
 						g.Expect(wl1.Status.Admission.PodSetAssignments).Should(gomega.HaveLen(1))
 						g.Expect(wl1.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeEquivalentTo(
-							&kueue.TopologyAssignment{
+							utiltas.V1Beta2From(&utiltas.TopologyAssignment{
 								Levels: []string{
 									corev1.LabelHostname,
 								},
-								Domains: []kueue.TopologyDomainAssignment{
+								Domains: []utiltas.TopologyDomainAssignment{
 									{
 										Count: 1,
 										Values: []string{
@@ -2545,7 +2545,7 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 										},
 									},
 								},
-							},
+							}),
 						))
 					}, util.Timeout, util.Interval).Should(gomega.Succeed())
 				})
@@ -2666,11 +2666,11 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 						g.Expect(wl1.Status.Admission).ShouldNot(gomega.BeNil())
 						g.Expect(wl1.Status.Admission.PodSetAssignments).Should(gomega.HaveLen(1))
 						g.Expect(wl1.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeEquivalentTo(
-							&kueue.TopologyAssignment{
+							utiltas.V1Beta2From(&utiltas.TopologyAssignment{
 								Levels: []string{
 									corev1.LabelHostname,
 								},
-								Domains: []kueue.TopologyDomainAssignment{
+								Domains: []utiltas.TopologyDomainAssignment{
 									{
 										Count: 1,
 										Values: []string{
@@ -2678,7 +2678,7 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 										},
 									},
 								},
-							},
+							}),
 						))
 					}, util.Timeout, util.Interval).Should(gomega.Succeed())
 				})
@@ -2810,13 +2810,13 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 						g.Expect(wl1.Status.Admission).ShouldNot(gomega.BeNil())
 						g.Expect(wl1.Status.Admission.PodSetAssignments).Should(gomega.HaveLen(1))
 						g.Expect(wl1.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeEquivalentTo(
-							&kueue.TopologyAssignment{
+							utiltas.V1Beta2From(&utiltas.TopologyAssignment{
 								Levels: []string{corev1.LabelHostname},
-								Domains: []kueue.TopologyDomainAssignment{{
+								Domains: []utiltas.TopologyDomainAssignment{{
 									Count:  1,
 									Values: []string{"x1"},
 								}},
-							},
+							}),
 						))
 					}, util.Timeout, util.Interval).Should(gomega.Succeed())
 
@@ -2938,11 +2938,11 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 				ginkgo.By("verify admission for the workload1", func() {
 					gomega.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(wl1), wl1)).To(gomega.Succeed())
 					gomega.Expect(wl1.Status.Admission.PodSetAssignments[0].TopologyAssignment).Should(gomega.BeComparableTo(
-						&kueue.TopologyAssignment{
+						utiltas.V1Beta2From(&utiltas.TopologyAssignment{
 							Levels: []string{
 								utiltesting.DefaultRackTopologyLevel,
 							},
-							Domains: []kueue.TopologyDomainAssignment{
+							Domains: []utiltas.TopologyDomainAssignment{
 								{
 									Count: 1,
 									Values: []string{
@@ -2950,14 +2950,14 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 									},
 								},
 							},
-						},
+						}),
 					))
 					gomega.Expect(wl1.Status.Admission.PodSetAssignments[1].TopologyAssignment).Should(gomega.BeComparableTo(
-						&kueue.TopologyAssignment{
+						utiltas.V1Beta2From(&utiltas.TopologyAssignment{
 							Levels: []string{
 								utiltesting.DefaultRackTopologyLevel,
 							},
-							Domains: []kueue.TopologyDomainAssignment{
+							Domains: []utiltas.TopologyDomainAssignment{
 								{
 									Count: 2,
 									Values: []string{
@@ -2965,7 +2965,7 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 									},
 								},
 							},
-						},
+						}),
 					))
 				})
 			})
@@ -3260,8 +3260,7 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 						gomega.Expect(wl.Status.Admission.PodSetAssignments).Should(gomega.HaveLen(1))
 						gomega.Expect(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment).ShouldNot(gomega.BeNil())
 						gomega.Expect(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment.Levels).Should(gomega.Equal([]string{corev1.LabelHostname}))
-						gomega.Expect(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment.Domains).Should(gomega.HaveLen(1))
-						gomega.Expect(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment.Domains[0].Count).Should(gomega.Equal(int32(1)))
+						gomega.Expect(slices.Collect(utiltas.PodCounts(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment))).To(gomega.Equal([]int32{1}))
 					})
 				})
 			})
@@ -3428,14 +3427,12 @@ var _ = ginkgo.Describe("Topology Aware Scheduling", ginkgo.Ordered, func() {
 						// First pod set (8 GPUs) should be assigned to a single node
 						gomega.Expect(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment).ShouldNot(gomega.BeNil())
 						gomega.Expect(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment.Levels).Should(gomega.Equal([]string{corev1.LabelHostname}))
-						gomega.Expect(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment.Domains).Should(gomega.HaveLen(1))
-						gomega.Expect(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment.Domains[0].Count).Should(gomega.Equal(int32(1)))
+						gomega.Expect(slices.Collect(utiltas.PodCounts(wl.Status.Admission.PodSetAssignments[0].TopologyAssignment))).To(gomega.Equal([]int32{1}))
 
 						// Second pod set (1 GPU) should be assigned to a single node
 						gomega.Expect(wl.Status.Admission.PodSetAssignments[1].TopologyAssignment).ShouldNot(gomega.BeNil())
 						gomega.Expect(wl.Status.Admission.PodSetAssignments[1].TopologyAssignment.Levels).Should(gomega.Equal([]string{corev1.LabelHostname}))
-						gomega.Expect(wl.Status.Admission.PodSetAssignments[1].TopologyAssignment.Domains).Should(gomega.HaveLen(1))
-						gomega.Expect(wl.Status.Admission.PodSetAssignments[1].TopologyAssignment.Domains[0].Count).Should(gomega.Equal(int32(1)))
+						gomega.Expect(slices.Collect(utiltas.PodCounts(wl.Status.Admission.PodSetAssignments[1].TopologyAssignment))).To(gomega.Equal([]int32{1}))
 					})
 
 					ginkgo.By("Demonstrating TAS prevents resource waste by allowing schedulable workloads", func() {