Skip to content

Add resistance-aware Trader searches - #10171

Open
mcagnion wants to merge 16 commits into
PathOfBuildingCommunity:devfrom
mcagnion:feature/trade-element-swap-search
Open

mcagnion wants to merge 16 commits into
PathOfBuildingCommunity:devfrom
mcagnion:feature/trade-element-swap-search

Conversation

@mcagnion

@mcagnion mcagnion commented Aug 7, 2026 •

Copy link
Copy Markdown
Contributor

Related: #9217

Description of the problem being solved

Trader currently gives resistance its full weight even after a build reaches its caps. It also treats Fire, Cold, and Lightning Resistance as fixed stats, although eligible modifiers can be changed with Harvest.

Changes

  • Resistance swaps searches elemental resistance as a total, then reevaluates the results using the best eligible swap. With Resistance caps, smaller elemental shortfalls must be met as listed, and only the largest can also be met by an explicit or crafted resistance of an element that is already capped.
  • Resistance caps uses the current Elemental and Chaos Resistance caps when choosing the estimated variant for each listing. Items that still miss a cap remain visible, resistance above caps does not improve that variant, and the selected result sort remains unchanged between listings.
  • Result evaluation yields between build calculations and reports progress so the interface remains responsive.
  • Holding Ctrl shows the original listing beside the estimated swapped item and marks changed lines with [Swap].

Swap values are estimates because the resistance roll may change. Results with incomplete or ambiguous Trade metadata are left unchanged.

Resistance filters with Resistance caps and Resistance swaps

Shortfalls are measured with the current item removed. A swapped affix covers one element only, so only the largest elemental shortfall may come from a swap, using an affix of an element that is already capped.

Missing resistance Required from a listing
None No elemental minimum
Lightning 28 (Fire and Cold capped) Total Lightning Resistance 28, or one explicit or crafted Fire or Cold Resistance affix of at least 28 to swap to Lightning
Cold 7, Lightning 39 (Fire capped) Total Cold Resistance 7, and either total Lightning Resistance 39 or one explicit or crafted Fire Resistance affix of at least 39 to swap to Lightning
Fire 10, Cold 20, Lightning 30 Total elemental resistance 60 (no capped element to swap from)

"Total" uses the Trade pseudo total, so implicit, hybrid and all-resistance values count; only a single-element explicit or crafted affix can be swapped.

Chaos Resistance keeps its own minimum, except with Chaos Inoculation, where it is not searched. Without Resistance swaps, each missing resistance is required as listed. A resistance the searched item class cannot roll, such as any resistance on a weapon, is not required.

Requiring only the total would let listings through that cannot be repaired. In the third example, +27% to all Elemental Resistances counts 81 toward a total of 46 but cannot be swapped, and a single +46% to Cold Resistance affix can cover Cold or Lightning, not both. When one item cannot cover every shortfall, the search can return no results.

Estimated swap comparison

Original trade item beside the estimated resistance swap

Query options

Resistance swaps option and tooltip

Verification

Focused tests cover:

  • Search filters with Resistance caps, with and without Resistance swaps: which shortfall may come from a swap, Chaos Inoculation, and weapons, which cannot roll any resistance.
  • Result evaluation: only swaps that can fill a missing elemental resistance are tried; swaps are still tried on capped listings when the build scales with resistance values; partially repaired listings stay visible; fewer swaps win a tie; sorting follows the selected stat.
  • Responsiveness: evaluation pauses between build calculations, and cached shortfalls are recalculated when the build's resistances change.

Manually checked both query options, retained partial results, result ordering, tooltip text, the Ctrl comparison, and interface responsiveness.

No specific build is required; the options use the current build's resistance requirements.

