OOKNET                             [ /  search the index  ]  
──────────────────────────────────────────────────────────────────────────────────────
══════════════════════════════════════════════════════════════════════════════════════
OOKNET   [ /  search  ]  
────────────────────────────────────────────────
════════════════════════════════════════════════
 
HASH      61373acd2b71
DATE      2025-11-13
SUBJECT   simulation: WIP trinket logic for professions
FILES     6 CHANGED
HASH      61373acd2b71
DATE      2025-11-13
SUBJECT   simulation: WIP trinket logic for
          professions
FILES     6 CHANGED
 

diff --git a/nix/lib/default.nix b/nix/lib/default.nix
index cb1fe98..7c38391 100644
--- a/nix/lib/default.nix
+++ b/nix/lib/default.nix
@@ -12,6 +12,6 @@
   party = import ./party.nix {inherit lib;};
   classes = import ./classes.nix {inherit lib;};
   itemDatabase = import ./itemDatabase.nix {inherit inputs lib;};
-  trinket = import ./trinket.nix {inherit lib;};
+  trinket = import ./trinket.nix {inherit inputs lib;};
   shellUtils = import ./shell-utils.nix {inherit lib;};
 }

diff --git a/nix/lib/default.nix b/nix/lib/d
efault.nix
index cb1fe98..7c38391 100644
--- a/nix/lib/default.nix
+++ b/nix/lib/default.nix
@@ -12,6 +12,6 @@
   party = import ./party.nix {inherit lib;}
;
   classes = import ./classes.nix {inherit l
ib;};
   itemDatabase = import ./itemDatabase.nix 
{inherit inputs lib;};
-  trinket = import ./trinket.nix {inherit l
ib;};
+  trinket = import ./trinket.nix {inherit i
nputs lib;};
   shellUtils = import ./shell-utils.nix {in
herit lib;};
 }
 

diff --git a/nix/lib/trinket.nix b/nix/lib/trinket.nix
index d122798..59cbc9e 100644
--- a/nix/lib/trinket.nix
+++ b/nix/lib/trinket.nix
@@ -1,4 +1,22 @@
-{lib, ...}: let
+{lib, inputs, ...}: let
+  wowsimsDb = lib.importJSON "${inputs.wowsims}/assets/database/db.json";
+
+  professionEnchantsByProfession = let
+    enchantsByEffectId = lib.listToAttrs (map (enchant: {
+      name = toString enchant.effectId;
+      value = enchant;
+    }) wowsimsDb.enchants);
+  in {
+    "Engineering" = lib.filter (e: e.requiredProfession or null == 4) wowsimsDb.e
nchants;
+    "Tailoring" = lib.filter (e: e.requiredProfession or null == 11) wowsimsDb.en
chants;
+    "Leatherworking" = lib.filter (e: e.requiredProfession or null == 8) wowsimsD
b.enchants;
+    "Inscription" = lib.filter (e: e.requiredProfession or null == 6) wowsimsDb.e
nchants;
+    "Enchanting" = lib.filter (e: e.requiredProfession or null == 3) wowsimsDb.en
chants;
+  };
+
+  professionEnchantEffectIds = lib.mapAttrs (prof: enchants:
+    map (e: e.effectId) enchants
+  ) professionEnchantsByProfession;
   # Remove trinkets from gearset (set slots 12-13 to empty objects)
   removeTrinkets = gearset:
     if !(gearset ? items)
@@ -38,6 +56,25 @@
   # Returns a list of gearsets, each with one trinket in slot 13
   generateTrinketGearsets = baselineGearset: trinketIds:
     map (trinketId: addTrinket baselineGearset trinketId) trinketIds;
