diff --git a/js/003-data/gameVariableData.js b/js/003-data/gameVariableData.js
index b91b7c0be7f55b610331272697f8dea67fdc56a2..3e89a95ab323572ffbbd88581a766a7d5ac23dde 100644
--- a/js/003-data/gameVariableData.js
+++ b/js/003-data/gameVariableData.js
@@ -362,7 +362,6 @@ App.Data.resetOnNGPlus = {
 	rivalID: 0,
 	eliteAuctioned: 0,
 	slavesSacrificedThisWeek: 0,
-	subSlaves: 0,
 
 	HGtraining: "",
 	mercenariesTitle: "",
diff --git a/src/endWeek/endWeek.js b/src/endWeek/endWeek.js
index d266db86c95b08f89345541b6887b72da0bedaea..871f5566d3a35ffc8af09754bcaea386d50e724d 100644
--- a/src/endWeek/endWeek.js
+++ b/src/endWeek/endWeek.js
@@ -9,7 +9,6 @@ globalThis.endWeek = (function() {
 
 		// globals setup
 		resetSlaveMarkets();
-		resetSlaveCounters();
 		for (const s of V.slaves) {
 			slavePrep(s);
 		}
@@ -17,7 +16,7 @@ globalThis.endWeek = (function() {
 		saveWeekTotals();
 
 		// pass time for objects that need it
-		weather ();
+		weather();
 		organs();
 		prosthetics();
 		nursery();
@@ -37,14 +36,7 @@ globalThis.endWeek = (function() {
 		}
 	}
 
-	function resetSlaveCounters() {
-		V.subSlaves = 0;
-	}
-
 	function slavePrep(s) {
-		if (s.assignment === Job.SUBORDINATE && s.subTarget === 0) {
-			V.subSlaves++;
-		}
 		s.lastWeeksCashIncome = 0;
 		s.lastWeeksRepIncome = 0;
 		s.lastWeeksRepExpenses = 0;
diff --git a/src/endWeek/healthFunctions.js b/src/endWeek/healthFunctions.js
index 987282793953e8edc998ad73efd733674ac78d0a..a23337026450cb4e5142f1e84334322c2398e682 100644
--- a/src/endWeek/healthFunctions.js
+++ b/src/endWeek/healthFunctions.js
@@ -443,13 +443,12 @@ globalThis.tired = function(slave) {
 					assignment += 5;
 				}
 			} else if (slave.subTarget === 0) {
-				const workload = ((V.dormitoryPopulation + V.roomsPopulation - V.subSlaves) > 5) ? (V.subSlaves / (V.dormitoryPopulation + V.roomsPopulation - V.subSlaves)) : 1;
 				if (slave.devotion > 20) {
 					assignment += 7;
 				} else {
 					assignment += 10;
 				}
-				assignment = Math.ceil(assignment / workload); // 50 if very overloaded, make sure to have enough girls serving!
+				assignment = Math.min(Math.ceil(assignment / App.EndWeek.saVars.subSlaveRatio), 50); // up to 50 if very overloaded, make sure to have enough girls serving!
 			} else {
 				if (slave.relationshipTarget === slave.subTarget && slave.health.tired > 60) {
 					assignment += 2;
diff --git a/src/endWeek/saReleaseRules.js b/src/endWeek/saReleaseRules.js
index 412f87c23ba8382da77b18b2c630768aba47b665..dd9c02069df06bd6402faab016b460841bf3e7d6 100644
--- a/src/endWeek/saReleaseRules.js
+++ b/src/endWeek/saReleaseRules.js
@@ -7,7 +7,23 @@ App.SlaveAssignment.nonAssignmentRelease = function(slave) {
 	const release = slave.rules.release;
 	const {he, his, him, himself} = getPronouns(slave);
 
-	if (!App.Utils.hasNonassignmentSex(slave) && release.masturbation === 0) {
+	const subSlaves = App.EndWeek.saVars.subSlaveMap.get(slave.ID);
+	if (subSlaves && subSlaves.length > 0) {
+		// if a slave has been assigned a specific personal subslave, or several, go to them first for relief
+		// there is no check for release rules in this case...permission is implicit in the assignment (saServeYourOtherSlaves also does not check)
+		const whom = subSlaves.length > 1 ? "several slaves" : getSlave(subSlaves[0]).slaveName;
+		r.push(`is <span class="devotion inc">delighted</span> that you've assigned ${whom} to ${him} for ${his} personal use, and <span class="trust inc">relishes</span> the feeling of being served.`);
+		// note rapid trust increase...power is dangerous if the target isn't devoted yet!
+		if (subSlaves.length > 1) {
+			slave.devotion += 2;
+			slave.trust += 6;
+		} else {
+			slave.devotion += 1;
+			slave.trust += 4;
+		}
+		// no fetish effects/discovery here...saServeYourOtherSlaves' subLife will take care of that
+		slave.need = 0;
+	} else if (!App.Utils.hasNonassignmentSex(slave) && release.masturbation === 0) {
 		if (release.master === 1) {
 			const toYou = assignmentVisible(slave) ? `to you` : `up to the penthouse`;
 			if ((slave.devotion <= 20) && (slave.trust >= -20)) {
diff --git a/src/endWeek/saRules.js b/src/endWeek/saRules.js
index da97998755f8fbe9b62d088fbda8af5be1dfb509..4ecf3c17775b2b33ae8311b97596fc420751be74 100644
--- a/src/endWeek/saRules.js
+++ b/src/endWeek/saRules.js
@@ -1,7 +1,7 @@
 /**
  *
  * @param {App.Entity.SlaveState} slave
- * @returns {Node}
+ * @returns {DocumentFragment}
  */
 App.SlaveAssignment.rules = function(slave) {
 	const el = new DocumentFragment();
@@ -1918,7 +1918,7 @@ App.SlaveAssignment.rules = function(slave) {
 									slave.trust -= 1;
 								}
 								slave.need -= 20;
-							} else if ((release.masturbation === 0)) {
+							} else if (release.masturbation === 0) {
 								r.push(`gets off from being milked, so being forbidden to masturbate doesn't affect ${him} seriously.`);
 								slave.need -= 20;
 							} else {
@@ -2209,7 +2209,7 @@ App.SlaveAssignment.rules = function(slave) {
 								slave.trust -= 1;
 							}
 							slave.need -= 20;
-						} else if ((release.masturbation === 0)) {
+						} else if (release.masturbation === 0) {
 							r.push(`gets off from working as a farmhand, so being forbidden to masturbate doesn't affect ${him} seriously.`);
 							slave.need -= 20;
 						} else {
@@ -2415,7 +2415,7 @@ App.SlaveAssignment.rules = function(slave) {
 								slave.trust -= 1;
 							}
 							slave.need -= 20;
-						} else if ((release.masturbation === 0)) {
+						} else if (release.masturbation === 0) {
 							r.push(`gets off regularly, so being forbidden to masturbate doesn't affect ${him} seriously.`);
 							slave.need -= 20;
 						} else {
@@ -2492,7 +2492,7 @@ App.SlaveAssignment.rules = function(slave) {
 								slave.trust -= 1;
 							}
 							slave.need -= 20;
-						} else if ((release.masturbation === 0)) {
+						} else if (release.masturbation === 0) {
 							r.push(`gets off with ${S.HeadGirl.slaveName}, so being forbidden to masturbate doesn't affect ${him} seriously.`);
 							slave.need -= 20;
 						} else {
@@ -2557,14 +2557,26 @@ App.SlaveAssignment.rules = function(slave) {
 								r.push(`${He} hates ${himself} for climaxing, and knows the mild aphrodisiacs in the food are forcing ${his} arousal, <span class="gold">frightening ${him}.</span>`);
 								slave.trust -= 1;
 							}
-						} else if ((release.masturbation === 0)) {
+						} else if (release.masturbation === 0) {
 							r.push(`gets off at work, so being forbidden to masturbate doesn't affect ${him} seriously.`);
 						} else {
 							r.push(`gets off at work, so ${he} doesn't feel the need to masturbate frequently.`);
 						}
 						slave.need -= 20;
 					} else {
-						r.push(App.SlaveAssignment.nonAssignmentRelease(slave));
+						// allowed to get off with other slaves, but not given a specific subslave...try to use the shared ones before going further
+						if (release.slaves === 1 && slave.assignment !== Job.SUBORDINATE && !App.EndWeek.saVars.subSlaveMap.get(slave.ID)) {
+							slave.need -= Math.min(50 * App.EndWeek.saVars.subSlaveRatio, slave.need);
+							r.push(`often uses the penthouse subordinate slaves to satisfy ${his}`);
+							if (slave.need > 0) {
+								r.push(`sexual need, but it's just not enough; ${he}`);
+							} else {
+								r.push(`sexual need.`);
+							}
+						}
+						if (slave.need > 0) {
+							r.push(App.SlaveAssignment.nonAssignmentRelease(slave));
+						}
 					}
 
 					r.push(App.EndWeek.Rules.speechRules(slave));
@@ -2753,7 +2765,7 @@ App.SlaveAssignment.rules = function(slave) {
 						if (slave.lactation === 1) {
 							slave.rules.lactation = "maintain";
 						}
-					} else if (slave.rules.lactation === "maintain" && (V.servantMilkers !== 1 || !setup.servantMilkersJobs.includes(slave.assignment))) {
+					} else if (slave.rules.lactation === "maintain" && (V.servantMilkers !== 1 || !App.Data.misc.servantMilkersJobs.includes(slave.assignment))) {
 						r.push(`${He} utilizes ${his} lactation during ${his} daily tasks as needed, and when ${he} isn't drained well enough, spends the evenings with a pair of automatic breast pumps.`);
 						slave.lactationDuration = 2;
 						slave.boobs -= slave.boobsMilk;
@@ -2761,10 +2773,6 @@ App.SlaveAssignment.rules = function(slave) {
 					}
 
 					r.push(App.SlaveAssignment.rewardAndPunishment(slave));
-					if (V.subSlaves > 0 && release.slaves === 1 && slave.assignment !== "serve your other slaves") {
-						slave.need -= (20 * V.subSlaves);
-						/* make those serve your other slaves do some work for once */
-					}
 			}
 		}
 	}
diff --git a/src/endWeek/saServeYourOtherSlaves.js b/src/endWeek/saServeYourOtherSlaves.js
index 10cd5d2480c6f0c64fc859e09bd12535a1cc3fda..3dd3ed3f4cd02b4efb8478aca1fac259f2041472 100644
--- a/src/endWeek/saServeYourOtherSlaves.js
+++ b/src/endWeek/saServeYourOtherSlaves.js
@@ -17,7 +17,6 @@ App.SlaveAssignment.serveYourOtherSlaves = (function() {
 	let mammaryUse;
 	let penetrativeUse;
 	let fuckCount;
-	let load;
 	let cervixPump;
 
 	let domSlave;
@@ -55,7 +54,6 @@ App.SlaveAssignment.serveYourOtherSlaves = (function() {
 		penetrativeUse = 0;
 		cervixPump = 0;
 		fuckCount = 0;
-		load = 0;
 
 		subName = slave.slaveName;
 		subSlaveLikedFetish = 0;
@@ -233,11 +231,9 @@ App.SlaveAssignment.serveYourOtherSlaves = (function() {
 		} else if (!canMove(slave)) {
 			r.push(`Since ${he}'s completely immobile, ${he}'s especially vulnerable.`);
 		}
-		if (V.subSlaves <= 0) {
-			V.subSlaves = 1;
-		}
-		if ((V.dormitoryPopulation + V.roomsPopulation - V.subSlaves) > 5) {
-			load = (V.subSlaves / (V.dormitoryPopulation + V.roomsPopulation - V.subSlaves));
+		const subSlaves = App.EndWeek.saVars.subSlaveMap.get(0) || [];
+		if ((V.dormitoryPopulation + V.roomsPopulation - subSlaves.length) > 5) {
+			const load = App.EndWeek.saVars.subSlaveRatio;
 			if (load > 0.8) {
 				r.push(`Since there are enough other slaves servicing your stock alongside ${him}, ${he} sees limited action.`);
 			} else if (load > 0.5) {
@@ -263,7 +259,7 @@ App.SlaveAssignment.serveYourOtherSlaves = (function() {
 				}
 			} else {
 				r.push(`Since`);
-				if (V.subSlaves === 1) {
+				if (subSlaves.length === 1) {
 					r.push(`${he} is the only slave`);
 				} else {
 					r.push(`there are so few other slaves`);
@@ -307,8 +303,8 @@ App.SlaveAssignment.serveYourOtherSlaves = (function() {
 		} else {
 			r.push(`Since you have so few slaves in need of release, ${he} sees little action.`);
 		}
-		// added a min
-		fuckCount = Math.min(300, Math.ceil((((V.dormitoryPopulation + V.roomsPopulation) + jsRandom(((V.dormitoryPopulation + V.roomsPopulation) * 1), (V.dormitoryPopulation + V.roomsPopulation) * 7)) / V.subSlaves) * healthPenalty(slave)));
+		// service the fraction of the eligible slave population that's not served by another subslave between 1 and 5 times per day
+		fuckCount = Math.ceil((jsRandom(7, 35) / App.EndWeek.saVars.subSlaveRatio) * healthPenalty(slave));
 		SimpleSexAct.Slave(slave, fuckCount);
 	}
 
@@ -1452,16 +1448,15 @@ App.SlaveAssignment.serveYourOtherSlaves = (function() {
 				if (slave.fetishStrength < 100) {
 					slave.fetishStrength++;
 				}
-			} else if (fetishChange > jsRandom(0, 100) && slave.fetish !== "masochist" && slave.fetish !== "submissive" && load <= 0.8) {
+			} else if (fetishChange > jsRandom(0, 100) && slave.fetish !== "masochist" && slave.fetish !== "submissive" && App.EndWeek.saVars.subSlaveRatio <= 0.8) {
 				r.push(`Being used as much as ${he} is starts to take a toll on ${him} sexuality; <span class="lightcoral">${he} begins to enjoy being your chattel's fucktoy.</span>`);
 				slave.fetish = "submissive";
 				slave.fetishStrength = 65;
 				slave.fetishKnown = 1;
 			}
 		} else if (jobType === "sub") {
-			domSlave.need = 0;
 			if (domSlaveUsedFetish) {
-				Math.clamp(domSlave.fetishStrength += 3, 0, 100);
+				domSlave.fetishStrength = Math.clamp(domSlave.fetishStrength + 3, 0, 100);
 			}
 			if (subSlaveLikedFetish) {
 				slave.need = 0;
@@ -1787,7 +1782,7 @@ App.SlaveAssignment.serveYourOtherSlaves = (function() {
 				}
 			}
 		} else if (jobType === "cumdump") {
-			if ((V.dormitoryPopulation + V.roomsPopulation - V.subSlaves) > 5 && load <= 0.8) {
+			if (App.EndWeek.saVars.subSlaveRatio <= 0.8) {
 				if (slave.sexualFlaw === "repressed") {
 					if (slave.devotion > 20 && jsRandom(1, 100) > (100 - fuckCount)) {
 						r.push(`After being brought to orgasm so many times, <span class="green">${he} begins to enjoy having sex.</span>`);
diff --git a/src/endWeek/saSharedVariables.js b/src/endWeek/saSharedVariables.js
index ac9ef5fcfbdc0a800be970692e085740d6ed7299..8fc356b65590ba174514ca70dc37f606a8d39e32 100644
--- a/src/endWeek/saSharedVariables.js
+++ b/src/endWeek/saSharedVariables.js
@@ -30,6 +30,10 @@ App.EndWeek.SASharedVariables = class {
 		this.unMadam = 0;
 		/** Why was the DJ fired this week? */
 		this.unDJ = 0;
+		/** Who are your subordinate slaves actually assigned to?
+		 * @type {Map<number, Array<number>>} - key is sub target, value is list of sub slaves (by ID) assigned to that target
+		 */
+		this.subSlaveMap = new Map();
 	}
 
 	/**
@@ -45,4 +49,14 @@ App.EndWeek.SASharedVariables = class {
 		this.inappropriateLactation = 0;
 		/** TODO: move $slaveUsedRest here after saRules is converted, and find others */
 	}
+
+	/** Compute shared subslave ratio (subslaves per ordinary slave) */
+	get subSlaveRatio() {
+		const subSlaves = this.subSlaveMap.get(0);
+		const subCount = subSlaves ? subSlaves.length : 0;
+		if (V.dormitoryPopulation + V.roomsPopulation <= subCount) {
+			return subCount; // avoid negative result or divide by zero
+		}
+		return subCount / (V.dormitoryPopulation + V.roomsPopulation - subCount);
+	}
 };
diff --git a/src/endWeek/slaveAssignmentReport.js b/src/endWeek/slaveAssignmentReport.js
index 48a33a764a154481f40ecda0ed9624b5b90395c4..6e2c5ba860109411a735b2d8b68d9feb4e9a7e2f 100644
--- a/src/endWeek/slaveAssignmentReport.js
+++ b/src/endWeek/slaveAssignmentReport.js
@@ -73,6 +73,16 @@ App.EndWeek.slaveAssignmentReport = function() {
 			case Job.FUCKTOY:
 				V.fuckSlaves++;
 				break;
+			case Job.SUBORDINATE: {
+				const map = App.EndWeek.saVars.subSlaveMap;
+				const curSubs = map.get(slave.subTarget);
+				if (curSubs) {
+					curSubs.push(slave.ID);
+				} else {
+					map.set(slave.subTarget, [slave.ID]);
+				}
+				break;
+			}
 		}
 
 		if (slave.bellyPain !== 0) {
diff --git a/src/js/SlaveState.js b/src/js/SlaveState.js
index 8a34958763da290a0ab2a73110b8ec0a6bd3e942..9bf380863a1e3f51be99fd54840e2279666edded 100644
--- a/src/js/SlaveState.js
+++ b/src/js/SlaveState.js
@@ -537,7 +537,7 @@ App.Entity.SlaveState = class SlaveState {
 		this.rivalry = 0;
 		/** target of rival (ID) */
 		this.rivalryTarget = 0;
-		/** slave will serve subTarget (ID) */
+		/** slave will serve subTarget (ID - 0 is all slaves, -1 is stud) */
 		this.subTarget = 0;
 		/** ID of father */
 		this.father = 0;
diff --git a/src/uncategorized/nextWeek.tw b/src/uncategorized/nextWeek.tw
index 4ce25632e4ee77e3e9ae5536109346081d4a617d..4eed4de160a64d291e08944d483d862562a19854 100644
--- a/src/uncategorized/nextWeek.tw
+++ b/src/uncategorized/nextWeek.tw
@@ -287,7 +287,7 @@
 <<set $thisWeeksIllegalWares = $merchantIllegalWares.randomMany(1)>>
 <<set $prisonCircuitIndex++>><<if $prisonCircuitIndex >= $prisonCircuit.length>><<set $prisonCircuitIndex = 0>><</if>>
 
-<<set $coursed = 0, $prestigeAuctioned = 0, $eliteAuctioned = 0, $shelterSlave = 0, $shelterSlaveBought = 0, $slaveMarketLimit = 10 + ($rep / 1000), $slavesSeen = 0, $slavesSacrificedThisWeek = 0, $subSlaves = 0>>
+<<set $coursed = 0, $prestigeAuctioned = 0, $eliteAuctioned = 0, $shelterSlave = 0, $shelterSlaveBought = 0, $slaveMarketLimit = 10 + ($rep / 1000), $slavesSeen = 0, $slavesSacrificedThisWeek = 0>>
 
 <<if $pit>>
 	<<set $pit.fought = false>>