Repository: kubernetes-sigs/kueue

Issue:
[AFS] Add entrance penalty for admitted Workloads
<!-- Please only use this template for submitting enhancement requests -->

**What would you like to be added**:
When a Workload gets admitted, we should increase the resource usage in LQ's FairSharing status. The penalty should be equivalent to the period of one `.usageSamplingInterval`

**Why is this needed**:
In case there are 2 LQs with the same (without the loss of generality, let's say 0) resource usage in FairSharing status, Kueue admits all Workloads with the respect of the priorities/creation timestamp until the status is recomputed (the worst case scenario, after the `.usageSamplingInterval` time).

We'd like to provide better support for such a case, so the admission of a Workload increases its LQ's FairSharing resource usage right away, and it's more fair

**Completion requirements**:

This feature doesn't require any API changes. It requires code changes in the code of Kueue's scheduler. During admission cycle we should update the LQ's usage by the entrance penalty. At the beginning of each scheduling cycle we should recreate heap to make sure the entrance penalty from the previous cycle is respected


Discussion:
@PBundyra: /cc @mbobrovskyi @mimowo: > This feature doesn't require any API changes.

Yes, but it changes the semantics of the mode, so @PBundyra I think we need to reflect this in the kEP first.@mimowo: IIUC the penalty should not be accounted on the restart of Kueue, right? So, maybe it is a good idea to account it during assumption into cache (which would happen on regular admission), but not on Kueue restart, IIRC.@PBundyra: Related PR that populates snapshot with `AdmissionScope` field 
https://github.com/kubernetes-sigs/kueue/pull/5632 @IrvingMg: /assign

Solution patch:
diff --git a/cmd/kueue/main.go b/cmd/kueue/main.go
index 8df5666ad..56496f1c9 100644
--- a/cmd/kueue/main.go
+++ b/cmd/kueue/main.go
@@ -426,6 +426,7 @@ func setupScheduler(mgr ctrl.Manager, cCache *cache.Cache, queues *queue.Manager
 		mgr.GetEventRecorderFor(constants.AdmissionName),
 		scheduler.WithPodsReadyRequeuingTimestamp(podsReadyRequeuingTimestamp(cfg)),
 		scheduler.WithFairSharing(cfg.FairSharing),
+		scheduler.WithAdmissionFairSharing(cfg.AdmissionFairSharing),
 	)
 	if err := mgr.Add(sched); err != nil {
 		return fmt.Errorf("unable to add scheduler to manager: %w", err)
diff --git a/pkg/cache/snapshot.go b/pkg/cache/snapshot.go
index 29672d38d..fb0fdb507 100644
--- a/pkg/cache/snapshot.go
+++ b/pkg/cache/snapshot.go
@@ -23,6 +23,7 @@ import (
 	"slices"
 
 	"github.com/go-logr/logr"
+	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/util/sets"
 	"k8s.io/klog/v2"
 	"sigs.k8s.io/controller-runtime/pkg/client"
@@ -32,6 +33,7 @@ import (
 	"sigs.k8s.io/kueue/pkg/hierarchy"
 	afs "sigs.k8s.io/kueue/pkg/util/admissionfairsharing"
 	utilmaps "sigs.k8s.io/kueue/pkg/util/maps"
+	utilqueue "sigs.k8s.io/kueue/pkg/util/queue"
 	"sigs.k8s.io/kueue/pkg/workload"
 )
 
@@ -103,10 +105,27 @@ func (s *Snapshot) Log(log logr.Logger) {
 	}
 }
 
-func (c *Cache) Snapshot(ctx context.Context) (*Snapshot, error) {
+type snapshotOption struct {
+	afsEntryPenalties *utilmaps.SyncMap[utilqueue.LocalQueueReference, corev1.ResourceList]
+}
+
+type SnapshotOption func(*snapshotOption)
+
+func WithAfsEntryPenalties(penalties *utilmaps.SyncMap[utilqueue.LocalQueueReference, corev1.ResourceList]) SnapshotOption {
+	return func(o *snapshotOption) {
+		o.afsEntryPenalties = penalties
+	}
+}
+
+func (c *Cache) Snapshot(ctx context.Context, options ...SnapshotOption) (*Snapshot, error) {
 	c.RLock()
 	defer c.RUnlock()
 
+	opts := &snapshotOption{}
+	for _, option := range options {
+		option(opts)
+	}
+
 	snap := Snapshot{
 		Manager:                  hierarchy.NewManager(newCohortSnapshot),
 		ResourceFlavors:          make(map[kueue.ResourceFlavorReference]*kueue.ResourceFlavor, len(c.resourceFlavors)),
@@ -139,7 +158,7 @@ func (c *Cache) Snapshot(ctx context.Context) (*Snapshot, error) {
 			snap.InactiveClusterQueueSets.Insert(cq.Name)
 			continue
 		}
-		cqSnapshot, err := c.snapshotClusterQueue(ctx, cq)
+		cqSnapshot, err := c.snapshotClusterQueue(ctx, cq, opts.afsEntryPenalties)
 		if err != nil {
 			return nil, err
 		}
@@ -162,7 +181,7 @@ func (c *Cache) Snapshot(ctx context.Context) (*Snapshot, error) {
 
 // snapshotClusterQueue creates a copy of ClusterQueue that includes
 // references to immutable objects and deep copies of changing ones.
-func (c *Cache) snapshotClusterQueue(ctx context.Context, cq *clusterQueue) (*ClusterQueueSnapshot, error) {
+func (c *Cache) snapshotClusterQueue(ctx context.Context, cq *clusterQueue, penalties *utilmaps.SyncMap[utilqueue.LocalQueueReference, corev1.ResourceList]) (*ClusterQueueSnapshot, error) {
 	cc := &ClusterQueueSnapshot{
 		Name:                          cq.Name,
 		ResourceGroups:                make([]ResourceGroup, len(cq.ResourceGroups)),
@@ -191,7 +210,7 @@ func (c *Cache) snapshotClusterQueue(ctx context.Context, cq *clusterQueue) (*Cl
 			return cc, nil
 		}
 		for _, wl := range cc.Workloads {
-			usage, err := wl.CalcLocalQueueFSUsage(ctx, c.client, resourceWeights)
+			usage, err := wl.CalcLocalQueueFSUsage(ctx, c.client, resourceWeights, penalties)
 			if err != nil {
 				return nil, fmt.Errorf("failed to calculate LocalQueue FS usage for LocalQueue %v", client.ObjectKey{Namespace: wl.Obj.Namespace, Name: string(wl.Obj.Spec.QueueName)})
 			}
diff --git a/pkg/cache/tas_flavor_snapshot.go b/pkg/cache/tas_flavor_snapshot.go
index 1dcc12c51..bb1e72c9a 100644
--- a/pkg/cache/tas_flavor_snapshot.go
+++ b/pkg/cache/tas_flavor_snapshot.go
@@ -22,8 +22,10 @@ import (
 	"errors"
 	"fmt"
 	"maps"
+	"math"
 	"slices"
 	"sort"
+	"strconv"
 	"strings"
 
 	"github.com/go-logr/logr"
@@ -78,6 +80,10 @@ type domain struct {
 	// domains.
 	sliceState int32
 
+	stateWithLeader      int32
+	sliceStateWithLeader int32
+	leaderState          int32
+
 	// levelValues stores the mapping from domain ID back to the
 	// ordered list of values
 	levelValues []string
@@ -430,31 +436,69 @@ func (s *TASFlavorSnapshot) FindTopologyAssignmentsForFlavor(flavorTASRequests F
 
 	result := make(map[kueue.PodSetReference]tasPodSetAssignmentResult)
 	assumedUsage := make(map[utiltas.TopologyDomainID]resources.Requests)
-	for _, tr := range flavorTASRequests {
+
+	groupedTASRequests := make(map[string]FlavorTASRequests)
+	groupsOrder := make([]string, 0)
+
+	for idx, tr := range flavorTASRequests {
+		groupKey := strconv.Itoa(idx)
+		if tr.PodSetGroupName != nil {
+			groupKey = *tr.PodSetGroupName
+		}
+
+		if !slices.Contains(groupsOrder, groupKey) {
+			groupsOrder = append(groupsOrder, groupKey)
+		}
+		groupedTASRequests[groupKey] = append(groupedTASRequests[groupKey], tr)
+	}
+
+	for _, groupKey := range groupsOrder {
+		trs := groupedTASRequests[groupKey]
 		if workload.HasNodeToReplace(opts.workload) {
-			// In case of looking for Node replacement, TopologyRequest has only
-			// PodSets with the Node to replace, so we match PodSetAssignment
-			psa := findPSA(opts.workload, tr.PodSet.Name)
-			if psa == nil || psa.TopologyAssignment == nil {
-				continue
-			}
-			// 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)
-			result[tr.PodSet.Name] = tasPodSetAssignmentResult{TopologyAssignment: newAssignment, FailureReason: reason}
-			if reason != "" {
-				return result
+			for _, tr := range trs {
+				// In case of looking for Node replacement, TopologyRequest has only
+				// PodSets with the Node to replace, so we match PodSetAssignment
+				psa := findPSA(opts.workload, tr.PodSet.Name)
+				if psa == nil || psa.TopologyAssignment == nil {
+					continue
+				}
+				// 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)
+				result[tr.PodSet.Name] = tasPodSetAssignmentResult{TopologyAssignment: newAssignment, FailureReason: reason}
+				if reason != "" {
+					return result
+				}
+				addAssumedUsage(assumedUsage, replacementAssignment, &tr)
 			}
-			addAssumedUsage(assumedUsage, replacementAssignment, &tr)
 		} else {
-			assignment, reason := s.findTopologyAssignment(tr, assumedUsage, opts.simulateEmpty, "")
-			result[tr.PodSet.Name] = tasPodSetAssignmentResult{TopologyAssignment: assignment, FailureReason: reason}
+			var leader *TASPodSetRequests = nil
+
+			workers := trs[0]
+			if len(trs) > 1 {
+				leader = &trs[1]
+
+				if leader.Count > workers.Count {
+					leader = &trs[0]
+					workers = trs[1]
+				}
+			}
+
+			assignments, reason := s.findTopologyAssignment(workers, leader, assumedUsage, opts.simulateEmpty, "")
+			for _, tr := range trs {
+				podSetName := tr.PodSet.Name
+				result[podSetName] = tasPodSetAssignmentResult{TopologyAssignment: assignments[podSetName], FailureReason: reason}
+			}
+
 			if reason != "" {
 				return result
 			}
-			addAssumedUsage(assumedUsage, assignment, &tr)
+			for _, tr := range trs {
+				addAssumedUsage(assumedUsage, assignments[tr.PodSet.Name], &tr)
+			}
 		}
 	}
+
 	return result
 }
 
@@ -468,12 +512,12 @@ func (s *TASFlavorSnapshot) findReplacementAssignment(tr *TASPodSetRequests, exi
 		return nil, nil, fmt.Sprintf("Cannot replace the node, because the existing topologyAssignment is invalid, as it contains the stale domain %v", staleDomain)
 	}
 	requiredReplacementDomain := s.requiredReplacementDomain(tr, existingAssignment)
-	replacementAssignment, reason := s.findTopologyAssignment(*tr, assumedUsage, false, requiredReplacementDomain)
+	replacementAssignment, reason := s.findTopologyAssignment(*tr, nil, assumedUsage, false, requiredReplacementDomain)
 	if reason != "" {
 		return nil, nil, reason
 	}
-	newAssignment := s.mergeTopologyAssignments(replacementAssignment, existingAssignment)
-	return newAssignment, replacementAssignment, ""
+	newAssignment := s.mergeTopologyAssignments(replacementAssignment[tr.PodSet.Name], existingAssignment)
+	return newAssignment, replacementAssignment[tr.PodSet.Name], ""
 }
 
 func addAssumedUsage(assumedUsage map[utiltas.TopologyDomainID]resources.Requests, ta *kueue.TopologyAssignment, tr *TASPodSetRequests) {
@@ -572,32 +616,43 @@ func deleteDomain(currentTopologyAssignment *kueue.TopologyAssignment, nodeToRep
 //	domains at each level
 //	d) build the assignment for the lowest level in the hierarchy
 func (s *TASFlavorSnapshot) findTopologyAssignment(
-	tasPodSetRequests TASPodSetRequests,
+	workersTasPodSetRequests TASPodSetRequests,
+	leaderTasPodSetRequests *TASPodSetRequests,
 	assumedUsage map[utiltas.TopologyDomainID]resources.Requests,
-	simulateEmpty bool, requiredReplacementDomain utiltas.TopologyDomainID) (*kueue.TopologyAssignment, string) {
-	requests := tasPodSetRequests.SinglePodRequests.Clone()
+	simulateEmpty bool, requiredReplacementDomain utiltas.TopologyDomainID) (map[kueue.PodSetReference]*kueue.TopologyAssignment, string) {
+	requests := workersTasPodSetRequests.SinglePodRequests.Clone()
 	requests.Add(resources.Requests{corev1.ResourcePods: 1})
-	info := podset.FromPodSet(tasPodSetRequests.PodSet)
-	for _, podSetUpdate := range tasPodSetRequests.PodSetUpdates {
+
+	leaderCount := int32(0)
+
+	var leaderRequests *resources.Requests
+	if leaderTasPodSetRequests != nil {
+		leaderRequests = ptr.To(leaderTasPodSetRequests.SinglePodRequests.Clone())
+		leaderRequests.Add(resources.Requests{corev1.ResourcePods: 1})
+		leaderCount = 1
+	}
+
+	info := podset.FromPodSet(workersTasPodSetRequests.PodSet)
+	for _, podSetUpdate := range workersTasPodSetRequests.PodSetUpdates {
 		if err := info.Merge(podset.FromUpdate(podSetUpdate)); err != nil {
-			return nil, fmt.Sprintf("invalid podSetUpdate for PodSet %s, error: %s", tasPodSetRequests.PodSet.Name, err.Error())
+			return nil, fmt.Sprintf("invalid podSetUpdate for PodSet %s, error: %s", workersTasPodSetRequests.PodSet.Name, err.Error())
 		}
 	}
 	podSetTolerations := info.Tolerations
 	podSetNodeSelectors := info.NodeSelector
-	count := tasPodSetRequests.Count
+	count := workersTasPodSetRequests.Count
 
 	// If slice topology is not requested then we can assume that slice is a single pod
-	sliceSize, reason := getSliceSizeWithSinglePodAsDefault(tasPodSetRequests.PodSet.TopologyRequest)
+	sliceSize, reason := getSliceSizeWithSinglePodAsDefault(workersTasPodSetRequests.PodSet.TopologyRequest)
 	if len(reason) > 0 {
 		return nil, reason
 	}
 
-	required := isRequired(tasPodSetRequests.PodSet.TopologyRequest)
-	topologyKey := s.levelKeyWithImpliedFallback(&tasPodSetRequests)
-	sliceTopologyKey := s.sliceLevelKeyWithDefault(tasPodSetRequests.PodSet.TopologyRequest, s.lowestLevel())
+	required := isRequired(workersTasPodSetRequests.PodSet.TopologyRequest)
+	topologyKey := s.levelKeyWithImpliedFallback(&workersTasPodSetRequests)
+	sliceTopologyKey := s.sliceLevelKeyWithDefault(workersTasPodSetRequests.PodSet.TopologyRequest, s.lowestLevel())
 
-	unconstrained := isUnconstrained(tasPodSetRequests.PodSet.TopologyRequest, &tasPodSetRequests)
+	unconstrained := isUnconstrained(workersTasPodSetRequests.PodSet.TopologyRequest, &workersTasPodSetRequests)
 	if topologyKey == nil {
 		return nil, "topology level not specified"
 	}
@@ -628,6 +683,7 @@ func (s *TASFlavorSnapshot) findTopologyAssignment(
 	// phase 1 - determine the number of pods and slices which can fit in each topology domain
 	s.fillInCounts(
 		requests,
+		leaderRequests,
 		assumedUsage,
 		sliceSize,
 		sliceLevelIdx,
@@ -639,7 +695,7 @@ func (s *TASFlavorSnapshot) findTopologyAssignment(
 
 	// phase 2a: determine the level at which the assignment is done along with
 	// the domains which can accommodate all pods/slices
-	fitLevelIdx, currFitDomain, reason := s.findLevelWithFitDomains(levelIdx, required, count, sliceSize, unconstrained)
+	fitLevelIdx, currFitDomain, reason := s.findLevelWithFitDomains(levelIdx, required, count, leaderCount, sliceSize, unconstrained)
 	if len(reason) > 0 {
 		return nil, reason
 	}
@@ -647,13 +703,13 @@ func (s *TASFlavorSnapshot) findTopologyAssignment(
 	// phase 2b: traverse the tree down level-by-level optimizing the number of
 	// topology domains at each level
 	// if unconstrained is set, we'll only do it once
-	currFitDomain = s.updateSliceCountsToMinimum(currFitDomain, count, sliceSize, unconstrained)
+	currFitDomain = s.updateSliceCountsToMinimum(currFitDomain, count, leaderCount, sliceSize, unconstrained)
 	for levelIdx := fitLevelIdx; levelIdx+1 < len(s.domainsPerLevel); levelIdx++ {
 		if levelIdx < sliceLevelIdx {
 			// If we are "above" the requested slice topology level, we're greedily assigning pods/slices to
 			// all domains without checking what we've assigned to parent domains.
 			sortedLowerDomains := s.sortedDomains(s.lowerLevelDomains(currFitDomain), unconstrained)
-			currFitDomain = s.updateSliceCountsToMinimum(sortedLowerDomains, count, sliceSize, unconstrained)
+			currFitDomain = s.updateSliceCountsToMinimum(sortedLowerDomains, count, leaderCount, sliceSize, unconstrained)
 		} else {
 			// If we are "at" or "below" the requested slice topology level, we have to carefully assign pods
 			// to domains based on what we've assigned to parent domains, that's why we're iterating through
@@ -662,13 +718,39 @@ func (s *TASFlavorSnapshot) findTopologyAssignment(
 			for _, domain := range currFitDomain {
 				sortedLowerDomains := s.sortedDomains(domain.children, unconstrained)
 
-				addCurrFitDomain := s.updateCountsToMinimum(sortedLowerDomains, domain.state, unconstrained)
+				addCurrFitDomain := s.updateCountsToMinimum(sortedLowerDomains, domain.state, domain.leaderState, unconstrained)
 				newCurrFitDomain = append(newCurrFitDomain, addCurrFitDomain...)
 			}
 			currFitDomain = newCurrFitDomain
 		}
 	}
-	return s.buildAssignment(currFitDomain), ""
+
+	assignments := make(map[kueue.PodSetReference]*kueue.TopologyAssignment)
+
+	if leaderTasPodSetRequests != nil {
+		var leaderFitDomains []*domain
+		var workerFitDomains []*domain
+		for _, domain := range currFitDomain {
+			// select domains with leaders
+			if domain.leaderState > 0 {
+				copiedDomain := *domain
+				copiedDomain.state = copiedDomain.leaderState
+				leaderFitDomains = append(leaderFitDomains, &copiedDomain)
+			}
+
+			// select domains with workers
+			if domain.state > 0 {
+				workerFitDomains = append(workerFitDomains, domain)
+			}
+		}
+
+		assignments[leaderTasPodSetRequests.PodSet.Name] = s.buildAssignment(leaderFitDomains)
+		currFitDomain = workerFitDomains
+	}
+
+	assignments[workersTasPodSetRequests.PodSet.Name] = s.buildAssignment(currFitDomain)
+
+	return assignments, ""
 }
 
 func getSliceSizeWithSinglePodAsDefault(podSetTopologyRequest *kueue.PodSetTopologyRequest) (int32, string) {
@@ -789,20 +871,32 @@ func isSliceTopologyOnlyRequest(tr *kueue.PodSetTopologyRequest) bool {
 // value of state, higher or equal than count.
 // If such a domain doesn't exist, it returns first domain as it's the domain with the
 // most available resources
-func findBestFitDomain(domains []*domain, count int32) *domain {
-	return findBestFitDomainBy(domains, count, func(d *domain) int32 {
+func findBestFitDomain(domains []*domain, count int32, leaderCount int32) *domain {
+	getState := func(d *domain) int32 {
 		return d.state
-	})
+	}
+	if leaderCount > 0 {
+		getState = func(d *domain) int32 {
+			return d.stateWithLeader
+		}
+	}
+	return findBestFitDomainBy(domains, count, getState)
 }
 
 // findBestFitDomainForSlices finds an index of the first domain with the lowest
 // value of sliceState, higher or equal than sliceCount.
 // If such a domain doesn't exist, it returns first domain as it's the domain with the
 // most available resources
-func findBestFitDomainForSlices(domains []*domain, sliceCount int32) *domain {
-	return findBestFitDomainBy(domains, sliceCount, func(d *domain) int32 {
+func findBestFitDomainForSlices(domains []*domain, sliceCount int32, leaderCount int32) *domain {
+	getState := func(d *domain) int32 {
 		return d.sliceState
-	})
+	}
+	if leaderCount > 0 {
+		getState = func(d *domain) int32 {
+			return d.sliceStateWithLeader
+		}
+	}
+	return findBestFitDomainBy(domains, sliceCount, getState)
 }
 
 type domainState func(d *domain) int32
@@ -824,19 +918,19 @@ func findBestFitDomainBy(domains []*domain, needed int32, state domainState) *do
 	return bestDomain
 }
 
-func (s *TASFlavorSnapshot) findLevelWithFitDomains(levelIdx int, required bool, podSetSize int32, sliceSize int32, unconstrained bool) (int, []*domain, string) {
+func (s *TASFlavorSnapshot) findLevelWithFitDomains(levelIdx int, required bool, podSetSize int32, leaderPodSetSize int32, sliceSize int32, unconstrained bool) (int, []*domain, string) {
 	domains := s.domainsPerLevel[levelIdx]
 	if len(domains) == 0 {
 		return 0, nil, fmt.Sprintf("no topology domains at level: %s", s.levelKeys[levelIdx])
 	}
 	levelDomains := slices.Collect(maps.Values(domains))
-	sortedDomain := s.sortedDomains(levelDomains, unconstrained)
+	sortedDomain := s.sortedDomainsWithLeader(levelDomains, unconstrained)
 	topDomain := sortedDomain[0]
 
 	sliceCount := podSetSize / sliceSize
-	if useBestFitAlgorithm(unconstrained) && topDomain.sliceState >= sliceCount {
+	if useBestFitAlgorithm(unconstrained) && topDomain.sliceStateWithLeader >= sliceCount && topDomain.leaderState >= leaderPodSetSize {
 		// optimize the potentially last domain
-		topDomain = findBestFitDomainForSlices(sortedDomain, sliceCount)
+		topDomain = findBestFitDomainForSlices(sortedDomain, sliceCount, leaderPodSetSize)
 	}
 	if useLeastFreeCapacityAlgorithm(unconstrained) {
 		for _, candidateDomain := range sortedDomain {
@@ -849,20 +943,45 @@ func (s *TASFlavorSnapshot) findLevelWithFitDomains(levelIdx int, required bool,
 			return 0, nil, s.notFitMessage(maxCapacityFound, sliceCount, sliceSize)
 		}
 	}
-	if topDomain.sliceState < sliceCount {
+	if topDomain.sliceStateWithLeader < sliceCount || topDomain.leaderState < leaderPodSetSize {
 		if required {
 			return 0, nil, s.notFitMessage(topDomain.sliceState, sliceCount, sliceSize)
 		}
 		if levelIdx > 0 && !unconstrained {
-			return s.findLevelWithFitDomains(levelIdx-1, required, podSetSize, sliceSize, unconstrained)
+			return s.findLevelWithFitDomains(levelIdx-1, required, podSetSize, leaderPodSetSize, sliceSize, unconstrained)
 		}
 		results := []*domain{}
 		remainingSliceCount := sliceCount
+		remainingLeaderCount := leaderPodSetSize
+
+		// Domains are sorted in a way that prioritizes domains with higher leader capacity.
+		// We want to assign leaders first. After we are assign all leaders, we sort the remaining
+		// "unused" domains based on worker capacity (sliceState, state and then levelValues) and
+		// try to assign remaining workers.
+		idx := 0
+		for ; remainingLeaderCount > 0 && idx < len(sortedDomain) && sortedDomain[idx].leaderState > 0; idx++ {
+			domain := sortedDomain[idx]
+			if useBestFitAlgorithm(unconstrained) && sortedDomain[idx].sliceStateWithLeader >= remainingSliceCount {
+				// optimize the last domain
+				domain = findBestFitDomainForSlices(sortedDomain[idx:], remainingSliceCount, remainingLeaderCount)
+			}
+			results = append(results, domain)
+
+			remainingLeaderCount -= domain.leaderState
+			remainingSliceCount -= domain.sliceStateWithLeader
+		}
+		if remainingLeaderCount > 0 {
+			return 0, nil, s.notFitMessage(leaderPodSetSize-remainingLeaderCount, sliceCount, sliceSize)
+		}
+
+		// At this point we have assigned all leaders, so we sort remaining domains based on worker capacity
+		// and assign remaining workers.
+		sortedDomain = s.sortedDomains(sortedDomain[idx:], unconstrained)
 		for idx := 0; remainingSliceCount > 0 && idx < len(sortedDomain) && sortedDomain[idx].sliceState > 0; idx++ {
 			domain := sortedDomain[idx]
 			if useBestFitAlgorithm(unconstrained) && sortedDomain[idx].sliceState >= remainingSliceCount {
 				// optimize the last domain
-				domain = findBestFitDomainForSlices(sortedDomain[idx:], remainingSliceCount)
+				domain = findBestFitDomainForSlices(sortedDomain[idx:], remainingSliceCount, 0)
 			}
 			results = append(results, domain)
 
@@ -887,51 +1006,113 @@ func useLeastFreeCapacityAlgorithm(unconstrained bool) bool {
 		(unconstrained && features.Enabled(features.TASProfileMixed))
 }
 
-func (s *TASFlavorSnapshot) updateSliceCountsToMinimum(domains []*domain, count int32, sliceSize int32, unconstrained bool) []*domain {
+func (s *TASFlavorSnapshot) updateSliceCountsToMinimum(domains []*domain, count int32, leaderCount int32, sliceSize int32, unconstrained bool) []*domain {
 	result := make([]*domain, 0)
 	remainingSlices := count / sliceSize
+	remainingLeaderCount := leaderCount
 	for i, domain := range domains {
-		if useBestFitAlgorithm(unconstrained) && domain.sliceState >= remainingSlices {
-			// optimize the last domain
-			domain = findBestFitDomainForSlices(domains[i:], remainingSlices)
-		}
+		if remainingLeaderCount > 0 {
+			if useBestFitAlgorithm(unconstrained) && domain.sliceStateWithLeader >= remainingSlices && domain.leaderState >= remainingLeaderCount {
+				// optimize the last domain
+				domain = findBestFitDomainForSlices(domains[i:], remainingSlices, remainingLeaderCount)
+			}
+
+			if domain.sliceStateWithLeader >= remainingSlices && domain.leaderState >= remainingLeaderCount {
+				domain.state = remainingSlices * sliceSize
+				domain.sliceState = remainingSlices
+				domain.leaderState = remainingLeaderCount
+				result = append(result, domain)
+				return result
+			}
+
+			if domain.sliceStateWithLeader > remainingSlices {
+				domain.sliceStateWithLeader = remainingSlices
+			}
+
+			if domain.leaderState > remainingLeaderCount {
+				domain.leaderState = remainingLeaderCount
+			}
+
+			domain.state = domain.sliceStateWithLeader * sliceSize
+			remainingLeaderCount -= domain.leaderState
+			remainingSlices -= domain.sliceStateWithLeader
+
+			result = append(result, domain)
+		} else {
+			if useBestFitAlgorithm(unconstrained) && domain.sliceState >= remainingSlices {
+				// optimize the last domain
+				domain = findBestFitDomainForSlices(domains[i:], remainingSlices, 0)
+			}
 
-		if domain.sliceState >= remainingSlices {
-			domain.state = remainingSlices * sliceSize
-			domain.sliceState = remainingSlices
+			domain.leaderState = 0
+
+			if domain.sliceState >= remainingSlices {
+				domain.state = remainingSlices * sliceSize
+				domain.sliceState = remainingSlices
+				result = append(result, domain)
+				return result
+			}
+			domain.state = domain.sliceState * sliceSize
+			remainingSlices -= domain.sliceState
 			result = append(result, domain)
-			return result
 		}
-		domain.state = domain.sliceState * sliceSize
-		remainingSlices -= domain.sliceState
-		result = append(result, domain)
 	}
 	s.log.Error(errCodeAssumptionsViolated, "unexpected remainingCount",
 		"remainingSlices", remainingSlices,
+		"remainingLeaderCount", remainingLeaderCount,
 		"count", count,
 		"leaves", s.leaves)
 	return nil
 }
 
-func (s *TASFlavorSnapshot) updateCountsToMinimum(domains []*domain, count int32, unconstrained bool) []*domain {
+func (s *TASFlavorSnapshot) updateCountsToMinimum(domains []*domain, count int32, leaderCount int32, unconstrained bool) []*domain {
 	result := make([]*domain, 0)
 	remainingCount := count
+	remainingLeaderCount := leaderCount
+
 	for i, domain := range domains {
-		if useBestFitAlgorithm(unconstrained) && domain.state >= remainingCount {
-			// optimize the last domain
-			domain = findBestFitDomain(domains[i:], remainingCount)
-		}
+		if remainingLeaderCount > 0 {
+			if useBestFitAlgorithm(unconstrained) && domain.stateWithLeader >= remainingCount && domain.leaderState >= remainingLeaderCount {
+				// optimize the last domain
+				domain = findBestFitDomain(domains[i:], remainingCount, remainingLeaderCount)
+			}
+
+			if domain.stateWithLeader >= remainingCount && domain.leaderState >= remainingLeaderCount {
+				domain.state = remainingCount
+				domain.leaderState = remainingLeaderCount
+				result = append(result, domain)
+				return result
+			}
+			remainingCount -= domain.stateWithLeader
+			remainingLeaderCount -= domain.leaderState
+
+			if domain.stateWithLeader > remainingCount {
+				domain.stateWithLeader = remainingCount
+			}
+			if domain.leaderState > remainingLeaderCount {
+				domain.leaderState = remainingLeaderCount
+			}
+			result = append(result, domain)
+		} else {
+			if useBestFitAlgorithm(unconstrained) && domain.state >= remainingCount {
+				// optimize the last domain
+				domain = findBestFitDomain(domains[i:], remainingCount, 0)
+			}
+
+			domain.leaderState = 0
 
-		if domain.state >= remainingCount {
-			domain.state = remainingCount
+			if domain.state >= remainingCount {
+				domain.state = remainingCount
+				result = append(result, domain)
+				return result
+			}
+			remainingCount -= domain.state
 			result = append(result, domain)
-			return result
 		}
-		remainingCount -= domain.state
-		result = append(result, domain)
 	}
 	s.log.Error(errCodeAssumptionsViolated, "unexpected remainingCount",
 		"remainingCount", remainingCount,
+		"remainingLeaderCount", remainingLeaderCount,
 		"count", count,
 		"leaves", s.leaves)
 	return nil
@@ -973,6 +1154,32 @@ func (s *TASFlavorSnapshot) lowerLevelDomains(domains []*domain) []*domain {
 	return result
 }
 
+func (s *TASFlavorSnapshot) sortedDomainsWithLeader(domains []*domain, unconstrained bool) []*domain {
+	isLeastFreeCapacity := useLeastFreeCapacityAlgorithm(unconstrained)
+	result := slices.Clone(domains)
+	slices.SortFunc(result, func(a, b *domain) int {
+		if a.leaderState != b.leaderState {
+			return cmp.Compare(b.leaderState, a.leaderState)
+		}
+
+		if a.sliceStateWithLeader != b.sliceStateWithLeader {
+			if isLeastFreeCapacity {
+				// Start from the domain with the least amount of free resources.
+				// Ascending order.
+				return cmp.Compare(a.sliceStateWithLeader, b.sliceStateWithLeader)
+			}
+			return cmp.Compare(b.sliceStateWithLeader, a.sliceStateWithLeader)
+		}
+
+		if a.stateWithLeader != b.stateWithLeader {
+			return cmp.Compare(a.stateWithLeader, b.stateWithLeader)
+		}
+
+		return slices.Compare(a.levelValues, b.levelValues)
+	})
+	return result
+}
+
 // This function sorts domains based on a specified algorithm: BestFit or LeastFreeCapacity.
 //
 // The sorting criteria are:
@@ -1002,7 +1209,9 @@ func (s *TASFlavorSnapshot) sortedDomains(domains []*domain, unconstrained bool)
 	return result
 }
 
-func (s *TASFlavorSnapshot) fillInCounts(requests resources.Requests,
+func (s *TASFlavorSnapshot) fillInCounts(
+	requests resources.Requests,
+	leaderRequests *resources.Requests,
 	assumedUsage map[utiltas.TopologyDomainID]resources.Requests,
 	sliceSize int32,
 	sliceLevelIdx int,
@@ -1014,7 +1223,10 @@ func (s *TASFlavorSnapshot) fillInCounts(requests resources.Requests,
 		// cleanup the state in case some remaining values are present from computing
 		// assignments for previous PodSets.
 		domain.state = 0
+		domain.stateWithLeader = 0
 		domain.sliceState = 0
+		domain.sliceStateWithLeader = 0
+		domain.leaderState = 0
 	}
 	for _, leaf := range s.leaves {
 		// 1. Check Tolerations against Node Taints
@@ -1051,9 +1263,17 @@ func (s *TASFlavorSnapshot) fillInCounts(requests resources.Requests,
 			remainingCapacity.Sub(leafAssumedUsage)
 		}
 		leaf.state = requests.CountIn(remainingCapacity)
+
+		leaf.leaderState = 0
+		if leaderRequests != nil && leaderRequests.CountIn(remainingCapacity) > 0 {
+			leaf.leaderState = 1
+			remainingCapacity.Sub(*leaderRequests)
+		}
+
+		leaf.stateWithLeader = requests.CountIn(remainingCapacity)
 	}
 	for _, root := range s.roots {
-		root.state, root.sliceState = s.fillInCountsHelper(root, sliceSize, sliceLevelIdx, 0)
+		root.state, root.sliceState, root.stateWithLeader, root.sliceStateWithLeader, root.leaderState = s.fillInCountsHelper(root, sliceSize, sliceLevelIdx, 0)
 	}
 }
 
@@ -1066,31 +1286,52 @@ func belongsToRequiredDomain(leaf *leafDomain, requiredReplacementDomain utiltas
 	return strings.HasPrefix(string(utiltas.DomainID(leaf.levelValues)), string(requiredReplacementDomain))
 }
 
-func (s *TASFlavorSnapshot) fillInCountsHelper(domain *domain, sliceSize int32, sliceLevelIdx int, level int) (int32, int32) {
+func (s *TASFlavorSnapshot) fillInCountsHelper(domain *domain, sliceSize int32, sliceLevelIdx int, level int) (int32, int32, int32, int32, int32) {
 	// logic for a leaf
 	if len(domain.children) == 0 {
 		if level == sliceLevelIdx {
 			// initialize the sliceState if leaf is the request slice level
 			domain.sliceState = domain.state / sliceSize
+			domain.sliceStateWithLeader = domain.stateWithLeader / sliceSize
 		}
-		return domain.state, domain.sliceState
+		return domain.state, domain.sliceState, domain.stateWithLeader, domain.sliceStateWithLeader, domain.leaderState
 	}
 	// logic for a parent
 	childrenCapacity := int32(0)
 	sliceCapacity := int32(0)
 
+	minStateWithLeaderDifference := int32(math.MaxInt32)
+	minSliceStateWithLeaderDifference := int32(math.MaxInt32)
+	leaderState := int32(0)
+
 	for _, child := range domain.children {
-		addChildrenCapacity, addChildrenSliceCapacity := s.fillInCountsHelper(child, sliceSize, sliceLevelIdx, level+1)
+		addChildrenCapacity, addChildrenSliceCapacity, addChildrenCapacityWithLeader, addChildrenSliceCapacityWithLeader, childLeaderState := s.fillInCountsHelper(child, sliceSize, sliceLevelIdx, level+1)
 		childrenCapacity += addChildrenCapacity
 		sliceCapacity += addChildrenSliceCapacity
+		if addChildrenCapacity-addChildrenCapacityWithLeader < minStateWithLeaderDifference {
+			minStateWithLeaderDifference = addChildrenCapacity - addChildrenCapacityWithLeader
+		}
+		if addChildrenSliceCapacity-addChildrenSliceCapacityWithLeader < minSliceStateWithLeaderDifference {
+			minSliceStateWithLeaderDifference = addChildrenSliceCapacity - addChildrenSliceCapacityWithLeader
+		}
+		if childLeaderState > leaderState {
+			leaderState = childLeaderState
+		}
 	}
 	domain.state = childrenCapacity
+	domain.stateWithLeader = childrenCapacity - minStateWithLeaderDifference
+	domain.leaderState = leaderState
+	sliceStateWithLeader := sliceCapacity - minSliceStateWithLeaderDifference
+
 	if level == sliceLevelIdx {
 		// initialize the sliceState for the requested slice level.
 		sliceCapacity = domain.state / sliceSize
+		sliceStateWithLeader = domain.stateWithLeader / sliceSize
 	}
 	domain.sliceState = sliceCapacity
-	return childrenCapacity, sliceCapacity
+	domain.sliceStateWithLeader = sliceStateWithLeader
+
+	return domain.state, domain.sliceState, domain.stateWithLeader, domain.sliceStateWithLeader, domain.leaderState
 }
 
 func (s *TASFlavorSnapshot) notFitMessage(slicesFitCount, totalRequestsSlicesCount, sliceSize int32) string {
diff --git a/pkg/controller/core/core.go b/pkg/controller/core/core.go
index 397df17ea..cdcbd1b45 100644
--- a/pkg/controller/core/core.go
+++ b/pkg/controller/core/core.go
@@ -91,6 +91,7 @@ func SetupControllers(mgr ctrl.Manager, qManager *queue.Manager, cc *cache.Cache
 		return "Workload", err
 	}
 	qManager.AddTopologyUpdateWatcher(cqRec)
+	qManager.AddWorkloadUpdateWatcher(qRec)
 	return "", nil
 }
 
diff --git a/pkg/controller/core/localqueue_controller.go b/pkg/controller/core/localqueue_controller.go
index 83c4a33a9..8f8eab6fc 100644
--- a/pkg/controller/core/localqueue_controller.go
+++ b/pkg/controller/core/localqueue_controller.go
@@ -18,7 +18,6 @@ package core
 
 import (
 	"context"
-	"math"
 
 	"github.com/go-logr/logr"
 	corev1 "k8s.io/api/core/v1"
@@ -49,6 +48,8 @@ import (
 	"sigs.k8s.io/kueue/pkg/features"
 	"sigs.k8s.io/kueue/pkg/metrics"
 	"sigs.k8s.io/kueue/pkg/queue"
+	afs "sigs.k8s.io/kueue/pkg/util/admissionfairsharing"
+	utilqueue "sigs.k8s.io/kueue/pkg/util/queue"
 	"sigs.k8s.io/kueue/pkg/util/resource"
 )
 
@@ -174,10 +175,11 @@ func (r *LocalQueueReconciler) Reconcile(ctx context.Context, req ctrl.Request)
 	if r.admissionFSConfig != nil && features.Enabled(features.AdmissionFairSharing) {
 		updated := r.initializeAdmissionFsStatus(ctx, &queueObj)
 		sinceLastUpdate := r.clock.Now().Sub(queueObj.Status.FairSharing.AdmissionFairSharingStatus.LastUpdate.Time)
-		if interval := r.admissionFSConfig.UsageSamplingInterval.Duration; !updated && sinceLastUpdate < interval {
+		lqKey := utilqueue.Key(&queueObj)
+		if interval := r.admissionFSConfig.UsageSamplingInterval.Duration; !updated && sinceLastUpdate < interval && !r.queues.HasPendingPenaltyFor(lqKey) {
 			return ctrl.Result{RequeueAfter: interval - sinceLastUpdate}, nil
 		}
-		if err := r.reconcileConsumedUsage(ctx, &queueObj, queueObj.Spec.ClusterQueue); err != nil {
+		if err := r.reconcileConsumedUsage(ctx, &queueObj); err != nil {
 			return ctrl.Result{}, client.IgnoreNotFound(err)
 		}
 		if err := r.queues.HeapifyClusterQueue(&cq, queueObj.Name); err != nil {
@@ -270,28 +272,36 @@ func (r *LocalQueueReconciler) initializeAdmissionFsStatus(ctx context.Context,
 	return false
 }
 
-func (r *LocalQueueReconciler) reconcileConsumedUsage(ctx context.Context, lq *kueue.LocalQueue, cqName kueue.ClusterQueueReference) error {
+func (r *LocalQueueReconciler) reconcileConsumedUsage(ctx context.Context, lq *kueue.LocalQueue) error {
 	halfLifeTime := r.admissionFSConfig.UsageHalfLifeTime.Seconds()
-
 	// reset usage to 0 if halfLife is 0
 	if halfLifeTime == 0 {
 		return r.updateAdmissionFsStatus(ctx, lq, corev1.ResourceList{})
 	}
-	cacheLq, err := r.cache.GetCacheLocalQueue(cqName, lq)
+	cacheLq, err := r.cache.GetCacheLocalQueue(lq.Spec.ClusterQueue, lq)
 	if err != nil {
 		return err
 	}
 	// calculate alpha rate
 	oldUsage := lq.Status.FairSharing.AdmissionFairSharingStatus.ConsumedResources
 	newUsage := cacheLq.GetAdmittedUsage()
-	timeSinceLastUpdate := r.clock.Now().Sub(lq.Status.FairSharing.AdmissionFairSharingStatus.LastUpdate.Time).Seconds()
-	alpha := 1.0 - math.Pow(0.5, timeSinceLastUpdate/halfLifeTime)
+	alpha := afs.CalculateAlphaRate(
+		r.clock.Now().Sub(lq.Status.FairSharing.AdmissionFairSharingStatus.LastUpdate.Time).Seconds(),
+		halfLifeTime,
+	)
 	// calculate weighted average of old and new usage
 	scaledNewUsage := resource.MulByFloat(newUsage, alpha)
 	scaledOldUsage := resource.MulByFloat(oldUsage, 1-alpha)
 	sum := resource.MergeResourceListKeepSum(scaledOldUsage, scaledNewUsage)
-	// update status
-	return r.updateAdmissionFsStatus(ctx, lq, sum)
+	// Add penalty to the final usage
+	lqKey := utilqueue.Key(lq)
+	err = r.queues.WithPenaltyLocked(lqKey, func(penalty corev1.ResourceList) error {
+		sum = resource.MergeResourceListKeepSum(sum, penalty)
+
+		// update status
+		return r.updateAdmissionFsStatus(ctx, lq, sum)
+	})
+	return err
 }
 
 func (r *LocalQueueReconciler) updateAdmissionFsStatus(ctx context.Context, lq *kueue.LocalQueue, consumedResources corev1.ResourceList) error {
diff --git a/pkg/queue/afs_entry_penalties.go b/pkg/queue/afs_entry_penalties.go
new file mode 100644
index 000000000..82254ec39
--- /dev/null
+++ b/pkg/queue/afs_entry_penalties.go
@@ -0,0 +1,94 @@
+// 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 queue
+
+import (
+	"sync"
+
+	corev1 "k8s.io/api/core/v1"
+
+	utilmaps "sigs.k8s.io/kueue/pkg/util/maps"
+	utilqueue "sigs.k8s.io/kueue/pkg/util/queue"
+	"sigs.k8s.io/kueue/pkg/util/resource"
+)
+
+type AfsEntryPenalties struct {
+	sync.RWMutex
+	penalties *utilmaps.SyncMap[utilqueue.LocalQueueReference, corev1.ResourceList]
+}
+
+func newPenaltyMap() *AfsEntryPenalties {
+	return &AfsEntryPenalties{
+		penalties: utilmaps.NewSyncMap[utilqueue.LocalQueueReference, corev1.ResourceList](0),
+	}
+}
+
+func (m *AfsEntryPenalties) Push(lqKey utilqueue.LocalQueueReference, penalty corev1.ResourceList) {
+	m.penalties.Add(lqKey, resource.MergeResourceListKeepSum(m.Peek(lqKey), penalty))
+}
+
+func (m *AfsEntryPenalties) Sub(lqKey utilqueue.LocalQueueReference, penalty corev1.ResourceList) {
+	for k, v := range penalty {
+		v.Neg()
+		penalty[k] = v
+	}
+	m.penalties.Add(lqKey, resource.MergeResourceListKeepSum(m.Peek(lqKey), penalty))
+}
+
+func (m *AfsEntryPenalties) Peek(lqKey utilqueue.LocalQueueReference) corev1.ResourceList {
+	penalty, found := m.penalties.Get(lqKey)
+	if !found {
+		return corev1.ResourceList{}
+	}
+
+	return penalty
+}
+
+func (m *AfsEntryPenalties) WithPenaltyLocked(lqKey utilqueue.LocalQueueReference, fn func(penalty corev1.ResourceList) error) error {
+	m.Lock()
+	defer m.Unlock()
+
+	penalty, found := m.penalties.Get(lqKey)
+	if !found {
+		penalty = corev1.ResourceList{}
+	}
+
+	err := fn(penalty)
+	if err == nil && found {
+		m.penalties.Delete(lqKey)
+	}
+
+	return err
+}
+
+func (m *AfsEntryPenalties) HasPendingFor(lqKey utilqueue.LocalQueueReference) bool {
+	m.Lock()
+	defer m.Unlock()
+
+	_, found := m.penalties.Get(lqKey)
+
+	return found
+}
+
+func (m *AfsEntryPenalties) HasAny() bool {
+	m.RLock()
+	defer m.RUnlock()
+
+	return m.penalties.Len() > 0
+}
+
+func (m *AfsEntryPenalties) GetPenalties() *utilmaps.SyncMap[utilqueue.LocalQueueReference, corev1.ResourceList] {
+	return m.penalties
+}
diff --git a/pkg/queue/cluster_queue.go b/pkg/queue/cluster_queue.go
index 4ebab979b..7d2076fae 100644
--- a/pkg/queue/cluster_queue.go
+++ b/pkg/queue/cluster_queue.go
@@ -36,7 +36,9 @@ import (
 	"sigs.k8s.io/kueue/pkg/hierarchy"
 	afs "sigs.k8s.io/kueue/pkg/util/admissionfairsharing"
 	"sigs.k8s.io/kueue/pkg/util/heap"
+	utilmaps "sigs.k8s.io/kueue/pkg/util/maps"
 	utilpriority "sigs.k8s.io/kueue/pkg/util/priority"
+	utilqueue "sigs.k8s.io/kueue/pkg/util/queue"
 	"sigs.k8s.io/kueue/pkg/workload"
 )
 
@@ -94,9 +96,9 @@ func workloadKey(i *workload.Info) workload.Reference {
 	return workload.Key(i.Obj)
 }
 
-func newClusterQueue(ctx context.Context, client client.Client, cq *kueue.ClusterQueue, wo workload.Ordering, afsConfig *config.AdmissionFairSharing) (*ClusterQueue, error) {
+func newClusterQueue(ctx context.Context, client client.Client, cq *kueue.ClusterQueue, wo workload.Ordering, afsConfig *config.AdmissionFairSharing, penalties *utilmaps.SyncMap[utilqueue.LocalQueueReference, corev1.ResourceList]) (*ClusterQueue, error) {
 	enableAdmissionFs, fsResWeights := afs.ResourceWeights(cq.Spec.AdmissionScope, afsConfig)
-	cqImpl := newClusterQueueImpl(ctx, client, wo, realClock, fsResWeights, enableAdmissionFs)
+	cqImpl := newClusterQueueImpl(ctx, client, wo, realClock, fsResWeights, enableAdmissionFs, penalties)
 	err := cqImpl.Update(cq)
 	if err != nil {
 		return nil, err
@@ -104,8 +106,8 @@ func newClusterQueue(ctx context.Context, client client.Client, cq *kueue.Cluste
 	return cqImpl, nil
 }
 
-func newClusterQueueImpl(ctx context.Context, client client.Client, wo workload.Ordering, clock clock.Clock, fsResWeights map[corev1.ResourceName]float64, enableAdmissionFs bool) *ClusterQueue {
-	lessFunc := queueOrderingFunc(ctx, client, wo, fsResWeights, enableAdmissionFs)
+func newClusterQueueImpl(ctx context.Context, client client.Client, wo workload.Ordering, clock clock.Clock, fsResWeights map[corev1.ResourceName]float64, enableAdmissionFs bool, penalties *utilmaps.SyncMap[utilqueue.LocalQueueReference, corev1.ResourceList]) *ClusterQueue {
+	lessFunc := queueOrderingFunc(ctx, client, wo, fsResWeights, enableAdmissionFs, penalties)
 	return &ClusterQueue{
 		heap:                   *heap.New(workloadKey, lessFunc),
 		inadmissibleWorkloads:  make(map[workload.Reference]*workload.Info),
@@ -426,12 +428,12 @@ func (c *ClusterQueue) RequeueIfNotPresent(wInfo *workload.Info, reason RequeueR
 // to sort workloads. The function sorts workloads based on their priority.
 // When priorities are equal, it uses the workload's creation or eviction
 // time.
-func queueOrderingFunc(ctx context.Context, c client.Client, wo workload.Ordering, fsResWeights map[corev1.ResourceName]float64, enableAdmissionFs bool) func(a, b *workload.Info) bool {
+func queueOrderingFunc(ctx context.Context, c client.Client, wo workload.Ordering, fsResWeights map[corev1.ResourceName]float64, enableAdmissionFs bool, penalties *utilmaps.SyncMap[utilqueue.LocalQueueReference, corev1.ResourceList]) func(a, b *workload.Info) bool {
 	log := ctrl.LoggerFrom(ctx)
 	return func(a, b *workload.Info) bool {
 		if enableAdmissionFs {
-			lqAUsage, errA := a.CalcLocalQueueFSUsage(ctx, c, fsResWeights)
-			lqBUsage, errB := b.CalcLocalQueueFSUsage(ctx, c, fsResWeights)
+			lqAUsage, errA := a.CalcLocalQueueFSUsage(ctx, c, fsResWeights, penalties)
+			lqBUsage, errB := b.CalcLocalQueueFSUsage(ctx, c, fsResWeights, penalties)
 			switch {
 			case errA != nil:
 				log.V(2).Error(errA, "Error determining LocalQueue usage")
@@ -457,3 +459,11 @@ func queueOrderingFunc(ctx context.Context, c client.Client, wo workload.Orderin
 		return !tB.Before(tA)
 	}
 }
+
+func (c *ClusterQueue) HeapifyAll() {
+	c.rwm.Lock()
+	defer c.rwm.Unlock()
+	for _, wl := range c.heap.List() {
+		c.heap.PushOrUpdate(wl)
+	}
+}
diff --git a/pkg/queue/manager.go b/pkg/queue/manager.go
index bc1abfd42..437f7e1a1 100644
--- a/pkg/queue/manager.go
+++ b/pkg/queue/manager.go
@@ -23,6 +23,7 @@ import (
 	"sync"
 	"time"
 
+	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/api/equality"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	"k8s.io/apimachinery/pkg/util/sets"
@@ -37,6 +38,8 @@ import (
 	"sigs.k8s.io/kueue/pkg/features"
 	"sigs.k8s.io/kueue/pkg/hierarchy"
 	"sigs.k8s.io/kueue/pkg/metrics"
+	utilmaps "sigs.k8s.io/kueue/pkg/util/maps"
+	utilqueue "sigs.k8s.io/kueue/pkg/util/queue"
 	"sigs.k8s.io/kueue/pkg/workload"
 )
 
@@ -112,6 +115,9 @@ type Manager struct {
 
 	admissionFairSharingConfig *config.AdmissionFairSharing
 	secondPassQueue            *secondPassQueue
+
+	afsEntryPenalties      *AfsEntryPenalties
+	workloadUpdateWatchers []WorkloadUpdateWatcher
 }
 
 func NewManager(client client.Client, checker StatusChecker, options ...Option) *Manager {
@@ -130,6 +136,7 @@ func NewManager(client client.Client, checker StatusChecker, options ...Option)
 
 		topologyUpdateWatchers: make([]TopologyUpdateWatcher, 0),
 		secondPassQueue:        newSecondPassQueue(),
+		afsEntryPenalties:      newPenaltyMap(),
 	}
 	for _, option := range options {
 		option(m)
@@ -174,7 +181,11 @@ func (m *Manager) AddClusterQueue(ctx context.Context, cq *kueue.ClusterQueue) e
 		return errClusterQueueAlreadyExists
 	}
 
-	cqImpl, err := newClusterQueue(ctx, m.client, cq, m.workloadOrdering, m.admissionFairSharingConfig)
+	var penalties *utilmaps.SyncMap[utilqueue.LocalQueueReference, corev1.ResourceList]
+	if features.Enabled(features.AdmissionFairSharing) {
+		penalties = m.afsEntryPenalties.GetPenalties()
+	}
+	cqImpl, err := newClusterQueue(ctx, m.client, cq, m.workloadOrdering, m.admissionFairSharingConfig, penalties)
 	if err != nil {
 		return err
 	}
@@ -796,3 +807,51 @@ func (m *Manager) queueSecondPass(ctx context.Context, w *kueue.Workload) {
 		m.Broadcast()
 	}
 }
+
+func (m *Manager) HeapifyAllClusterQueues() {
+	m.Lock()
+	defer m.Unlock()
+	for _, cq := range m.hm.ClusterQueues() {
+		if cq != nil {
+			cq.HeapifyAll()
+		}
+	}
+}
+
+func (m *Manager) PushEntryPenalty(lqKey utilqueue.LocalQueueReference, penalty corev1.ResourceList) {
+	m.afsEntryPenalties.Push(lqKey, penalty)
+}
+
+func (m *Manager) SubEntryPenalty(lqKey utilqueue.LocalQueueReference, penalty corev1.ResourceList) {
+	m.afsEntryPenalties.Sub(lqKey, penalty)
+}
+
+func (m *Manager) WithPenaltyLocked(lqKey utilqueue.LocalQueueReference, fn func(penalty corev1.ResourceList) error) error {
+	return m.afsEntryPenalties.WithPenaltyLocked(lqKey, fn)
+}
+
+func (m *Manager) HasPendingPenaltyFor(lqKey utilqueue.LocalQueueReference) bool {
+	return m.afsEntryPenalties.HasPendingFor(lqKey)
+}
+
+func (m *Manager) HasAnyEntryPenalty() bool {
+	return m.afsEntryPenalties.HasAny()
+}
+
+func (m *Manager) GetAfsEntryPenalties() *utilmaps.SyncMap[utilqueue.LocalQueueReference, corev1.ResourceList] {
+	return m.afsEntryPenalties.GetPenalties()
+}
+
+type WorkloadUpdateWatcher interface {
+	NotifyWorkloadUpdate(oldWl, newWl *kueue.Workload)
+}
+
+func (m *Manager) NotifyWorkloadUpdateWatchers(oldWorkload, newWorkload *kueue.Workload) {
+	for _, watcher := range m.workloadUpdateWatchers {
+		watcher.NotifyWorkloadUpdate(oldWorkload, newWorkload)
+	}
+}
+
+func (m *Manager) AddWorkloadUpdateWatcher(watcher WorkloadUpdateWatcher) {
+	m.workloadUpdateWatchers = append(m.workloadUpdateWatchers, watcher)
+}
diff --git a/pkg/scheduler/scheduler.go b/pkg/scheduler/scheduler.go
index bca54f904..4ad72da2d 100644
--- a/pkg/scheduler/scheduler.go
+++ b/pkg/scheduler/scheduler.go
@@ -48,8 +48,10 @@ import (
 	"sigs.k8s.io/kueue/pkg/resources"
 	"sigs.k8s.io/kueue/pkg/scheduler/flavorassigner"
 	"sigs.k8s.io/kueue/pkg/scheduler/preemption"
+	afs "sigs.k8s.io/kueue/pkg/util/admissionfairsharing"
 	"sigs.k8s.io/kueue/pkg/util/api"
 	"sigs.k8s.io/kueue/pkg/util/priority"
+	utilqueue "sigs.k8s.io/kueue/pkg/util/queue"
 	"sigs.k8s.io/kueue/pkg/util/routine"
 	"sigs.k8s.io/kueue/pkg/util/wait"
 	"sigs.k8s.io/kueue/pkg/workload"
@@ -75,6 +77,7 @@ type Scheduler struct {
 	preemptor               *preemption.Preemptor
 	workloadOrdering        workload.Ordering
 	fairSharing             config.FairSharing
+	admissionFairSharing    *config.AdmissionFairSharing
 	clock                   clock.Clock
 
 	// schedulingCycle identifies the number of scheduling
@@ -88,6 +91,7 @@ type Scheduler struct {
 type options struct {
 	podsReadyRequeuingTimestamp config.RequeuingTimestamp
 	fairSharing                 config.FairSharing
+	admissionFairSharing        *config.AdmissionFairSharing
 	clock                       clock.Clock
 }
 
@@ -115,6 +119,12 @@ func WithFairSharing(fs *config.FairSharing) Option {
 	}
 }
 
+func WithAdmissionFairSharing(afs *config.AdmissionFairSharing) Option {
+	return func(o *options) {
+		o.admissionFairSharing = afs
+	}
+}
+
 func WithClock(_ testing.TB, c clock.Clock) Option {
 	return func(o *options) {
 		o.clock = c
@@ -139,6 +149,7 @@ func New(queues *queue.Manager, cache *cache.Cache, cl client.Client, recorder r
 		admissionRoutineWrapper: routine.DefaultWrapper,
 		workloadOrdering:        wo,
 		clock:                   options.clock,
+		admissionFairSharing:    options.admissionFairSharing,
 	}
 	s.applyAdmission = s.applyAdmissionWithSSA
 	return s
@@ -183,6 +194,12 @@ func (s *Scheduler) schedule(ctx context.Context) wait.SpeedSignal {
 	log := ctrl.LoggerFrom(ctx).WithValues("schedulingCycle", s.schedulingCycle)
 	ctx = ctrl.LoggerInto(ctx, log)
 
+	snapshotOpts := make([]cache.SnapshotOption, 0)
+	if features.Enabled(features.AdmissionFairSharing) && s.queues.HasAnyEntryPenalty() {
+		s.queues.HeapifyAllClusterQueues()
+		snapshotOpts = append(snapshotOpts, cache.WithAfsEntryPenalties(s.queues.GetAfsEntryPenalties()))
+	}
+
 	// 1. Get the heads from the queues, including their desired clusterQueue.
 	// This operation blocks while the queues are empty.
 	headWorkloads := s.queues.Heads(ctx)
@@ -193,7 +210,7 @@ func (s *Scheduler) schedule(ctx context.Context) wait.SpeedSignal {
 	startTime := s.clock.Now()
 
 	// 2. Take a snapshot of the cache.
-	snapshot, err := s.cache.Snapshot(ctx)
+	snapshot, err := s.cache.Snapshot(ctx, snapshotOpts...)
 	if err != nil {
 		log.Error(err, "failed to build snapshot for scheduling")
 		return wait.SlowDown
@@ -605,6 +622,13 @@ func (s *Scheduler) admit(ctx context.Context, e *entry, cq *cache.ClusterQueueS
 	e.status = assumed
 	log.V(2).Info("Workload assumed in the cache")
 
+	if features.Enabled(features.AdmissionFairSharing) {
+		s.addEntryPenaltyToLq(log, e)
+
+		// Trigger LocalQueue reconciler to apply any pending penalties
+		s.queues.NotifyWorkloadUpdateWatchers(e.Obj, newWorkload)
+	}
+
 	s.admissionRoutineWrapper.Run(func() {
 		err := s.applyAdmission(ctx, newWorkload)
 		if err == nil {
@@ -617,6 +641,9 @@ func (s *Scheduler) admit(ctx context.Context, e *entry, cq *cache.ClusterQueueS
 		// Ignore errors because the workload or clusterQueue could have been deleted
 		// by an event.
 		_ = s.cache.ForgetWorkload(log, newWorkload)
+		if features.Enabled(features.AdmissionFairSharing) {
+			s.subEntryPenaltyToLq(log, e)
+		}
 		if apierrors.IsNotFound(err) {
 			log.V(2).Info("Workload not admitted because it was deleted")
 			return
@@ -824,3 +851,19 @@ func (s *Scheduler) replaceWorkloadSlice(ctx context.Context, oldQueue kueue.Clu
 	metrics.ReportReplacedWorkloadSlices(oldQueue)
 	return nil
 }
+
+func (s *Scheduler) addEntryPenaltyToLq(log logr.Logger, e *entry) {
+	lqKey := utilqueue.NewLocalQueueReference(e.Obj.Namespace, e.Obj.Spec.QueueName)
+	penalty := afs.CalculateEntryPenalty(e.SumTotalRequests(), s.admissionFairSharing)
+	s.queues.PushEntryPenalty(lqKey, penalty)
+
+	log.V(3).Info("Entry penalty added to lq", "lqKey", lqKey, "penalty", penalty)
+}
+
+func (s *Scheduler) subEntryPenaltyToLq(log logr.Logger, e *entry) {
+	lqKey := utilqueue.NewLocalQueueReference(e.Obj.Namespace, e.Obj.Spec.QueueName)
+	penalty := afs.CalculateEntryPenalty(e.SumTotalRequests(), s.admissionFairSharing)
+	s.queues.SubEntryPenalty(lqKey, penalty)
+
+	log.V(3).Info("Entry penalty subtracted from lq", "lqKey", lqKey, "penalty", penalty)
+}
diff --git a/pkg/util/admissionfairsharing/admission_fair_sharing.go b/pkg/util/admissionfairsharing/admission_fair_sharing.go
index 143c6f93e..ef2a873a4 100644
--- a/pkg/util/admissionfairsharing/admission_fair_sharing.go
+++ b/pkg/util/admissionfairsharing/admission_fair_sharing.go
@@ -17,11 +17,14 @@ limitations under the License.
 package admissionfairsharing
 
 import (
+	"math"
+
 	corev1 "k8s.io/api/core/v1"
 
 	config "sigs.k8s.io/kueue/apis/config/v1beta1"
 	kueue "sigs.k8s.io/kueue/apis/kueue/v1beta1"
 	"sigs.k8s.io/kueue/pkg/features"
+	"sigs.k8s.io/kueue/pkg/util/resource"
 )
 
 func ResourceWeights(cqAdmissionScope *kueue.AdmissionScope, afsConfig *config.AdmissionFairSharing) (bool, map[corev1.ResourceName]float64) {
@@ -32,3 +35,20 @@ func ResourceWeights(cqAdmissionScope *kueue.AdmissionScope, afsConfig *config.A
 	}
 	return enableAdmissionFs, fsResWeights
 }
+
+func CalculateAlphaRate(sampling, halfLifeTime float64) float64 {
+	if halfLifeTime == 0 {
+		return 0.0
+	}
+
+	return 1.0 - math.Pow(0.5, sampling/halfLifeTime)
+}
+
+func CalculateEntryPenalty(totalRequests corev1.ResourceList, afs *config.AdmissionFairSharing) corev1.ResourceList {
+	alpha := CalculateAlphaRate(
+		afs.UsageSamplingInterval.Seconds(),
+		afs.UsageHalfLifeTime.Seconds(),
+	)
+
+	return resource.MulByFloat(totalRequests, alpha)
+}
diff --git a/pkg/util/queue/local_queue.go b/pkg/util/queue/local_queue.go
new file mode 100644
index 000000000..04cf1a691
--- /dev/null
+++ b/pkg/util/queue/local_queue.go
@@ -0,0 +1,29 @@
+// 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 queue
+
+import (
+	kueue "sigs.k8s.io/kueue/apis/kueue/v1beta1"
+)
+
+type LocalQueueReference string
+
+func NewLocalQueueReference(namespace string, name kueue.LocalQueueName) LocalQueueReference {
+	return LocalQueueReference(namespace + "/" + string(name))
+}
+
+func Key(q *kueue.LocalQueue) LocalQueueReference {
+	return NewLocalQueueReference(q.Namespace, kueue.LocalQueueName(q.Name))
+}
diff --git a/pkg/workload/workload.go b/pkg/workload/workload.go
index a4eddf51c..07f8ca411 100644
--- a/pkg/workload/workload.go
+++ b/pkg/workload/workload.go
@@ -49,7 +49,9 @@ import (
 	"sigs.k8s.io/kueue/pkg/resources"
 	"sigs.k8s.io/kueue/pkg/util/api"
 	clientutil "sigs.k8s.io/kueue/pkg/util/client"
+	utilmaps "sigs.k8s.io/kueue/pkg/util/maps"
 	utilptr "sigs.k8s.io/kueue/pkg/util/ptr"
+	utilqueue "sigs.k8s.io/kueue/pkg/util/queue"
 	utilslices "sigs.k8s.io/kueue/pkg/util/slices"
 )
 
@@ -300,7 +302,7 @@ func dropExcludedResources(input corev1.ResourceList, excludedPrefixes []string)
 	return res
 }
 
-func (i *Info) CalcLocalQueueFSUsage(ctx context.Context, c client.Client, resWeights map[corev1.ResourceName]float64) (float64, error) {
+func (i *Info) CalcLocalQueueFSUsage(ctx context.Context, c client.Client, resWeights map[corev1.ResourceName]float64, penalties *utilmaps.SyncMap[utilqueue.LocalQueueReference, corev1.ResourceList]) (float64, error) {
 	var lq kueue.LocalQueue
 	lqKey := client.ObjectKey{Namespace: i.Obj.Namespace, Name: string(i.Obj.Spec.QueueName)}
 	if err := c.Get(ctx, lqKey, &lq); err != nil {
@@ -318,6 +320,18 @@ func (i *Info) CalcLocalQueueFSUsage(ctx context.Context, c client.Client, resWe
 		}
 		usage += weight * resVal.AsApproximateFloat64()
 	}
+	penalty := corev1.ResourceList{}
+	if penalties != nil {
+		penalty, _ = penalties.Get(utilqueue.Key(&lq))
+	}
+	for resName, penaltyVal := range penalty {
+		weight, found := resWeights[resName]
+		if !found {
+			weight = 1
+		}
+		usage += weight * penaltyVal.AsApproximateFloat64()
+	}
+
 	if lq.Spec.FairSharing != nil && lq.Spec.FairSharing.Weight != nil {
 		// if no weight for lq was defined, use default weight of 1
 		usage /= lq.Spec.FairSharing.Weight.AsApproximateFloat64()
@@ -361,6 +375,14 @@ func (i *Info) TASUsage() TASUsage {
 	return result
 }
 
+func (i *Info) SumTotalRequests() corev1.ResourceList {
+	reqs := make(resources.Requests)
+	for _, psReqs := range i.TotalRequests {
+		reqs.Add(psReqs.Requests)
+	}
+	return reqs.ToResourceList()
+}
+
 func applyResourceTransformations(input corev1.ResourceList, transforms map[corev1.ResourceName]*config.ResourceTransformation) corev1.ResourceList {
 	match := false
 	for resourceName := range input {
diff --git a/site/content/zh-CN/docs/reference/kubectl-kueue/commands/kueuectl_delete/_index.md b/site/content/zh-CN/docs/reference/kubectl-kueue/commands/kueuectl_delete/_index.md
index 37b4b954f..8a573d258 100644
--- a/site/content/zh-CN/docs/reference/kubectl-kueue/commands/kueuectl_delete/_index.md
+++ b/site/content/zh-CN/docs/reference/kubectl-kueue/commands/kueuectl_delete/_index.md
@@ -5,18 +5,13 @@ auto_generated: true
 no_list: true
 ---
 
-<!--
-The file is auto-generated from the Go source code of the component using the
-[generator](https://github.com/kubernetes-sigs/kueue/tree/main/cmd/kueuectl-docs).
--->
+## 概要 {#synopsis}
 
-## Synopsis
 
+删除资源
 
-Delete a resource
 
-
-## Options
+## 选项 {#options}
 
 
 <table style="width: 100%; table-layout: fixed;">
@@ -31,7 +26,7 @@ Delete a resource
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>help for delete</p>
+            <p>delete 命令的帮助信息</p>
         </td>
     </tr>
     </tbody>
@@ -39,7 +34,7 @@ Delete a resource
 
 
 
-## Options inherited from parent commands
+## 从父命令继承的选项 {#options-inherited-from-parent-commands}
 <table style="width: 100%; table-layout: fixed;">
     <colgroup>
         <col span="1" style="width: 10px;" />
@@ -52,7 +47,7 @@ Delete a resource
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Username to impersonate for the operation. User could be a regular user or a service account in a namespace.</p>
+            <p>为操作模拟的用户名。用户可以是普通用户或命名空间中的服务账户。</p>
         </td>
     </tr>
     <tr>
@@ -61,7 +56,7 @@ Delete a resource
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Group to impersonate for the operation, this flag can be repeated to specify multiple groups.</p>
+            <p>为操作模拟的组，此标志可以重复使用，以指定多个组。</p>
         </td>
     </tr>
     <tr>
@@ -70,7 +65,7 @@ Delete a resource
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>UID to impersonate for the operation.</p>
+            <p>为操作模拟的 UID。</p>
         </td>
     </tr>
     <tr>
@@ -79,7 +74,7 @@ Delete a resource
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Default cache directory</p>
+            <p>默认缓存目录</p>
         </td>
     </tr>
     <tr>
@@ -88,7 +83,7 @@ Delete a resource
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Path to a cert file for the certificate authority</p>
+            <p>证书颁发机构证书文件的路径</p>
         </td>
     </tr>
     <tr>
@@ -97,7 +92,7 @@ Delete a resource
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Path to a client certificate file for TLS</p>
+            <p>TLS 客户端证书文件的路径</p>
         </td>
     </tr>
     <tr>
@@ -106,7 +101,7 @@ Delete a resource
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Path to a client key file for TLS</p>
+            <p>TLS 客户端密钥文件的路径</p>
         </td>
     </tr>
     <tr>
@@ -115,7 +110,7 @@ Delete a resource
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>The name of the kubeconfig cluster to use</p>
+            <p>要使用的 kubeconfig 集群的名称</p>
         </td>
     </tr>
     <tr>
@@ -124,7 +119,7 @@ Delete a resource
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>The name of the kubeconfig context to use</p>
+            <p>要使用的 kubeconfig 上下文的名称</p>
         </td>
     </tr>
     <tr>
@@ -133,7 +128,7 @@ Delete a resource
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>If true, opt-out of response compression for all requests to the server</p>
+            <p>如果为 true，则取消对所有服务器请求的响应压缩</p>
         </td>
     </tr>
     <tr>
@@ -142,7 +137,7 @@ Delete a resource
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>If true, the server&#39;s certificate will not be checked for validity. This will make your HTTPS connections insecure</p>
+            <p>如果为 true，将不检查服务器证书的有效性。这将使你的 HTTPS 连接不安全</p>
         </td>
     </tr>
     <tr>
@@ -151,7 +146,7 @@ Delete a resource
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Path to the kubeconfig file to use for CLI requests.</p>
+            <p>用于 CLI 请求的 kubeconfig 文件路径。</p>
         </td>
     </tr>
     <tr>
@@ -160,16 +155,16 @@ Delete a resource
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>If present, the namespace scope for this CLI request</p>
+            <p>如果存在，则为此次 CLI 请求的命名空间范围</p>
         </td>
     </tr>
     <tr>
-        <td colspan="2">--request-timeout string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Default: &#34;0&#34;</td>
+        <td colspan="2">--request-timeout string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;默认值: &#34;0&#34;</td>
     </tr>
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don&#39;t timeout requests.</p>
+            <p>在放弃单个服务器请求之前等待的时间长度。非零值应包含相应的时间单位（例如 1s、2m、3h）。零值表示不超时请求。</p>
         </td>
     </tr>
     <tr>
@@ -178,7 +173,7 @@ Delete a resource
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>The address and port of the Kubernetes API server</p>
+            <p>Kubernetes API 服务器的地址和端口</p>
         </td>
     </tr>
     <tr>
@@ -187,7 +182,7 @@ Delete a resource
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used</p>
+            <p>用于服务器证书验证的服务器名称。如果未提供，则使用联系服务器所用的主机名</p>
         </td>
     </tr>
     <tr>
@@ -196,7 +191,7 @@ Delete a resource
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Bearer token for authentication to the API server</p>
+            <p>API 服务器身份验证所用的持有者令牌</p>
         </td>
     </tr>
     <tr>
@@ -205,7 +200,7 @@ Delete a resource
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>The name of the kubeconfig user to use</p>
+            <p>要使用的 kubeconfig 用户的名称</p>
         </td>
     </tr>
     </tbody>
@@ -213,11 +208,11 @@ Delete a resource
 
 
 
-## See Also
+## 另请参阅 {#see-also}
 
-* [kueuectl](../kueuectl/)	 - Controls Kueue queueing manager
-* [kueuectl delete clusterqueue](kueuectl_delete_clusterqueue/)	 - Pass-through &#34;delete clusterqueue&#34; to kubectl
-* [kueuectl delete localqueue](kueuectl_delete_localqueue/)	 - Pass-through &#34;delete localqueue&#34; to kubectl
-* [kueuectl delete resourceflavor](kueuectl_delete_resourceflavor/)	 - Pass-through &#34;delete resourceflavor&#34; to kubectl
-* [kueuectl delete workload](kueuectl_delete_workload/)	 - Delete the given Workload and its corresponding Job
+* [kueuectl](../kueuectl/) - 控制 Kueue 队列管理器
+* [kueuectl delete clusterqueue](kueuectl_delete_clusterqueue/) - 将"delete clusterqueue"透传给 kubectl
+* [kueuectl delete localqueue](kueuectl_delete_localqueue/) - 将"delete localqueue"透传给 kubectl
+* [kueuectl delete resourceflavor](kueuectl_delete_resourceflavor/) - 将"delete resourceflavor"透传给 kubectl
+* [kueuectl delete workload](kueuectl_delete_workload/) - 删除给定的 Workload 及其对应的 Job
 
diff --git a/site/content/zh-CN/docs/reference/kubectl-kueue/commands/kueuectl_delete/kueuectl_delete_clusterqueue.md b/site/content/zh-CN/docs/reference/kubectl-kueue/commands/kueuectl_delete/kueuectl_delete_clusterqueue.md
index b63e0f0af..0e47d750b 100644
--- a/site/content/zh-CN/docs/reference/kubectl-kueue/commands/kueuectl_delete/kueuectl_delete_clusterqueue.md
+++ b/site/content/zh-CN/docs/reference/kubectl-kueue/commands/kueuectl_delete/kueuectl_delete_clusterqueue.md
@@ -5,22 +5,17 @@ auto_generated: true
 no_list: false
 ---
 
-<!--
-The file is auto-generated from the Go source code of the component using the
-[generator](https://github.com/kubernetes-sigs/kueue/tree/main/cmd/kueuectl-docs).
--->
+## 概要 {#synopsis}
 
-## Synopsis
 
-
-Pass-through &#34;delete clusterqueue&#34; to kubectl
+将"delete clusterqueue"透传给 kubectl
 
 ```
 kueuectl delete clusterqueue [flags]
 ```
 
 
-## Options
+## 选项 {#options}
 
 
 <table style="width: 100%; table-layout: fixed;">
@@ -35,7 +30,7 @@ kueuectl delete clusterqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>help for clusterqueue</p>
+            <p>clusterqueue 命令的帮助信息</p>
         </td>
     </tr>
     </tbody>
@@ -43,7 +38,7 @@ kueuectl delete clusterqueue [flags]
 
 
 
-## Options inherited from parent commands
+## 从父命令继承的选项 {#options-inherited-from-parent-commands}
 <table style="width: 100%; table-layout: fixed;">
     <colgroup>
         <col span="1" style="width: 10px;" />
@@ -56,7 +51,7 @@ kueuectl delete clusterqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Username to impersonate for the operation. User could be a regular user or a service account in a namespace.</p>
+            <p>为操作模拟的用户名。用户可以是普通用户或命名空间中的服务账户。</p>
         </td>
     </tr>
     <tr>
@@ -65,7 +60,7 @@ kueuectl delete clusterqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Group to impersonate for the operation, this flag can be repeated to specify multiple groups.</p>
+            <p>为操作模拟的组，此标志可以重复使用，以指定多个组。</p>
         </td>
     </tr>
     <tr>
@@ -74,7 +69,7 @@ kueuectl delete clusterqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>UID to impersonate for the operation.</p>
+            <p>为操作模拟的 UID。</p>
         </td>
     </tr>
     <tr>
@@ -83,7 +78,7 @@ kueuectl delete clusterqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Default cache directory</p>
+            <p>默认缓存目录</p>
         </td>
     </tr>
     <tr>
@@ -92,7 +87,7 @@ kueuectl delete clusterqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Path to a cert file for the certificate authority</p>
+            <p>证书颁发机构证书文件的路径</p>
         </td>
     </tr>
     <tr>
@@ -101,7 +96,7 @@ kueuectl delete clusterqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Path to a client certificate file for TLS</p>
+            <p>TLS 客户端证书文件的路径</p>
         </td>
     </tr>
     <tr>
@@ -110,7 +105,7 @@ kueuectl delete clusterqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Path to a client key file for TLS</p>
+            <p>TLS 客户端密钥文件的路径</p>
         </td>
     </tr>
     <tr>
@@ -119,7 +114,7 @@ kueuectl delete clusterqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>The name of the kubeconfig cluster to use</p>
+            <p>要使用的 kubeconfig 集群的名称</p>
         </td>
     </tr>
     <tr>
@@ -128,7 +123,7 @@ kueuectl delete clusterqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>The name of the kubeconfig context to use</p>
+            <p>要使用的 kubeconfig 上下文的名称</p>
         </td>
     </tr>
     <tr>
@@ -137,7 +132,7 @@ kueuectl delete clusterqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>If true, opt-out of response compression for all requests to the server</p>
+            <p>如果为 true，则取消对所有服务器请求的响应压缩</p>
         </td>
     </tr>
     <tr>
@@ -146,7 +141,7 @@ kueuectl delete clusterqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>If true, the server&#39;s certificate will not be checked for validity. This will make your HTTPS connections insecure</p>
+            <p>如果为 true，将不检查服务器证书的有效性。这将使你的 HTTPS 连接不安全</p>
         </td>
     </tr>
     <tr>
@@ -155,7 +150,7 @@ kueuectl delete clusterqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Path to the kubeconfig file to use for CLI requests.</p>
+            <p>用于 CLI 请求的 kubeconfig 文件路径。</p>
         </td>
     </tr>
     <tr>
@@ -164,16 +159,16 @@ kueuectl delete clusterqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>If present, the namespace scope for this CLI request</p>
+            <p>如果存在，则为此次 CLI 请求的命名空间范围</p>
         </td>
     </tr>
     <tr>
-        <td colspan="2">--request-timeout string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Default: &#34;0&#34;</td>
+        <td colspan="2">--request-timeout string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;默认值: &#34;0&#34;</td>
     </tr>
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don&#39;t timeout requests.</p>
+            <p>在放弃单个服务器请求之前等待的时间长度。非零值应包含相应的时间单位（例如 1s、2m、3h）。零值表示不超时请求。</p>
         </td>
     </tr>
     <tr>
@@ -182,7 +177,7 @@ kueuectl delete clusterqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>The address and port of the Kubernetes API server</p>
+            <p>Kubernetes API 服务器的地址和端口</p>
         </td>
     </tr>
     <tr>
@@ -191,7 +186,7 @@ kueuectl delete clusterqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used</p>
+            <p>用于服务器证书验证的服务器名称。如果未提供，则使用联系服务器所用的主机名</p>
         </td>
     </tr>
     <tr>
@@ -200,7 +195,7 @@ kueuectl delete clusterqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Bearer token for authentication to the API server</p>
+            <p>API 服务器身份验证所用的持有者令牌</p>
         </td>
     </tr>
     <tr>
@@ -209,7 +204,7 @@ kueuectl delete clusterqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>The name of the kubeconfig user to use</p>
+            <p>要使用的 kubeconfig 用户的名称</p>
         </td>
     </tr>
     </tbody>
@@ -217,7 +212,7 @@ kueuectl delete clusterqueue [flags]
 
 
 
-## See Also
+## 另请参阅 {#see-also}
 
-* [kueuectl delete](../)	 - Delete a resource
+* [kueuectl delete](../) - 删除资源
 
diff --git a/site/content/zh-CN/docs/reference/kubectl-kueue/commands/kueuectl_delete/kueuectl_delete_localqueue.md b/site/content/zh-CN/docs/reference/kubectl-kueue/commands/kueuectl_delete/kueuectl_delete_localqueue.md
index 0e6ca50db..267e08191 100644
--- a/site/content/zh-CN/docs/reference/kubectl-kueue/commands/kueuectl_delete/kueuectl_delete_localqueue.md
+++ b/site/content/zh-CN/docs/reference/kubectl-kueue/commands/kueuectl_delete/kueuectl_delete_localqueue.md
@@ -5,22 +5,17 @@ auto_generated: true
 no_list: false
 ---
 
-<!--
-The file is auto-generated from the Go source code of the component using the
-[generator](https://github.com/kubernetes-sigs/kueue/tree/main/cmd/kueuectl-docs).
--->
+## 概要 {#synopsis}
 
-## Synopsis
 
-
-Pass-through &#34;delete localqueue&#34; to kubectl
+将"delete localqueue"透传给 kubectl
 
 ```
 kueuectl delete localqueue [flags]
 ```
 
 
-## Options
+## 选项 {#options}
 
 
 <table style="width: 100%; table-layout: fixed;">
@@ -35,7 +30,7 @@ kueuectl delete localqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>help for localqueue</p>
+            <p>localqueue 命令的帮助信息</p>
         </td>
     </tr>
     </tbody>
@@ -43,7 +38,7 @@ kueuectl delete localqueue [flags]
 
 
 
-## Options inherited from parent commands
+## 从父命令继承的选项 {#options-inherited-from-parent-commands}
 <table style="width: 100%; table-layout: fixed;">
     <colgroup>
         <col span="1" style="width: 10px;" />
@@ -56,7 +51,7 @@ kueuectl delete localqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Username to impersonate for the operation. User could be a regular user or a service account in a namespace.</p>
+            <p>为操作模拟的用户名。用户可以是普通用户或命名空间中的服务账户。</p>
         </td>
     </tr>
     <tr>
@@ -65,7 +60,7 @@ kueuectl delete localqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Group to impersonate for the operation, this flag can be repeated to specify multiple groups.</p>
+            <p>为操作模拟的组，此标志可以重复使用，以指定多个组。</p>
         </td>
     </tr>
     <tr>
@@ -74,7 +69,7 @@ kueuectl delete localqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>UID to impersonate for the operation.</p>
+            <p>为操作模拟的 UID。</p>
         </td>
     </tr>
     <tr>
@@ -83,7 +78,7 @@ kueuectl delete localqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Default cache directory</p>
+            <p>默认缓存目录</p>
         </td>
     </tr>
     <tr>
@@ -92,7 +87,7 @@ kueuectl delete localqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Path to a cert file for the certificate authority</p>
+            <p>证书颁发机构证书文件的路径</p>
         </td>
     </tr>
     <tr>
@@ -101,7 +96,7 @@ kueuectl delete localqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Path to a client certificate file for TLS</p>
+            <p>TLS 客户端证书文件的路径</p>
         </td>
     </tr>
     <tr>
@@ -110,7 +105,7 @@ kueuectl delete localqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Path to a client key file for TLS</p>
+            <p>TLS 客户端密钥文件的路径</p>
         </td>
     </tr>
     <tr>
@@ -119,7 +114,7 @@ kueuectl delete localqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>The name of the kubeconfig cluster to use</p>
+            <p>要使用的 kubeconfig 集群的名称</p>
         </td>
     </tr>
     <tr>
@@ -128,7 +123,7 @@ kueuectl delete localqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>The name of the kubeconfig context to use</p>
+            <p>要使用的 kubeconfig 上下文的名称</p>
         </td>
     </tr>
     <tr>
@@ -137,7 +132,7 @@ kueuectl delete localqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>If true, opt-out of response compression for all requests to the server</p>
+            <p>如果为 true，则取消对所有服务器请求的响应压缩</p>
         </td>
     </tr>
     <tr>
@@ -146,7 +141,7 @@ kueuectl delete localqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>If true, the server&#39;s certificate will not be checked for validity. This will make your HTTPS connections insecure</p>
+            <p>如果为 true，将不检查服务器证书的有效性。这将使你的 HTTPS 连接不安全</p>
         </td>
     </tr>
     <tr>
@@ -155,7 +150,7 @@ kueuectl delete localqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Path to the kubeconfig file to use for CLI requests.</p>
+            <p>用于 CLI 请求的 kubeconfig 文件路径。</p>
         </td>
     </tr>
     <tr>
@@ -164,7 +159,7 @@ kueuectl delete localqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>If present, the namespace scope for this CLI request</p>
+            <p>如果存在，则为此次 CLI 请求的命名空间范围</p>
         </td>
     </tr>
     <tr>
@@ -173,7 +168,7 @@ kueuectl delete localqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don&#39;t timeout requests.</p>
+            <p>在放弃单个服务器请求之前等待的时间长度。非零值应包含相应的时间单位（例如 1s、2m、3h）。零值表示不超时请求。</p>
         </td>
     </tr>
     <tr>
@@ -182,7 +177,7 @@ kueuectl delete localqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>The address and port of the Kubernetes API server</p>
+            <p>Kubernetes API 服务器的地址和端口</p>
         </td>
     </tr>
     <tr>
@@ -191,7 +186,7 @@ kueuectl delete localqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used</p>
+            <p>用于服务器证书验证的服务器名称。如果未提供，则使用联系服务器所用的主机名</p>
         </td>
     </tr>
     <tr>
@@ -200,7 +195,7 @@ kueuectl delete localqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Bearer token for authentication to the API server</p>
+            <p>API 服务器身份验证所用的持有者令牌</p>
         </td>
     </tr>
     <tr>
@@ -209,7 +204,7 @@ kueuectl delete localqueue [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>The name of the kubeconfig user to use</p>
+            <p>要使用的 kubeconfig 用户的名称</p>
         </td>
     </tr>
     </tbody>
@@ -217,7 +212,7 @@ kueuectl delete localqueue [flags]
 
 
 
-## See Also
+## 另请参阅 {#see-also}
 
-* [kueuectl delete](../)	 - Delete a resource
+* [kueuectl delete](../) - 删除资源
 
diff --git a/site/content/zh-CN/docs/reference/kubectl-kueue/commands/kueuectl_delete/kueuectl_delete_resourceflavor.md b/site/content/zh-CN/docs/reference/kubectl-kueue/commands/kueuectl_delete/kueuectl_delete_resourceflavor.md
index e8e6c930e..97e9cb44d 100644
--- a/site/content/zh-CN/docs/reference/kubectl-kueue/commands/kueuectl_delete/kueuectl_delete_resourceflavor.md
+++ b/site/content/zh-CN/docs/reference/kubectl-kueue/commands/kueuectl_delete/kueuectl_delete_resourceflavor.md
@@ -5,22 +5,17 @@ auto_generated: true
 no_list: false
 ---
 
-<!--
-The file is auto-generated from the Go source code of the component using the
-[generator](https://github.com/kubernetes-sigs/kueue/tree/main/cmd/kueuectl-docs).
--->
+## 概要 {#synopsis}
 
-## Synopsis
 
-
-Pass-through &#34;delete resourceflavor&#34; to kubectl
+将"delete resourceflavor"透传给 kubectl
 
 ```
 kueuectl delete resourceflavor [flags]
 ```
 
 
-## Options
+## 选项 {#options}
 
 
 <table style="width: 100%; table-layout: fixed;">
@@ -35,7 +30,7 @@ kueuectl delete resourceflavor [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>help for resourceflavor</p>
+            <p>resourceflavor 命令的帮助信息</p>
         </td>
     </tr>
     </tbody>
@@ -43,7 +38,7 @@ kueuectl delete resourceflavor [flags]
 
 
 
-## Options inherited from parent commands
+## 从父命令继承的选项 {#options-inherited-from-parent-commands}
 <table style="width: 100%; table-layout: fixed;">
     <colgroup>
         <col span="1" style="width: 10px;" />
@@ -56,7 +51,7 @@ kueuectl delete resourceflavor [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Username to impersonate for the operation. User could be a regular user or a service account in a namespace.</p>
+            <p>为操作模拟的用户名。用户可以是普通用户或命名空间中的服务账户。</p>
         </td>
     </tr>
     <tr>
@@ -65,7 +60,7 @@ kueuectl delete resourceflavor [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Group to impersonate for the operation, this flag can be repeated to specify multiple groups.</p>
+            <p>为操作模拟的组，此标志可以重复使用，以指定多个组。</p>
         </td>
     </tr>
     <tr>
@@ -74,7 +69,7 @@ kueuectl delete resourceflavor [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>UID to impersonate for the operation.</p>
+            <p>为操作模拟的 UID。</p>
         </td>
     </tr>
     <tr>
@@ -83,7 +78,7 @@ kueuectl delete resourceflavor [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Default cache directory</p>
+            <p>默认缓存目录</p>
         </td>
     </tr>
     <tr>
@@ -92,7 +87,7 @@ kueuectl delete resourceflavor [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Path to a cert file for the certificate authority</p>
+            <p>证书颁发机构证书文件的路径</p>
         </td>
     </tr>
     <tr>
@@ -101,7 +96,7 @@ kueuectl delete resourceflavor [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Path to a client certificate file for TLS</p>
+            <p>TLS 客户端证书文件的路径</p>
         </td>
     </tr>
     <tr>
@@ -110,7 +105,7 @@ kueuectl delete resourceflavor [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Path to a client key file for TLS</p>
+            <p>TLS 客户端密钥文件的路径</p>
         </td>
     </tr>
     <tr>
@@ -119,7 +114,7 @@ kueuectl delete resourceflavor [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>The name of the kubeconfig cluster to use</p>
+            <p>要使用的 kubeconfig 集群的名称</p>
         </td>
     </tr>
     <tr>
@@ -128,7 +123,7 @@ kueuectl delete resourceflavor [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>The name of the kubeconfig context to use</p>
+            <p>要使用的 kubeconfig 上下文的名称</p>
         </td>
     </tr>
     <tr>
@@ -137,7 +132,7 @@ kueuectl delete resourceflavor [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>If true, opt-out of response compression for all requests to the server</p>
+            <p>如果为 true，则取消对所有服务器请求的响应压缩</p>
         </td>
     </tr>
     <tr>
@@ -146,7 +141,7 @@ kueuectl delete resourceflavor [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>If true, the server&#39;s certificate will not be checked for validity. This will make your HTTPS connections insecure</p>
+            <p>如果为 true，将不检查服务器证书的有效性。这将使你的 HTTPS 连接不安全</p>
         </td>
     </tr>
     <tr>
@@ -155,7 +150,7 @@ kueuectl delete resourceflavor [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Path to the kubeconfig file to use for CLI requests.</p>
+            <p>用于 CLI 请求的 kubeconfig 文件路径。</p>
         </td>
     </tr>
     <tr>
@@ -164,7 +159,7 @@ kueuectl delete resourceflavor [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>If present, the namespace scope for this CLI request</p>
+            <p>如果存在，则为此次 CLI 请求的命名空间范围</p>
         </td>
     </tr>
     <tr>
@@ -173,7 +168,7 @@ kueuectl delete resourceflavor [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don&#39;t timeout requests.</p>
+            <p>在放弃单个服务器请求之前等待的时间长度。非零值应包含相应的时间单位（例如 1s、2m、3h）。零值表示不超时请求。</p>
         </td>
     </tr>
     <tr>
@@ -182,7 +177,7 @@ kueuectl delete resourceflavor [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>The address and port of the Kubernetes API server</p>
+            <p>Kubernetes API 服务器的地址和端口</p>
         </td>
     </tr>
     <tr>
@@ -191,7 +186,7 @@ kueuectl delete resourceflavor [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used</p>
+            <p>用于服务器证书验证的服务器名称。如果未提供，则使用联系服务器所用的主机名</p>
         </td>
     </tr>
     <tr>
@@ -200,7 +195,7 @@ kueuectl delete resourceflavor [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Bearer token for authentication to the API server</p>
+            <p>API 服务器身份验证所用的持有者令牌</p>
         </td>
     </tr>
     <tr>
@@ -209,7 +204,7 @@ kueuectl delete resourceflavor [flags]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>The name of the kubeconfig user to use</p>
+            <p>要使用的 kubeconfig 用户的名称</p>
         </td>
     </tr>
     </tbody>
@@ -217,7 +212,7 @@ kueuectl delete resourceflavor [flags]
 
 
 
-## See Also
+## 另请参阅 {#see-also}
 
-* [kueuectl delete](../)	 - Delete a resource
+* [kueuectl delete](../) - 删除资源
 
diff --git a/site/content/zh-CN/docs/reference/kubectl-kueue/commands/kueuectl_delete/kueuectl_delete_workload.md b/site/content/zh-CN/docs/reference/kubectl-kueue/commands/kueuectl_delete/kueuectl_delete_workload.md
index 7fc73be1c..7d7ed183f 100644
--- a/site/content/zh-CN/docs/reference/kubectl-kueue/commands/kueuectl_delete/kueuectl_delete_workload.md
+++ b/site/content/zh-CN/docs/reference/kubectl-kueue/commands/kueuectl_delete/kueuectl_delete_workload.md
@@ -5,30 +5,25 @@ auto_generated: true
 no_list: false
 ---
 
-<!--
-The file is auto-generated from the Go source code of the component using the
-[generator](https://github.com/kubernetes-sigs/kueue/tree/main/cmd/kueuectl-docs).
--->
+## 概要 {#synopsis}
 
-## Synopsis
 
-
-If the Workload has associated Jobs, the command will prompt for deletion approval of the affected Jobs, and delete them. The Workload will then be asynchronously deleted by the garbage collector. If there are no associated Jobs, the command will directly delete the Workload.
+如果 Workload 有关联的 Jobs，命令将提示删除受影响 Jobs 的批准，并删除它们。然后 Workload 将由垃圾收集器异步删除。如果没有关联的 Jobs，命令将直接删除 Workload。
 
 ```
 kueuectl delete workload NAME [--yes] [--all] [--dry-run STRATEGY]
 ```
 
 
-## Examples
+## 示例 {#examples}
 
 ```
-  # Delete the Workload
+  # 删除 Workload
   kueuectl delete workload my-workload
 ```
 
 
-## Options
+## 选项 {#options}
 
 
 <table style="width: 100%; table-layout: fixed;">
@@ -43,7 +38,7 @@ kueuectl delete workload NAME [--yes] [--all] [--dry-run STRATEGY]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Delete all Workloads, in the specified namespace.</p>
+            <p>删除指定命名空间中的所有 Workload。</p>
         </td>
     </tr>
     <tr>
@@ -52,7 +47,7 @@ kueuectl delete workload NAME [--yes] [--all] [--dry-run STRATEGY]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.</p>
+            <p>如果存在，则列出所有命名空间中的请求对象。即使使用--namespace 指定，当前上下文中的命名空间也会被忽略。</p>
         </td>
     </tr>
     <tr>
@@ -61,7 +56,7 @@ kueuectl delete workload NAME [--yes] [--all] [--dry-run STRATEGY]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Must be &#34;none&#34;, &#34;server&#34;, or &#34;client&#34;. If client strategy, only print the object that would be sent, without sending it. If server strategy, submit server-side request without persisting the resource.</p>
+            <p>必须是&#34;none&#34;、&#34;server&#34;或&#34;client&#34;。如果是客户端策略，只打印将要发送的对象，而不发送它。如果是服务器策略，提交服务器端请求而不持久化资源。</p>
         </td>
     </tr>
     <tr>
@@ -70,7 +65,7 @@ kueuectl delete workload NAME [--yes] [--all] [--dry-run STRATEGY]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>help for workload</p>
+            <p>workload 命令的帮助信息</p>
         </td>
     </tr>
     <tr>
@@ -79,7 +74,7 @@ kueuectl delete workload NAME [--yes] [--all] [--dry-run STRATEGY]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Automatic yes to the prompt for deleting the Workload.</p>
+            <p>自动确认删除 Workload 的提示。</p>
         </td>
     </tr>
     </tbody>
@@ -87,7 +82,7 @@ kueuectl delete workload NAME [--yes] [--all] [--dry-run STRATEGY]
 
 
 
-## Options inherited from parent commands
+## 从父命令继承的选项 {#options-inherited-from-parent-commands}
 <table style="width: 100%; table-layout: fixed;">
     <colgroup>
         <col span="1" style="width: 10px;" />
@@ -100,7 +95,7 @@ kueuectl delete workload NAME [--yes] [--all] [--dry-run STRATEGY]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Username to impersonate for the operation. User could be a regular user or a service account in a namespace.</p>
+            <p>为操作模拟的用户名。用户可以是普通用户或命名空间中的服务账户。</p>
         </td>
     </tr>
     <tr>
@@ -109,7 +104,7 @@ kueuectl delete workload NAME [--yes] [--all] [--dry-run STRATEGY]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Group to impersonate for the operation, this flag can be repeated to specify multiple groups.</p>
+            <p>为操作模拟的组，此标志可以重复使用，以指定多个组。</p>
         </td>
     </tr>
     <tr>
@@ -118,7 +113,7 @@ kueuectl delete workload NAME [--yes] [--all] [--dry-run STRATEGY]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>UID to impersonate for the operation.</p>
+            <p>为操作模拟的 UID。</p>
         </td>
     </tr>
     <tr>
@@ -127,7 +122,7 @@ kueuectl delete workload NAME [--yes] [--all] [--dry-run STRATEGY]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Default cache directory</p>
+            <p>默认缓存目录</p>
         </td>
     </tr>
     <tr>
@@ -136,7 +131,7 @@ kueuectl delete workload NAME [--yes] [--all] [--dry-run STRATEGY]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Path to a cert file for the certificate authority</p>
+            <p>证书颁发机构证书文件的路径</p>
         </td>
     </tr>
     <tr>
@@ -145,7 +140,7 @@ kueuectl delete workload NAME [--yes] [--all] [--dry-run STRATEGY]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Path to a client certificate file for TLS</p>
+            <p>TLS 客户端证书文件的路径</p>
         </td>
     </tr>
     <tr>
@@ -154,7 +149,7 @@ kueuectl delete workload NAME [--yes] [--all] [--dry-run STRATEGY]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Path to a client key file for TLS</p>
+            <p>TLS 客户端密钥文件的路径</p>
         </td>
     </tr>
     <tr>
@@ -163,7 +158,7 @@ kueuectl delete workload NAME [--yes] [--all] [--dry-run STRATEGY]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>The name of the kubeconfig cluster to use</p>
+            <p>要使用的 kubeconfig 集群的名称</p>
         </td>
     </tr>
     <tr>
@@ -172,7 +167,7 @@ kueuectl delete workload NAME [--yes] [--all] [--dry-run STRATEGY]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>The name of the kubeconfig context to use</p>
+            <p>要使用的 kubeconfig 上下文的名称</p>
         </td>
     </tr>
     <tr>
@@ -181,7 +176,7 @@ kueuectl delete workload NAME [--yes] [--all] [--dry-run STRATEGY]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>If true, opt-out of response compression for all requests to the server</p>
+            <p>如果为 true，则取消对所有服务器请求的响应压缩</p>
         </td>
     </tr>
     <tr>
@@ -190,7 +185,7 @@ kueuectl delete workload NAME [--yes] [--all] [--dry-run STRATEGY]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>If true, the server&#39;s certificate will not be checked for validity. This will make your HTTPS connections insecure</p>
+            <p>如果为 true，将不检查服务器证书的有效性。这将使你的 HTTPS 连接不安全</p>
         </td>
     </tr>
     <tr>
@@ -199,7 +194,7 @@ kueuectl delete workload NAME [--yes] [--all] [--dry-run STRATEGY]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Path to the kubeconfig file to use for CLI requests.</p>
+            <p>用于 CLI 请求的 kubeconfig 文件路径。</p>
         </td>
     </tr>
     <tr>
@@ -208,16 +203,16 @@ kueuectl delete workload NAME [--yes] [--all] [--dry-run STRATEGY]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>If present, the namespace scope for this CLI request</p>
+            <p>如果存在，则为此次 CLI 请求的命名空间范围</p>
         </td>
     </tr>
     <tr>
-        <td colspan="2">--request-timeout string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Default: &#34;0&#34;</td>
+        <td colspan="2">--request-timeout string&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;默认值: &#34;0&#34;</td>
     </tr>
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don&#39;t timeout requests.</p>
+            <p>在放弃单个服务器请求之前等待的时间长度。非零值应包含相应的时间单位（例如 1s、2m、3h）。零值表示不超时请求。</p>
         </td>
     </tr>
     <tr>
@@ -226,7 +221,7 @@ kueuectl delete workload NAME [--yes] [--all] [--dry-run STRATEGY]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>The address and port of the Kubernetes API server</p>
+            <p>Kubernetes API 服务器的地址和端口</p>
         </td>
     </tr>
     <tr>
@@ -235,7 +230,7 @@ kueuectl delete workload NAME [--yes] [--all] [--dry-run STRATEGY]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used</p>
+            <p>用于服务器证书验证的服务器名称。如果未提供，则使用联系服务器所用的主机名</p>
         </td>
     </tr>
     <tr>
@@ -244,7 +239,7 @@ kueuectl delete workload NAME [--yes] [--all] [--dry-run STRATEGY]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>Bearer token for authentication to the API server</p>
+            <p>API 服务器身份验证所用的持有者令牌</p>
         </td>
     </tr>
     <tr>
@@ -253,7 +248,7 @@ kueuectl delete workload NAME [--yes] [--all] [--dry-run STRATEGY]
     <tr>
         <td></td>
         <td style="line-height: 130%; word-wrap: break-word;">
-            <p>The name of the kubeconfig user to use</p>
+            <p>要使用的 kubeconfig 用户的名称</p>
         </td>
     </tr>
     </tbody>
@@ -261,7 +256,7 @@ kueuectl delete workload NAME [--yes] [--all] [--dry-run STRATEGY]
 
 
 
-## See Also
+## 另请参阅 {#see-also}
 
-* [kueuectl delete](../)	 - Delete a resource
+* [kueuectl delete](../) - 删除资源
 
diff --git a/site/content/zh-CN/docs/tasks/run/multikueue/appwrapper.md b/site/content/zh-CN/docs/tasks/run/multikueue/appwrapper.md
index 46f96f982..940cf0148 100644
--- a/site/content/zh-CN/docs/tasks/run/multikueue/appwrapper.md
+++ b/site/content/zh-CN/docs/tasks/run/multikueue/appwrapper.md
@@ -1,33 +1,32 @@
 ---
-title: "Run AppWrappers in Multi-Cluster"
+title: "在多集群环境中运行 AppWrappers"
 linkTitle: "AppWrappers"
 weight: 3
 date: 2025-06-23
-description: >
-  Run a MultiKueue scheduled AppWrapper.
+description: 在多集群环境中运行 AppWrappers
 ---
 
-## Before you begin
+## 开始之前 {#before-you-begin}
 
-Check the [MultiKueue installation guide](/docs/tasks/manage/setup_multikueue) on how to properly setup MultiKueue clusters.
+请查阅 [MultiKueue 安装指南](/zh-CN/docs/tasks/manage/setup_multikueue)了解如何正确设置 MultiKueue 集群。
 
-For the ease of setup and use we recommend using at least Kueue v0.11.0 and at least AppWrapper Operator v1.1.1.
+为方便安装和使用，建议至少使用 Kueue v0.11.0 及 AppWrapper Operator v1.1.1 及以上版本。
 
-See [AppWrapper Quick-Start Guide](https://project-codeflare.github.io/appwrapper/quick-start/) for installation and configuration details of the AppWrapper Operator.
+有关 AppWrapper Operator 的安装和配置详情，请参见 [AppWrapper 快速入门指南](https://project-codeflare.github.io/appwrapper/quick-start/)。
 
-{{% alert title="Note" color="primary" %}}
-MultiKueue support for AppWrappers is not available in versions of Kueue before v0.11.0.
+{{% alert title="注意" color="primary" %}}
+MultiKueue 对 AppWrappers 的支持在 Kueue v0.11.0 之前的版本中不可用。
 {{% /alert %}}
 
-## MultiKueue integration
+## MultiKueue 集成 {#multikueue-integration}
 
-Once the setup is complete you can test it by running an AppWrapper [`appwrapper-pytorch-sample.yaml`](/docs/tasks/run/appwrappers/#example-appwrapper-containing-a-pytorchjob).
+完成设置后，你可以通过运行 AppWrapper [`appwrapper-pytorch-sample.yaml`](/zh-CN/docs/tasks/run/appwrappers/#example-appwrapper-containing-a-pytorchjob)进行测试。
 
-{{% alert title="Note" color="primary" %}}
-Note: Kueue defaults the `spec.managedBy` field to `kueue.x-k8s.io/multikueue` on the management cluster for AppWrappers.
+{{% alert title="注意" color="primary" %}}
+注意：Kueue 会在管理集群上的 AppWrappers 默认设置 `spec.managedBy` 字段为 `kueue.x-k8s.io/multikueue`。
 
-This allows the AppWrapper Operator to ignore the Jobs managed by MultiKueue on the management cluster, and in particular skip creation of the wrapped resources.
+这使得 AppWrapper Operator 能够忽略由 MultiKueue 管理的 AppWrapper 任务，特别是跳过对被包装资源的创建。
 
-The resources are created and the actual computation will happen on the mirror copy of the AppWrapper on the selected worker cluster.
-The mirror copy of the AppWrapper does not have the field set.
+这些资源会在选定的工作集群上的 AppWrapper 镜像副本中被创建并实际运行。
+AppWrapper 镜像副本未设置此字段。
 {{% /alert %}}
diff --git a/site/content/zh-CN/docs/tasks/run/multikueue/mpijob.md b/site/content/zh-CN/docs/tasks/run/multikueue/mpijob.md
index 0efabdc74..3cf650c64 100644
--- a/site/content/zh-CN/docs/tasks/run/multikueue/mpijob.md
+++ b/site/content/zh-CN/docs/tasks/run/multikueue/mpijob.md
@@ -1,36 +1,35 @@
 ---
-title: "Run MPIJobs in Multi-Cluster"
+title: "在多集群环境中运行 MPIJob"
 linkTitle: "MPIJob"
 weight: 5
 date: 2024-10-25
-description: >
-  Run a MultiKueue scheduled MPIJobs.
+description: 在多集群环境中运行 MPIJob
 ---
 
-## Before you begin
+## 开始之前 {#before-you-begin}
 
-Check the [MultiKueue installation guide](/docs/tasks/manage/setup_multikueue) on how to properly setup MultiKueue clusters.
+请查阅 [MultiKueue 安装指南](/zh-CN/docs/tasks/manage/setup_multikueue)了解如何正确设置 MultiKueue 集群。
 
-For the proper setup and use it is required using at least Kueue v0.9.0 and for MPI Operator at least v0.6.0.
+为保证正确安装和使用，需至少使用 Kueue v0.9.0 及 MPI Operator v0.6.0。
 
-### Installation on the Clusters
+### 集群上的安装 {#installation-on-the-clusters}
 
-{{% alert title="Note" color="primary" %}}
-Note: While both MPI Operator and Trainer must be running on the same cluster, there are special steps that has to be applied to Trainer deployment.
-See [Working alongside MPI Operator](/docs/tasks/run/multikueue/kubeflow#working-alongside-mpi-operator) for more details.
+{{% alert title="注意" color="primary" %}}
+注意：MPI Operator 和 Trainer 必须同时运行在同一集群上，但 Trainer 部署需做特殊配置。
+详见 [与 MPI Operator 协同工作](/zh-CN/docs/tasks/run/multikueue/kubeflow#working-alongside-mpi-operator)。
 {{% /alert %}}
 
-See [MPI Operator Installation](https://www.kubeflow.org/docs/components/training/user-guides/mpi/#installation) for installation and configuration details of MPI Operator.
+有关 MPI Operator 的安装和配置详情，请参见 [MPI Operator 安装文档](https://www.kubeflow.org/docs/components/training/user-guides/mpi/#installation)。
 
-## MultiKueue integration
+## MultiKueue 集成 {#multikueue-integration}
 
-Once the setup is complete you can test it by running a MPIJob [`sample-mpijob.yaml`](/docs/tasks/run/kubeflow/mpijobs/#sample-mpijob).
+完成设置后，你可以通过运行 MPIJob [`sample-mpijob.yaml`](/zh-CN/docs/tasks/run/kubeflow/mpijobs/#sample-mpijob)进行测试。
 
-{{% alert title="Note" color="primary" %}}
-Note: Kueue defaults the `spec.runPolicy.managedBy` field to `kueue.x-k8s.io/multikueue` on the management cluster for MPIJob. 
+{{% alert title="注意" color="primary" %}}
+注意：Kueue 会在管理集群上的 MPIJob 默认设置 `spec.runPolicy.managedBy` 字段为 `kueue.x-k8s.io/multikueue`。
 
-This allows the MPI Operator to ignore the Jobs managed by MultiKueue on the management cluster, and in particular skip Pod creation. 
+这使得 MPI Operator 能够忽略由 MultiKueue 管理的 Job，特别是跳过 Pod 的创建。
 
-The pods are created and the actual computation will happen on the mirror copy of the Job on the selected worker cluster. 
-The mirror copy of the Job does not have the field set.
+Pod 会在选定的工作集群上的 Job 镜像副本中被创建并实际运行。
+Job 镜像副本未设置此字段。
 {{% /alert %}}
\ No newline at end of file


Test patch:
diff --git a/pkg/cache/tas_cache_test.go b/pkg/cache/tas_cache_test.go
index 77160caa9..a92698166 100644
--- a/pkg/cache/tas_cache_test.go
+++ b/pkg/cache/tas_cache_test.go
@@ -3051,6 +3051,7 @@ func TestFindTopologyAssignment(t *testing.T) {
 func TestFindTopologyAssignmentForTwoPodSets(t *testing.T) {
 	const (
 		tasBlockLabel = "cloud.com/topology-block"
+		tasRackLabel  = "cloud.com/topology-rack"
 	)
 
 	t.Run("find topology assignment for two podsets with overlapping domain", func(t *testing.T) {
@@ -3125,14 +3126,723 @@ func TestFindTopologyAssignmentForTwoPodSets(t *testing.T) {
 
 		snapshot := buildSnapshot(ctx, t, nodes, levels)
 
-		tasInput1 := buildTASInput("podset1", topologyRequest, requests, 3)
-		tasInput2 := buildTASInput("podset2", topologyRequest, requests, 3)
+		tasInput1 := buildTASInput("podset1", topologyRequest, requests, 3, "group1")
+		tasInput2 := buildTASInput("podset2", topologyRequest, requests, 3, "group2")
+
+		flavorTASRequests := []TASPodSetRequests{tasInput1, tasInput2}
+
+		wantResult := make(TASAssignmentsResult)
+		wantResult["podset1"] = buildWantedResult(wantAssignment1, nil)
+		wantResult["podset2"] = buildWantedResult(wantAssignment2, nil)
+
+		gotResult := snapshot.FindTopologyAssignmentsForFlavor(flavorTASRequests)
+		if diff := cmp.Diff(wantResult, gotResult); diff != "" {
+			t.Errorf("unexpected topology assignment (-want,+got): %s", diff)
+		}
+	})
+
+	t.Run("find topology assignment for two podsets with the same group", func(t *testing.T) {
+		ctx, _ := utiltesting.ContextWithLog(t)
+		nodes := []corev1.Node{
+			*testingnode.MakeNode("b1").
+				Label(tasBlockLabel, "b1").
+				StatusAllocatable(corev1.ResourceList{
+					corev1.ResourceCPU:    resource.MustParse("2"),
+					"example.com/gpu":     resource.MustParse("2"),
+					corev1.ResourceMemory: resource.MustParse("2Gi"),
+					corev1.ResourcePods:   resource.MustParse("10"),
+				}).
+				Ready().
+				Obj(),
+			*testingnode.MakeNode("b2").
+				Label(tasBlockLabel, "b2").
+				StatusAllocatable(corev1.ResourceList{
+					corev1.ResourceCPU:  resource.MustParse("5"),
+					"example.com/gpu":   resource.MustParse("4"),
+					corev1.ResourcePods: resource.MustParse("10"),
+				}).
+				Ready().
+				Obj(),
+			*testingnode.MakeNode("b3").
+				Label(tasBlockLabel, "b3").
+				StatusAllocatable(corev1.ResourceList{
+					corev1.ResourceCPU:  resource.MustParse("2"),
+					"example.com/gpu":   resource.MustParse("2"),
+					corev1.ResourcePods: resource.MustParse("10"),
+				}).
+				Ready().
+				Obj(),
+		}
+		levels := []string{tasBlockLabel}
+		leaderRequests := resources.Requests{
+			corev1.ResourceCPU: 1000,
+		}
+		workersRequests := resources.Requests{
+			corev1.ResourceCPU: 1000,
+			"example.com/gpu":  1,
+		}
+		topologyRequest := &kueue.PodSetTopologyRequest{
+			Required: ptr.To(tasBlockLabel),
+		}
+		wantAssignment1 := &kueue.TopologyAssignment{
+			Levels: []string{tasBlockLabel},
+			Domains: []kueue.TopologyDomainAssignment{
+				{
+					Count: 1,
+					Values: []string{
+						"b2",
+					},
+				},
+			},
+		}
+		wantAssignment2 := &kueue.TopologyAssignment{
+			Levels: []string{tasBlockLabel},
+			Domains: []kueue.TopologyDomainAssignment{
+				{
+					Count: 4,
+					Values: []string{
+						"b2",
+					},
+				},
+			},
+		}
+
+		snapshot := buildSnapshot(ctx, t, nodes, levels)
+
+		tasInput1 := buildTASInput("leader", topologyRequest, leaderRequests, 1, "sameGroup")
+		tasInput2 := buildTASInput("workers", topologyRequest, workersRequests, 4, "sameGroup")
+
+		flavorTASRequests := []TASPodSetRequests{tasInput1, tasInput2}
+
+		wantResult := make(TASAssignmentsResult)
+		wantResult["leader"] = buildWantedResult(wantAssignment1, nil)
+		wantResult["workers"] = buildWantedResult(wantAssignment2, nil)
+
+		gotResult := snapshot.FindTopologyAssignmentsForFlavor(flavorTASRequests)
+		if diff := cmp.Diff(wantResult, gotResult); diff != "" {
+			t.Errorf("unexpected topology assignment (-want,+got): %s", diff)
+		}
+	})
+
+	t.Run("find topology assignment for two podsets with the same group with domains that can tightly fit leader and workers", func(t *testing.T) {
+		ctx, _ := utiltesting.ContextWithLog(t)
+		nodes := []corev1.Node{
+			*testingnode.MakeNode("b1").
+				Label(tasBlockLabel, "b1").
+				StatusAllocatable(corev1.ResourceList{
+					corev1.ResourceCPU:  resource.MustParse("10"),
+					"example.com/gpu":   resource.MustParse("0"),
+					corev1.ResourcePods: resource.MustParse("10"),
+				}).
+				Ready().
+				Obj(),
+			*testingnode.MakeNode("b2").
+				Label(tasBlockLabel, "b2").
+				StatusAllocatable(corev1.ResourceList{
+					corev1.ResourceCPU:  resource.MustParse("8"),
+					"example.com/gpu":   resource.MustParse("8"),
+					corev1.ResourcePods: resource.MustParse("10"),
+				}).
+				Ready().
+				Obj(),
+			*testingnode.MakeNode("b3").
+				Label(tasBlockLabel, "b3").
+				StatusAllocatable(corev1.ResourceList{
+					corev1.ResourceCPU:  resource.MustParse("14"),
+					"example.com/gpu":   resource.MustParse("4"),
+					corev1.ResourcePods: resource.MustParse("10"),
+				}).
+				Ready().
+				Obj(),
+		}
+		levels := []string{tasBlockLabel}
+		leaderRequests := resources.Requests{
+			corev1.ResourceCPU: 10000,
+		}
+		workersRequests := resources.Requests{
+			corev1.ResourceCPU: 1000,
+			"example.com/gpu":  1,
+		}
+		topologyRequest := &kueue.PodSetTopologyRequest{
+			Required: ptr.To(tasBlockLabel),
+		}
+		wantAssignment1 := &kueue.TopologyAssignment{
+			Levels: []string{tasBlockLabel},
+			Domains: []kueue.TopologyDomainAssignment{
+				{
+					Count: 1,
+					Values: []string{
+						"b3",
+					},
+				},
+			},
+		}
+		wantAssignment2 := &kueue.TopologyAssignment{
+			Levels: []string{tasBlockLabel},
+			Domains: []kueue.TopologyDomainAssignment{
+				{
+					Count: 4,
+					Values: []string{
+						"b3",
+					},
+				},
+			},
+		}
+
+		snapshot := buildSnapshot(ctx, t, nodes, levels)
+
+		tasInput1 := buildTASInput("leader", topologyRequest, leaderRequests, 1, "sameGroup")
+		tasInput2 := buildTASInput("workers", topologyRequest, workersRequests, 4, "sameGroup")
+
+		flavorTASRequests := []TASPodSetRequests{tasInput1, tasInput2}
+
+		wantResult := make(TASAssignmentsResult)
+		wantResult["leader"] = buildWantedResult(wantAssignment1, nil)
+		wantResult["workers"] = buildWantedResult(wantAssignment2, nil)
+
+		gotResult := snapshot.FindTopologyAssignmentsForFlavor(flavorTASRequests)
+		if diff := cmp.Diff(wantResult, gotResult); diff != "" {
+			t.Errorf("unexpected topology assignment (-want,+got): %s", diff)
+		}
+	})
+
+	t.Run("find topology assignment for two podsets with the same group with domains that can tightly fit leader and workers", func(t *testing.T) {
+		ctx, _ := utiltesting.ContextWithLog(t)
+		nodes := []corev1.Node{
+			*testingnode.MakeNode("b1").
+				Label(tasBlockLabel, "b1").
+				StatusAllocatable(corev1.ResourceList{
+					corev1.ResourceCPU:  resource.MustParse("20"),
+					"example.com/gpu":   resource.MustParse("0"),
+					corev1.ResourcePods: resource.MustParse("10"),
+				}).
+				Ready().
+				Obj(),
+			*testingnode.MakeNode("b2").
+				Label(tasBlockLabel, "b2").
+				StatusAllocatable(corev1.ResourceList{
+					corev1.ResourceCPU:  resource.MustParse("8"),
+					"example.com/gpu":   resource.MustParse("8"),
+					corev1.ResourcePods: resource.MustParse("10"),
+				}).
+				Ready().
+				Obj(),
+			*testingnode.MakeNode("b3").
+				Label(tasBlockLabel, "b3").
+				StatusAllocatable(corev1.ResourceList{
+					corev1.ResourceCPU:  resource.MustParse("14"),
+					"example.com/gpu":   resource.MustParse("4"),
+					corev1.ResourcePods: resource.MustParse("10"),
+				}).
+				Ready().
+				Obj(),
+		}
+		levels := []string{tasBlockLabel}
+		leaderRequests := resources.Requests{
+			corev1.ResourceCPU: 10000,
+		}
+		workersRequests := resources.Requests{
+			corev1.ResourceCPU: 1000,
+			"example.com/gpu":  1,
+		}
+		topologyRequest := &kueue.PodSetTopologyRequest{
+			Required: ptr.To(tasBlockLabel),
+		}
+		wantAssignment1 := &kueue.TopologyAssignment{
+			Levels: []string{tasBlockLabel},
+			Domains: []kueue.TopologyDomainAssignment{
+				{
+					Count: 1,
+					Values: []string{
+						"b3",
+					},
+				},
+			},
+		}
+		wantAssignment2 := &kueue.TopologyAssignment{
+			Levels: []string{tasBlockLabel},
+			Domains: []kueue.TopologyDomainAssignment{
+				{
+					Count: 4,
+					Values: []string{
+						"b3",
+					},
+				},
+			},
+		}
+
+		snapshot := buildSnapshot(ctx, t, nodes, levels)
+
+		tasInput1 := buildTASInput("leader", topologyRequest, leaderRequests, 1, "sameGroup")
+		tasInput2 := buildTASInput("workers", topologyRequest, workersRequests, 4, "sameGroup")
+
+		flavorTASRequests := []TASPodSetRequests{tasInput1, tasInput2}
+
+		wantResult := make(TASAssignmentsResult)
+		wantResult["leader"] = buildWantedResult(wantAssignment1, nil)
+		wantResult["workers"] = buildWantedResult(wantAssignment2, nil)
+
+		gotResult := snapshot.FindTopologyAssignmentsForFlavor(flavorTASRequests)
+		if diff := cmp.Diff(wantResult, gotResult); diff != "" {
+			t.Errorf("unexpected topology assignment (-want,+got): %s", diff)
+		}
+	})
+
+	t.Run("find topology assignment for two podsets with the same group - no fit", func(t *testing.T) {
+		ctx, _ := utiltesting.ContextWithLog(t)
+		nodes := []corev1.Node{
+			*testingnode.MakeNode("b1").
+				Label(tasBlockLabel, "b1").
+				StatusAllocatable(corev1.ResourceList{
+					corev1.ResourceCPU:  resource.MustParse("1"),
+					"example.com/gpu":   resource.MustParse("0"),
+					corev1.ResourcePods: resource.MustParse("10"),
+				}).
+				Ready().
+				Obj(),
+			*testingnode.MakeNode("b2").
+				Label(tasBlockLabel, "b2").
+				StatusAllocatable(corev1.ResourceList{
+					corev1.ResourceCPU:  resource.MustParse("4"),
+					"example.com/gpu":   resource.MustParse("4"),
+					corev1.ResourcePods: resource.MustParse("10"),
+				}).
+				Ready().
+				Obj(),
+		}
+		levels := []string{tasBlockLabel}
+		leaderRequests := resources.Requests{
+			corev1.ResourceCPU: 1000,
+		}
+		workersRequests := resources.Requests{
+			corev1.ResourceCPU: 1000,
+			"example.com/gpu":  1,
+		}
+		topologyRequest := &kueue.PodSetTopologyRequest{
+			Required: ptr.To(tasBlockLabel),
+		}
+		snapshot := buildSnapshot(ctx, t, nodes, levels)
+
+		tasInput1 := buildTASInput("leader", topologyRequest, leaderRequests, 1, "sameGroup")
+		tasInput2 := buildTASInput("workers", topologyRequest, workersRequests, 4, "sameGroup")
+
+		flavorTASRequests := []TASPodSetRequests{tasInput1, tasInput2}
+
+		wantResult := make(TASAssignmentsResult)
+		wantResult["leader"] = buildWantedResult(nil, ptr.To(`topology "default" allows to fit only 4 out of 4 pod(s)`))
+		wantResult["workers"] = buildWantedResult(nil, ptr.To(`topology "default" allows to fit only 4 out of 4 pod(s)`))
+
+		gotResult := snapshot.FindTopologyAssignmentsForFlavor(flavorTASRequests)
+		if diff := cmp.Diff(wantResult, gotResult); diff != "" {
+			t.Errorf("unexpected topology assignment (-want,+got): %s", diff)
+		}
+	})
+
+	t.Run("find topology assignment for two podsets with the same group - optimizes domain for both leader and workers", func(t *testing.T) {
+		ctx, _ := utiltesting.ContextWithLog(t)
+		nodes := []corev1.Node{
+			*testingnode.MakeNode("b1").
+				Label(tasBlockLabel, "b1").
+				StatusAllocatable(corev1.ResourceList{
+					corev1.ResourceCPU:  resource.MustParse("11"),
+					"example.com/gpu":   resource.MustParse("8"),
+					corev1.ResourcePods: resource.MustParse("10"),
+				}).
+				Ready().
+				Obj(),
+			*testingnode.MakeNode("b2").
+				Label(tasBlockLabel, "b2").
+				StatusAllocatable(corev1.ResourceList{
+					corev1.ResourceCPU:  resource.MustParse("4"),
+					"example.com/gpu":   resource.MustParse("4"),
+					corev1.ResourcePods: resource.MustParse("10"),
+				}).
+				Ready().
+				Obj(),
+		}
+		levels := []string{tasBlockLabel}
+		leaderRequests := resources.Requests{
+			corev1.ResourceCPU: 1000,
+		}
+		workersRequests := resources.Requests{
+			corev1.ResourceCPU: 1000,
+			"example.com/gpu":  1,
+		}
+		topologyRequest := &kueue.PodSetTopologyRequest{
+			Required: ptr.To(tasBlockLabel),
+		}
+		wantAssignment1 := &kueue.TopologyAssignment{
+			Levels: []string{tasBlockLabel},
+			Domains: []kueue.TopologyDomainAssignment{
+				{
+					Count: 1,
+					Values: []string{
+						"b1",
+					},
+				},
+			},
+		}
+		wantAssignment2 := &kueue.TopologyAssignment{
+			Levels: []string{tasBlockLabel},
+			Domains: []kueue.TopologyDomainAssignment{
+				{
+					Count: 4,
+					Values: []string{
+						"b1",
+					},
+				},
+			},
+		}
+
+		snapshot := buildSnapshot(ctx, t, nodes, levels)
+
+		tasInput1 := buildTASInput("leader", topologyRequest, leaderRequests, 1, "sameGroup")
+		tasInput2 := buildTASInput("workers", topologyRequest, workersRequests, 4, "sameGroup")
+
+		flavorTASRequests := []TASPodSetRequests{tasInput1, tasInput2}
+
+		wantResult := make(TASAssignmentsResult)
+		wantResult["leader"] = buildWantedResult(wantAssignment1, nil)
+		wantResult["workers"] = buildWantedResult(wantAssignment2, nil)
+
+		gotResult := snapshot.FindTopologyAssignmentsForFlavor(flavorTASRequests)
+		if diff := cmp.Diff(wantResult, gotResult); diff != "" {
+			t.Errorf("unexpected topology assignment (-want,+got): %s", diff)
+		}
+	})
+
+	t.Run("find topology assignment for two podsets with the same group - leader does not fit anywhere", func(t *testing.T) {
+		ctx, _ := utiltesting.ContextWithLog(t)
+		nodes := []corev1.Node{
+			*testingnode.MakeNode("b1").
+				Label(tasBlockLabel, "b1").
+				StatusAllocatable(corev1.ResourceList{
+					corev1.ResourceCPU:  resource.MustParse("4"),
+					"example.com/gpu":   resource.MustParse("4"),
+					corev1.ResourcePods: resource.MustParse("10"),
+				}).
+				Ready().
+				Obj(),
+			*testingnode.MakeNode("b2").
+				Label(tasBlockLabel, "b2").
+				StatusAllocatable(corev1.ResourceList{
+					corev1.ResourceCPU:  resource.MustParse("4"),
+					"example.com/gpu":   resource.MustParse("4"),
+					corev1.ResourcePods: resource.MustParse("10"),
+				}).
+				Ready().
+				Obj(),
+		}
+		levels := []string{tasBlockLabel}
+		leaderRequests := resources.Requests{
+			corev1.ResourceCPU: 1000,
+		}
+		workersRequests := resources.Requests{
+			corev1.ResourceCPU: 1000,
+			"example.com/gpu":  1,
+		}
+		topologyRequest := &kueue.PodSetTopologyRequest{
+			Required: ptr.To(tasBlockLabel),
+		}
+		snapshot := buildSnapshot(ctx, t, nodes, levels)
+
+		tasInput1 := buildTASInput("leader", topologyRequest, leaderRequests, 1, "sameGroup")
+		tasInput2 := buildTASInput("workers", topologyRequest, workersRequests, 4, "sameGroup")
+
+		flavorTASRequests := []TASPodSetRequests{tasInput1, tasInput2}
+
+		wantResult := make(TASAssignmentsResult)
+		wantResult["leader"] = buildWantedResult(nil, ptr.To(`topology "default" allows to fit only 4 out of 4 pod(s)`))
+		wantResult["workers"] = buildWantedResult(nil, ptr.To(`topology "default" allows to fit only 4 out of 4 pod(s)`))
+
+		gotResult := snapshot.FindTopologyAssignmentsForFlavor(flavorTASRequests)
+		if diff := cmp.Diff(wantResult, gotResult); diff != "" {
+			t.Errorf("unexpected topology assignment (-want,+got): %s", diff)
+		}
+	})
+
+	t.Run("find topology assignment for two podsets with the same group - multiple hosts", func(t *testing.T) {
+		ctx, _ := utiltesting.ContextWithLog(t)
+		//       b1              b2
+		//        |               |
+		//       r1              r2
+		//    /   |   \       /   |   \
+		//  x1   x2   x3    x4   x5   x6
+		//
+		nodes := []corev1.Node{
+			*testingnode.MakeNode("b1-r1-x1").
+				Label(tasBlockLabel, "b1").
+				Label(tasRackLabel, "r1").
+				Label(corev1.LabelHostname, "x1").
+				StatusAllocatable(corev1.ResourceList{
+					corev1.ResourceCPU:  resource.MustParse("2"),
+					corev1.ResourcePods: resource.MustParse("10"),
+					"example.com/gpu":   resource.MustParse("1"),
+				}).
+				Ready().
+				Obj(),
+			*testingnode.MakeNode("b1-r1-x2").
+				Label(tasBlockLabel, "b1").
+				Label(tasRackLabel, "r1").
+				Label(corev1.LabelHostname, "x2").
+				StatusAllocatable(corev1.ResourceList{
+					corev1.ResourceCPU:  resource.MustParse("2"),
+					corev1.ResourcePods: resource.MustParse("10"),
+					"example.com/gpu":   resource.MustParse("1"),
+				}).
+				Ready().
+				Obj(),
+			*testingnode.MakeNode("b1-r1-x3").
+				Label(tasBlockLabel, "b1").
+				Label(tasRackLabel, "r1").
+				Label(corev1.LabelHostname, "x3").
+				StatusAllocatable(corev1.ResourceList{
+					corev1.ResourceCPU:  resource.MustParse("2"),
+					corev1.ResourcePods: resource.MustParse("10"),
+					"example.com/gpu":   resource.MustParse("1"),
+				}).
+				Ready().
+				Obj(),
+			*testingnode.MakeNode("b2-r4-x4").
+				Label(tasBlockLabel, "b2").
+				Label(tasRackLabel, "r4").
+				Label(corev1.LabelHostname, "x4").
+				StatusAllocatable(corev1.ResourceList{
+					corev1.ResourceCPU:  resource.MustParse("1"),
+					corev1.ResourcePods: resource.MustParse("10"),
+					"example.com/gpu":   resource.MustParse("1"),
+				}).
+				Ready().
+				Obj(),
+			*testingnode.MakeNode("b2-r5-x5").
+				Label(tasBlockLabel, "b2").
+				Label(tasRackLabel, "r5").
+				Label(corev1.LabelHostname, "x5").
+				StatusAllocatable(corev1.ResourceList{
+					corev1.ResourceCPU:  resource.MustParse("2"),
+					corev1.ResourcePods: resource.MustParse("10"),
+					"example.com/gpu":   resource.MustParse("1"),
+				}).
+				Ready().
+				Obj(),
+			*testingnode.MakeNode("b2-r6-x6").
+				Label(tasBlockLabel, "b2").
+				Label(tasRackLabel, "r6").
+				Label(corev1.LabelHostname, "x6").
+				StatusAllocatable(corev1.ResourceList{
+					corev1.ResourceCPU:  resource.MustParse("2"),
+					corev1.ResourcePods: resource.MustParse("10"),
+					"example.com/gpu":   resource.MustParse("1"),
+				}).
+				Ready().
+				Obj(),
+		}
+		levels := []string{tasBlockLabel, tasRackLabel, corev1.LabelHostname}
+		leaderRequests := resources.Requests{
+			corev1.ResourceCPU: 2000,
+		}
+		workersRequests := resources.Requests{
+			corev1.ResourceCPU: 2000,
+			"example.com/gpu":  1,
+		}
+		topologyRequest := &kueue.PodSetTopologyRequest{
+			Required: ptr.To(tasBlockLabel),
+		}
+		wantAssignment1 := &kueue.TopologyAssignment{
+			Levels: []string{corev1.LabelHostname},
+			Domains: []kueue.TopologyDomainAssignment{
+				{
+					Count: 1,
+					Values: []string{
+						"x1",
+					},
+				},
+			},
+		}
+		wantAssignment2 := &kueue.TopologyAssignment{
+			Levels: []string{corev1.LabelHostname},
+			Domains: []kueue.TopologyDomainAssignment{
+				{
+					Count: 1,
+					Values: []string{
+						"x2",
+					},
+				},
+				{
+					Count: 1,
+					Values: []string{
+						"x3",
+					},
+				},
+			},
+		}
+
+		snapshot := buildSnapshot(ctx, t, nodes, levels)
+
+		tasInput1 := buildTASInput("leader", topologyRequest, leaderRequests, 1, "sameGroup")
+		tasInput2 := buildTASInput("workers", topologyRequest, workersRequests, 2, "sameGroup")
+
+		flavorTASRequests := []TASPodSetRequests{tasInput1, tasInput2}
+
+		wantResult := make(TASAssignmentsResult)
+		wantResult["leader"] = buildWantedResult(wantAssignment1, nil)
+		wantResult["workers"] = buildWantedResult(wantAssignment2, nil)
+
+		gotResult := snapshot.FindTopologyAssignmentsForFlavor(flavorTASRequests)
+		if diff := cmp.Diff(wantResult, gotResult); diff != "" {
+			t.Errorf("unexpected topology assignment (-want,+got): %s", diff)
+		}
+	})
+
+	t.Run("find topology assignment for two podsets with the same group requesting same resources and nodes in the same rack", func(t *testing.T) {
+		ctx, _ := utiltesting.ContextWithLog(t)
+		//         b1                 b2
+		//        /   \             /    \
+		//      r1     r2         r3     r4
+		//    /  |     |  \     /  |     |  \
+		//  x1  x2    x3  x4  x5   x6   x7   x8
+		//
+		nodes := []corev1.Node{
+			*testingnode.MakeNode("b1-r1-x1").
+				Label(tasBlockLabel, "b1").
+				Label(tasRackLabel, "r1").
+				Label(corev1.LabelHostname, "x1").
+				StatusAllocatable(corev1.ResourceList{
+					corev1.ResourceCPU:  resource.MustParse("1"),
+					corev1.ResourcePods: resource.MustParse("10"),
+					"example.com/gpu":   resource.MustParse("1"),
+				}).
+				Ready().
+				Obj(),
+			*testingnode.MakeNode("b1-r1-x2").
+				Label(tasBlockLabel, "b1").
+				Label(tasRackLabel, "r1").
+				Label(corev1.LabelHostname, "x2").
+				StatusAllocatable(corev1.ResourceList{
+					corev1.ResourceCPU:  resource.MustParse("1"),
+					corev1.ResourcePods: resource.MustParse("10"),
+					"example.com/gpu":   resource.MustParse("1"),
+				}).
+				Ready().
+				Obj(),
+			*testingnode.MakeNode("b1-r2-x3").
+				Label(tasBlockLabel, "b1").
+				Label(tasRackLabel, "r2").
+				Label(corev1.LabelHostname, "x3").
+				StatusAllocatable(corev1.ResourceList{
+					corev1.ResourceCPU:  resource.MustParse("1"),
+					corev1.ResourcePods: resource.MustParse("10"),
+					"example.com/gpu":   resource.MustParse("1"),
+				}).
+				Ready().
+				Obj(),
+			*testingnode.MakeNode("b1-r2-x4").
+				Label(tasBlockLabel, "b1").
+				Label(tasRackLabel, "r2").
+				Label(corev1.LabelHostname, "x4").
+				StatusAllocatable(corev1.ResourceList{
+					corev1.ResourceCPU:  resource.MustParse("1"),
+					corev1.ResourcePods: resource.MustParse("10"),
+					"example.com/gpu":   resource.MustParse("1"),
+				}).
+				Ready().
+				Obj(),
+			*testingnode.MakeNode("b2-r3-x5").
+				Label(tasBlockLabel, "b2").
+				Label(tasRackLabel, "r3").
+				Label(corev1.LabelHostname, "x5").
+				StatusAllocatable(corev1.ResourceList{
+					corev1.ResourceCPU:  resource.MustParse("1"),
+					corev1.ResourcePods: resource.MustParse("10"),
+					"example.com/gpu":   resource.MustParse("1"),
+				}).
+				Ready().
+				Obj(),
+			*testingnode.MakeNode("b2-r3-x6").
+				Label(tasBlockLabel, "b2").
+				Label(tasRackLabel, "r3").
+				Label(corev1.LabelHostname, "x6").
+				StatusAllocatable(corev1.ResourceList{
+					corev1.ResourceCPU:  resource.MustParse("1"),
+					corev1.ResourcePods: resource.MustParse("10"),
+					"example.com/gpu":   resource.MustParse("1"),
+				}).
+				Ready().
+				Obj(),
+			*testingnode.MakeNode("b2-r4-x7").
+				Label(tasBlockLabel, "b2").
+				Label(tasRackLabel, "r4").
+				Label(corev1.LabelHostname, "x7").
+				StatusAllocatable(corev1.ResourceList{
+					corev1.ResourceCPU:  resource.MustParse("1"),
+					corev1.ResourcePods: resource.MustParse("10"),
+					"example.com/gpu":   resource.MustParse("1"),
+				}).
+				Ready().
+				Obj(),
+			*testingnode.MakeNode("b2-r4-x8").
+				Label(tasBlockLabel, "b2").
+				Label(tasRackLabel, "r4").
+				Label(corev1.LabelHostname, "x8").
+				StatusAllocatable(corev1.ResourceList{
+					corev1.ResourceCPU:  resource.MustParse("1"),
+					corev1.ResourcePods: resource.MustParse("10"),
+					"example.com/gpu":   resource.MustParse("1"),
+				}).
+				Ready().
+				Obj(),
+		}
+		levels := []string{tasBlockLabel, tasRackLabel, corev1.LabelHostname}
+		leaderRequests := resources.Requests{
+			corev1.ResourceCPU: 1000,
+			"example.com/gpu":  1,
+		}
+		workersRequests := resources.Requests{
+			corev1.ResourceCPU: 1000,
+			"example.com/gpu":  1,
+		}
+		topologyRequest := &kueue.PodSetTopologyRequest{
+			Required: ptr.To(tasBlockLabel),
+		}
+		wantAssignment1 := &kueue.TopologyAssignment{
+			Levels: []string{corev1.LabelHostname},
+			Domains: []kueue.TopologyDomainAssignment{
+				{
+					Count: 1,
+					Values: []string{
+						"x1",
+					},
+				},
+			},
+		}
+		wantAssignment2 := &kueue.TopologyAssignment{
+			Levels: []string{corev1.LabelHostname},
+			Domains: []kueue.TopologyDomainAssignment{
+				{
+					Count: 1,
+					Values: []string{
+						"x2",
+					},
+				},
+				{
+					Count: 1,
+					Values: []string{
+						"x3",
+					},
+				},
+			},
+		}
+
+		snapshot := buildSnapshot(ctx, t, nodes, levels)
+
+		tasInput1 := buildTASInput("leader", topologyRequest, leaderRequests, 1, "sameGroup")
+		tasInput2 := buildTASInput("workers", topologyRequest, workersRequests, 2, "sameGroup")
 
 		flavorTASRequests := []TASPodSetRequests{tasInput1, tasInput2}
 
 		wantResult := make(TASAssignmentsResult)
-		wantResult["podset1"] = buildWantedResult(wantAssignment1)
-		wantResult["podset2"] = buildWantedResult(wantAssignment2)
+		wantResult["leader"] = buildWantedResult(wantAssignment1, nil)
+		wantResult["workers"] = buildWantedResult(wantAssignment2, nil)
 
 		gotResult := snapshot.FindTopologyAssignmentsForFlavor(flavorTASRequests)
 		if diff := cmp.Diff(wantResult, gotResult); diff != "" {
@@ -3167,7 +3877,7 @@ func buildSnapshot(ctx context.Context, t *testing.T, nodes []corev1.Node, level
 	return snapshot
 }
 
-func buildTASInput(podsetName kueue.PodSetReference, topologyRequest *kueue.PodSetTopologyRequest, requests resources.Requests, podCount int32) TASPodSetRequests {
+func buildTASInput(podsetName kueue.PodSetReference, topologyRequest *kueue.PodSetTopologyRequest, requests resources.Requests, podCount int32, podSetGroupName string) TASPodSetRequests {
 	return TASPodSetRequests{
 		PodSet: &kueue.PodSet{
 			Name:            podsetName,
@@ -3179,14 +3889,20 @@ func buildTASInput(podsetName kueue.PodSetReference, topologyRequest *kueue.PodS
 				},
 			},
 		},
+		PodSetGroupName:   &podSetGroupName,
 		SinglePodRequests: requests,
 		Count:             podCount,
 	}
 }
-func buildWantedResult(wantAssignment *kueue.TopologyAssignment) tasPodSetAssignmentResult {
+func buildWantedResult(wantAssignment *kueue.TopologyAssignment, reason *string) tasPodSetAssignmentResult {
 	wantPodSetResult := tasPodSetAssignmentResult{
 		FailureReason: "",
 	}
+
+	if reason != nil {
+		wantPodSetResult.FailureReason = *reason
+	}
+
 	wantPodSetResult.TopologyAssignment = wantAssignment
 	return wantPodSetResult
 }
diff --git a/pkg/queue/cluster_queue_test.go b/pkg/queue/cluster_queue_test.go
index 1051c38e6..911642f14 100644
--- a/pkg/queue/cluster_queue_test.go
+++ b/pkg/queue/cluster_queue_test.go
@@ -156,7 +156,7 @@ func Test_PushOrUpdate(t *testing.T) {
 	}
 	for name, tc := range cases {
 		t.Run(name, func(t *testing.T) {
-			cq := newClusterQueueImpl(t.Context(), nil, defaultOrdering, fakeClock, nil, false)
+			cq := newClusterQueueImpl(t.Context(), nil, defaultOrdering, fakeClock, nil, false, nil)
 
 			if cq.Pending() != 0 {
 				t.Error("ClusterQueue should be empty")
@@ -185,7 +185,7 @@ func Test_PushOrUpdate(t *testing.T) {
 
 func Test_Pop(t *testing.T) {
 	now := time.Now()
-	cq := newClusterQueueImpl(t.Context(), nil, defaultOrdering, testingclock.NewFakeClock(now), nil, false)
+	cq := newClusterQueueImpl(t.Context(), nil, defaultOrdering, testingclock.NewFakeClock(now), nil, false, nil)
 	wl1 := workload.NewInfo(utiltesting.MakeWorkload("workload-1", defaultNamespace).Creation(now).Obj())
 	wl2 := workload.NewInfo(utiltesting.MakeWorkload("workload-2", defaultNamespace).Creation(now.Add(time.Second)).Obj())
 	if cq.Pop() != nil {
@@ -207,7 +207,7 @@ func Test_Pop(t *testing.T) {
 }
 
 func Test_Delete(t *testing.T) {
-	cq := newClusterQueueImpl(t.Context(), nil, defaultOrdering, testingclock.NewFakeClock(time.Now()), nil, false)
+	cq := newClusterQueueImpl(t.Context(), nil, defaultOrdering, testingclock.NewFakeClock(time.Now()), nil, false, nil)
 	wl1 := utiltesting.MakeWorkload("workload-1", defaultNamespace).Obj()
 	wl2 := utiltesting.MakeWorkload("workload-2", defaultNamespace).Obj()
 	cq.PushOrUpdate(workload.NewInfo(wl1))
@@ -228,7 +228,7 @@ func Test_Delete(t *testing.T) {
 }
 
 func Test_Info(t *testing.T) {
-	cq := newClusterQueueImpl(t.Context(), nil, defaultOrdering, testingclock.NewFakeClock(time.Now()), nil, false)
+	cq := newClusterQueueImpl(t.Context(), nil, defaultOrdering, testingclock.NewFakeClock(time.Now()), nil, false, nil)
 	wl := utiltesting.MakeWorkload("workload-1", defaultNamespace).Obj()
 	if info := cq.Info(workload.Key(wl)); info != nil {
 		t.Error("Workload should not exist")
@@ -240,7 +240,7 @@ func Test_Info(t *testing.T) {
 }
 
 func Test_AddFromLocalQueue(t *testing.T) {
-	cq := newClusterQueueImpl(t.Context(), nil, defaultOrdering, testingclock.NewFakeClock(time.Now()), nil, false)
+	cq := newClusterQueueImpl(t.Context(), nil, defaultOrdering, testingclock.NewFakeClock(time.Now()), nil, false, nil)
 	wl := utiltesting.MakeWorkload("workload-1", defaultNamespace).Obj()
 	queue := &LocalQueue{
 		items: map[workload.Reference]*workload.Info{
@@ -258,7 +258,7 @@ func Test_AddFromLocalQueue(t *testing.T) {
 }
 
 func Test_DeleteFromLocalQueue(t *testing.T) {
-	cq := newClusterQueueImpl(t.Context(), nil, defaultOrdering, testingclock.NewFakeClock(time.Now()), nil, false)
+	cq := newClusterQueueImpl(t.Context(), nil, defaultOrdering, testingclock.NewFakeClock(time.Now()), nil, false, nil)
 	q := utiltesting.MakeLocalQueue("foo", "").ClusterQueue("cq").Obj()
 	qImpl := newLocalQueue(q)
 	wl1 := utiltesting.MakeWorkload("wl1", "").Queue(kueue.LocalQueueName(q.Name)).Obj()
@@ -413,7 +413,7 @@ func TestClusterQueueImpl(t *testing.T) {
 
 	for name, test := range tests {
 		t.Run(name, func(t *testing.T) {
-			cq := newClusterQueueImpl(t.Context(), nil, defaultOrdering, fakeClock, nil, false)
+			cq := newClusterQueueImpl(t.Context(), nil, defaultOrdering, fakeClock, nil, false, nil)
 			err := cq.Update(utiltesting.MakeClusterQueue("cq").
 				NamespaceSelector(&metav1.LabelSelector{
 					MatchExpressions: []metav1.LabelSelectorRequirement{
@@ -466,7 +466,7 @@ func TestClusterQueueImpl(t *testing.T) {
 }
 
 func TestQueueInadmissibleWorkloadsDuringScheduling(t *testing.T) {
-	cq := newClusterQueueImpl(t.Context(), nil, defaultOrdering, testingclock.NewFakeClock(time.Now()), nil, false)
+	cq := newClusterQueueImpl(t.Context(), nil, defaultOrdering, testingclock.NewFakeClock(time.Now()), nil, false, nil)
 	cq.namespaceSelector = labels.Everything()
 	wl := utiltesting.MakeWorkload("workload-1", defaultNamespace).Obj()
 	cl := utiltesting.NewFakeClient(wl, utiltesting.MakeNamespace(defaultNamespace))
@@ -550,7 +550,7 @@ func TestBackoffWaitingTimeExpired(t *testing.T) {
 	}
 	for name, tc := range cases {
 		t.Run(name, func(t *testing.T) {
-			cq := newClusterQueueImpl(t.Context(), nil, defaultOrdering, fakeClock, nil, false)
+			cq := newClusterQueueImpl(t.Context(), nil, defaultOrdering, fakeClock, nil, false, nil)
 			got := cq.backoffWaitingTimeExpired(tc.workloadInfo)
 			if tc.want != got {
 				t.Errorf("Unexpected result from backoffWaitingTimeExpired\nwant: %v\ngot: %v\n", tc.want, got)
@@ -614,7 +614,7 @@ func TestBestEffortFIFORequeueIfNotPresent(t *testing.T) {
 					},
 				},
 				workload.Ordering{PodsReadyRequeuingTimestamp: config.EvictionTimestamp},
-				nil)
+				nil, nil)
 			wl := utiltesting.MakeWorkload("workload-1", defaultNamespace).Obj()
 			info := workload.NewInfo(wl)
 			info.LastAssignment = tc.lastAssignment
@@ -643,7 +643,7 @@ func TestFIFOClusterQueue(t *testing.T) {
 		},
 		workload.Ordering{
 			PodsReadyRequeuingTimestamp: config.EvictionTimestamp,
-		}, nil)
+		}, nil, nil)
 	if err != nil {
 		t.Fatalf("Failed creating ClusterQueue %v", err)
 	}
@@ -847,7 +847,7 @@ func TestStrictFIFO(t *testing.T) {
 					},
 				},
 				*tt.workloadOrdering,
-				nil)
+				nil, nil)
 			if err != nil {
 				t.Fatalf("Failed creating ClusterQueue %v", err)
 			}
@@ -890,7 +890,7 @@ func TestStrictFIFORequeueIfNotPresent(t *testing.T) {
 					},
 				},
 				workload.Ordering{PodsReadyRequeuingTimestamp: config.EvictionTimestamp},
-				nil)
+				nil, nil)
 			wl := utiltesting.MakeWorkload("workload-1", defaultNamespace).Obj()
 			if ok := cq.RequeueIfNotPresent(workload.NewInfo(wl), reason); !ok {
 				t.Error("failed to requeue nonexistent workload")
@@ -1113,7 +1113,7 @@ func TestFsAdmission(t *testing.T) {
 			client := builder.Build()
 			ctx := context.Background()
 
-			cq, _ := newClusterQueue(ctx, client, tc.cq, defaultOrdering, tc.afsConfig)
+			cq, _ := newClusterQueue(ctx, client, tc.cq, defaultOrdering, tc.afsConfig, nil)
 			for _, wl := range tc.wls {
 				cq.PushOrUpdate(workload.NewInfo(&wl))
 			}
diff --git a/test/e2e/tas/leaderworkerset_test.go b/test/e2e/tas/leaderworkerset_test.go
index fd86165c6..54d3c2b73 100644
--- a/test/e2e/tas/leaderworkerset_test.go
+++ b/test/e2e/tas/leaderworkerset_test.go
@@ -57,7 +57,7 @@ var _ = ginkgo.Describe("TopologyAwareScheduling for LeaderWorkerSet", func() {
 		util.MustCreate(ctx, k8sClient, tasFlavor)
 
 		clusterQueue = testing.MakeClusterQueue("cluster-queue").
-			ResourceGroup(*testing.MakeFlavorQuotas("tas-flavor").Resource(extraResource, "8").Obj()).
+			ResourceGroup(*testing.MakeFlavorQuotas("tas-flavor").Resource(extraResource, "8").Resource(corev1.ResourceCPU, "1").Obj()).
 			Obj()
 		util.MustCreate(ctx, k8sClient, clusterQueue)
 		util.ExpectClusterQueuesToBeActive(ctx, k8sClient, clusterQueue)
@@ -169,7 +169,7 @@ var _ = ginkgo.Describe("TopologyAwareScheduling for LeaderWorkerSet", func() {
 		)
 	})
 
-	ginkgo.When("creating a LeaderWorkerSet with leader grouped with workers", func() {
+	ginkgo.When("creating a LeaderWorkerSet with leader grouped with workers with the same resource requests", func() {
 		ginkgo.It("should place pods based on the ranks-ordering", func() {
 			const (
 				replicas = int32(1)
@@ -207,32 +207,31 @@ var _ = ginkgo.Describe("TopologyAwareScheduling for LeaderWorkerSet", func() {
 						},
 					},
 				}).
-				LeaderTemplate(
-					corev1.PodTemplateSpec{
-						ObjectMeta: metav1.ObjectMeta{
-							Annotations: map[string]string{
-								kueuealpha.PodSetRequiredTopologyAnnotation: testing.DefaultBlockTopologyLevel,
-								kueuealpha.PodSetGroupName:                  "same-group",
-							},
+				LeaderTemplate(corev1.PodTemplateSpec{
+					ObjectMeta: metav1.ObjectMeta{
+						Annotations: map[string]string{
+							kueuealpha.PodSetRequiredTopologyAnnotation: testing.DefaultBlockTopologyLevel,
+							kueuealpha.PodSetGroupName:                  "same-group",
 						},
-						Spec: corev1.PodSpec{
-							Containers: []corev1.Container{
-								{
-									Name:  "c",
-									Image: util.GetAgnHostImage(),
-									Args:  util.BehaviorWaitForDeletion,
-									Resources: corev1.ResourceRequirements{
-										Limits: map[corev1.ResourceName]resource.Quantity{
-											extraResource: resource.MustParse("1"),
-										},
-										Requests: map[corev1.ResourceName]resource.Quantity{
-											extraResource: resource.MustParse("1"),
-										},
+					},
+					Spec: corev1.PodSpec{
+						Containers: []corev1.Container{
+							{
+								Name:  "c",
+								Image: util.GetAgnHostImage(),
+								Args:  util.BehaviorWaitForDeletion,
+								Resources: corev1.ResourceRequirements{
+									Limits: map[corev1.ResourceName]resource.Quantity{
+										extraResource: resource.MustParse("1"),
+									},
+									Requests: map[corev1.ResourceName]resource.Quantity{
+										extraResource: resource.MustParse("1"),
 									},
 								},
 							},
 						},
-					}).
+					},
+				}).
 				TerminationGracePeriod(1).
 				Obj()
 			ginkgo.By("Creating a LeaderWorkerSet", func() {
@@ -278,4 +277,129 @@ var _ = ginkgo.Describe("TopologyAwareScheduling for LeaderWorkerSet", func() {
 		},
 		)
 	})
+
+	ginkgo.When("creating a LeaderWorkerSet with leader grouped with workers with the different resource requests", func() {
+		ginkgo.It("should place pods based on the ranks-ordering", func() {
+			const (
+				replicas = int32(2)
+				size     = int32(4)
+			)
+
+			podsTotalCount := replicas * size
+
+			lws := leaderworkersettesting.MakeLeaderWorkerSet("lws", ns.Name).
+				Replicas(replicas).
+				Size(size).
+				Queue(localQueue.Name).
+				WorkerTemplate(corev1.PodTemplateSpec{
+					ObjectMeta: metav1.ObjectMeta{
+						Annotations: map[string]string{
+							kueuealpha.PodSetRequiredTopologyAnnotation: testing.DefaultBlockTopologyLevel,
+							kueuealpha.PodSetGroupName:                  "same-group",
+						},
+					},
+					Spec: corev1.PodSpec{
+						Containers: []corev1.Container{
+							{
+								Name:  "c",
+								Image: util.GetAgnHostImage(),
+								Args:  util.BehaviorWaitForDeletion,
+								Resources: corev1.ResourceRequirements{
+									Limits: map[corev1.ResourceName]resource.Quantity{
+										corev1.ResourceCPU: resource.MustParse("100m"),
+										extraResource:      resource.MustParse("1"),
+									},
+									Requests: map[corev1.ResourceName]resource.Quantity{
+										corev1.ResourceCPU: resource.MustParse("100m"),
+										extraResource:      resource.MustParse("1"),
+									},
+								},
+							},
+						},
+					},
+				}).
+				LeaderTemplate(corev1.PodTemplateSpec{
+					ObjectMeta: metav1.ObjectMeta{
+						Annotations: map[string]string{
+							kueuealpha.PodSetRequiredTopologyAnnotation: testing.DefaultBlockTopologyLevel,
+							kueuealpha.PodSetGroupName:                  "same-group",
+						},
+					},
+					Spec: corev1.PodSpec{
+						Containers: []corev1.Container{
+							{
+								Name:  "c",
+								Image: util.GetAgnHostImage(),
+								Args:  util.BehaviorWaitForDeletion,
+								Resources: corev1.ResourceRequirements{
+									Limits: map[corev1.ResourceName]resource.Quantity{
+										corev1.ResourceCPU: resource.MustParse("100m"),
+									},
+									Requests: map[corev1.ResourceName]resource.Quantity{
+										corev1.ResourceCPU: resource.MustParse("100m"),
+									},
+								},
+							},
+						},
+					},
+				}).
+				TerminationGracePeriod(1).
+				Obj()
+			ginkgo.By("Creating a LeaderWorkerSet", func() {
+				util.MustCreate(ctx, k8sClient, lws)
+			})
+
+			ginkgo.By("Waiting for replicas to be ready", func() {
+				createdLeaderWorkerSet := &leaderworkersetv1.LeaderWorkerSet{}
+				gomega.Eventually(func(g gomega.Gomega) {
+					g.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(lws), createdLeaderWorkerSet)).To(gomega.Succeed())
+					g.Expect(createdLeaderWorkerSet.Status.ReadyReplicas).To(gomega.Equal(replicas))
+					g.Expect(createdLeaderWorkerSet.Status.Conditions).To(testing.HaveConditionStatusTrueAndReason("Available", "AllGroupsReady"))
+				}, util.LongTimeout, util.Interval).Should(gomega.Succeed())
+			})
+
+			pods := &corev1.PodList{}
+			ginkgo.By("ensure all pods are scheduled", func() {
+				listOpts := &client.ListOptions{
+					FieldSelector: fields.OneTermNotEqualSelector("spec.nodeName", ""),
+				}
+				gomega.Eventually(func(g gomega.Gomega) {
+					g.Expect(k8sClient.List(ctx, pods, client.InNamespace(ns.Name), listOpts)).To(gomega.Succeed())
+					g.Expect(pods.Items).Should(gomega.HaveLen(int(podsTotalCount)))
+				}, util.LongTimeout, util.Interval).Should(gomega.Succeed())
+			})
+
+			ginkgo.By("verify the assignment of pods are as expected with rank-based ordering", func() {
+				gomega.Expect(k8sClient.List(ctx, pods, client.InNamespace(ns.Name))).To(gomega.Succeed())
+				gotAssignment := make(map[string]string, podsTotalCount)
+				for _, pod := range pods.Items {
+					index := fmt.Sprintf("%s/%s", pod.Labels[leaderworkersetv1.GroupIndexLabelKey], pod.Labels[leaderworkersetv1.WorkerIndexLabelKey])
+					gotAssignment[index] = pod.Spec.NodeName
+				}
+				gomega.Expect(gotAssignment).Should(gomega.Or(
+					gomega.BeComparableTo(map[string]string{
+						"0/0": "kind-worker",
+						"0/1": "kind-worker",
+						"0/2": "kind-worker2",
+						"0/3": "kind-worker3",
+						"1/0": "kind-worker5",
+						"1/1": "kind-worker5",
+						"1/2": "kind-worker6",
+						"1/3": "kind-worker7",
+					}),
+					gomega.BeComparableTo(map[string]string{
+						"1/0": "kind-worker",
+						"1/1": "kind-worker",
+						"1/2": "kind-worker2",
+						"1/3": "kind-worker3",
+						"0/0": "kind-worker5",
+						"0/1": "kind-worker5",
+						"0/2": "kind-worker6",
+						"0/3": "kind-worker7",
+					}),
+				))
+			})
+		},
+		)
+	})
 })
diff --git a/test/integration/singlecluster/scheduler/fairsharing/fair_sharing_test.go b/test/integration/singlecluster/scheduler/fairsharing/fair_sharing_test.go
index 248e54b00..067ae807d 100644
--- a/test/integration/singlecluster/scheduler/fairsharing/fair_sharing_test.go
+++ b/test/integration/singlecluster/scheduler/fairsharing/fair_sharing_test.go
@@ -394,7 +394,7 @@ var _ = ginkgo.Describe("Scheduler", func() {
 		})
 	})
 
-	ginkgo.When("Using AdmissionFairSharing", func() {
+	ginkgo.When("Using AdmissionFairSharing at Cohort level", func() {
 		var (
 			cq1 *kueue.ClusterQueue
 			cq2 *kueue.ClusterQueue
@@ -508,6 +508,172 @@ var _ = ginkgo.Describe("Scheduler", func() {
 			util.ExpectWorkloadsToBePreempted(ctx, k8sClient, wlHighA)
 		})
 	})
+
+	ginkgo.When("Using AdmissionFairSharing at ClusterQueue level", func() {
+		var (
+			cq1 *kueue.ClusterQueue
+			lqA *kueue.LocalQueue
+			lqB *kueue.LocalQueue
+			lqC *kueue.LocalQueue
+		)
+
+		ginkgo.BeforeEach(func() {
+			gomega.Expect(features.SetEnable(features.AdmissionFairSharing, true)).To(gomega.Succeed())
+
+			cq1 = createQueue(testing.MakeClusterQueue("cq1").
+				ResourceGroup(*testing.MakeFlavorQuotas(defaultFlavor.Name).Resource(corev1.ResourceCPU, "8").Obj()).
+				AdmissionMode(kueue.UsageBasedAdmissionFairSharing).
+				Obj())
+
+			lqA = testing.MakeLocalQueue("lq-a", ns.Name).
+				FairSharing(&kueue.FairSharing{Weight: ptr.To(resource.MustParse("1"))}).
+				ClusterQueue(cq1.Name).Obj()
+			lqB = testing.MakeLocalQueue("lq-b", ns.Name).
+				FairSharing(&kueue.FairSharing{Weight: ptr.To(resource.MustParse("1"))}).
+				ClusterQueue(cq1.Name).Obj()
+			lqC = testing.MakeLocalQueue("lq-c", ns.Name).
+				FairSharing(&kueue.FairSharing{Weight: ptr.To(resource.MustParse("1"))}).
+				ClusterQueue(cq1.Name).Obj()
+			lqs = append(lqs, lqA)
+			lqs = append(lqs, lqB)
+			lqs = append(lqs, lqC)
+
+			util.MustCreate(ctx, k8sClient, lqA)
+			util.MustCreate(ctx, k8sClient, lqB)
+			util.MustCreate(ctx, k8sClient, lqC)
+		})
+
+		ginkgo.It("admits one workload from each LocalQueue when quota is limited", func() {
+			ginkgo.By("Saturating the cq with lq-a and lq-b")
+			initialWls := []*kueue.Workload{
+				createWorkload("lq-a", "4"),
+				createWorkload("lq-b", "4"),
+			}
+			util.ExpectWorkloadsToBeAdmitted(ctx, k8sClient, initialWls...)
+
+			ginkgo.By("Creating two pending workloads for each lq")
+			lqAWls := []*kueue.Workload{
+				createWorkload("lq-a", "4"),
+				createWorkload("lq-a", "4"),
+			}
+			util.ExpectWorkloadsToBePending(ctx, k8sClient, lqAWls...)
+			lqBWls := []*kueue.Workload{
+				createWorkload("lq-b", "4"),
+				createWorkload("lq-b", "4"),
+			}
+			util.ExpectWorkloadsToBePending(ctx, k8sClient, lqBWls...)
+
+			ginkgo.By("Checking that LQ's resource usage is updated")
+			util.ExpectLocalQueueUsageToBe(ctx, k8sClient, client.ObjectKeyFromObject(lqA), ">", 0)
+			util.ExpectLocalQueueUsageToBe(ctx, k8sClient, client.ObjectKeyFromObject(lqB), ">", 0)
+
+			ginkgo.By("Releasing quota")
+			util.FinishWorkloads(ctx, k8sClient, initialWls...)
+
+			ginkgo.By("Verifying one workload from each lq is admitted")
+			util.ExpectWorkloadsToBeAdmittedCount(ctx, k8sClient, 1, lqAWls...)
+			util.ExpectWorkloadsToBeAdmittedCount(ctx, k8sClient, 1, lqBWls...)
+		})
+
+		ginkgo.It("prioritizes workloads from less active LocalQueues to maintain fairness", func() {
+			ginkgo.By("Saturating the cq with lq-a")
+			initialWls := []*kueue.Workload{
+				createWorkload("lq-a", "4"),
+				createWorkload("lq-a", "4"),
+			}
+			util.ExpectWorkloadsToBeAdmitted(ctx, k8sClient, initialWls...)
+
+			ginkgo.By("Creating pending workloads for lq-a")
+			lqAWls := []*kueue.Workload{
+				createWorkload("lq-a", "4"),
+				createWorkload("lq-a", "4"),
+				createWorkload("lq-a", "4"),
+			}
+			util.ExpectWorkloadsToBePending(ctx, k8sClient, lqAWls...)
+
+			ginkgo.By("Creating a pending workload for lq-b")
+			wlB := createWorkload("lq-b", "4")
+			util.ExpectWorkloadsToBePending(ctx, k8sClient, wlB)
+
+			ginkgo.By("Checking that LQ's resource usage is updated")
+			util.ExpectLocalQueueUsageToBe(ctx, k8sClient, client.ObjectKeyFromObject(lqA), ">", 0)
+			util.ExpectLocalQueueUsageToBe(ctx, k8sClient, client.ObjectKeyFromObject(lqB), "==", 0)
+
+			ginkgo.By("Releasing quota")
+			util.FinishWorkloads(ctx, k8sClient, initialWls...)
+
+			ginkgo.By("Verifying workload from lq-b is admitted")
+			util.ExpectWorkloadsToBeAdmitted(ctx, k8sClient, wlB)
+		})
+
+		ginkgo.It("admits workload from new LocalQueue when all others have high usage", func() {
+			ginkgo.By("Saturating the cq with lq-a and lq-b")
+			initialWls := []*kueue.Workload{
+				createWorkload("lq-a", "4"),
+				createWorkload("lq-b", "4"),
+			}
+			util.ExpectWorkloadsToBeAdmitted(ctx, k8sClient, initialWls...)
+
+			ginkgo.By("Creating pending workloads for lq-a and lq-b")
+			lqAWls := []*kueue.Workload{
+				createWorkload("lq-a", "4"),
+				createWorkload("lq-a", "4"),
+			}
+			util.ExpectWorkloadsToBePending(ctx, k8sClient, lqAWls...)
+			lqBWls := []*kueue.Workload{
+				createWorkload("lq-b", "4"),
+				createWorkload("lq-b", "4"),
+			}
+			util.ExpectWorkloadsToBePending(ctx, k8sClient, lqBWls...)
+
+			ginkgo.By("Creating a pending workload for lq-c")
+			wlC := createWorkload("lq-c", "4")
+			util.ExpectWorkloadsToBePending(ctx, k8sClient, wlC)
+
+			ginkgo.By("Checking that LQ's resource usage is updated")
+			util.ExpectLocalQueueUsageToBe(ctx, k8sClient, client.ObjectKeyFromObject(lqA), ">", 0)
+			util.ExpectLocalQueueUsageToBe(ctx, k8sClient, client.ObjectKeyFromObject(lqB), ">", 0)
+			util.ExpectLocalQueueUsageToBe(ctx, k8sClient, client.ObjectKeyFromObject(lqC), "==", 0)
+
+			ginkgo.By("Releasing quota")
+			util.FinishWorkloads(ctx, k8sClient, initialWls...)
+
+			ginkgo.By("Verifying workload from lq-c is admitted")
+			util.ExpectWorkloadsToBeAdmitted(ctx, k8sClient, wlC)
+		})
+
+		ginkgo.It("admits workloads from less active LocalQueues after quota is released", func() {
+			ginkgo.By("Saturating the cq with lq-a")
+			initialWls := []*kueue.Workload{
+				createWorkload("lq-a", "4"),
+				createWorkload("lq-a", "4"),
+			}
+			util.ExpectWorkloadsToBeAdmitted(ctx, k8sClient, initialWls...)
+
+			ginkgo.By("Creating pending workloads for lq-b")
+			lqBWls := []*kueue.Workload{
+				createWorkload("lq-b", "4"),
+				createWorkload("lq-b", "4"),
+			}
+			util.ExpectWorkloadsToBePending(ctx, k8sClient, lqBWls...)
+
+			ginkgo.By("Creating a pending workload for lq-c")
+			wlC := createWorkload("lq-c", "4")
+			util.ExpectWorkloadsToBePending(ctx, k8sClient, wlC)
+
+			ginkgo.By("Checking that LQ's resource usage is updated")
+			util.ExpectLocalQueueUsageToBe(ctx, k8sClient, client.ObjectKeyFromObject(lqA), ">", 0)
+			util.ExpectLocalQueueUsageToBe(ctx, k8sClient, client.ObjectKeyFromObject(lqB), "==", 0)
+			util.ExpectLocalQueueUsageToBe(ctx, k8sClient, client.ObjectKeyFromObject(lqC), "==", 0)
+
+			ginkgo.By("Releasing quota")
+			util.FinishWorkloads(ctx, k8sClient, initialWls...)
+
+			ginkgo.By("Verifying one workload from lq-b and one from lq-c to be admitted")
+			util.ExpectWorkloadsToBeAdmittedCount(ctx, k8sClient, 1, lqBWls...)
+			util.ExpectWorkloadsToBeAdmitted(ctx, k8sClient, wlC)
+		})
+	})
 })
 
 func expectCohortWeightedShare(cohortName string, weightedShare int64) {
diff --git a/test/integration/singlecluster/scheduler/fairsharing/suite_test.go b/test/integration/singlecluster/scheduler/fairsharing/suite_test.go
index e79cd10ee..75e2ea241 100644
--- a/test/integration/singlecluster/scheduler/fairsharing/suite_test.go
+++ b/test/integration/singlecluster/scheduler/fairsharing/suite_test.go
@@ -76,10 +76,10 @@ func managerAndSchedulerSetup(ctx context.Context, mgr manager.Manager) {
 	}
 	admissionFairSharing := &config.AdmissionFairSharing{
 		UsageHalfLifeTime: metav1.Duration{
-			Duration: 250 * time.Microsecond,
+			Duration: 3 * time.Second,
 		},
 		UsageSamplingInterval: metav1.Duration{
-			Duration: 250 * time.Millisecond,
+			Duration: 3 * time.Second,
 		},
 	}
 
@@ -104,7 +104,7 @@ func managerAndSchedulerSetup(ctx context.Context, mgr manager.Manager) {
 	gomega.Expect(err).NotTo(gomega.HaveOccurred())
 
 	sched := scheduler.New(queues, cCache, mgr.GetClient(), mgr.GetEventRecorderFor(constants.AdmissionName),
-		scheduler.WithFairSharing(fairSharing))
+		scheduler.WithFairSharing(fairSharing), scheduler.WithAdmissionFairSharing(admissionFairSharing))
 	err = sched.Start(ctx)
 	gomega.Expect(err).NotTo(gomega.HaveOccurred())
 }
diff --git a/test/util/util.go b/test/util/util.go
index 3965cb65b..73d1e1b3d 100644
--- a/test/util/util.go
+++ b/test/util/util.go
@@ -1109,3 +1109,15 @@ func SetNodeCondition(ctx context.Context, k8sClient client.Client, node *corev1
 		}
 	}, Timeout, Interval).Should(gomega.Succeed(), "Failed to set node condition %s to %s for node %s", newCondition.Type, newCondition.Status, node.Name)
 }
+
+func ExpectLocalQueueUsageToBe(ctx context.Context, k8sClient client.Client, lqKey client.ObjectKey, comparator string, compareTo any) {
+	lq := &kueue.LocalQueue{}
+	gomega.Eventually(func(g gomega.Gomega) {
+		g.Expect(k8sClient.Get(ctx, lqKey, lq)).Should(gomega.Succeed())
+		g.Expect(lq.Status.FairSharing).ShouldNot(gomega.BeNil())
+		g.Expect(lq.Status.FairSharing.AdmissionFairSharingStatus).ShouldNot(gomega.BeNil())
+		g.Expect(lq.Status.FairSharing.AdmissionFairSharingStatus.ConsumedResources).Should(gomega.HaveLen(1))
+		usage := lq.Status.FairSharing.AdmissionFairSharingStatus.ConsumedResources[corev1.ResourceCPU]
+		g.Expect(usage.MilliValue()).To(gomega.BeNumerically(comparator, compareTo))
+	}, Timeout, Interval).Should(gomega.Succeed())
+}