Codebase Audit: Data, Constants & Types Analysis #67
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
<longcat_arg_value>Comprehensive audit of all files in data/, constants/, and types/ directories. Checking for duplicates, conflicts, type mismatches, banned content, missing entries, naming inconsistencies, data integrity issues, and balance problems.
<longcat_arg_value>## Comprehensive Codebase Audit Report
I read and analyzed all 50+ files across
data/,constants/, andtypes/directories. Here are all findings organized by category.1. DUPLICATE / CONFLICTING DEFINITIONS
[ISSUE 1]
EquipmentSlotdefined in TWO places with potential for driftsrc/lib/game/types/equipmentSlot.ts(line 3-10) — canonical type:'mainHand' | 'offHand' | 'head' | 'body' | 'hands' | 'feet' | 'accessory1' | 'accessory2'src/lib/game/data/equipment/types.ts(line 3) — re-exports fromequipmentSlot.tsviaexport type { EquipmentSlot } from '../../types/equipmentSlot'data/equipment/types.tshas a redundant re-export. TheEQUIPMENT_SLOTSarray indata/equipment/types.ts(line 6-7) manually lists the same values. If one changes without the other, they'll drift.EQUIPMENT_SLOTSarray and derive it from a shared source, or add a compile-time assertion.[ISSUE 2]
rawCostandelemCosthelper functions defined in THREE placessrc/lib/game/constants/elements.ts(lines 7-14) — used by spell definitionssrc/lib/game/data/golems/types.ts(lines 7-13) — duplicate implementationsrc/lib/game/types/spells.ts—SpellCostinterface defines the same shaperawCost/elemCostthat could diverge from the canonical versions inconstants/elements.ts.constants/elements.tsin golem types instead of redefining.[ISSUE 3]
SPELL_EFFECTSindata/enchantments/spell-effects/index.tsre-exportsEnchantmentEffectDeffrom../../enchantment-typesbut theindex.tsatdata/enchantments/index.tsalso re-exports the same type from../enchantment-types. The spell-effects sub-index re-exports it as a type-only export which is fine, but creates two import paths to the same type.[ISSUE 4]
ALL_CASTERconstant defined indata/enchantments/spell-effects/types.ts(line 7) is a local['caster']array. Meanwhiledata/enchantments/combat-effects.tsdefines its ownCASTER_AND_HANDSlocally. These are separate constants for overlapping concepts with no shared source.2. MISSING EXPORTS / BROKEN RE-EXPORTS
[ISSUE 5]
types/index.tsdoes NOT exportDisciplinesAttunementType,PerkType,DisciplinePerk,DisciplineDefinition,DisciplineState,MAX_CONCURRENT_DISCIPLINES, orBASE_CONCURRENT_DISCIPLINESfromtypes/disciplines.tssrc/lib/game/types/index.ts(line 1) — only re-exports fromelements,attunements,spells,equipment,equipmentSlot, andgametypes/disciplinesrather than the barrel export, breaking the pattern used by all other type files.export type { DisciplinesAttunementType, PerkType, DisciplinePerk, DisciplineDefinition, DisciplineState } from './disciplines'andexport { MAX_CONCURRENT_DISCIPLINES, BASE_CONCURRENT_DISCIPLINES } from './disciplines'totypes/index.ts.[ISSUE 6]
types/index.tsdoes NOT exportGolemDef,GolemManaCostfromdata/golems/types.ts— but these aren't in thetypes/directory, they're indata/golems/types.ts. Thetypes/index.tsbarrel doesn't cover data types at all.[ISSUE 7]
constants/index.tsdoes NOT exportELEMENT_OPPOSITES,ELEMENT_ICON_NAMES, orBASE_UNLOCKED_ELEMENTSfromelements.ts— wait, actually it does re-export them (line 7). However,FLOOR_ELEM_CYCLEis NOT exported from the barrel.src/lib/game/constants/index.ts(line 6) — exportsELEMENTSandFLOOR_ELEM_CYCLEis missing from the re-export list.FLOOR_ELEM_CYCLEmust import directly fromconstants/elements.3. TYPE MISMATCHES
[ISSUE 8]
SpellEffect.typeintypes/spells.ts(line 33) includes'shield'and'buff'as effect types, but these are never used in any spell definition across all spell module files. Conversely, spell definitions use effect types'chain','aoe','armor_pierce'which ARE used but the type definition does include'armor_pierce'— however'chain','cast_speed','crit_chance','crit_damage','raw_damage','void_resist','all_damage'used in guardian effects are NOT in theSpellEffect.typeunion.src/lib/game/types/spells.ts(line 33):type: 'burn' | 'freeze' | 'stun' | 'pierce' | 'multicast' | 'shield' | 'buff' | 'chain' | 'aoe' | 'armor_pierce'constants/guardians.tsuse:'burn','armor_pierce','cast_speed','crit_chance','crit_damage','raw_damage','void_resist','all_damage''cast_speed','crit_chance','crit_damage','raw_damage','void_resist','all_damage'that are NOT in theSpellEffect.typeunion. If guardian effects are ever validated against this type, they'll fail.SpellEffect.typeunion.[ISSUE 9]
GuardianDef.effectsintypes/attunements.ts(line 56) is typed as{ type: string; value: number }[]— usingstringinstead of a union type. This is a weak type that bypasses type checking.SpellEffect.typeor a shared effect type.[ISSUE 10]
GolemDefindata/golems/types.tshasbaseManaType: stringandarmorPierce: numberfields. TheGolemManaCostinterface in the same file duplicates the shape ofSpellCostfromtypes/spells.tsbut withelement?: stringinstead of the more specific typing.data/golems/types.ts(lines 15-19):GolemManaCost={ type: 'raw' | 'element'; element?: string; amount: number }types/spells.ts(lines 5-9):SpellCost={ type: 'raw' | 'element'; element?: string; amount: number }[ISSUE 11]
AchievementDef.rewardintypes/game.ts(lines 53-59) hasunlockEffect?: stringbut the type doesn't constrain what values are valid. ThemasterEnchanterachievement usesunlockEffect: 'efficiencyBoost'but there's no enum or union for valid effect IDs.4. HARDCODED VALUES THAT SHOULD BE DERIVED
[ISSUE 12]
FLOOR_ELEM_CYCLEinconstants/elements.ts(line 76) is hardcoded as["fire", "water", "air", "earth", "light", "dark", "death"]— this should be derived from theELEMENTSrecord's base category entries.ELEMENTS, the cycle won't update automatically.[ISSUE 13]
BASE_UNLOCKED_ELEMENTSinconstants/elements.ts(line 79) is hardcoded as['transference']— should be derived fromELEMENTSentries wherecat === 'utility'or similar logic.[ISSUE 14]
MAX_ATTUNEMENT_LEVEL = 10indata/attunements.ts(line 196) is hardcoded. ThegetAttunementXPForLevelfunction has a comment describing scaling up to level 5 but the max is 10 with no XP formula beyond level 5.Math.floor(1000 * Math.pow(2, level - 2) * (level >= 3 ? 1.25 : 1))grows exponentially and will produce enormous numbers for levels 6-10.[ISSUE 15]
getAttunementXPForLevelindata/attunements.ts(lines 178-186) has a broken formula. The comment says "each level requires 2x the previous, starting from 1000" but the code does1000 * Math.pow(2, level - 2) * 1.25for level 3+, which means:1000 * 2^1 * 1.25 = 2500✓ (matches comment)1000 * 2^2 * 1.25 = 5000✓ (matches comment)1000 * 2^3 * 1.25 = 10000✓ (matches comment)1000 * 2^4 * 1.25 = 20000— but the comment says "etc." implying this continues1000 * 2^8 * 1.25 = 320,000— extremely steep5. MISSING ENTRIES IN ARRAYS/RECORDS
[ISSUE 16]
ELEMENT_OPPOSITESinconstants/elements.ts(lines 68-72) is incomplete. It covers fire/water, air/earth, light/dark, and lightning/earth, but is missing opposites for:death— no opposite definedmetal— no opposite definedsand— no opposite definedcrystal— no opposite definedstellar— no opposite definedvoid— no opposite definedtransference— no opposite defined[ISSUE 17]
ELEMENT_ICON_NAMESinconstants/elements.ts(lines 74-79) is missing entries for composite and exotic elements. It has entries for all base + utility + composite + exotic elements (15 entries for 15 elements). Actually, checking: fire, water, air, earth, light, dark, death, transference, metal, sand, lightning, crystal, stellar, void, raw = 15 entries for 15 ELEMENTS entries. This is complete. ✓[ISSUE 18]
GUARDIANSinconstants/guardians.tshas entries for floors 10, 20, 30, 40, 50, 60, 80, 90, 100 — but floor 70 is MISSING. The sequence jumps from 60 to 80.GUARDIANS[70], it getsundefined, which will cause a runtime crash.[ISSUE 19]
CRAFTING_RECIPESindata/crafting-recipes.tsreferences equipment types like'oakStaff','crystalWand','scholarRobe','arcanistStaff','battlestaff','fireCatalyst','runicShield','wizardHat','spellweaveGloves','travelerBoots','silverRing','silverAmulet'. Cross-referencing withEQUIPMENT_TYPES:oakStaff→ ✓ exists incasters.tscrystalWand→ ✓ exists incasters.tsscholarRobe→ ✓ exists inbody.tsarcanistStaff→ ✓ exists incasters.tsbattlestaff→ ✓ exists incasters.tsfireCatalyst→ ✓ exists incatalysts.tsrunicShield→ ✓ exists inshields.tswizardHat→ ✓ exists inhead.tsspellweaveGloves→ ✓ exists inhands.tstravelerBoots→ ✓ exists infeet.tssilverRing→ ✓ exists inaccessories.tssilverAmulet→ ✓ exists inaccessories.ts[ISSUE 20] Spell effect enchantments reference spell IDs via
spellIdin theireffectfield. Cross-referencing a sample:spell_manaBolt→spellId: 'manaBolt'→ ✓ exists inRAW_SPELLSspell_fireball→spellId: 'fireball'→ ✓ exists inBASIC_ELEMENTAL_SPELLSspell_stellarNova→spellId: 'stellarNova'→ ✓ exists inLEGENDARY_SPELLS[ISSUE 21]
DEFENSE_EFFECTSindata/enchantments/defense-effects.tsis an EMPTY record{}. The file comment says "Currently empty - no defense effects defined."EnchantmentEffectCategorytype includes'defense'as a valid category, but no effects exist for it.6. INCONSISTENT NAMING CONVENTIONS
[ISSUE 22] Inconsistent spell naming: some use camelCase keys (
fireball,waterJet,stoneBullet), but the AOE variants use a different pattern:fireballAoe(lowercase 'aoe') vsearthquakeAoe. The pattern is inconsistent —fireballAoeappends 'Aoe' whileearthquakeAoealso appends 'aoe'. However,meteorShowerandblizzarddon't use the Aoe suffix despite being AOE spells.src/lib/game/constants/spells-modules/aoe-spells.ts—fireballAoe,frostNova,meteorShower,blizzard,earthquakeAoe,apocalypseAoesuffix, others don't.[ISSUE 23] Inconsistent enchantment effect ID naming:
damage_5,damage_10,damage_pct_10,crit_5,attack_speed_10(snake_case with numbers)mana_cap_50,mana_regen_1,click_mana_1(snake_case with numbers)sword_fire,sword_frost(snake_case)spell_echo_10,guardian_dmg_10(snake_case with numbers)meditate_10,study_10,insight_5(snake_case with numbers)spell_manaBolt,spell_fireball(snake_case with camelCase spell IDs)spell_while others don't use category prefixes.[ISSUE 24]
EquipmentTypeindata/equipment/types.tsusesbaseDamageandbaseCastSpeedfor swords, butSpellDefintypes/spells.tsusesdmg(notbaseDamage) andcastSpeed(notbaseCastSpeed). Different naming for the same concepts.baseDamagevsdmg,baseCastSpeedvscastSpeed— inconsistent naming for equivalent concepts.[ISSUE 25]
AttunementDefusesprimaryManaType(optional, can beundefinedfor Invoker) whileGolemDefusesbaseManaType(required string). Different prefix for the same concept ("primary" vs "base").7. BANNED CONTENT CHECK
[ISSUE 26] ✅ No lifesteal or healing found. The
Drainspell (death element,Siphon vital energy) andMana Rip/Essence Drain(transference element,Rip mana from the enemy) deal damage — they don't heal the player. Theadrenaline_rushspecial effect restores mana (not HP) on enemy defeat. No banned healing mechanics detected.[ISSUE 27] ✅ No banned mana types found. Scanned all files for
life,blood,wood,mental,forceas mana types. Theconstants/elements.tsfile explicitly notes: "Life, Blood, Wood, Mental, and Force mana types have been removed." TheManaTypeunion intypes/element.tscontains only:raw, fire, water, air, earth, light, dark, death, transference, metal, sand, lightning, crystal, stellar, void— all valid.[ISSUE 28] ⚠️
vitalityEssenceDropindata/loot-drops.ts(lines 103-109) — "Vitality Essence" could be confused with a life/healing mechanic, but it's typed as'essence'and grants elemental mana. The name is suspicious but the implementation doesn't violate banned content rules.8. MISSING OR INCORRECT TYPE ANNOTATIONS
[ISSUE 29]
DisciplineDefinition.attunementfield intypes/disciplines.ts(line 37) is typed asDisciplinesAttunementType(the enum), but the discipline data files (base.ts,enchanter.ts, etc.) use string literals like'base','enchanter','fabricator','invoker'. The enum values match these strings, so this works, but the enum is a const enum-like pattern usingenumwith string values. This is actually correct since TypeScript string enums accept their defined values. ✓[ISSUE 30]
getUnlockedAttunementsindata/attunements.ts(line 93) returnsAttunementDef[]but uses.filter(Boolean)on the result of.map()which can includeundefinedvalues (whenATTUNEMENTS_DEF[id]doesn't exist). The return type claims it'sAttunementDef[]but the.filter(Boolean)is needed precisely becauseundefinedis possible. The type signature hides this.[ISSUE 31]
getAvailableDropsindata/loot-drops.ts(line 176) returnsLootDrop[]but the filter usesdrop.minFloor > floorwhich means drops withminFloor === floorare included. This is correct (≥), but the function name "available" could be clearer.[ISSUE 32]
CraftingRecipeindata/crafting-recipes.ts(line 7) importsEquipmentSlotfrom./equipment/typesbut doesn't use it in the interface. TheCraftingRecipeinterface has noslotfield — the slot is determined by the resulting equipment type.isolatedModules).9. DATA INTEGRITY ISSUES
[ISSUE 33]
GUARDIANSfloor 70 is MISSING (see ISSUE 18 above). This is the most critical data integrity issue.[ISSUE 34]
GUARDIANSfloor 80 guardian (Mors Ultima) haselement: "death"butunlocksMana: ['death']— it only unlocks its own element. Meanwhile floor 90 (Primordialis, void) unlocks['void', 'stellar']and floor 100 (The Awakened One, stellar) only unlocks['stellar']. The pattern is inconsistent — some guardians unlock 1 mana type, others unlock 2.[ISSUE 35]
enchantment-effects.ts(line 1) re-exports everything fromenchantments/index, which in turn imports fromspell-effects/index. Thespell-effects/index.tsimports fromtypes.tswhich re-exportsEnchantmentEffectDeffrom../../enchantment-types. This creates a re-export chain:enchantment-effects.ts→enchantments/index.ts→spell-effects/index.ts→spell-effects/types.ts→enchantment-types.ts. The typeEnchantmentEffectDefis available through multiple import paths.[ISSUE 36]
data/equipment/types.ts(line 3) re-exportsEquipmentSlotfrom../../types/equipmentSlot, buttypes/index.tsalso re-exportes it from./equipmentSlot. Code can importEquipmentSlotfrom eitherdata/equipment/typesortypes/index— two canonical paths.10. BALANCE ISSUES
[ISSUE 37]
Mana Bolt(tier 0) hasdmg: 5atcost: rawCost(3)withcastSpeed: 3→ DPS = 15, mana cost per second = 9.Ember Shot(tier 1) hasdmg: 10atcost: elemCost("fire", 1)withcastSpeed: 3→ DPS = 30, mana cost per second = 3. Ember Shot is 2x the DPS at 1/3 the mana cost of Mana Bolt. Tier 1 basic spells dramatically outclass tier 0 raw spells, which is expected progression, but the gap is very large.[ISSUE 38]
Apocalypse(tier 3 AOE) hasdmg: 80atcost: elemCost("fire", 20)withcastSpeed: 0.5hitting 10 targets. Total DPS = 400, mana cost per second = 10. Compare toPyroclasm(tier 3 single target):dmg: 250atcost: elemCost("fire", 25)withcastSpeed: 0.6→ DPS = 150, mana cost per second = 15. Apocalypse is both higher DPS AND more mana efficient while hitting 10 targets. This makes single-target tier 3 spells obsolete.[ISSUE 39]
Crystal Shatter(tier 4, crystal) costselemCost("crystal", 10)fordmg: 400atcastSpeed: 0.5→ DPS = 200, mana cost per second = 5.Void Collapse(tier 4, void) costselemCost("void", 12)fordmg: 450atcastSpeed: 0.45→ DPS = 202.5, mana cost per second = 5.4.Stellar Nova(tier 4, stellar) costselemCost("stellar", 15)fordmg: 500atcastSpeed: 0.4→ DPS = 200, mana cost per second = 6. All three legendary spells have nearly identical DPS/mana efficiency (~40 DPS per mana/sec), which is actually well-balanced. ✓[ISSUE 40]
getGolemMaintenanceMultiplierindata/golems/utils.ts(line 107) returns1 - (skills.golemSiphon || 0) * 0.1. At skill level 10, this returns0(free maintenance). At skill level 11+, it goes NEGATIVE (the game would pay you to maintain golems). There's no floor clamp.Math.max(0, ...)clamp. High skill levels could cause negative maintenance costs, effectively generating mana.[ISSUE 41]
getStudyCostMultiplierinconstants/core.ts(line 25) returns1 - (skills.focusedMind || 0) * 0.05. At skill level 20+, this goes NEGATIVE (negative study costs). No floor clamp.Math.max(0, ...)or similar.[ISSUE 42]
getStudySpeedMultiplierinconstants/core.ts(line 21) returns1 + (skills.quickLearner || 0) * 0.1. No upper bound — at skill level 100, study speed is 11x. This may be intentional but could cause balance issues.SUMMARY TABLE
equipmentSlot.ts,equipment/types.tselements.ts,golems/types.tsrawCost/elemCostduplicatedenchantments/index.ts,spell-effects/index.tsEnchantmentEffectDefspell-effects/types.ts,combat-effects.tstypes/index.tstypes/index.tsconstants/index.tsFLOOR_ELEM_CYCLEnot re-exportedspells.ts,guardians.tsSpellEffect.typeunionattunements.tsGuardianDef.effectsuses weakstringtypegolems/types.ts,spells.tsGolemManaCostduplicatesSpellCostshapegame.tsunlockEffectnot constrained to valid IDselements.tsFLOOR_ELEM_CYCLEshould be derivedelements.tsBASE_UNLOCKED_ELEMENTSshould be derivedattunements.tsattunements.tselements.tsELEMENT_OPPOSITESincomplete for composite/exoticelements.tsELEMENT_ICON_NAMES— verified complete ✓guardians.tscrafting-recipes.tsdefense-effects.tsDEFENSE_EFFECTSis emptyaoe-spells.tsequipment/types.ts,spells.tsbaseDamagevsdmg,baseCastSpeedvscastSpeedattunements.ts,golems/types.tsprimaryManaTypevsbaseManaTypeloot-drops.tsdisciplines.tsattunements.tsgetUnlockedAttunementsreturn type hides undefinedloot-drops.tscrafting-recipes.tsguardians.tsguardians.tsequipment/types.tsEquipmentSlotraw-spells.ts,basic-elemental-spells.tsaoe-spells.ts,master-spells.tslegendary-spells.tsgolems/utils.tscore.tscore.tsTOP PRIORITY FIXES (Severity ≥ 3)
constants/guardians.tsMath.max(0, ...)clamp ingolems/utils.tsline 107Math.max(0, ...)clamp inconstants/core.tsline 25rawCost/elemCostduplication (Severity 3) — Import from canonical source ingolems/types.tstypes/index.tsbarrelELEMENT_OPPOSITES(Severity 3) — Add opposites for composite/exotic elementsSpellEffect.typeunionAudit complete. 42 issues found across 50+ files. Top priorities: missing floor 70 guardian (sev 4), negative maintenance/study costs at high skill levels (sev 3), duplicated rawCost/elemCost helpers (sev 3), missing discipline type barrel exports (sev 3), incomplete ELEMENT_OPPOSITES (sev 3), AOE vs single-target balance (sev 3), and guardian effect type mismatches (sev 3). No banned content (lifesteal, healing, life/blood/wood/mental/force mana) found. Full report in previous comment.
Audit complete — 42 issues documented across 50+ files. Issue closed. Awaiting orchestrator direction on which fixes to implement.