docs: spec + plan for weapon-type-by-skill multi-select filter + OD column

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-07-15 08:38:18 +02:00
parent d5febaabda
commit 29d400f86a
2 changed files with 404 additions and 0 deletions

View file

@ -0,0 +1,78 @@
# Weapon-type (by skill) multi-select filter + OD column for weapon searches
**Date:** 2026-07-15
**Status:** Pre-approved by user
## Problem
Weapon searching is weak: the current weapon-type filter is a single-select
dropdown (`weapon_type`, shown only under the "Weapons" item type) and the OD
column is hidden by default. The user wants to search across weapon types by
skill (Heavy, Light, Finesse, Two-Handed, Missile, War/Void casters), pick
more than one at once, and see the OD value in the results columns.
## Field semantics (verified against live data)
- Melee (`object_class = 1`): WeaponSkill `int_values->>'218103840'` = 44 Heavy,
45 Light, 46 Finesse, 41 Two-Handed.
- Missile (`object_class = 9`): WeaponSkill `218103840` = 47; subtype from
mastery `int_values->>'353'` = 8 Bow, 9 Crossbow, 10 Thrown. Arrows/ammo lack
skill 47, so gating on it excludes them — and fixes the existing bug where
the name-based `%bow%` clause matched "Bowl".
- Wands (`object_class = 31`): WeaponSkill is null; use equip skill
`int_values->>'159'` = 34 War Magic, 43 Void Magic (the only caster schools
the OD table rates).
## Decisions
1. **Weapon-type becomes multi-select** (checkbox group) with seven
skill-level categories: Heavy, Light, Finesse, Two-Handed, Missile,
War Magic, Void Magic. Any combination; none = all weapons. Shown when the
"Weapons" item type is selected (same nesting the single dropdown used).
2. **Backend** accepts a new `weapon_types` CSV param → OR of per-type clauses,
ANDed into the query. The legacy single `weapon_type` param is kept for
back-compat. `weaponTypeClause` is reworked to be object-class/key aware
(melee by 218103840, missile launcher by 218103840=47 + mastery, casters by
159), replacing the melee-only `exists(skill)` helper. Existing type keys
(bow/crossbow/thrown/caster/light/finesse/heavy/two_handed) keep working;
bow/crossbow/thrown switch to the robust mastery-based clause.
3. **OD column auto-shows for weapon searches**: when `itemType === 'weapon'`,
the results table includes the `od_rating` column regardless of the user's
saved column set (union, non-destructive — their other prefs and the column
picker still work; OD just can't be hidden while weapon-searching). No
change to default sort.
## Frontend model
- `SearchFilters.weaponType: string``weaponTypes: string[]`. Update
DEFAULT_FILTERS, `validateFilterValue` (string array), `buildParams`
(`weapon_types` CSV when non-empty), FilterSidebar (checkbox group replacing
the `<select>`), ActiveChips (one chip per selected type, removable).
- `WEAPON_TYPES` in constants becomes the seven skill categories
`{value,label}`: heavy/light/finesse/two_handed/missile/war/void.
- ResultsTable computes effective visible columns = saved set
(`itemType==='weapon'` ? {od_rating} : {}).
## Testing
- Backend: Go unit tests on the reworked `weaponTypeClause` (correct SQL per
type: object_class, keys, mastery) and the `weapon_types` CSV → OR
composition in `runSearch` (via the existing search-string test approach if
present, else targeted clause tests). No DB-backed tests (consistent with the
rest of search.go); live verification after deploy.
- Frontend: `npm run build` (tsc) green; live browser verification.
## Verification (live)
- `weapon_types=heavy,two_handed` returns only skill-44 and skill-41 melee.
- `weapon_types=missile` returns bows/xbows/thrown, no "Bowl".
- `weapon_types=war` / `void` return the respective caster schools.
- Multi-select in the UI; OD column visible automatically on weapon searches;
chips add/remove; sort by OD works.
## Out of scope
- Changing OD math or the best-values table.
- Non-weapon filters, suitbuilder.
- Splitting missile back into per-subtype UI checkboxes (Missile is one
category; the backend still supports bow/crossbow/thrown individually).