@mcagnion
mcagnion marked this pull request as draft August 8, 2026 16:04
@mcagnion
mcagnion force-pushed the feature/trade-element-swap-search branch 2 times, most recently from 2399075 to 8fc3682 Compare August 18, 2026 21:03
Separate resistance swaps from cap requirements so searches can broaden elemental candidates without overvaluing excess resistance. Validate fetched permutations against the build's actual elemental and Chaos caps while preserving the listed item for import.
Keep the listed trade item unchanged while Ctrl shows the exact variant used for ranking. Highlight swapped mod lines and clarify that Harvest rolls may change.
Evaluate fetched variants cooperatively, reuse unchanged cached results, and
skip permutations only when cap state and resistance dependencies prove they
cannot affect the selected result.
Replace the cspell-rejected "reranking" term without changing test behavior.
Remove an unused integration-only argument and align nearby comments with project terminology. Behavior is unchanged on the standalone feature branch.
Track fetch identity independently from UI labels and invalidate stale selections while cooperative evaluation is pending. Clear capped candidate state when pasted URL results replace a generated search.
Construct tooltip instances explicitly after the upstream class-constructor migration, including the Ctrl preview and its focused tests.
Align option, cache, and evaluation names with their actual behavior. Remove duplicated result state and descriptor fields that had no production consumer.
Keep fetch, evaluation, cache, and resistance-swap preview state cohesive while preserving the complete search behavior.
Replace repeated fixtures with local builders and labelled cases while covering the generated-search activation seam.
Label grouped baseline cases and name the generated-search handler factory by its shape.
@mcagnion
mcagnion force-pushed the feature/trade-element-swap-search branch from a79c3b1 to 00fbe47 Compare August 26, 2026 18:15
@mcagnion
mcagnion marked this pull request as ready for review September 1, 2026 15:51
mcagnion and others added 5 commits September 27, 2026 12:42
Assert lifecycle transitions and swap preview meaning without pinning full labels or tooltip sentences.

Tests: pob-check.ps1 -Mode Fast -Spec spec/System/TestTradeQuery_spec.lua (94 passed)
With resistance caps enabled, the generated query started at a zero
weight threshold and was sent through the plain search. When a market
exceeds 10,000 matches the trade API does not return the global weight
top, and the threshold refinement that handles this case was skipped, so
the fetched window could miss the heaviest listings entirely.

Keep the zero starting threshold for caps, since the current item's
stat difference still counts resistances that caps turn into minimums,
but route every query with weighted filters through the weight-adjusted
search. That search no longer repeats an identical query when its
threshold is already zero and too few results come back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With resistance caps and swaps, the query required one total elemental
resistance. All-resistance listings and a deficient element's own affix
satisfied that total although a swapped affix can repair only one
element, so the fetched window was often filled with listings that
stayed uncapped.

When at least one element is short and another is capped, keep listed
minimums for the smaller shortfalls and let the largest one be met
either as listed or by an explicit or crafted single-element resistance
of a capped element. Without a shortfall, or with all three elements
short, the total minimum is unchanged.
Resistance caps turned the Chaos shortfall into a required Chaos
Resistance minimum on every listing. Chaos Inoculation makes the build
immune to chaos damage, so that minimum only restricted the search to
listings stacking an irrelevant stat, often leaving a handful of results.

Report no Chaos shortfall when the output has Chaos Inoculation.
Elemental shortfalls are unchanged.
Resistance caps required every missing resistance on the searched slot, even when no mod for that item class grants it. Weapons cannot roll any resistance, so a weapon search with a missing resistance returned no results. Shortfalls are now kept only for resistance types that at least one QueryMods entry can roll on the item class.
@mcagnion

Copy link
Copy Markdown
Contributor Author

Four fixes since e0b891a, found while measuring result quality on live searches:

  • With Resistance caps, a search with too many results is narrowed by weight like other weighted searches, so the fetched results are the best weighted ones rather than an arbitrary subset.
  • With Resistance caps and Resistance swaps, only the largest elemental shortfall may come from a swap, using a resistance that is already capped; the other shortfalls must be met as listed. The description has examples.
  • Chaos Inoculation builds no longer get a Chaos Resistance minimum.
  • A resistance the searched item class cannot roll, such as any resistance on a weapon, is no longer required. Weapon searches with Resistance caps returned no results before.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant