diff --git a/src/004-base/proxies.js b/src/004-base/proxies.js
index 0b39cd557d8bc07c7f9760ab3fb070c1c9904abe..03fc68bf390c917ca8c95735fa47a3463e24287a 100644
--- a/src/004-base/proxies.js
+++ b/src/004-base/proxies.js
@@ -1,96 +1,102 @@
-window.createReadonlyProxy = function(target) {
-	if (target == null) return target; //intentionally ==
-	if (target.__isReadonlyProxy) { return target; }
-	if (_.isArray(target)) {
-		return new Proxy(target, {
-			get:function(o, prop) {
-			const val = o[prop];
-				if (typeof val === 'function') {
-					if (['push', 'unshift', 'pop'].includes(prop)) {
-						return function () {
-							throw Error("Cannot modify a readonly array");
+(function() {
+	const readOnlySymbol = Symbol("readonly proxy");
+	window.createReadonlyProxy = function(target) {
+		if (target == null) return target; //intentionally ==
+		if (target[readOnlySymbol]) { return target; }
+		if (_.isArray(target)) {
+			return new Proxy(target, {
+				get:function(o, prop) {
+					if(prop === readOnlySymbol) { return true; }
+					const val = o[prop];
+					if (typeof val === 'function') {
+						if (['push', 'unshift', 'pop'].includes(prop)) {
+							return function () {
+								throw Error("Cannot modify a readonly array");
+							}
 						}
+						return val.bind(target);
 					}
-					return val.bind(target);
+					return createReadonlyProxy(val);
+				},
+				set:function(o, prop, value) {
+					return true;
+				},
+				deleteProperty:function(o, prop) {
+					return true;
 				}
-				return createReadonlyProxy(val);
-			},
-			set:function(o, prop, value) {
-				return true;
-			},
-			deleteProperty:function(o, prop) {
-				return true;
-			}
-		});
-	}
-	if (_.isObject(target)) {
-		return new Proxy(target, {
-			get:function(o, prop) {
-				if(prop == '__isReadonlyProxy') { return true; }
-				return createReadonlyProxy(o[prop]);
-			},
-			set:function(o, prop, value) {
-				return true;
-			},
-			deleteProperty:function(o, prop) {
-				return true;
-			}
-		});
-	}
-	return target;
-};
-window.createCheatProxy = function(target) {
-	if (target == null) return target; //intentionally ==
-	if (target.__isCheatProxy) { return target; }
-	if (_.isArray(target)) {
-		return new Proxy(target, {
-			get:function(o, prop) {
-				const val = o[prop];
-				if (typeof val === 'function') {
-					if (['push', 'unshift', 'pop'].includes(prop)) {
-						return function (el) {
-							const retval = Array.prototype[prop].apply(o, arguments);
-							//Make sure we set cheater after calling the function
-							State.variables.cheater = 1;
-							return retval;
+			});
+		}
+		if (_.isObject(target)) {
+			return new Proxy(target, {
+				get:function(o, prop) {
+					if(prop === readOnlySymbol) { return true; }
+					return createReadonlyProxy(o[prop]);
+				},
+				set:function(o, prop, value) {
+					return true;
+				},
+				deleteProperty:function(o, prop) {
+					return true;
+				}
+			});
+		}
+		return target;
+	};
+	const cheaterSymbol = Symbol("cheating proxy");
+	window.createCheatProxy = function(target) {
+		if (target == null) return target; //intentionally ==
+		if (target[cheaterSymbol]) { return target; }
+		if (_.isArray(target)) {
+			return new Proxy(target, {
+				get:function(o, prop) {
+					if(prop === cheaterSymbol) { return true; }
+					const val = o[prop];
+					if (typeof val === 'function') {
+						if (['push', 'unshift', 'pop'].includes(prop)) {
+							return function (el) {
+								const retval = Array.prototype[prop].apply(o, arguments);
+								//Make sure we set cheater after calling the function
+								State.variables.cheater = 1;//Can't use `V` because it probably points to a proxy.
+								return retval;
+							}
 						}
+						return val.bind(target);
 					}
-					return val.bind(target);
+					return createCheatProxy(val);
+				},
+				set:function(o, prop, value) {
+					o[prop] = value;
+					State.variables.cheater = 1;//Can't use `V` because it probably points to a proxy.
+					return true;
+				},
+				deleteProperty:function(o, prop) {
+					delete o[prop];
+					State.variables.cheater = 1;//Can't use `V` because it probably points to a proxy.
+					return true;
 				}
-				return createCheatProxy(val);
-			},
-			set:function(o, prop, value) {
-				o[prop] = value;
-				State.variables.cheater = 1;
-				return true;
-			},
-			deleteProperty:function(o, prop) {
-				delete o[prop];
-				State.variables.cheater = 1;
-				return true;
-			}
-		});
-	}
-	if (_.isObject(target)) {
-		return new Proxy(target, {
-			get:function(o, prop) {
-				if(prop == '__isCheatProxy') { return true; }
-				return createCheatProxy(o[prop]);
-			},
-			set:function(o, prop, value) {
-				o[prop] = value;
-				State.variables.cheater = 1;
-				return true;
-			},
-			deleteProperty:function(o, prop) {
-				delete o[prop];
-				State.variables.cheater = 1;
-				return true;
-			}
-		});
-	}
-	return target;
-};
+			});
+		}
+		if (_.isObject(target)) {
+			return new Proxy(target, {
+				get:function(o, prop) {
+					if(prop === cheaterSymbol) { return true; }
+					return createCheatProxy(o[prop]);
+				},
+				set:function(o, prop, value) {
+					o[prop] = value;
+					State.variables.cheater = 1;
+					return true;
+				},
+				deleteProperty:function(o, prop) {
+					delete o[prop];
+					State.variables.cheater = 1;
+					return true;
+				}
+			});
+		}
+		return target;
+	};
+})();
 Object.defineProperty(window, "V", {
 	get: function() {
 		if (window.storyProxy != null) { return window.storyProxy; }
diff --git a/src/js/DefaultRules.js b/src/js/DefaultRules.js
index a1cc473e971efd4e2c8546cecc75bb0cc84350ad..cd5fd6efe7a120ac3f2aa55da62c1579d685e8b8 100644
--- a/src/js/DefaultRules.js
+++ b/src/js/DefaultRules.js
@@ -2937,9 +2937,20 @@ window.DefaultRules = (function() {
 		}
 	}
 
-	let rxCheckEqual = /[^!=<>]=[^=<>]/gi;
+	const rxCheckEqual = /[^!=<>]=[^=<>]/gi;
+	const compileCheck = function(code) {
+		try {
+			//TODO: This should use a cached Function, which should be the same as below.
+			new Function(`return ${code}`);
+		}
+		catch(e) {
+			return false;
+		}
+		return true;
+	}
 	window.RuleHasError = (rule) => rule.condition.function === "custom"
-	                             && rule.condition.data.match(rxCheckEqual);
+	                             &&(rule.condition.data.match(rxCheckEqual)
+	                             || !compileCheck(rule.condition.data));
 	window.DefaultRulesError = () => V.defaultRules.some(r => RuleHasError(r));
 	return DefaultRules;
 })();
diff --git a/src/js/rulesAssistant.js b/src/js/rulesAssistant.js
index a10b2367642d63a911edf29acb5fc964fa9ce593..4f4a1da41b2dd0cf2a7389476262dfa3873cdcb0 100644
--- a/src/js/rulesAssistant.js
+++ b/src/js/rulesAssistant.js
@@ -209,6 +209,7 @@ window.ruleAppliesP = function ruleAppliesP(cond, slave) {
 			flag = cond.data.value.includes(slave[cond.data.attribute]);
 			break;
 		case "custom": // user provided JS function
+			//TODO: This should use a cached Function instead of 'eval'ing 
 			flag = eval(cond.data)(slave);
 			break;
 	}
diff --git a/src/js/rulesAssistantOptions.js b/src/js/rulesAssistantOptions.js
index d6cdfc95f72f9f177bc3b735ff8a332b19de2535..7ada7683e3e2835ecb7b4db1cda8b278c30a8d86 100644
--- a/src/js/rulesAssistantOptions.js
+++ b/src/js/rulesAssistantOptions.js
@@ -10,7 +10,7 @@ window.rulesAssistantOptions = (function() {
 	const noDefaultSetting = {value: "!NDS!", text: "no default setting"};
 
 	/** @type {App.RA.Rule} */
-	let current_rule;
+	let current_rule, root;
 
 	function rulesAssistantOptions(element) {
 		V.nextButton = "Back to Main";
@@ -26,19 +26,19 @@ window.rulesAssistantOptions = (function() {
 				current_rule = V.defaultRules[idx];
 			}
 		}
-		const root = new Root(element);
+		root = new Root(element);
 	}
 
 	function returnP(e) { return e.keyCode === 13; }
 
-	function newRule(root) {
+	function newRule() {
 		const rule = emptyDefaultRule();
 		V.defaultRules.push(rule);
 		V.currentRule = rule.ID;
-		reload(root);
+		reload();
 	}
 
-	function removeRule(root) {
+	function removeRule() {
 		const idx = V.defaultRules.findIndex(rule => rule.ID === current_rule.ID);
 		V.defaultRules.splice(idx, 1);
 		if (V.defaultRules.length > 0) {
@@ -47,33 +47,33 @@ window.rulesAssistantOptions = (function() {
 		} else {
 			V.currentRule = null;
 		}
-		reload(root);
+		reload();
 	}
 
-	function lowerPriority(root) {
+	function lowerPriority() {
 		if (V.defaultRules.length === 1) { return; } // nothing to swap with
 		const idx = V.defaultRules.findIndex(rule => rule.ID === current_rule.ID);
 		if (idx === 0) { return; } // no lower rule
 		arraySwap(V.defaultRules, idx, idx - 1);
-		reload(root);
+		reload();
 	}
 
-	function higherPriority(root) {
+	function higherPriority() {
 		if (V.defaultRules.length === 1) { return; } // nothing to swap with
 		const idx = V.defaultRules.findIndex(rule => rule.ID === current_rule.ID);
 		if (idx === V.defaultRules.length - 1) { return; } // no higher rule
 		arraySwap(V.defaultRules, idx, idx + 1);
-		reload(root);
+		reload();
 	}
 
-	function changeName(name, root) {
+	function changeName(name) {
 		if (name === current_rule.name) { return; }
 		current_rule.name = name;
-		reload(root);
+		reload();
 	}
 
 	// reload the passage
-	function reload(root) {
+	function reload() {
 		const elem = root.element;
 		elem.innerHTML = "";
 		rulesAssistantOptions(elem);
@@ -905,9 +905,8 @@ window.rulesAssistantOptions = (function() {
 
 	// rule import field
 	class NewRuleField extends Element {
-		constructor(root) {
+		constructor() {
 			super();
-			this.root = root;
 		}
 
 		render() {
@@ -940,7 +939,7 @@ window.rulesAssistantOptions = (function() {
 				} else {
 					V.defaultRules.push(App.Entity.Utils.RARuleDatatypeCleanup(rule));
 				}
-				reload(this.root);
+				reload();
 			} catch (e) {
 				alert(`Couldn't import that rule:\n${e.message}`);
 			}
@@ -975,41 +974,40 @@ window.rulesAssistantOptions = (function() {
 
 	// options displayed when there are no rules
 	class NoRules extends Options {
-		constructor(root) {
+		constructor() {
 			super();
-			this.root = root;
-			const newrule = new OptionsItem("Add a new rule", () => { newRule(this.root); });
+			const newrule = new OptionsItem("Add a new rule", () => { newRule(); });
 			this.appendChild(newrule);
-			const importrule = new OptionsItem("Import a rule", () => { this.root.appendChild(new NewRuleField(this.root)); });
+			const importrule = new OptionsItem("Import a rule", () => { root.appendChild(new NewRuleField()); });
 			this.appendChild(importrule);
 		}
 	}
 
 	// buttons for selecting the current rule
 	class RuleSelector extends List {
-		constructor(root) {
+		constructor() {
 			super("Current rule", V.defaultRules.map(i => [(i.name + (!!RuleHasError(i) ? " <span class='yellow'>[!]</span>" : "")), i]), false);
 			this.setValue(current_rule.name);
 			this.onchange = function(rule) {
 				V.currentRule = rule.ID;
-				reload(root);
+				reload();
 			};
 		}
 	}
 
 	// buttons for doing transformations on rules
 	class RuleOptions extends Options {
-		constructor(root) {
+		constructor() {
 			super();
-			this.appendChild(new OptionsItem("New Rule", () => newRule(root)));
-			this.appendChild(new OptionsItem("Remove Rule", () => removeRule(root)));
+			this.appendChild(new OptionsItem("New Rule", newRule));
+			this.appendChild(new OptionsItem("Remove Rule", removeRule));
 			this.appendChild(new OptionsItem("Apply rules", () => this.appendChild(new ApplicationLog())));
-			this.appendChild(new OptionsItem("Lower Priority", () => lowerPriority(root)));
-			this.appendChild(new OptionsItem("Higher Priority", () => higherPriority(root)));
-			this.appendChild(new OptionsItem("Rename", () => this.appendChild(new RenameField(root))));
+			this.appendChild(new OptionsItem("Lower Priority", lowerPriority));
+			this.appendChild(new OptionsItem("Higher Priority", higherPriority));
+			this.appendChild(new OptionsItem("Rename", () => this.appendChild(new RenameField())));
 			this.appendChild(new OptionsItem("Export this rule", () => this.appendChild(new ExportField(current_rule))));
 			this.appendChild(new OptionsItem("Export all rules", () => this.appendChild(new ExportField(...V.defaultRules))));
-			this.appendChild(new OptionsItem("Import rule(s)", () => this.appendChild(new NewRuleField(root))));
+			this.appendChild(new OptionsItem("Import rule(s)", () => this.appendChild(new NewRuleField())));
 		}
 	}
 
@@ -1024,10 +1022,10 @@ window.rulesAssistantOptions = (function() {
 	}
 
 	class RenameField extends Element {
-		constructor(root) {
+		constructor() {
 			super();
-			this.element.onblur = () => changeName(this.element.value, root);
-			this.element.onkeypress = (e) => { if (returnP(e)) { changeName(this.element.value, root); } };
+			this.element.onblur = () => changeName(this.element.value);
+			this.element.onkeypress = (e) => { if (returnP(e)) { changeName(this.element.value); } };
 		}
 
 		render() {
@@ -1196,15 +1194,22 @@ window.rulesAssistantOptions = (function() {
 		render(data) {
 			const elem = document.createElement("div");
 			const textarea = document.createElement("textarea");
-			const errorMessage = document.createElement("div");
-			$(errorMessage).addClass("yellow");
 			textarea.innerHTML = data;
-			let checkRules = () => errorMessage.innerText = RuleHasError(current_rule) ? "WARNING: This rule attempts to set a variable; please ensure any '=' is replaced with '=='" : "";
-			$(textarea).blur(() => current_rule.condition.data = textarea.value);
-			$(textarea).blur(checkRules);
-			checkRules();
+			$(textarea).blur(() => {
+				current_rule.condition.data = textarea.value;
+				//TODO: this would be a good place to cache the Function object that will be used by RuleHasError and ruleAppliesP
+				reload();
+			});
 			elem.appendChild(textarea);
-			elem.appendChild(errorMessage);
+
+			if(RuleHasError(current_rule))
+			{
+				const errorMessage = document.createElement("div");
+				$(errorMessage).addClass("yellow");
+				errorMessage.innerText =  "WARNING: There are errors in this condition. Please ensure the syntax is correct and equality is either '==' or '===', not '='";
+				elem.appendChild(errorMessage);
+			}
+
 			const explanation = document.createElement("div");
 			explanation.innerHTML = "Insert a valid <a target='_blank' class='link-external' href='https://www.w3schools.com/js/js_comparisons.asp'>JavaScript comparison and/or logical operation</a>.";
 			elem.appendChild(explanation);
diff --git a/src/uncategorized/main.tw b/src/uncategorized/main.tw
index 6d4b70e117d0a98493cb4d6f01b5c68efbfc1ee1..481b4988cf4f00abe3718a7da18905884c1efeab 100644
--- a/src/uncategorized/main.tw
+++ b/src/uncategorized/main.tw
@@ -104,7 +104,7 @@ __''MAIN MENU''__&nbsp;&nbsp;&nbsp;&nbsp;//[[Summary Options]]//
 	<<else>>
 		| //<<link "Stop applying Rules Assistant at week end" "Main">><<set $rulesAssistantAuto = 0>><</link>>//
 	<</if>>
-	| //<<if DefaultRulesError()>>@@.yellow; WARNING: some custom rules will change slave variables @@<</if>><<link "Re-apply Rules Assistant now (this will only check slaves in the Penthouse)" "Main">><<for _i = 0;_i < _SL;_i++>><<if $slaves[_i].assignmentVisible == 1 && $slaves[_i].useRulesAssistant == 1>><<= DefaultRules($slaves[_i])>><</if>><</for>><</link>>//
+	| //<<if DefaultRulesError()>>@@.yellow; WARNING: One or more rules' custom conditions has errors! @@<</if>><<link "Re-apply Rules Assistant now (this will only check slaves in the Penthouse)" "Main">><<for _i = 0;_i < _SL;_i++>><<if $slaves[_i].assignmentVisible == 1 && $slaves[_i].useRulesAssistant == 1>><<= DefaultRules($slaves[_i])>><</if>><</for>><</link>>//
 <</if>>
 
 <<print App.UI.SlaveList.penthousePage()>>
diff --git a/src/uncategorized/storyCaption.tw b/src/uncategorized/storyCaption.tw
index 518dde903caffca7a85de10eb5aa662715fc903b..2b58dccd294e4df2728f0471ea874f7b7a0438b0 100644
--- a/src/uncategorized/storyCaption.tw
+++ b/src/uncategorized/storyCaption.tw
@@ -10,7 +10,7 @@
 			<<link "$nextButton">> <<goto $nextLink>> <</link>> @@.cyan;[Ent]@@
 			</span> </strong>
 			<<if $rulesAssistantAuto == 1 && DefaultRulesError()>>
-				<br>@@.yellow;WARNING: some custom rules will change slave variables@@
+				<br>@@.yellow;WARNING: Rules Assistant has rules with errors!@@
 			<</if>>
 		<<else>>
 			<strong> <span id="nextButton"> <<if $nextButton != " ">> <br><br>