OOKNET                             [ /  search the index  ]  
──────────────────────────────────────────────────────────────────────────────────────
══════════════════════════════════════════════════════════════════════════════════════
OOKNET   [ /  search  ]  
────────────────────────────────────────────────
════════════════════════════════════════════════
 
HASH      bc67f8bcebb9
DATE      2025-07-22
SUBJECT   nix: formatting with alejandra
FILES     22 CHANGED
HASH      bc67f8bcebb9
DATE      2025-07-22
SUBJECT   nix: formatting with alejandra
FILES     22 CHANGED
 

diff --git a/nix/apps/simulation/default.nix b/nix/apps/simulation/default.nix
index db7e3f3..87ba8d8 100644
--- a/nix/apps/simulation/default.nix
+++ b/nix/apps/simulation/default.nix
@@ -8,10 +8,10 @@
   inputs,
   ...
 }: let
-  # Mass simulations using mkMassSim
   massSimFunctions = import ./mkMassSim.nix {inherit lib pkgs classes encounter b
uffs debuffs inputs;};
   inherit (massSimFunctions) mkMassSim mkRaceComparison;
 
+  # TODO: abstract this.
   massSimulations = {
     dps-p1-raid-single-long = mkMassSim {
       specs = "dps"; # shortcut to all DPS classes templates
@@ -57,7 +57,7 @@
       template = "multiTarget";
     };
     dps-p1-raid-single-short = mkMassSim {
-      specs = "dps"; # shortcut to all DPS classes templates
+      specs = "dps";
       encounter = encounter.raid.short.singleTarget;
       iterations = 10000;
       phase = "p1";
@@ -100,7 +100,7 @@
       template = "multiTarget";
     };
     dps-p1-raid-single-burst = mkMassSim {
-      specs = "dps"; # burstcut to all DPS classes templates
+      specs = "dps";
       encounter = encounter.raid.burst.singleTarget;
       iterations = 10000;
       phase = "p1";
@@ -144,139 +144,199 @@
     };
   };
 
-  # Race comparison simulations for all DPS specs
+  # for all race combinations
+  raceScenarios = [
+    {
+      targetCount = "single";
+      duration = "long";
+      encounter = encounter.raid.long.singleTarget;
+      template = "singleTarget";
+    }
+    {
+      targetCount = "single";
+      duration = "short";
+      encounter = encounter.raid.short.singleTarget;
+      template = "singleTarget";
+    }
+    {
+      targetCount = "single";
+      duration = "burst";
+      encounter = encounter.raid.burst.singleTarget;
+      template = "singleTarget";
+    }
+
+    {
+      targetCount = "three";
+      duration = "long";
+      encounter = encounter.raid.long.threeTarget;
+      template = "multiTarget";
+    }
+    {
+      targetCount = "three";
+      duration = "short";
+      encounter = encounter.raid.short.threeTarget;
+      template = "multiTarget";
+    }
+    {
+      targetCount = "three";
+      duration = "burst";
+      encounter = encounter.raid.burst.threeTarget;
+      template = "multiTarget";
+    }
+
+    {
+      targetCount = "cleave";
+      duration = "long";
+      encounter = encounter.raid.long.cleave;
+      template = "cleave";
+    }
+    {
+      targetCount = "cleave";
+      duration = "short";
+      encounter = encounter.raid.short.cleave;
+      template = "cleave";
+    }
+    {
+      targetCount = "cleave";
+      duration = "burst";
+      encounter = encounter.raid.burst.cleave;
+      template = "cleave";
+    }
+
+    {
+      targetCount = "ten";
+      duration = "long";
+      encounter = encounter.raid.long.tenTarget;
+      template = "multiTarget";
+    }
+    {
+      targetCount = "ten";
+      duration = "short";
+      encounter = encounter.raid.short.tenTarget;
+      template = "multiTarget";
+    }
+    {
+      targetCount = "ten";
+      duration = "burst";
+      encounter = encounter.raid.burst.tenTarget;
+      template = "multiTarget";
+    }
+  ];
+
   raceComparisonSpecs = [
     {
       class = "death_knight";
       spec = "frost";
-      template = "singleTarget";
     }
     {
       class = "death_knight";
       spec = "unholy";
-      template = "singleTarget";
     }
     {
       class = "druid";
       spec = "balance";
-      template = "singleTarget";
     }
-    # { class = "druid"; spec = "feral"; template = "singleTarget"; }
+    # { class = "druid"; spec = "feral"; }
     {
       class = "hunter";
       spec = "beast_mastery";
-      template = "singleTarget";
     }
     {
       class = "hunter";
       spec = "marksmanship";
-      template = "singleTarget";
     }
     {
       class = "hunter";
       spec = "survival";
-      template = "singleTarget";
     }
     {
       class = "mage";
       spec = "arcane";
-      template = "singleTarget";
     }
     {
       class = "mage";
       spec = "fire";
-      template = "singleTarget";
     }
     {
       class = "mage";
       spec = "frost";
-      template = "singleTarget";
     }
     {
       class = "monk";
       spec = "windwalker";
-      template = "singleTarget";
     }
     {
       class = "paladin";
       spec = "retribution";
-      template = "singleTarget";
     }
     {
       class = "priest";
       spec = "shadow";
-      template = "singleTarget";
     }
     {
       class = "rogue";
       spec = "assassination";
-      template = "singleTarget";
     }
     {
       class = "rogue";
       spec = "combat";
-      template = "singleTarget";
     }
     {
       class = "rogue";
       spec = "subtlety";
-      template = "singleTarget";
     }
     {
       class = "shaman";
       spec = "elemental";
-      template = "singleTarget";
     }
     {
       class = "shaman";
       spec = "enhancement";
-      template = "singleTarget";
     }
     {
       class = "warlock";
       spec = "affliction";
-      template = "singleTarget";
     }
     {
       class = "warlock";
       spec = "demonology";
-      template = "singleTarget";
     }
     {
       class = "warlock";
       spec = "destruction";
-      template = "singleTarget";
     }
     {
       class = "warrior";
       spec = "arms";
-      template = "singleTarget";
     }
     {
       class = "warrior";
       spec = "fury";
-      template = "singleTarget";
     }
   ];
 
-  # Generate race comparison simulations for single target long encounters
-  raceComparisons = lib.listToAttrs (map (specConfig: {
-      name = "race-${specConfig.class}-${specConfig.spec}-p1-raid-single-long";
-      value = mkRaceComparison {
-        class = specConfig.class;
-        spec = specConfig.spec;
-        encounter = encounter.raid.long.singleTarget;
-        iterations = 10000;
-        phase = "p1";
-        encounterType = "raid";
-        targetCount = "single";
-        duration = "long";
-        template = specConfig.template;
-      };
-    })
-    raceComparisonSpecs);
+  # generate all race comparison combinations (specs ? scenarios)
+  raceComparisons = lib.listToAttrs (lib.flatten (map (
+      specConfig:
+        map (scenario: {
+          name = "race-${specConfig.class}-${specConfig.spec}-p1-raid-${scenario.
targetCount}-${scenario.duration}";
+          value = mkRaceComparison {
+            class = specConfig.class;
+            spec = specConfig.spec;
+            encounter = scenario.encounter;
+            iterations = 10000;
+            phase = "p1";
+            encounterType = "raid";
+            targetCount = scenario.targetCount;
+            duration = scenario.duration;
+            template = scenario.template;
+          };
+        })
+        raceScenarios
+    )
+    raceComparisonSpecs));
 
-  # Script that runs all simulations
+  # script that runs all simulations
   allSimulationsScript = pkgs.writeShellApplication {
     name = "all-simulations";
     text = ''
@@ -310,7 +370,7 @@
     runtimeInputs = [pkgs.coreutils pkgs.findutils];
   };
 
-  # Convert mass simulations to apps and add the all-simulations app
+  # nix app
   simulationApps =
     lib.mapAttrs (name: massSim: {
       type = "app";
@@ -318,7 +378,6 @@
     })
     massSimulations;
 
-  # Convert race comparisons to apps
   raceComparisonApps =
     lib.mapAttrs (name: raceComp: {
       type = "app";

diff --git a/nix/apps/simulation/default.nix
 b/nix/apps/simulation/default.nix
index db7e3f3..87ba8d8 100644
--- a/nix/apps/simulation/default.nix
+++ b/nix/apps/simulation/default.nix
@@ -8,10 +8,10 @@
   inputs,
   ...
 }: let
-  # Mass simulations using mkMassSim
   massSimFunctions = import ./mkMassSim.nix
 {inherit lib pkgs classes encounter buffs d
ebuffs inputs;};
   inherit (massSimFunctions) mkMassSim mkRa
ceComparison;
 
+  # TODO: abstract this.
   massSimulations = {
     dps-p1-raid-single-long = mkMassSim {
       specs = "dps"; # shortcut to all DPS 
classes templates
@@ -57,7 +57,7 @@
       template = "multiTarget";
     };
     dps-p1-raid-single-short = mkMassSim {
-      specs = "dps"; # shortcut to all DPS 
classes templates
+      specs = "dps";
       encounter = encounter.raid.short.sing
leTarget;
       iterations = 10000;
       phase = "p1";
@@ -100,7 +100,7 @@
       template = "multiTarget";
     };
     dps-p1-raid-single-burst = mkMassSim {
-      specs = "dps"; # burstcut to all DPS 
classes templates
+      specs = "dps";
       encounter = encounter.raid.burst.sing
leTarget;
       iterations = 10000;
       phase = "p1";
@@ -144,139 +144,199 @@
     };
   };
 
-  # Race comparison simulations for all DPS
 specs
+  # for all race combinations
+  raceScenarios = [
+    {
+      targetCount = "single";
+      duration = "long";
+      encounter = encounter.raid.long.singl
eTarget;
+      template = "singleTarget";
+    }
+    {
+      targetCount = "single";
+      duration = "short";
+      encounter = encounter.raid.short.sing
leTarget;
+      template = "singleTarget";
+    }
+    {
+      targetCount = "single";
+      duration = "burst";
+      encounter = encounter.raid.burst.sing
leTarget;
+      template = "singleTarget";
+    }
+
+    {
+      targetCount = "three";
+      duration = "long";
+      encounter = encounter.raid.long.three
Target;
+      template = "multiTarget";
+    }
+    {
+      targetCount = "three";
+      duration = "short";
+      encounter = encounter.raid.short.thre
eTarget;
+      template = "multiTarget";
+    }
+    {
+      targetCount = "three";
+      duration = "burst";
+      encounter = encounter.raid.burst.thre
eTarget;
+      template = "multiTarget";
+    }
+
+    {
+      targetCount = "cleave";
+      duration = "long";
+      encounter = encounter.raid.long.cleav
e;
+      template = "cleave";
+    }
+    {
+      targetCount = "cleave";
+      duration = "short";
+      encounter = encounter.raid.short.clea
ve;
+      template = "cleave";
+    }
+    {
+      targetCount = "cleave";
+      duration = "burst";
+      encounter = encounter.raid.burst.clea
ve;
+      template = "cleave";
+    }
+
+    {
+      targetCount = "ten";
+      duration = "long";
+      encounter = encounter.raid.long.tenTa
rget;
+      template = "multiTarget";
+    }
+    {
+      targetCount = "ten";
+      duration = "short";
+      encounter = encounter.raid.short.tenT
arget;
+      template = "multiTarget";
+    }
+    {
+      targetCount = "ten";
+      duration = "burst";
+      encounter = encounter.raid.burst.tenT
arget;
+      template = "multiTarget";
+    }
+  ];
+
   raceComparisonSpecs = [
     {
       class = "death_knight";
       spec = "frost";
-      template = "singleTarget";
     }
     {
       class = "death_knight";
       spec = "unholy";
-      template = "singleTarget";
     }
     {
       class = "druid";
       spec = "balance";
-      template = "singleTarget";
     }
-    # { class = "druid"; spec = "feral"; te
mplate = "singleTarget"; }
+    # { class = "druid"; spec = "feral"; }
     {
       class = "hunter";
       spec = "beast_mastery";
-      template = "singleTarget";
     }
     {
       class = "hunter";
       spec = "marksmanship";
-      template = "singleTarget";
     }
     {
       class = "hunter";
       spec = "survival";
-      template = "singleTarget";
     }
     {
       class = "mage";
       spec = "arcane";
-      template = "singleTarget";
     }
     {
       class = "mage";
       spec = "fire";
-      template = "singleTarget";
     }
     {
       class = "mage";
       spec = "frost";
-      template = "singleTarget";
     }
     {
       class = "monk";
       spec = "windwalker";
-      template = "singleTarget";
     }
     {
       class = "paladin";
       spec = "retribution";
-      template = "singleTarget";
     }
     {
       class = "priest";
       spec = "shadow";
-      template = "singleTarget";
     }
     {
       class = "rogue";
       spec = "assassination";
-      template = "singleTarget";
     }
     {
       class = "rogue";
       spec = "combat";
-      template = "singleTarget";
     }
     {
       class = "rogue";
       spec = "subtlety";
-      template = "singleTarget";
     }
     {
       class = "shaman";
       spec = "elemental";
-      template = "singleTarget";
     }
     {
       class = "shaman";
       spec = "enhancement";
-      template = "singleTarget";
     }
     {
       class = "warlock";
       spec = "affliction";
-      template = "singleTarget";
     }
     {
       class = "warlock";
       spec = "demonology";
-      template = "singleTarget";
     }
     {
       class = "warlock";
       spec = "destruction";
-      template = "singleTarget";
     }
     {
       class = "warrior";
       spec = "arms";
-      template = "singleTarget";
     }
     {
       class = "warrior";
       spec = "fury";
-      template = "singleTarget";
     }
   ];
 
-  # Generate race comparison simulations fo
r single target long encounters
-  raceComparisons = lib.listToAttrs (map (s
pecConfig: {
-      name = "race-${specConfig.class}-${sp
ecConfig.spec}-p1-raid-single-long";
-      value = mkRaceComparison {
-        class = specConfig.class;
-        spec = specConfig.spec;
-        encounter = encounter.raid.long.sin
gleTarget;
-        iterations = 10000;
-        phase = "p1";
-        encounterType = "raid";
-        targetCount = "single";
-        duration = "long";
-        template = specConfig.template;
-      };
-    })
-    raceComparisonSpecs);
+  # generate all race comparison combinatio
ns (specs ? scenarios)
+  raceComparisons = lib.listToAttrs (lib.fl
atten (map (
+      specConfig:
+        map (scenario: {
+          name = "race-${specConfig.class}-
${specConfig.spec}-p1-raid-${scenario.target
Count}-${scenario.duration}";
+          value = mkRaceComparison {
+            class = specConfig.class;
+            spec = specConfig.spec;
+            encounter = scenario.encounter;
+            iterations = 10000;
+            phase = "p1";
+            encounterType = "raid";
+            targetCount = scenario.targetCo
unt;
+            duration = scenario.duration;
+            template = scenario.template;
+          };
+        })
+        raceScenarios
+    )
+    raceComparisonSpecs));
 
-  # Script that runs all simulations
+  # script that runs all simulations
   allSimulationsScript = pkgs.writeShellApp
lication {
     name = "all-simulations";
     text = ''
@@ -310,7 +370,7 @@
     runtimeInputs = [pkgs.coreutils pkgs.fi
ndutils];
   };
 
-  # Convert mass simulations to apps and ad
d the all-simulations app
+  # nix app
   simulationApps =
     lib.mapAttrs (name: massSim: {
       type = "app";
@@ -318,7 +378,6 @@
     })
     massSimulations;
 
-  # Convert race comparisons to apps
   raceComparisonApps =
     lib.mapAttrs (name: raceComp: {
       type = "app";
 

diff --git a/nix/apps/simulation/mkMassSim.nix b/nix/apps/simulation/mkMassSim.nix
index 9adbf3b..9555de5 100644
--- a/nix/apps/simulation/mkMassSim.nix
+++ b/nix/apps/simulation/mkMassSim.nix
@@ -8,14 +8,17 @@
   inputs,
   ...
 }: let
+  # TODO: this is cursed, consolidate the functions.
   inherit (lib.sim.simulation) mkSim;
 
-  # Extract playable races from class definitions
-  getPlayableRaces = className: 
+  # extract playable races from class definitions
+  getPlayableRaces = className:
     if lib.hasAttr className classes && lib.hasAttr "playableRaces" classes.${cla
ssName}
     then classes.${className}.playableRaces
     else throw "playableRaces not defined for class ${className}. Please add play
ableRaces = [...] to nix/classes/${className}/default.nix";
 
+  # categorize specs by role
+  # TODO: tanks
   getAllDPSSpecs = classes: template: let
     dpsSpecs = {
       death_knight = ["frost" "unholy"];
@@ -31,7 +34,7 @@
       warrior = ["arms" "fury"];
     };
 
-    # Extract specs that exist in classes and have the template structure
+    # extract specs that exist in classes and have the template structure
     validSpecs = lib.flatten (lib.mapAttrsToList (
         className: specNames:
           lib.filter (spec: spec != null) (map (
@@ -45,7 +48,8 @@
                   defaultRace = classes.${className}.${specName}.defaultRace;
                   spec = classes.${className}.${specName};
                 in
-                  if lib.hasAttr defaultRace spec.template
+                  if
+                    lib.hasAttr defaultRace spec.template
                     && lib.hasAttr "p1" spec.template.${defaultRace}
                     && lib.hasAttr "raid" spec.template.${defaultRace}.p1
                     && lib.hasAttr template spec.template.${defaultRace}.p1.raid
@@ -62,40 +66,38 @@
   in
     validSpecs;
 
-  # Get race configurations for a specific class/spec combination
   getRaceConfigs = classes: className: specName: template: phase: encounterType: 
let
     availableRaces = getPlayableRaces className;
     baseSpec = classes.${className}.${specName};
   in
     map (raceName: {
       inherit className specName raceName;
-      # Access the race-specific config from the new template structure
-      config = 
-        if lib.hasAttr "template" baseSpec 
+      config =
+        if
+          lib.hasAttr "template" baseSpec
           && lib.hasAttr raceName baseSpec.template
           && lib.hasAttr phase baseSpec.template.${raceName}
           && lib.hasAttr encounterType baseSpec.template.${raceName}.${phase}
           && lib.hasAttr template baseSpec.template.${raceName}.${phase}.${encoun
terType}
         then baseSpec.template.${raceName}.${phase}.${encounterType}.${template}
         else throw "Template ${template} not found for ${className}/${specName}/$
{raceName} at ${phase}.${encounterType}";
-    }) availableRaces;
+    })
+    availableRaces;
 
-  # Race comparison function
   mkRaceComparison = {
     class,
     spec,
     encounter,
     iterations ? 10000,
-    phase ? "p1", 
+    phase ? "p1",
     encounterType ? "raid",
     targetCount ? "single",
     duration ? "long",
     template ? "singleTarget",
   }: let
-    # Get race configurations for this class/spec
     raceConfigs = getRaceConfigs classes class spec template phase encounterType;
-    
-    # Create individual simulation derivations for each race
+
+    # create individual simulation derivations for each race
     simDerivations = lib.listToAttrs (map (raceConfig: {
         name = "${raceConfig.className}-${raceConfig.specName}-${raceConfig.raceN
ame}";
         value = let
@@ -111,21 +113,19 @@
             buildInputs = [pkgs.jq];
             nativeBuildInputs = [inputs.wowsims.packages.${pkgs.system}.wowsimcli
];
           } ''
-            # Generate input JSON file
             cat > input.json << 'EOF'
             ${simInput}
             EOF
 
-            # Run simulation
             echo "Running ${raceConfig.className}/${raceConfig.specName}/${raceCo
nfig.raceName} simulation..."
             if wowsimcli sim --infile input.json --outfile output.json; then
-              # Extract DPS statistics
+              # extract dps statistics
               avgDps=$(jq -r '.raidMetrics.dps.avg // 0' output.json)
               maxDps=$(jq -r '.raidMetrics.dps.max // 0' output.json)
               minDps=$(jq -r '.raidMetrics.dps.min // 0' output.json)
               stdevDps=$(jq -r '.raidMetrics.dps.stdev // 0' output.json)
 
-              # Create loadout info
+              # construct loadout info
               loadout=$(echo '${builtins.toJSON raceConfig.config}' | jq '{
                 consumables,
                 talentsString,
@@ -137,7 +137,7 @@
                 profession2
               }')
 
-              # Create final result
+              # create final result
               jq -n \
                 --arg raceName "${raceConfig.raceName}" \
                 --arg avgDps "$avgDps" \
@@ -161,10 +161,8 @@
       })
       raceConfigs);
 
-    # Generate output filename: <class>_<spec>_race_<phase>_<encounter-type>_<tar
get-count>_<duration>
     structuredOutput = "${class}_${spec}_race_${phase}_${encounterType}_${targetC
ount}_${duration}";
 
-    # Aggregation script for race comparison
     aggregationScript = pkgs.writeShellApplication {
       name = "${structuredOutput}-aggregator";
       text = ''
@@ -173,11 +171,10 @@
         echo "Aggregating race comparison results for: ${class}/${spec}"
         echo "Races simulated: ${toString (lib.length raceConfigs)}"
 
-        # Create base structure
         result=$(jq -n '{}')
 
         ${lib.concatMapStringsSep "\n" (raceConfig: ''
-            # Add ${raceConfig.raceName} results
+            # ${raceConfig.raceName} results
             raceData=$(cat ${simDerivations."${raceConfig.className}-${raceConfig
.specName}-${raceConfig.raceName}"})
 
             result=$(echo "$result" | jq \
@@ -193,7 +190,6 @@
           '')
           raceConfigs}
 
-        # Create final output with metadata
         finalResult=$(echo "$result" | jq \
           --arg class "${class}" \
           --arg spec "${spec}" \
@@ -219,9 +215,8 @@
             results: .
           }')
 
-        echo "$finalResult" | tee "${structuredOutput}.json"
+        echo "$finalResult" | jq -c '.' | tee "${structuredOutput}.json"
 
-        # Copy to web public directory with new structure
         repo_root=""
         current_dir="$PWD"
         while [[ "$current_dir" != "/" ]]; do
@@ -237,11 +232,10 @@
           repo_root="$PWD"
         fi
 
-        # Create directory structure: /comparison/<class>/<spec>/
         comparison_dir="$repo_root/web/public/data/comparison/${class}/${spec}"
         mkdir -p "$comparison_dir"
 
-        # Copy race comparison file
+        # copy race comparison file
         cp "${structuredOutput}.json" "$comparison_dir/"
         echo "Copied to: $comparison_dir/${structuredOutput}.json"
 
@@ -253,14 +247,14 @@
           select(.value.dps != null and .value.dps > 0) |
           "\(.key): \(.value.dps | floor) DPS"
         ' | sort -k2 -nr
-        
+
         # Show any failed races
         failed_races=$(echo "$finalResult" | jq -r '
           .results | to_entries[] |
           select(.value.dps == null or .value.dps <= 0) |
           .key
         ')
-        
+
         if [[ -n "$failed_races" ]]; then
           echo ""
           echo "Failed races (no valid DPS data):"
@@ -273,10 +267,8 @@
       runtimeInputs = [pkgs.jq pkgs.coreutils];
     };
   in {
-    # Individual race simulation derivations (for debugging)
     simulations = simDerivations;
 
-    # Main aggregation script
     script = aggregationScript;
 
     metadata = {
@@ -287,7 +279,6 @@
     };
   };
 
-  # Main mkMassSim function
   mkMassSim = {
     specs ? "dps",
     encounter,
@@ -298,7 +289,7 @@
     duration ? "long",
     template ? "singleTarget",
   }: let
-    # Get the list of specs based on the specs parameter
+    # get the list of specs based on the specs parameter
     specConfigs =
       if specs == "dps"
       then getAllDPSSpecs classes template
@@ -306,7 +297,7 @@
       then specs
       else throw "specs must be 'dps' or a list of spec configurations";
 
-    # Create individual simulation derivations for each spec
+    # create individual simulation derivations for each spec
     simDerivations = lib.listToAttrs (map (spec: {
         name = "${spec.className}-${spec.specName}";
         value = let
@@ -327,16 +318,16 @@
             ${simInput}
             EOF
 
-            # Run simulation
             echo "Running ${spec.className}/${spec.specName} simulation..."
             if wowsimcli sim --infile input.json --outfile output.json; then
-              # Extract DPS statistics
+
               avgDps=$(jq -r '.raidMetrics.dps.avg // 0' output.json)
               maxDps=$(jq -r '.raidMetrics.dps.max // 0' output.json)
               minDps=$(jq -r '.raidMetrics.dps.min // 0' output.json)
               stdevDps=$(jq -r '.raidMetrics.dps.stdev // 0' output.json)
 
-              # Create loadout without rotation (only keep consumables, talents, 
glyphs, gear)
+              # create loadout without rotation (only keep consumables, talents, 
glyphs, gear)
+              # TODO: should we output the apl?
               loadout=$(echo '${builtins.toJSON spec.config}' | jq '{
                 consumables,
                 talentsString,
@@ -348,7 +339,7 @@
                 profession2
               }')
 
-              # Create final result with all DPS statistics
+              # create final result with all DPS statistics
               jq -n \
                 --arg className "${spec.className}" \
                 --arg specName "${spec.specName}" \
@@ -431,10 +422,10 @@
             results: .
           }')
 
-        echo "$finalResult" | tee "${structuredOutput}.json"
+        echo "$finalResult" | jq -c '.' | tee "${structuredOutput}.json"
 
         # copy to web public directory for web frontend
-        # Find the repo root by looking for flake.nix
+        # find the repo root by looking for flake.nix
         repo_root=""
         current_dir="$PWD"
         while [[ "$current_dir" != "/" ]]; do
@@ -459,14 +450,12 @@
         mkdir -p "$rankings_dir"
         mkdir -p "$archive_dir"
 
-        # Archive existing file if it exists
         if [[ -f "$existing_file" ]]; then
           timestamp=$(date +"%Y%m%d_%H%M%S")
           archived_name="${structuredOutput}_$timestamp.json"
           cp "$existing_file" "$archive_dir/$archived_name"
           echo "Archived existing file: $archived_name"
 
-          # Generate changelog by comparing with archived version
           echo "Generating changelog..."
           changes=$(echo "$finalResult" | jq --slurpfile archived "$existing_file
" '
             .results as $current |
@@ -497,7 +486,6 @@
             echo "Found $change_count DPS changes:"
             echo "$changes" | jq -r '.[] | "  \(.class)/\(.spec): \(if .absolute_
change > 0 then "+" else "" end)\(.absolute_change) DPS (\(if .percent_change > 0 
then "+" else "" end)\(.percent_change)%)"'
 
-            # Update or create changelog
             changelog_file="$web_data_dir/changelog.json"
             if [[ -f "$changelog_file" ]]; then
               current_changelog=$(cat "$changelog_file")

diff --git a/nix/apps/simulation/mkMassSim.n
ix b/nix/apps/simulation/mkMassSim.nix
index 9adbf3b..9555de5 100644
--- a/nix/apps/simulation/mkMassSim.nix
+++ b/nix/apps/simulation/mkMassSim.nix
@@ -8,14 +8,17 @@
   inputs,
   ...
 }: let
+  # TODO: this is cursed, consolidate the f
unctions.
   inherit (lib.sim.simulation) mkSim;
 
-  # Extract playable races from class defin
itions
-  getPlayableRaces = className: 
+  # extract playable races from class defin
itions
+  getPlayableRaces = className:
     if lib.hasAttr className classes && lib
.hasAttr "playableRaces" classes.${className
}
     then classes.${className}.playableRaces
     else throw "playableRaces not defined f
or class ${className}. Please add playableRa
ces = [...] to nix/classes/${className}/defa
ult.nix";
 
+  # categorize specs by role
+  # TODO: tanks
   getAllDPSSpecs = classes: template: let
     dpsSpecs = {
       death_knight = ["frost" "unholy"];
@@ -31,7 +34,7 @@
       warrior = ["arms" "fury"];
     };
 
-    # Extract specs that exist in classes a
nd have the template structure
+    # extract specs that exist in classes a
nd have the template structure
     validSpecs = lib.flatten (lib.mapAttrsT
oList (
         className: specNames:
           lib.filter (spec: spec != null) (
map (
@@ -45,7 +48,8 @@
                   defaultRace = classes.${c
lassName}.${specName}.defaultRace;
                   spec = classes.${classNam
e}.${specName};
                 in
-                  if lib.hasAttr defaultRac
e spec.template
+                  if
+                    lib.hasAttr defaultRace
 spec.template
                     && lib.hasAttr "p1" spe
c.template.${defaultRace}
                     && lib.hasAttr "raid" s
pec.template.${defaultRace}.p1
                     && lib.hasAttr template
 spec.template.${defaultRace}.p1.raid
@@ -62,40 +66,38 @@
   in
     validSpecs;
 
-  # Get race configurations for a specific 
class/spec combination
   getRaceConfigs = classes: className: spec
Name: template: phase: encounterType: let
     availableRaces = getPlayableRaces class
Name;
     baseSpec = classes.${className}.${specN
ame};
   in
     map (raceName: {
       inherit className specName raceName;
-      # Access the race-specific config fro
m the new template structure
-      config = 
-        if lib.hasAttr "template" baseSpec 
+      config =
+        if
+          lib.hasAttr "template" baseSpec
           && lib.hasAttr raceName baseSpec.
template
           && lib.hasAttr phase baseSpec.tem
plate.${raceName}
           && lib.hasAttr encounterType base
Spec.template.${raceName}.${phase}
           && lib.hasAttr template baseSpec.
template.${raceName}.${phase}.${encounterTyp
e}
         then baseSpec.template.${raceName}.
${phase}.${encounterType}.${template}
         else throw "Template ${template} no
t found for ${className}/${specName}/${raceN
ame} at ${phase}.${encounterType}";
-    }) availableRaces;
+    })
+    availableRaces;
 
-  # Race comparison function
   mkRaceComparison = {
     class,
     spec,
     encounter,
     iterations ? 10000,
-    phase ? "p1", 
+    phase ? "p1",
     encounterType ? "raid",
     targetCount ? "single",
     duration ? "long",
     template ? "singleTarget",
   }: let
-    # Get race configurations for this clas
s/spec
     raceConfigs = getRaceConfigs classes cl
ass spec template phase encounterType;
-    
-    # Create individual simulation derivati
ons for each race
+
+    # create individual simulation derivati
ons for each race
     simDerivations = lib.listToAttrs (map (
raceConfig: {
         name = "${raceConfig.className}-${r
aceConfig.specName}-${raceConfig.raceName}";
         value = let
@@ -111,21 +113,19 @@
             buildInputs = [pkgs.jq];
             nativeBuildInputs = [inputs.wow
sims.packages.${pkgs.system}.wowsimcli];
           } ''
-            # Generate input JSON file
             cat > input.json << 'EOF'
             ${simInput}
             EOF
 
-            # Run simulation
             echo "Running ${raceConfig.clas
sName}/${raceConfig.specName}/${raceConfig.r
aceName} simulation..."
             if wowsimcli sim --infile input
.json --outfile output.json; then
-              # Extract DPS statistics
+              # extract dps statistics
               avgDps=$(jq -r '.raidMetrics.
dps.avg // 0' output.json)
               maxDps=$(jq -r '.raidMetrics.
dps.max // 0' output.json)
               minDps=$(jq -r '.raidMetrics.
dps.min // 0' output.json)
               stdevDps=$(jq -r '.raidMetric
s.dps.stdev // 0' output.json)
 
-              # Create loadout info
+              # construct loadout info
               loadout=$(echo '${builtins.to
JSON raceConfig.config}' | jq '{
                 consumables,
                 talentsString,
@@ -137,7 +137,7 @@
                 profession2
               }')
 
-              # Create final result
+              # create final result
               jq -n \
                 --arg raceName "${raceConfi
g.raceName}" \
                 --arg avgDps "$avgDps" \
@@ -161,10 +161,8 @@
       })
       raceConfigs);
 
-    # Generate output filename: <class>_<sp
ec>_race_<phase>_<encounter-type>_<target-co
unt>_<duration>
     structuredOutput = "${class}_${spec}_ra
ce_${phase}_${encounterType}_${targetCount}_
${duration}";
 
-    # Aggregation script for race compariso
n
     aggregationScript = pkgs.writeShellAppl
ication {
       name = "${structuredOutput}-aggregato
r";
       text = ''
@@ -173,11 +171,10 @@
         echo "Aggregating race comparison r
esults for: ${class}/${spec}"
         echo "Races simulated: ${toString (
lib.length raceConfigs)}"
 
-        # Create base structure
         result=$(jq -n '{}')
 
         ${lib.concatMapStringsSep "\n" (rac
eConfig: ''
-            # Add ${raceConfig.raceName} re
sults
+            # ${raceConfig.raceName} result
s
             raceData=$(cat ${simDerivations
."${raceConfig.className}-${raceConfig.specN
ame}-${raceConfig.raceName}"})
 
             result=$(echo "$result" | jq \
@@ -193,7 +190,6 @@
           '')
           raceConfigs}
 
-        # Create final output with metadata
         finalResult=$(echo "$result" | jq \
           --arg class "${class}" \
           --arg spec "${spec}" \
@@ -219,9 +215,8 @@
             results: .
           }')
 
-        echo "$finalResult" | tee "${struct
uredOutput}.json"
+        echo "$finalResult" | jq -c '.' | t
ee "${structuredOutput}.json"
 
-        # Copy to web public directory with
 new structure
         repo_root=""
         current_dir="$PWD"
         while [[ "$current_dir" != "/" ]]; 
do
@@ -237,11 +232,10 @@
           repo_root="$PWD"
         fi
 
-        # Create directory structure: /comp
arison/<class>/<spec>/
         comparison_dir="$repo_root/web/publ
ic/data/comparison/${class}/${spec}"
         mkdir -p "$comparison_dir"
 
-        # Copy race comparison file
+        # copy race comparison file
         cp "${structuredOutput}.json" "$com
parison_dir/"
         echo "Copied to: $comparison_dir/${
structuredOutput}.json"
 
@@ -253,14 +247,14 @@
           select(.value.dps != null and .va
lue.dps > 0) |
           "\(.key): \(.value.dps | floor) D
PS"
         ' | sort -k2 -nr
-        
+
         # Show any failed races
         failed_races=$(echo "$finalResult" 
| jq -r '
           .results | to_entries[] |
           select(.value.dps == null or .val
ue.dps <= 0) |
           .key
         ')
-        
+
         if [[ -n "$failed_races" ]]; then
           echo ""
           echo "Failed races (no valid DPS 
data):"
@@ -273,10 +267,8 @@
       runtimeInputs = [pkgs.jq pkgs.coreuti
ls];
     };
   in {
-    # Individual race simulation derivation
s (for debugging)
     simulations = simDerivations;
 
-    # Main aggregation script
     script = aggregationScript;
 
     metadata = {
@@ -287,7 +279,6 @@
     };
   };
 
-  # Main mkMassSim function
   mkMassSim = {
     specs ? "dps",
     encounter,
@@ -298,7 +289,7 @@
     duration ? "long",
     template ? "singleTarget",
   }: let
-    # Get the list of specs based on the sp
ecs parameter
+    # get the list of specs based on the sp
ecs parameter
     specConfigs =
       if specs == "dps"
       then getAllDPSSpecs classes template
@@ -306,7 +297,7 @@
       then specs
       else throw "specs must be 'dps' or a 
list of spec configurations";
 
-    # Create individual simulation derivati
ons for each spec
+    # create individual simulation derivati
ons for each spec
     simDerivations = lib.listToAttrs (map (
spec: {
         name = "${spec.className}-${spec.sp
ecName}";
         value = let
@@ -327,16 +318,16 @@
             ${simInput}
             EOF
 
-            # Run simulation
             echo "Running ${spec.className}
/${spec.specName} simulation..."
             if wowsimcli sim --infile input
.json --outfile output.json; then
-              # Extract DPS statistics
+
               avgDps=$(jq -r '.raidMetrics.
dps.avg // 0' output.json)
               maxDps=$(jq -r '.raidMetrics.
dps.max // 0' output.json)
               minDps=$(jq -r '.raidMetrics.
dps.min // 0' output.json)
               stdevDps=$(jq -r '.raidMetric
s.dps.stdev // 0' output.json)
 
-              # Create loadout without rota
tion (only keep consumables, talents, glyphs
, gear)
+              # create loadout without rota
tion (only keep consumables, talents, glyphs
, gear)
+              # TODO: should we output the 
apl?
               loadout=$(echo '${builtins.to
JSON spec.config}' | jq '{
                 consumables,
                 talentsString,
@@ -348,7 +339,7 @@
                 profession2
               }')
 
-              # Create final result with al
l DPS statistics
+              # create final result with al
l DPS statistics
               jq -n \
                 --arg className "${spec.cla
ssName}" \
                 --arg specName "${spec.spec
Name}" \
@@ -431,10 +422,10 @@
             results: .
           }')
 
-        echo "$finalResult" | tee "${struct
uredOutput}.json"
+        echo "$finalResult" | jq -c '.' | t
ee "${structuredOutput}.json"
 
         # copy to web public directory for 
web frontend
-        # Find the repo root by looking for
 flake.nix
+        # find the repo root by looking for
 flake.nix
         repo_root=""
         current_dir="$PWD"
         while [[ "$current_dir" != "/" ]]; 
do
@@ -459,14 +450,12 @@
         mkdir -p "$rankings_dir"
         mkdir -p "$archive_dir"
 
-        # Archive existing file if it exist
s
         if [[ -f "$existing_file" ]]; then
           timestamp=$(date +"%Y%m%d_%H%M%S"
)
           archived_name="${structuredOutput
}_$timestamp.json"
           cp "$existing_file" "$archive_dir
/$archived_name"
           echo "Archived existing file: $ar
chived_name"
 
-          # Generate changelog by comparing
 with archived version
           echo "Generating changelog..."
           changes=$(echo "$finalResult" | j
q --slurpfile archived "$existing_file" '
             .results as $current |
@@ -497,7 +486,6 @@
             echo "Found $change_count DPS c
hanges:"
             echo "$changes" | jq -r '.[] | 
"  \(.class)/\(.spec): \(if .absolute_change
 > 0 then "+" else "" end)\(.absolute_change
) DPS (\(if .percent_change > 0 then "+" els
e "" end)\(.percent_change)%)"'
 
-            # Update or create changelog
             changelog_file="$web_data_dir/c
hangelog.json"
             if [[ -f "$changelog_file" ]]; 
then
               current_changelog=$(cat "$cha
ngelog_file")
 

diff --git a/nix/checks.nix b/nix/checks.nix
deleted file mode 100644
index f6a1e14..0000000
--- a/nix/checks.nix
+++ /dev/null
@@ -1,155 +0,0 @@
-{
-  lib,
-  classes,
-  encounter,
-  buffs,
-  debuffs,
-  inputs,
-  ...
-}: {
-  perSystem = {pkgs, ...}: let
-    inherit (lib.sim.simulation) mkSim;
-    
-    # Helper function to get all available class/spec combinations
-    getAllClassSpecs = classes: 
-      lib.flatten (lib.mapAttrsToList (className: classSpecs:
-        lib.mapAttrsToList (specName: specConfigs:
-          if lib.hasAttr "template" specConfigs 
-             && lib.hasAttr "p1" specConfigs.template
-             && lib.hasAttr "raid" specConfigs.template.p1
-             && lib.hasAttr "singleTarget" specConfigs.template.p1.raid
-          then { inherit className specName; config = specConfigs.template.p1.rai
d.singleTarget; }
-          else null
-        ) classSpecs
-      ) classes);
-    
-    # Filter out null values
-    availableSpecs = lib.filter (x: x != null) (getAllClassSpecs classes);
-    
-    # Create test simulation for a given spec
-    createSpecTest = {className, specName, config}: let
-      testSim = mkSim {
-        requestId = "test-${className}-${specName}";
-        iterations = 100; # Smaller iteration count for faster testing
-        player = config;
-        buffs = buffs.full;
-        debuffs = debuffs.full;
-        encounter = encounter.raid.long.singleTarget;
-      };
-      
-      testScript = pkgs.writeShellScript "test-${className}-${specName}" ''
-        set -euo pipefail
-        
-        echo "Testing ${className}/${specName}..."
-        
-        # Generate input file
-        cat > input.json << 'EOF'
-        ${testSim}
-        EOF
-        
-        # Run simulation
-        if ! wowsimcli sim --infile input.json --outfile output.json; then
-          echo "ERROR: wowsimcli failed for ${className}/${specName}"
-          exit 1
-        fi
-        
-        # Validate output
-        if [ ! -f output.json ]; then
-          echo "ERROR: No output file generated for ${className}/${specName}"
-          exit 1
-        fi
-        
-        # Check DPS value exists and is reasonable
-        avgDps=$(jq -r '.raidMetrics.dps.avg // "null"' output.json)
-        if [ "$avgDps" = "null" ]; then
-          echo "ERROR: No DPS value found for ${className}/${specName}"
-          exit 1
-        fi
-        
-        # Basic sanity check - DPS should be positive and reasonable (>1000)
-        # But let's debug what we're getting first
-        echo "DEBUG: Raw DPS value: '$avgDps'"
-        
-        if [ "$(echo "$avgDps <= 0" | bc -l)" = "1" ]; then
-          echo "ERROR: DPS too low or zero ($avgDps) for ${className}/${specName}
"
-          echo "DEBUG: Full output:"
-          jq '.' output.json | head -20
-          exit 1
-        fi
-        
-        echo "SUCCESS: ${className}/${specName} - DPS: $avgDps"
-        rm -f input.json output.json
-      '';
-    in testScript;
-    
-    # Create individual tests for each spec
-    specTests = lib.listToAttrs (map (spec: {
-      name = "${spec.className}-${spec.specName}";
-      value = createSpecTest spec;
-    }) availableSpecs);
-    
-    # Create combined test that runs all specs
-    allSpecsTest = pkgs.writeShellScript "test-all-specs" ''
-      set -euo pipefail
-      
-      echo "Running WoW simulation tests for all available specs..."
-      echo "Found ${toString (lib.length availableSpecs)} specs to test"
-      echo ""
-      
-      failed_tests=()
-      
-      ${lib.concatMapStringsSep "\n" (spec: ''
-        if ! ${createSpecTest spec}; then
-          failed_tests+=("${spec.className}/${spec.specName}")
-        fi
-      '') availableSpecs}
-      
-      echo ""
-      if [ ''${#failed_tests[@]} -eq 0 ]; then
-        echo "? All ${toString (lib.length availableSpecs)} specs passed!"
-        exit 0
-      else
-        echo "? ''${#failed_tests[@]} specs failed:"
-        printf '%s\n' "''${failed_tests[@]}"
-        exit 1
-      fi
-    '';
-    
-  in {
-    checks = {
-      # Individual spec tests
-      } // specTests // {
-      # Combined test
-      all-specs = pkgs.runCommand "test-all-specs" {
-        buildInputs = [
-          pkgs.jq 
-          pkgs.bc
-          inputs.wowsims.packages.${pkgs.system}.wowsimcli
-        ];
-      } ''
-        cd $TMPDIR
-        ${allSpecsTest}
-        touch $out
-      '';
-      
-      # Quick test with just a few representative specs
-      smoke-test = pkgs.runCommand "smoke-test" {
-        buildInputs = [
-          pkgs.jq 
-          pkgs.bc
-          inputs.wowsims.packages.${pkgs.system}.wowsimcli
-        ];
-      } ''
-        cd $TMPDIR
-        echo "Running smoke test with a few representative specs..."
-        
-        ${lib.concatMapStringsSep "\n" (spec: 
-          "${createSpecTest spec}"
-        ) (lib.take 3 availableSpecs)}
-        
-        echo "? Smoke test passed!"
-        touch $out
-      '';
-    };
-  };
-}
\ No newline at end of file

diff --git a/nix/checks.nix b/nix/checks.nix
deleted file mode 100644
index f6a1e14..0000000
--- a/nix/checks.nix
+++ /dev/null
@@ -1,155 +0,0 @@
-{
-  lib,
-  classes,
-  encounter,
-  buffs,
-  debuffs,
-  inputs,
-  ...
-}: {
-  perSystem = {pkgs, ...}: let
-    inherit (lib.sim.simulation) mkSim;
-    
-    # Helper function to get all available 
class/spec combinations
-    getAllClassSpecs = classes: 
-      lib.flatten (lib.mapAttrsToList (clas
sName: classSpecs:
-        lib.mapAttrsToList (specName: specC
onfigs:
-          if lib.hasAttr "template" specCon
figs 
-             && lib.hasAttr "p1" specConfig
s.template
-             && lib.hasAttr "raid" specConf
igs.template.p1
-             && lib.hasAttr "singleTarget" 
specConfigs.template.p1.raid
-          then { inherit className specName
; config = specConfigs.template.p1.raid.sing
leTarget; }
-          else null
-        ) classSpecs
-      ) classes);
-    
-    # Filter out null values
-    availableSpecs = lib.filter (x: x != nu
ll) (getAllClassSpecs classes);
-    
-    # Create test simulation for a given sp
ec
-    createSpecTest = {className, specName, 
config}: let
-      testSim = mkSim {
-        requestId = "test-${className}-${sp
ecName}";
-        iterations = 100; # Smaller iterati
on count for faster testing
-        player = config;
-        buffs = buffs.full;
-        debuffs = debuffs.full;
-        encounter = encounter.raid.long.sin
gleTarget;
-      };
-      
-      testScript = pkgs.writeShellScript "t
est-${className}-${specName}" ''
-        set -euo pipefail
-        
-        echo "Testing ${className}/${specNa
me}..."
-        
-        # Generate input file
-        cat > input.json << 'EOF'
-        ${testSim}
-        EOF
-        
-        # Run simulation
-        if ! wowsimcli sim --infile input.j
son --outfile output.json; then
-          echo "ERROR: wowsimcli failed for
 ${className}/${specName}"
-          exit 1
-        fi
-        
-        # Validate output
-        if [ ! -f output.json ]; then
-          echo "ERROR: No output file gener
ated for ${className}/${specName}"
-          exit 1
-        fi
-        
-        # Check DPS value exists and is rea
sonable
-        avgDps=$(jq -r '.raidMetrics.dps.av
g // "null"' output.json)
-        if [ "$avgDps" = "null" ]; then
-          echo "ERROR: No DPS value found f
or ${className}/${specName}"
-          exit 1
-        fi
-        
-        # Basic sanity check - DPS should b
e positive and reasonable (>1000)
-        # But let's debug what we're gettin
g first
-        echo "DEBUG: Raw DPS value: '$avgDp
s'"
-        
-        if [ "$(echo "$avgDps <= 0" | bc -l
)" = "1" ]; then
-          echo "ERROR: DPS too low or zero 
($avgDps) for ${className}/${specName}"
-          echo "DEBUG: Full output:"
-          jq '.' output.json | head -20
-          exit 1
-        fi
-        
-        echo "SUCCESS: ${className}/${specN
ame} - DPS: $avgDps"
-        rm -f input.json output.json
-      '';
-    in testScript;
-    
-    # Create individual tests for each spec
-    specTests = lib.listToAttrs (map (spec:
 {
-      name = "${spec.className}-${spec.spec
Name}";
-      value = createSpecTest spec;
-    }) availableSpecs);
-    
-    # Create combined test that runs all sp
ecs
-    allSpecsTest = pkgs.writeShellScript "t
est-all-specs" ''
-      set -euo pipefail
-      
-      echo "Running WoW simulation tests fo
r all available specs..."
-      echo "Found ${toString (lib.length av
ailableSpecs)} specs to test"
-      echo ""
-      
-      failed_tests=()
-      
-      ${lib.concatMapStringsSep "\n" (spec:
 ''
-        if ! ${createSpecTest spec}; then
-          failed_tests+=("${spec.className}
/${spec.specName}")
-        fi
-      '') availableSpecs}
-      
-      echo ""
-      if [ ''${#failed_tests[@]} -eq 0 ]; t
hen
-        echo "? All ${toString (lib.length 
availableSpecs)} specs passed!"
-        exit 0
-      else
-        echo "? ''${#failed_tests[@]} specs
 failed:"
-        printf '%s\n' "''${failed_tests[@]}
"
-        exit 1
-      fi
-    '';
-    
-  in {
-    checks = {
-      # Individual spec tests
-      } // specTests // {
-      # Combined test
-      all-specs = pkgs.runCommand "test-all
-specs" {
-        buildInputs = [
-          pkgs.jq 
-          pkgs.bc
-          inputs.wowsims.packages.${pkgs.sy
stem}.wowsimcli
-        ];
-      } ''
-        cd $TMPDIR
-        ${allSpecsTest}
-        touch $out
-      '';
-      
-      # Quick test with just a few represen
tative specs
-      smoke-test = pkgs.runCommand "smoke-t
est" {
-        buildInputs = [
-          pkgs.jq 
-          pkgs.bc
-          inputs.wowsims.packages.${pkgs.sy
stem}.wowsimcli
-        ];
-      } ''
-        cd $TMPDIR
-        echo "Running smoke test with a few
 representative specs..."
-        
-        ${lib.concatMapStringsSep "\n" (spe
c: 
-          "${createSpecTest spec}"
-        ) (lib.take 3 availableSpecs)}
-        
-        echo "? Smoke test passed!"
-        touch $out
-      '';
-    };
-  };
-}
\ No newline at end of file
 

diff --git a/nix/classes/death_knight/blood.nix b/nix/classes/death_knight/blood.n
ix
index b05ea50..e1c68c6 100644
--- a/nix/classes/death_knight/blood.nix
+++ b/nix/classes/death_knight/blood.nix
@@ -53,4 +53,4 @@
     };
   };
 in
-  blood
\ No newline at end of file
+  blood

diff --git a/nix/classes/death_knight/blood.
nix b/nix/classes/death_knight/blood.nix
index b05ea50..e1c68c6 100644
--- a/nix/classes/death_knight/blood.nix
+++ b/nix/classes/death_knight/blood.nix
@@ -53,4 +53,4 @@
     };
   };
 in
-  blood
\ No newline at end of file
+  blood
 

diff --git a/nix/classes/death_knight/default.nix b/nix/classes/death_knight/defau
lt.nix
index efb9a20..9892eba 100644
--- a/nix/classes/death_knight/default.nix
+++ b/nix/classes/death_knight/default.nix
@@ -21,4 +21,3 @@
   unholy = import ./unholy.nix {inherit lib consumables;};
   # blood = import ./blood.nix {inherit lib consumables;};
 }
-

diff --git a/nix/classes/death_knight/defaul
t.nix b/nix/classes/death_knight/default.nix
index efb9a20..9892eba 100644
--- a/nix/classes/death_knight/default.nix
+++ b/nix/classes/death_knight/default.nix
@@ -21,4 +21,3 @@
   unholy = import ./unholy.nix {inherit lib
 consumables;};
   # blood = import ./blood.nix {inherit lib
 consumables;};
 }
-
 

diff --git a/nix/classes/druid/feral.nix b/nix/classes/druid/feral.nix
index 055e05e..2b40aef 100644
--- a/nix/classes/druid/feral.nix
+++ b/nix/classes/druid/feral.nix
@@ -22,12 +22,11 @@
       options = {};
       inherit race gearset talents apl consumables profession1 profession2 distan
ceFromTarget;
       glyphs = {
-        major1 = 54812; # Rip
+        major1 = 54812;
       };
     };
 
   feral = {
-    # Talent configurations
     talents = {
       primal = "321232";
     };
@@ -67,4 +66,3 @@
   };
 in
   feral
-

diff --git a/nix/classes/druid/feral.nix b/n
ix/classes/druid/feral.nix
index 055e05e..2b40aef 100644
--- a/nix/classes/druid/feral.nix
+++ b/nix/classes/druid/feral.nix
@@ -22,12 +22,11 @@
       options = {};
       inherit race gearset talents apl cons
umables profession1 profession2 distanceFrom
Target;
       glyphs = {
-        major1 = 54812; # Rip
+        major1 = 54812;
       };
     };
 
   feral = {
-    # Talent configurations
     talents = {
       primal = "321232";
     };
@@ -67,4 +66,3 @@
   };
 in
   feral
-
 

diff --git a/nix/classes/druid/guardian.nix b/nix/classes/druid/guardian.nix
index 9e3f98e..a42e2f9 100644
--- a/nix/classes/druid/guardian.nix
+++ b/nix/classes/druid/guardian.nix
@@ -26,17 +26,15 @@
       };
       inherit race gearset talents apl consumables profession1 profession2 distan
ceFromTarget;
       glyphs = {
-        major1 = 94390; # frenzied regeneration
-        major2 = 40897; # maul
-        major3 = 54818; # survival instincts
+        major1 = 94390;
+        major2 = 40897;
+        major3 = 54818;
       };
     };
 
   guardian = {
-    # Talent configurations
+    # talent configurations
     talents = {
-      incarnation = "312122";
-      heartOfTheWild = "312112";
     };
 
     p1 = {
@@ -51,4 +49,4 @@
     };
   };
 in
-  guardian
\ No newline at end of file
+  guardian

diff --git a/nix/classes/druid/guardian.nix 
b/nix/classes/druid/guardian.nix
index 9e3f98e..a42e2f9 100644
--- a/nix/classes/druid/guardian.nix
+++ b/nix/classes/druid/guardian.nix
@@ -26,17 +26,15 @@
       };
       inherit race gearset talents apl cons
umables profession1 profession2 distanceFrom
Target;
       glyphs = {
-        major1 = 94390; # frenzied regenera
tion
-        major2 = 40897; # maul
-        major3 = 54818; # survival instinct
s
+        major1 = 94390;
+        major2 = 40897;
+        major3 = 54818;
       };
     };
 
   guardian = {
-    # Talent configurations
+    # talent configurations
     talents = {
-      incarnation = "312122";
-      heartOfTheWild = "312112";
     };
 
     p1 = {
@@ -51,4 +49,4 @@
     };
   };
 in
-  guardian
\ No newline at end of file
+  guardian
 

diff --git a/nix/classes/mage/default.nix b/nix/classes/mage/default.nix
index 5e5280d..e54a263 100644
--- a/nix/classes/mage/default.nix
+++ b/nix/classes/mage/default.nix
@@ -21,4 +21,3 @@
   fire = import ./fire.nix {inherit lib consumables;};
   frost = import ./frost.nix {inherit lib consumables;};
 }
-

diff --git a/nix/classes/mage/default.nix b/
nix/classes/mage/default.nix
index 5e5280d..e54a263 100644
--- a/nix/classes/mage/default.nix
+++ b/nix/classes/mage/default.nix
@@ -21,4 +21,3 @@
   fire = import ./fire.nix {inherit lib con
sumables;};
   frost = import ./frost.nix {inherit lib c
onsumables;};
 }
-
 

diff --git a/nix/classes/monk/brewmaster.nix b/nix/classes/monk/brewmaster.nix
index 9f08134..f07b22b 100644
--- a/nix/classes/monk/brewmaster.nix
+++ b/nix/classes/monk/brewmaster.nix
@@ -34,8 +34,8 @@
   brewmaster = {
     # Talent configurations
     talents = {
-      xuen = "213322"; # Single target build with Xuen
-      rjw = "233321"; # AoE build with RJW
+      xuen = "213322";
+      rjw = "233321";
     };
 
     glyphs = {

diff --git a/nix/classes/monk/brewmaster.nix
 b/nix/classes/monk/brewmaster.nix
index 9f08134..f07b22b 100644
--- a/nix/classes/monk/brewmaster.nix
+++ b/nix/classes/monk/brewmaster.nix
@@ -34,8 +34,8 @@
   brewmaster = {
     # Talent configurations
     talents = {
-      xuen = "213322"; # Single target buil
d with Xuen
-      rjw = "233321"; # AoE build with RJW
+      xuen = "213322";
+      rjw = "233321";
     };
 
     glyphs = {
 

diff --git a/nix/classes/monk/windwalker.nix b/nix/classes/monk/windwalker.nix
index eac0d91..ecd4884 100644
--- a/nix/classes/monk/windwalker.nix
+++ b/nix/classes/monk/windwalker.nix
@@ -10,8 +10,8 @@
     defaultRace = "orc";
 
     talents = {
-      xuen = "213322"; # Single target build with Xuen
-      rjw = "233321"; # AoE build with RJW
+      xuen = "213322";
+      rjw = "233321";
     };
 
     glyphs = {

diff --git a/nix/classes/monk/windwalker.nix
 b/nix/classes/monk/windwalker.nix
index eac0d91..ecd4884 100644
--- a/nix/classes/monk/windwalker.nix
+++ b/nix/classes/monk/windwalker.nix
@@ -10,8 +10,8 @@
     defaultRace = "orc";
 
     talents = {
-      xuen = "213322"; # Single target buil
d with Xuen
-      rjw = "233321"; # AoE build with RJW
+      xuen = "213322";
+      rjw = "233321";
     };
 
     glyphs = {
 

diff --git a/nix/classes/paladin/default.nix b/nix/classes/paladin/default.nix
index e64ce9b..1685639 100644
--- a/nix/classes/paladin/default.nix
+++ b/nix/classes/paladin/default.nix
@@ -14,4 +14,3 @@
   retribution = import ./retribution.nix {inherit lib consumables;};
   # protection = import ./protection.nix {inherit lib consumables;};
 }
-

diff --git a/nix/classes/paladin/default.nix
 b/nix/classes/paladin/default.nix
index e64ce9b..1685639 100644
--- a/nix/classes/paladin/default.nix
+++ b/nix/classes/paladin/default.nix
@@ -14,4 +14,3 @@
   retribution = import ./retribution.nix {i
nherit lib consumables;};
   # protection = import ./protection.nix {i
nherit lib consumables;};
 }
-
 

diff --git a/nix/classes/paladin/protection.nix b/nix/classes/paladin/protection.n
ix
index 11f5071..792ff3a 100644
--- a/nix/classes/paladin/protection.nix
+++ b/nix/classes/paladin/protection.nix
@@ -27,13 +27,12 @@
       inherit race gearset talents apl consumables profession1 profession2 distan
ceFromTarget;
       glyphs = {
         major1 = 41101; # consecration
-        major2 = 54928; # hammer of the righteous  
+        major2 = 54928; # hammer of the righteous
         major3 = 54927; # focused shield
       };
     };
 
   protection = {
-    # Talent configurations
     talents = {
       hammer = "311111";
       zealotry = "311121";
@@ -51,4 +50,4 @@
     };
   };
 in
-  protection
\ No newline at end of file
+  protection

diff --git a/nix/classes/paladin/protection.
nix b/nix/classes/paladin/protection.nix
index 11f5071..792ff3a 100644
--- a/nix/classes/paladin/protection.nix
+++ b/nix/classes/paladin/protection.nix
@@ -27,13 +27,12 @@
       inherit race gearset talents apl cons
umables profession1 profession2 distanceFrom
Target;
       glyphs = {
         major1 = 41101; # consecration
-        major2 = 54928; # hammer of the rig
hteous  
+        major2 = 54928; # hammer of the rig
hteous
         major3 = 54927; # focused shield
       };
     };
 
   protection = {
-    # Talent configurations
     talents = {
       hammer = "311111";
       zealotry = "311121";
@@ -51,4 +50,4 @@
     };
   };
 in
-  protection
\ No newline at end of file
+  protection
 

diff --git a/nix/classes/priest/default.nix b/nix/classes/priest/default.nix
index 77ea529..dfa3bf7 100644
--- a/nix/classes/priest/default.nix
+++ b/nix/classes/priest/default.nix
@@ -19,4 +19,3 @@
   ];
   shadow = import ./shadow.nix {inherit lib consumables;};
 }
-

diff --git a/nix/classes/priest/default.nix 
b/nix/classes/priest/default.nix
index 77ea529..dfa3bf7 100644
--- a/nix/classes/priest/default.nix
+++ b/nix/classes/priest/default.nix
@@ -19,4 +19,3 @@
   ];
   shadow = import ./shadow.nix {inherit lib
 consumables;};
 }
-
 

diff --git a/nix/classes/rogue/default.nix b/nix/classes/rogue/default.nix
index 6c24604..8bba83e 100644
--- a/nix/classes/rogue/default.nix
+++ b/nix/classes/rogue/default.nix
@@ -20,4 +20,3 @@
   combat = import ./combat.nix {inherit lib consumables;};
   subtlety = import ./subtlety.nix {inherit lib consumables;};
 }
-

diff --git a/nix/classes/rogue/default.nix b
/nix/classes/rogue/default.nix
index 6c24604..8bba83e 100644
--- a/nix/classes/rogue/default.nix
+++ b/nix/classes/rogue/default.nix
@@ -20,4 +20,3 @@
   combat = import ./combat.nix {inherit lib
 consumables;};
   subtlety = import ./subtlety.nix {inherit
 lib consumables;};
 }
-
 

diff --git a/nix/classes/shaman/default.nix b/nix/classes/shaman/default.nix
index fbb3798..4448c61 100644
--- a/nix/classes/shaman/default.nix
+++ b/nix/classes/shaman/default.nix
@@ -15,4 +15,3 @@
   elemental = import ./elemental.nix {inherit lib consumables;};
   enhancement = import ./enhancement.nix {inherit lib consumables;};
 }
-

diff --git a/nix/classes/shaman/default.nix 
b/nix/classes/shaman/default.nix
index fbb3798..4448c61 100644
--- a/nix/classes/shaman/default.nix
+++ b/nix/classes/shaman/default.nix
@@ -15,4 +15,3 @@
   elemental = import ./elemental.nix {inher
it lib consumables;};
   enhancement = import ./enhancement.nix {i
nherit lib consumables;};
 }
-
 

diff --git a/nix/classes/warlock/default.nix b/nix/classes/warlock/default.nix
index 6eae7f1..3c86bbf 100644
--- a/nix/classes/warlock/default.nix
+++ b/nix/classes/warlock/default.nix
@@ -18,4 +18,3 @@
   demonology = import ./demonology.nix {inherit lib consumables;};
   destruction = import ./destruction.nix {inherit lib consumables;};
 }
-

diff --git a/nix/classes/warlock/default.nix
 b/nix/classes/warlock/default.nix
index 6eae7f1..3c86bbf 100644
--- a/nix/classes/warlock/default.nix
+++ b/nix/classes/warlock/default.nix
@@ -18,4 +18,3 @@
   demonology = import ./demonology.nix {inh
erit lib consumables;};
   destruction = import ./destruction.nix {i
nherit lib consumables;};
 }
-
 

diff --git a/nix/classes/warrior/default.nix b/nix/classes/warrior/default.nix
index 0ea0740..c4aef9f 100644
--- a/nix/classes/warrior/default.nix
+++ b/nix/classes/warrior/default.nix
@@ -23,4 +23,3 @@
   fury = import ./fury.nix {inherit lib consumables;};
   # protection = import ./protection.nix {inherit lib consumables;};
 }
-

diff --git a/nix/classes/warrior/default.nix
 b/nix/classes/warrior/default.nix
index 0ea0740..c4aef9f 100644
--- a/nix/classes/warrior/default.nix
+++ b/nix/classes/warrior/default.nix
@@ -23,4 +23,3 @@
   fury = import ./fury.nix {inherit lib con
sumables;};
   # protection = import ./protection.nix {i
nherit lib consumables;};
 }
-
 

diff --git a/nix/classes/warrior/protection.nix b/nix/classes/warrior/protection.n
ix
index f932927..7392ddc 100644
--- a/nix/classes/warrior/protection.nix
+++ b/nix/classes/warrior/protection.nix
@@ -26,17 +26,11 @@
       };
       inherit race gearset talents apl consumables profession1 profession2 distan
ceFromTarget;
       glyphs = {
-        major1 = 58375; # shield slam
-        major2 = 58388; # revenge
-        major3 = 58387; # devastate
       };
     };
 
   protection = {
-    # Talent configurations
     talents = {
-      shockwave = "132112";
-      dragonRoar = "132122";
     };
 
     p1 = {
@@ -52,4 +46,3 @@
   };
 in
   protection
-

diff --git a/nix/classes/warrior/protection.
nix b/nix/classes/warrior/protection.nix
index f932927..7392ddc 100644
--- a/nix/classes/warrior/protection.nix
+++ b/nix/classes/warrior/protection.nix
@@ -26,17 +26,11 @@
       };
       inherit race gearset talents apl cons
umables profession1 profession2 distanceFrom
Target;
       glyphs = {
-        major1 = 58375; # shield slam
-        major2 = 58388; # revenge
-        major3 = 58387; # devastate
       };
     };
 
   protection = {
-    # Talent configurations
     talents = {
-      shockwave = "132112";
-      dragonRoar = "132122";
     };
 
     p1 = {
@@ -52,4 +46,3 @@
   };
 in
   protection
-
 

diff --git a/nix/encounter/default.nix b/nix/encounter/default.nix
index 9922523..dfd8ccb 100644
--- a/nix/encounter/default.nix
+++ b/nix/encounter/default.nix
@@ -6,7 +6,6 @@
   inherit (lib.sim.encounter) mkEncounter;
   inherit (lib) mapAttrs genList;
 
-  # Target count configurations
   targetConfigs = {
     singleTarget = [target.defaultRaidBoss];
     cleave = [target.defaultRaidBoss target.defaultRaidBoss];
@@ -16,7 +15,6 @@
     twentyTarget = genList (_: target.defaultRaidBoss) 20;
   };
 
-  # Duration configurations
   durations = {
     long = {
       duration = 300;
@@ -32,7 +30,6 @@
     };
   };
 
-  # Generate encounters for a duration type
   mkDurationEncounters = durationConfig:
     mapAttrs (
       name: targets:

diff --git a/nix/encounter/default.nix b/nix
/encounter/default.nix
index 9922523..dfd8ccb 100644
--- a/nix/encounter/default.nix
+++ b/nix/encounter/default.nix
@@ -6,7 +6,6 @@
   inherit (lib.sim.encounter) mkEncounter;
   inherit (lib) mapAttrs genList;
 
-  # Target count configurations
   targetConfigs = {
     singleTarget = [target.defaultRaidBoss]
;
     cleave = [target.defaultRaidBoss target
.defaultRaidBoss];
@@ -16,7 +15,6 @@
     twentyTarget = genList (_: target.defau
ltRaidBoss) 20;
   };
 
-  # Duration configurations
   durations = {
     long = {
       duration = 300;
@@ -32,7 +30,6 @@
     };
   };
 
-  # Generate encounters for a duration type
   mkDurationEncounters = durationConfig:
     mapAttrs (
       name: targets:
 

diff --git a/nix/lib/encounter.nix b/nix/lib/encounter.nix
index f1aba53..f66d916 100644
--- a/nix/lib/encounter.nix
+++ b/nix/lib/encounter.nix
@@ -1,5 +1,4 @@
 let
-  # Base encounter template
   mkEncounter = {
     duration ? 300,
     durationVariation ? 60,
@@ -15,5 +14,4 @@ let
     executeProportion45 = 0.45;
     executeProportion90 = 0.9;
   };
-  # Duration-based encounter templates
 in {inherit mkEncounter;}

diff --git a/nix/lib/encounter.nix b/nix/lib
/encounter.nix
index f1aba53..f66d916 100644
--- a/nix/lib/encounter.nix
+++ b/nix/lib/encounter.nix
@@ -1,5 +1,4 @@
 let
-  # Base encounter template
   mkEncounter = {
     duration ? 300,
     durationVariation ? 60,
@@ -15,5 +14,4 @@ let
     executeProportion45 = 0.45;
     executeProportion90 = 0.9;
   };
-  # Duration-based encounter templates
 in {inherit mkEncounter;}
 

diff --git a/nix/pkgs/testRaid.nix b/nix/pkgs/testRaid.nix
index 3413a4c..a5d30e3 100644
--- a/nix/pkgs/testRaid.nix
+++ b/nix/pkgs/testRaid.nix
@@ -12,17 +12,17 @@
   # quickly sim a single spec for testing purposes
   inherit (lib.sim.simulation) mkSim;
 
-  class = "monk";
-  spec = "windwalker";
+  class = "warlock";
+  spec = "demonology";
   encounterType = "raid";
 
   raid = mkSim {
     requestId = "raidSimAsync-f2cf5e22118a43c7";
     iterations = 10000;
-    player = classes.${class}.${spec}.template.p1.${encounterType}.singleTarget;
+    player = classes.${class}.${spec}.template.troll.p1.${encounterType}.multiTar
get;
     buffs = buffs.full;
     debuffs = debuffs.full;
-    encounter = encounter.${encounterType}.long.singleTarget;
+    encounter = encounter.${encounterType}.long.threeTarget;
   };
   testRaid = writeShellApplication {
     name = "testRaid";

diff --git a/nix/pkgs/testRaid.nix b/nix/pkg
s/testRaid.nix
index 3413a4c..a5d30e3 100644
--- a/nix/pkgs/testRaid.nix
+++ b/nix/pkgs/testRaid.nix
@@ -12,17 +12,17 @@
   # quickly sim a single spec for testing p
urposes
   inherit (lib.sim.simulation) mkSim;
 
-  class = "monk";
-  spec = "windwalker";
+  class = "warlock";
+  spec = "demonology";
   encounterType = "raid";
 
   raid = mkSim {
     requestId = "raidSimAsync-f2cf5e22118a4
3c7";
     iterations = 10000;
-    player = classes.${class}.${spec}.templ
ate.p1.${encounterType}.singleTarget;
+    player = classes.${class}.${spec}.templ
ate.troll.p1.${encounterType}.multiTarget;
     buffs = buffs.full;
     debuffs = debuffs.full;
-    encounter = encounter.${encounterType}.
long.singleTarget;
+    encounter = encounter.${encounterType}.
long.threeTarget;
   };
   testRaid = writeShellApplication {
     name = "testRaid";
 

diff --git a/nix/target/default.nix b/nix/target/default.nix
index 4de419a..b8d1d35 100644
--- a/nix/target/default.nix
+++ b/nix/target/default.nix
@@ -1,7 +1,16 @@
 {lib, ...}: let
   inherit (lib.sim.target) mkTarget;
   target = {
+    # default raid boss from wowsims
+    # id 31146
+    # level 93
+    # mechanical
+    # 550000 base damage
+    # 0.4 damage spread
+    # 2 swing timer
     defaultRaidBoss = mkTarget {};
+
+    # modeled after the party monkeys in stormstout
     smallTrash = mkTarget {
       level = 90;
       minBaseDamage = 15000;

diff --git a/nix/target/default.nix b/nix/ta
rget/default.nix
index 4de419a..b8d1d35 100644
--- a/nix/target/default.nix
+++ b/nix/target/default.nix
@@ -1,7 +1,16 @@
 {lib, ...}: let
   inherit (lib.sim.target) mkTarget;
   target = {
+    # default raid boss from wowsims
+    # id 31146
+    # level 93
+    # mechanical
+    # 550000 base damage
+    # 0.4 damage spread
+    # 2 swing timer
     defaultRaidBoss = mkTarget {};
+
+    # modeled after the party monkeys in st
ormstout
     smallTrash = mkTarget {
       level = 90;
       minBaseDamage = 15000;
 
[ BACK TO LOG ]
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET