`purchase` listed a shop's offers with no ordering while `getShopView` orders
by `sortOrder`, so the two paths answered "which offer does this key mean" by
different rules, one of them at the database's discretion. Harmless today
because item and bag keys are disjoint, but not a difference worth keeping.
The faction lookup behind requirement labels also read every faction while the
condition engine only matches enabled ones, so a gate on a disabled faction
would have shown that faction's name next to a requirement the engine treats
as unmeetable.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`resolveTarget` gave a bag target the same string for `description` and
`effectSummary`, and the shop row renders both, so the slice's two flagship
offers showed "Capacity: 5 Raider Trophies" on consecutive lines. Spec §5's
worked example shows it once.
A bag definition carries no flavour text of its own, so the description is now
empty and the row omits the span entirely rather than emitting an empty one.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Adds a second, mutually exclusive target column (loot_bag_definition_id)
and a bypass_conditions column to shop_offers, so a later slice's quest
referral can open one offer that reputation alone would not. Keeps
shop.service.ts compiling against the now-nullable itemDefinition with
temporary non-null assertions; Task 4 replaces them with a real branch
on offer kind.