+
+  # Remove profession-specific enchants from gearset
+  # Note: This operates on raw equipment BEFORE enrichment, so item.enchant is ju
st a number (effectId)
+  removeProfessionEnchants = gearset: professionName:
+    if !(gearset ? items) || !(professionEnchantEffectIds ? ${professionName})
+    then gearset
+    else let
+      enchantIds = professionEnchantEffectIds.${professionName};
+      hasProfessionEnchant = item:
+        (item ? enchant) && (builtins.elem item.enchant enchantIds);
+    in
+      gearset
+      // {
+        items = map (item:
+          if hasProfessionEnchant item
+          then builtins.removeAttrs item ["enchant"]
+          else item
+        ) gearset.items;
+      };
 in {
-  inherit removeTrinkets addTrinket generateTrinketGearsets;
+  inherit removeTrinkets addTrinket generateTrinketGearsets removeProfessionEncha
nts;
 }

diff --git a/nix/lib/trinket.nix b/nix/lib/t
rinket.nix
index d122798..59cbc9e 100644
--- a/nix/lib/trinket.nix
+++ b/nix/lib/trinket.nix
@@ -1,4 +1,22 @@
-{lib, ...}: let
+{lib, inputs, ...}: let
+  wowsimsDb = lib.importJSON "${inputs.wows
ims}/assets/database/db.json";
+
+  professionEnchantsByProfession = let
+    enchantsByEffectId = lib.listToAttrs (m
ap (enchant: {
+      name = toString enchant.effectId;
+      value = enchant;
+    }) wowsimsDb.enchants);
+  in {
+    "Engineering" = lib.filter (e: e.requir
edProfession or null == 4) wowsimsDb.enchant
s;
+    "Tailoring" = lib.filter (e: e.required
Profession or null == 11) wowsimsDb.enchants
;
+    "Leatherworking" = lib.filter (e: e.req
uiredProfession or null == 8) wowsimsDb.ench
ants;
+    "Inscription" = lib.filter (e: e.requir
edProfession or null == 6) wowsimsDb.enchant
s;
+    "Enchanting" = lib.filter (e: e.require
dProfession or null == 3) wowsimsDb.enchants
;
+  };
+
+  professionEnchantEffectIds = lib.mapAttrs
 (prof: enchants:
+    map (e: e.effectId) enchants
+  ) professionEnchantsByProfession;
   # Remove trinkets from gearset (set slots
 12-13 to empty objects)
   removeTrinkets = gearset:
     if !(gearset ? items)
@@ -38,6 +56,25 @@
   # Returns a list of gearsets, each with o
ne trinket in slot 13
   generateTrinketGearsets = baselineGearset
: trinketIds:
     map (trinketId: addTrinket baselineGear
set trinketId) trinketIds;
+
+  # Remove profession-specific enchants fro
m gearset
+  # Note: This operates on raw equipment BE
FORE enrichment, so item.enchant is just a n
umber (effectId)
+  removeProfessionEnchants = gearset: profe
ssionName:
+    if !(gearset ? items) || !(professionEn
chantEffectIds ? ${professionName})
+    then gearset
+    else let
+      enchantIds = professionEnchantEffectI
ds.${professionName};
+      hasProfessionEnchant = item:
+        (item ? enchant) && (builtins.elem 
item.enchant enchantIds);
+    in
+      gearset
+      // {
+        items = map (item:
+          if hasProfessionEnchant item
+          then builtins.removeAttrs item ["
enchant"]
+          else item
+        ) gearset.items;
+      };
 in {
-  inherit removeTrinkets addTrinket generat
eTrinketGearsets;
+  inherit removeTrinkets addTrinket generat
eTrinketGearsets removeProfessionEnchants;
 }
 

diff --git a/nix/pkgs/default.nix b/nix/pkgs/default.nix
index 6a77513..17bf37a 100644
--- a/nix/pkgs/default.nix
+++ b/nix/pkgs/default.nix
@@ -39,6 +39,7 @@
       // {
         inherit ookstats;
         allSimulations = simulation.generateAllSimulationsScript pkgs;
+        simInputs = simulation.generateSimInputs pkgs;
         testRaid = callPackage ./testRaid.nix {
           inherit lib classes encounter buffs debuffs wowsimcli;
         };

diff --git a/nix/pkgs/default.nix b/nix/pkgs
/default.nix
index 6a77513..17bf37a 100644
--- a/nix/pkgs/default.nix
+++ b/nix/pkgs/default.nix
@@ -39,6 +39,7 @@
       // {
         inherit ookstats;
         allSimulations = simulation.generat
eAllSimulationsScript pkgs;
+        simInputs = simulation.generateSimI
nputs pkgs;
         testRaid = callPackage ./testRaid.n
ix {
           inherit lib classes encounter buf
fs debuffs wowsimcli;
         };
 

diff --git a/nix/simulation/default.nix b/nix/simulation/default.nix
index 1c2283d..26bda0a 100644
--- a/nix/simulation/default.nix
+++ b/nix/simulation/default.nix
@@ -142,9 +142,15 @@
       runtimeInputs = [pkgs.coreutils pkgs.findutils];
     };
 
+  # Function to generate simulation inputs with pkgs
+  generateSimInputs = pkgs: let
+    simInputsModule = import ./inputs.nix {inherit lib pkgs classes encounter buf
fs debuffs inputs trinket;};
+  in
+    simInputsModule.simInputs;
+
   simulation = {
     # Generation functions that take pkgs as parameter
-    inherit generateMassSimulations generateRaceComparisons generateTrinketCompar
isons generateAllSimulationsScript generateTestGroupSim;
+    inherit generateMassSimulations generateRaceComparisons generateTrinketCompar
isons generateAllSimulationsScript generateTestGroupSim generateSimInputs;
 
     # Configuration and utilities
     inherit config generateScenarios scenarios;

diff --git a/nix/simulation/default.nix b/ni
x/simulation/default.nix
index 1c2283d..26bda0a 100644
--- a/nix/simulation/default.nix
+++ b/nix/simulation/default.nix
@@ -142,9 +142,15 @@
       runtimeInputs = [pkgs.coreutils pkgs.
findutils];
     };
 
+  # Function to generate simulation inputs 
with pkgs
+  generateSimInputs = pkgs: let
+    simInputsModule = import ./inputs.nix {
inherit lib pkgs classes encounter buffs deb
uffs inputs trinket;};
+  in
+    simInputsModule.simInputs;
+
   simulation = {
     # Generation functions that take pkgs a
s parameter
-    inherit generateMassSimulations generat
eRaceComparisons generateTrinketComparisons 
generateAllSimulationsScript generateTestGro
upSim;
+    inherit generateMassSimulations generat
eRaceComparisons generateTrinketComparisons 
generateAllSimulationsScript generateTestGro
upSim generateSimInputs;
 
     # Configuration and utilities
     inherit config generateScenarios scenar
ios;
 

diff --git a/nix/simulation/inputs.nix b/nix/simulation/inputs.nix
new file mode 100644
index 0000000..d0a9218
--- /dev/null
+++ b/nix/simulation/inputs.nix
@@ -0,0 +1,252 @@
+{
+  lib,
+  pkgs,
+  classes,
+  encounter,
+  buffs,
+  debuffs,
+  inputs,
+  trinket,
+  ...
+}: let
+  inherit (lib.sim.simulation) mkSim;
+  config = import ./config.nix {inherit encounter;};
+  massSimFunctions = import ./mkMassSim.nix {inherit lib pkgs classes encounter b
uffs debuffs inputs;};
+  inherit (massSimFunctions) getAllDPSSpecs getRaceConfigs getPlayableRaces;
+
+  # Generate scenarios (target count ? duration combinations)
+  generateScenarios = targetConfigs: durations:
+    lib.flatten (lib.mapAttrsToList (
+        targetCount: targetConfig:
+          map (duration: {
+            inherit targetCount duration;
+            inherit (targetConfig) template;
+            encounter = targetConfig.encounters.${duration};
+          })
+          durations
+      )
+      targetConfigs);
+
+  scenarios = generateScenarios config.targetConfigs config.durations;
+
+  # Helper to make simulation ID
+  makeSimID = {
+    class,
+    spec,
+    phase,
+    targetCount,
+    duration,
+    race ? null,
+    trinket ? null,
+  }:
+    if race != null
+    then "${class}-${spec}-${race}-${phase}-${targetCount}-${duration}"
+    else if trinket != null
+    then "${class}-${spec}-${toString trinket}-${phase}-${targetCount}-${duration
}"
+    else "${class}-${spec}-${phase}-${targetCount}-${duration}";
+
+  # Generate all benchmark (DPS) specs across scenarios
+  allBenchmarkSpecs = lib.flatten (map (
+      phase:
+        lib.flatten (map (scenario: let
+          validSpecs = getAllDPSSpecs classes scenario.template phase;
+        in
+          map (spec: {
+            id = makeSimID {
+              class = spec.className;
+              spec = spec.specName;
+              inherit phase;
+              inherit (scenario) targetCount duration;
+            };
+            inherit (spec) className specName config;
+            inherit phase;
+            inherit (scenario) targetCount duration encounter;
+          })
+          validSpecs)
+        scenarios)
+    )
+    config.phases);
+
+  # Generate all race comparison configs
+  allRaceConfigs = lib.flatten (map (
+      specConfig:
+        lib.flatten (map (scenario: let
+          raceConfigs = getRaceConfigs classes specConfig.class specConfig.spec s
cenario.template "p1" "raid";
+        in
+          map (raceConfig: {
+            id = makeSimID {
+              class = raceConfig.className;
+              spec = raceConfig.specName;
+              race = raceConfig.raceName;
+              phase = "p1";
+              inherit (scenario) targetCount duration;
+            };
+            inherit (raceConfig) className specName raceName config;
+            phase = "p1";
+            inherit (scenario) targetCount duration encounter;
+          })
+          raceConfigs)
+        scenarios)
+    )
+    config.raceComparisonSpecs);
+
+  # Generate all trinket comparison configs
+  allTrinketConfigs = lib.flatten (map (
+      specConfig:
+        lib.flatten (map (scenario: let
+          # Get the spec's default race configuration
+          spec = classes.${specConfig.class}.${specConfig.spec};
+          defaultRace = spec.defaultRace;
+          baseConfig =
+            if
+              lib.hasAttr "template" spec
+              && lib.hasAttr defaultRace spec.template
+              && lib.hasAttr "p1" spec.template.${defaultRace}
+              && lib.hasAttr "raid" spec.template.${defaultRace}.p1
+              && lib.hasAttr scenario.template spec.template.${defaultRace}.p1.ra
id
+            then spec.template.${defaultRace}.p1.raid.${scenario.template}
+            else throw "Template ${scenario.template} not found for ${specConfig.
class}/${specConfig.spec}/${defaultRace}";
+
+          # Get trinket list for this category from presets.p1
+          trinketList = trinket.presets.p1.${specConfig.trinketCategory} or [];
+        in
+          map (trinketID: {
+            id = makeSimID {
+              class = specConfig.class;
+              spec = specConfig.spec;
+              trinket = trinketID;
+              phase = "p1";
+              inherit (scenario) targetCount duration;
+            };
+            className = specConfig.class;
+            specName = specConfig.spec;
+            inherit trinketID;
+            # Create config with trinket equipped
+            config =
+              baseConfig
+              // {
+                equipment =
+                  baseConfig.equipment
+                  // {
+                    items = let
+                      items = baseConfig.equipment.items;
+                      # Replace trinket slot 12 (first trinket slot)
+                      replaceAt = index: value: list:
+                        lib.imap0 (i: v:
+                          if i == index
+                          then value
+                          else v)
+                        list;
+                    in
+                      replaceAt 12 {id = trinketID;} items;
+                  };
+              };
+            phase = "p1";
+            inherit (scenario) targetCount duration encounter;
+          })
+          trinketList)
+        scenarios)
+    )
+    config.trinketComparisonSpecs);
+
+  wowsimsCommit = inputs.wowsims-upstream.shortRev;
+
+  # Create class-specific buff adjustments
+  getClassSpecificBuffs = class:
+    if class == "ClassWarrior"
+    then buffs.full // {skullBannerCount = 1;}
+    else if class == "ClassShaman"
+    then buffs.full // {stormlashTotemCount = 3;}
+    else buffs.full;
+
+  # Main derivation that generates all input files
+  simInputs = pkgs.runCommand "sim-inputs" {} ''
+    mkdir -p $out/inputs/{benchmark,race,trinket}
+
+    echo "Generating benchmark simulation inputs..."
+    ${lib.concatMapStringsSep "\n" (spec: ''
+        cat > "$out/inputs/benchmark/${spec.id}.json" <<'EOF'
+        ${mkSim {
+          iterations = config.common.iterations;
+          player = spec.config;
+          buffs = getClassSpecificBuffs spec.config.class;
+          debuffs = debuffs.full;
+          encounter = spec.encounter;
+        }}
+        EOF
+      '')
+      allBenchmarkSpecs}
+
+    echo "Generating race comparison inputs..."
+    ${lib.concatMapStringsSep "\n" (raceConfig: ''
+        cat > "$out/inputs/race/${raceConfig.id}.json" <<'EOF'
+        ${mkSim {
+          iterations = config.common.iterations;
+          player = raceConfig.config;
+          buffs = getClassSpecificBuffs raceConfig.config.class;
+          debuffs = debuffs.full;
+          encounter = raceConfig.encounter;
+        }}
+        EOF
+      '')
+      allRaceConfigs}
+
+    echo "Generating trinket comparison inputs..."
+    ${lib.concatMapStringsSep "\n" (trinketConfig: ''
+        cat > "$out/inputs/trinket/${trinketConfig.id}.json" <<'EOF'
+        ${mkSim {
+          iterations = config.common.iterations;
+          player = trinketConfig.config;
+          buffs = getClassSpecificBuffs trinketConfig.config.class;
+          debuffs = debuffs.full;
+          encounter = trinketConfig.encounter;
+        }}
+        EOF
+      '')
+      allTrinketConfigs}
+
+    echo "Generating manifest..."
+    cat > "$out/inputs/manifest.json" <<'EOF'
+    ${builtins.toJSON {
+      version = wowsimsCommit;
+      simulations = {
+        benchmark =
+          map (s: {
+            inherit (s) id className specName phase targetCount duration;
+            file = "benchmark/${s.id}.json";
+            class = s.className;
+            spec = s.specName;
+          })
+          allBenchmarkSpecs;
+        race =
+          map (r: {
+            inherit (r) id className specName raceName phase targetCount duration
;
+            file = "race/${r.id}.json";
+            class = r.className;
+            spec = r.specName;
+            race = r.raceName;
+          })
+          allRaceConfigs;
+        trinket =
+          map (t: {
+            inherit (t) id className specName trinketID phase targetCount duratio
n;
+            file = "trinket/${t.id}.json";
+            class = t.className;
+            spec = t.specName;
+            trinket = t.trinketID;
+          })
+          allTrinketConfigs;
+      };
+    }}
+    EOF
+
+    echo "Generated simulation inputs:"
+    echo "  Benchmark: ${toString (lib.length allBenchmarkSpecs)} inputs"
+    echo "  Race: ${toString (lib.length allRaceConfigs)} inputs"
+    echo "  Trinket: ${toString (lib.length allTrinketConfigs)} inputs"
+  '';
+in {
+  inherit simInputs;
+  # Export for debugging
+  inherit allBenchmarkSpecs allRaceConfigs allTrinketConfigs;
+}

diff --git a/nix/simulation/inputs.nix b/nix
/simulation/inputs.nix
new file mode 100644
index 0000000..d0a9218
--- /dev/null
+++ b/nix/simulation/inputs.nix
@@ -0,0 +1,252 @@
+{
+  lib,
+  pkgs,
+  classes,
+  encounter,
+  buffs,
+  debuffs,
+  inputs,
+  trinket,
+  ...
+}: let
+  inherit (lib.sim.simulation) mkSim;
+  config = import ./config.nix {inherit enc
ounter;};
+  massSimFunctions = import ./mkMassSim.nix
 {inherit lib pkgs classes encounter buffs d
ebuffs inputs;};
+  inherit (massSimFunctions) getAllDPSSpecs
 getRaceConfigs getPlayableRaces;
+
+  # Generate scenarios (target count ? dura
tion combinations)
+  generateScenarios = targetConfigs: durati
ons:
+    lib.flatten (lib.mapAttrsToList (
+        targetCount: targetConfig:
+          map (duration: {
+            inherit targetCount duration;
+            inherit (targetConfig) template
;
+            encounter = targetConfig.encoun
ters.${duration};
+          })
+          durations
+      )
+      targetConfigs);
+
+  scenarios = generateScenarios config.targ
etConfigs config.durations;
+
+  # Helper to make simulation ID
+  makeSimID = {
+    class,
+    spec,
+    phase,
+    targetCount,
+    duration,
+    race ? null,
+    trinket ? null,
+  }:
+    if race != null
+    then "${class}-${spec}-${race}-${phase}
-${targetCount}-${duration}"
+    else if trinket != null
+    then "${class}-${spec}-${toString trink
et}-${phase}-${targetCount}-${duration}"
+    else "${class}-${spec}-${phase}-${targe
tCount}-${duration}";
+
+  # Generate all benchmark (DPS) specs acro
ss scenarios
+  allBenchmarkSpecs = lib.flatten (map (
+      phase:
+        lib.flatten (map (scenario: let
+          validSpecs = getAllDPSSpecs class
es scenario.template phase;
+        in
+          map (spec: {
+            id = makeSimID {
+              class = spec.className;
+              spec = spec.specName;
+              inherit phase;
+              inherit (scenario) targetCoun
t duration;
+            };
+            inherit (spec) className specNa
me config;
+            inherit phase;
+            inherit (scenario) targetCount 
duration encounter;
+          })
+          validSpecs)
+        scenarios)
+    )
+    config.phases);
+
+  # Generate all race comparison configs
+  allRaceConfigs = lib.flatten (map (
+      specConfig:
+        lib.flatten (map (scenario: let
+          raceConfigs = getRaceConfigs clas
ses specConfig.class specConfig.spec scenari
o.template "p1" "raid";
+        in
+          map (raceConfig: {
+            id = makeSimID {
+              class = raceConfig.className;
+              spec = raceConfig.specName;
+              race = raceConfig.raceName;
+              phase = "p1";
+              inherit (scenario) targetCoun
t duration;
+            };
+            inherit (raceConfig) className 
specName raceName config;
+            phase = "p1";
+            inherit (scenario) targetCount 
duration encounter;
+          })
+          raceConfigs)
+        scenarios)
+    )
+    config.raceComparisonSpecs);
+
+  # Generate all trinket comparison configs
+  allTrinketConfigs = lib.flatten (map (
+      specConfig:
+        lib.flatten (map (scenario: let
+          # Get the spec's default race con
figuration
+          spec = classes.${specConfig.class
}.${specConfig.spec};
+          defaultRace = spec.defaultRace;
+          baseConfig =
+            if
+              lib.hasAttr "template" spec
+              && lib.hasAttr defaultRace sp
ec.template
+              && lib.hasAttr "p1" spec.temp
late.${defaultRace}
+              && lib.hasAttr "raid" spec.te
mplate.${defaultRace}.p1
+              && lib.hasAttr scenario.templ
ate spec.template.${defaultRace}.p1.raid
+            then spec.template.${defaultRac
e}.p1.raid.${scenario.template}
+            else throw "Template ${scenario
.template} not found for ${specConfig.class}
/${specConfig.spec}/${defaultRace}";
+
+          # Get trinket list for this categ
ory from presets.p1
+          trinketList = trinket.presets.p1.
${specConfig.trinketCategory} or [];
+        in
+          map (trinketID: {
+            id = makeSimID {
+              class = specConfig.class;
+              spec = specConfig.spec;
+              trinket = trinketID;
+              phase = "p1";
+              inherit (scenario) targetCoun
t duration;
+            };
+            className = specConfig.class;
+            specName = specConfig.spec;
+            inherit trinketID;
+            # Create config with trinket eq
uipped
+            config =
+              baseConfig
+              // {
+                equipment =
+                  baseConfig.equipment
+                  // {
+                    items = let
+                      items = baseConfig.eq
uipment.items;
+                      # Replace trinket slo
t 12 (first trinket slot)
+                      replaceAt = index: va
lue: list:
+                        lib.imap0 (i: v:
+                          if i == index
+                          then value
+                          else v)
+                        list;
+                    in
+                      replaceAt 12 {id = tr
inketID;} items;
+                  };
+              };
+            phase = "p1";
+            inherit (scenario) targetCount 
duration encounter;
+          })
+          trinketList)
+        scenarios)
+    )
+    config.trinketComparisonSpecs);
+
+  wowsimsCommit = inputs.wowsims-upstream.s
hortRev;
+
+  # Create class-specific buff adjustments
+  getClassSpecificBuffs = class:
+    if class == "ClassWarrior"
+    then buffs.full // {skullBannerCount = 
1;}
+    else if class == "ClassShaman"
+    then buffs.full // {stormlashTotemCount
 = 3;}
+    else buffs.full;
+
+  # Main derivation that generates all inpu
t files
+  simInputs = pkgs.runCommand "sim-inputs" 
{} ''
+    mkdir -p $out/inputs/{benchmark,race,tr
inket}
+
+    echo "Generating benchmark simulation i
nputs..."
+    ${lib.concatMapStringsSep "\n" (spec: '
'
+        cat > "$out/inputs/benchmark/${spec
.id}.json" <<'EOF'
+        ${mkSim {
+          iterations = config.common.iterat
ions;
+          player = spec.config;
+          buffs = getClassSpecificBuffs spe
c.config.class;
+          debuffs = debuffs.full;
+          encounter = spec.encounter;
+        }}
+        EOF
+      '')
+      allBenchmarkSpecs}
+
+    echo "Generating race comparison inputs
..."
+    ${lib.concatMapStringsSep "\n" (raceCon
fig: ''
+        cat > "$out/inputs/race/${raceConfi
g.id}.json" <<'EOF'
+        ${mkSim {
+          iterations = config.common.iterat
ions;
+          player = raceConfig.config;
+          buffs = getClassSpecificBuffs rac
eConfig.config.class;
+          debuffs = debuffs.full;
+          encounter = raceConfig.encounter;
+        }}
+        EOF
+      '')
+      allRaceConfigs}
+
+    echo "Generating trinket comparison inp
uts..."
+    ${lib.concatMapStringsSep "\n" (trinket
Config: ''
+        cat > "$out/inputs/trinket/${trinke
tConfig.id}.json" <<'EOF'
+        ${mkSim {
+          iterations = config.common.iterat
ions;
+          player = trinketConfig.config;
+          buffs = getClassSpecificBuffs tri
nketConfig.config.class;
+          debuffs = debuffs.full;
+          encounter = trinketConfig.encount
er;
+        }}
+        EOF
+      '')
+      allTrinketConfigs}
+
+    echo "Generating manifest..."
+    cat > "$out/inputs/manifest.json" <<'EO
F'
+    ${builtins.toJSON {
+      version = wowsimsCommit;
+      simulations = {
+        benchmark =
+          map (s: {
+            inherit (s) id className specNa
me phase targetCount duration;
+            file = "benchmark/${s.id}.json"
;
+            class = s.className;
+            spec = s.specName;
+          })
+          allBenchmarkSpecs;
+        race =
+          map (r: {
+            inherit (r) id className specNa
me raceName phase targetCount duration;
+            file = "race/${r.id}.json";
+            class = r.className;
+            spec = r.specName;
+            race = r.raceName;
+          })
+          allRaceConfigs;
+        trinket =
+          map (t: {
+            inherit (t) id className specNa
me trinketID phase targetCount duration;
+            file = "trinket/${t.id}.json";
+            class = t.className;
+            spec = t.specName;
+            trinket = t.trinketID;
+          })
+          allTrinketConfigs;
+      };
+    }}
+    EOF
+
+    echo "Generated simulation inputs:"
+    echo "  Benchmark: ${toString (lib.leng
th allBenchmarkSpecs)} inputs"
+    echo "  Race: ${toString (lib.length al
lRaceConfigs)} inputs"
+    echo "  Trinket: ${toString (lib.length
 allTrinketConfigs)} inputs"
+  '';
+in {
+  inherit simInputs;
+  # Export for debugging
+  inherit allBenchmarkSpecs allRaceConfigs 
allTrinketConfigs;
+}
 

diff --git a/nix/simulation/mkTrinketComparison.nix b/nix/simulation/mkTrinketComp
arison.nix
index 7a670aa..0aa850f 100644
--- a/nix/simulation/mkTrinketComparison.nix
+++ b/nix/simulation/mkTrinketComparison.nix
@@ -75,10 +75,24 @@
         # Modify profession if trinket requires it
         configWithProfession =
           if requiredProfession != null
-          then
+          then let
+            # Determine which profession is being replaced
+            droppedProfession =
+              if baseConfig.profession2 != requiredProfession
+              then baseConfig.profession2
+              else if baseConfig.profession1 != requiredProfession
+              then baseConfig.profession1
+              else null;
+
+            # Remove enchants from the dropped profession
+            cleanedGearset =
+              if droppedProfession != null
+              then trinketLib.removeProfessionEnchants gearset droppedProfession
+              else gearset;
+          in
             baseConfig
             // {
-              equipment = gearset;
+              equipment = cleanedGearset;
               profession2 = requiredProfession;
             }
           else baseConfig // {equipment = gearset;};

diff --git a/nix/simulation/mkTrinketCompari
son.nix b/nix/simulation/mkTrinketComparison
.nix
index 7a670aa..0aa850f 100644
--- a/nix/simulation/mkTrinketComparison.nix
+++ b/nix/simulation/mkTrinketComparison.nix
@@ -75,10 +75,24 @@
         # Modify profession if trinket requ
ires it
         configWithProfession =
           if requiredProfession != null
-          then
+          then let
+            # Determine which profession is
 being replaced
+            droppedProfession =
+              if baseConfig.profession2 != 
requiredProfession
+              then baseConfig.profession2
+              else if baseConfig.profession
1 != requiredProfession
+              then baseConfig.profession1
+              else null;
+
+            # Remove enchants from the drop
ped profession
+            cleanedGearset =
+              if droppedProfession != null
+              then trinketLib.removeProfess
ionEnchants gearset droppedProfession
+              else gearset;
+          in
             baseConfig
             // {
-              equipment = gearset;
+              equipment = cleanedGearset;
               profession2 = requiredProfess
ion;
             }
           else baseConfig // {equipment = g
earset;};
 
[ BACK TO LOG ]
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET