Skip to content

Research 008 — Buy-vs-craft pricing ​

Status: complete — all six verifications confirmed; F1 and F2 resolved by human decision on 2026-08-01 (F1: keep the engine, soften the framing; F2: full Bifrost end-to-end — which discovery then showed needs only four curated Forge recipes). The approval gate — moving spec.md to approved — remains the human's.

Step 1.5 output, written between the spec draft and the approval gate. Every [NEEDS VERIFICATION] marker in spec.md has a verdict below. Discovery also surfaced two findings that were not refuted verifications but challenged the spec's framing and scope (F1, F2); both were put to the human and are now resolved.

Verified against: the live GW2 API v2 (https://api.guildwars2.com/v2), the GW2 Wiki (wiki.guildwars2.com) and gw2bltc, and the repo at branch 008-buy-vs-craft-pricing, on 2026-08-01. GW2 drifts static shapes with game patches and prices move constantly — re-check if a finding stops holding.

V1 — Exact ingredients of Gift of Might (19672) and Gift of Magic (19673)? ​

Question. R12/P3 curates these two forge intermediates; their contents must be known and buyable for the Bifrost cost to be real.

Verdict. Confirmed. Both are Mystic Forge recipes of 4 × 250 tier-6 crafting materials, all TP-tradeable:

  • Gift of Might (19672) = 250 Vicious Fang + 250 Armored Scale + 250 Vicious Claw + 250 Ancient Bone.
  • Gift of Magic (19673) = 250 Vial of Powerful Blood + 250 Powerful Venom Sac + 250 Elaborate Totem + 250 Pile of Crystalline Dust.

Evidence. GW2 Wiki Gift of Might / Gift of Magic (2026-08-01). Sample T6 mat flags via items?ids=24295,24358 → Vial of Powerful Blood / Ancient Bone carry only NoSalvage (no AccountBound) ⇒ 007 classifies them buyable. Both gifts themselves are AccountBound (see V5 note) ⇒ classified gated, and being craftable they follow the gated-craftable → craft rule (P1 #5).

Caveat. Exact T6-mat item ids were not all pinned here (names only). Curation must resolve each id (e.g. via items by id) — a mechanical step, not a risk.

V2 — Exact ingredients of Gift of The Bifrost (19654) and its sub-gifts? ​

Question. P3 curates the weapon-specific gift down to buyable raw materials; its full subtree must be known.

Verdict. Confirmed and fully resolved — and it needs less curation than feared. The name collisions were settled by pinning exact item ids and checking /v2/recipes; only the Forge steps need curation, because the two sub-gifts are ordinary discipline recipes 007's station path already resolves:

  • Gift of The Bifrost (19654) [Forge — CURATE] = 1 Gift of Energy (19623) + 1 Gift of Color (19638)
    • 100 Icy Runestone + 1 Superior Sigil of Nullification.
  • Gift of Energy (19623) → /v2/recipes 4315 (Artificer 400) = 250× each Pile of Radiant/Luminous/ Incandescent/Crystalline Dust (24274/24275/24276/24277) — all buyable. 007 resolves via station path; no curation.
  • Gift of Color (19638) → /v2/recipes 3165 (Chef 400) = 100 Unidentified Dye (20323) + 100 Opal Orb (24522) + 250 Pile of Crystalline Dust (24277) + 1 Gift of Zhaitan (19669). Buyable except Zhaitan. 007 resolves via station path; no curation.
  • Gift of Zhaitan (19669) → recipes/search [] — a dungeon-token vendor purchase (500 Tales of Dungeon Delving), AccountBound ⇒ a correct gated leaf = 0.
  • Icy Runestone — karma-vendor, not on the TP ⇒ gated/0. Superior Sigil of Nullification — TP-buyable.

Evidence. items?ids=19620..19685 (2026-08-01) pinned the gift ids (Gift of Energy 19623, Color 19638, Zhaitan 19669, Bifrost gift 19654). recipes/search?output= returned a discipline recipe for 19623 ([4315]) and 19638 ([3165]), but [] for 19654/19672/19673/19675/19669 (Forge or vendor). recipes?ids=4315,3165 gave the ingredient lists above; items?ids=24274,24275,24276,24277,20323,24522 shows each is NoSalvage only (⇒ buyable).

Caveat. The Forge-recipe ingredient ids for Gift of The Bifrost (19623/19638) can't be read from the API (Forge recipes aren't in /v2/recipes); they are pinned from the item list + confirmed by each having the expected discipline recipe. Curation of the four Forge recipes must still cite each ingredient id from the wiki per R12.

V3 — Mystic Clover recipe and expected yield (the fractional outputCount)? ​

Question. R11/P3 #3 encode Mystic Clover as an expected-value recipe with a fractional outputCount. The recipe and its yield rate must be known.

Verdict. Confirmed. The Forge recipe is probabilistic, ~31% success:

  • 10-input batch: 10 Obsidian Shard + 10 Mystic Coin + 10 Glob of Ectoplasm + 10 Mystic Crystal → ≈3.1 clovers per attempt.
  • Single: 1 Obsidian + 1 Mystic Coin + 1 Ecto + 6 Philosopher's Stone → ≈0.31 clover.
  • ⇒ fractional outputCount ≈ 3.1 on the batch recipe. Only Mystic Coin + Ecto carry gold cost (both buyable); Obsidian is gated (0); Mystic Crystal / Philosopher's Stone are vendor/karma (0). Per-clover gold ≈ (10 × coin + 10 × ecto) / 3.1 ≈ 3.2 × (coin + ecto).

Evidence. GW2 Wiki Mystic Clover (2026-08-01): "estimated through drop research to be about 31%." Item flags via items?ids=19976,19925 → Mystic Coin NoSalvage,NoSell (no AccountBound ⇒ buyable); Obsidian Shard AccountBound (⇒ gated).

Caveat. Failed forge attempts return some T6 mats / currency, so the true expected cost is slightly below the naïve 3.2×-per-clover figure. Ignoring the return offset is a conservative approximation (accepted per the spec's Assumptions). The exact rate (31%) is community drop-research, not an official number.

V4 — Does prices() omit absent ids, and is an empty market detectable? ​

Question. R2/R3 rely on "absent from the price map" (and sells.quantity === 0) as a reliable "no usable price" signal.

Verdict. Confirmed. Gw2Client.getByIds drops any id the API doesn't return (206 partial or 404 chunk) from the result array, so prices(ids) omits unknown/untradeable ids.

Evidence. apps/api/src/gw2/gw2-client.ts:197-215 (404 → continue; final flatMap omits missing ids). Live probe: commerce/prices?ids=30698,19676,19721 returned HTTP 206 with only 30698 and 19721 — the non-tradeable 19676 was silently omitted (2026-08-01). Prices carry buys/sells { quantity, unit_price } (copper), so an empty side reads as quantity: 0 / unit_price: 0.

Caveat. Low stakes — unpriced is a non-issue by human decision (R3). This only confirms the mechanism is sound if it ever triggers.

V5 — Is the Bifrost root sellable and classified buyable? ​

Question. R6/R7 compute netSell/profit only if the root has a buys order and is classified buyable (not AccountBound).

Verdict. Confirmed. The Bifrost trades on the TP and is not AccountBound:

  • Live commerce/prices?ids=30698: buys.unit_price 12500105 (≈1250 g), sells.unit_price 15005050 (2026-08-01). ⇒ netSell = floor(0.85 × 12500105) = 10625089 (≈1062 g).
  • items?ids=30698 flags = HideSuffix, NoSalvage, NoSell, AccountBindOnUse, DeleteWarning — no AccountBound ⇒ 007's gated ⟺ AccountBound classifier returns buyable (NoSell + AccountBindOnUse do not imply gated — domain.md, confirmed by The Legend precedent).

Evidence. Live commerce/prices and items calls above (2026-08-01).

Caveat. whitelisted: false on the price row is a commerce flag, unrelated to bind state; the live buys order is the authoritative "sellable" signal.

V6 — Does adding the curated recipes keep the guard tests green, and what shape must they take? ​

Question. R12 adds new curated outputs; R11 relaxes outputCount. Neither may break existing tests.

Verdict. Confirmed, with two shape facts for the plan:

  • The real-data guard (packages/legendary-recipes/src/index.test.ts) only pins the 21 legendary-weapon recipes (4 item ingredients each), Eternity's recipe, "no precursor is an output," and the duplicate-output guard. Adding Gift-of-Might/Magic/Clover/weapon-gift/sub-gifts as new outputs touches none of these; no test asserts outputCount is an integer. 007's resolver service tests use mocked recipes, not the real dataset, so curation cannot break them.
  • Curated recipe shape (packages/legendary-recipes/src/schema.ts:21-27): each recipe is { outputItemId, outputCount, method, ingredients[≥1], source(url) }, method ∈ {mystic-forge, discipline, vendor, collection}. New forge recipes use method: 'mystic-forge'. R11's fractional relaxation targets schema.ts:23 (z.number().int().positive() → .positive()) and the API response RecipeOptionSchema.outputCount in apps/api/src/recipe-graph/recipe-graph.schema.ts.

Evidence. packages/legendary-recipes/src/index.test.ts:19-165; schema.ts:15-27; apps/api/src/recipe-graph/recipe-graph.service.test.ts (mocked CuratedRecipeService).

Caveat. Ingredient count stays a positive integer (schema line 7/12); only outputCount is relaxed — so the fractional value lives on the clover recipe's yield, not on any ingredient count.

F1 — The buy-vs-craft min never fires on the Gen 1 path (framing challenge) ​

Discovery finding, not asked about. On the entire Bifrost tree there is no node that is both buyable and craftable, so the spec's headline "buy-vs-craft optimizer" changes no decision for the flagship:

  • Every craftable intermediate (Gift of Fortune/Mastery/Might/Magic, Mystic Clover, Gift of The Bifrost + its sub-gifts) is AccountBound/gated — it cannot be bought, so it is force-crafted.
  • Every buyable node (precursor, T6 mats, Mystic Coins, Ectos, dyes, sigil) is a leaf — nothing to craft, so it is force-bought.
  • The genuine min(buy, craft) choice only exists for a buyable-and-craftable node — a Gen 2/3 / armor situation (e.g. Bolt of Damask, 007 V1), absent from Gen 1.

Why it matters. Touches the spec's central framing (P1, R2–R4). The engine's min is still correct and forward-compatible (it will bite on Gen 2/3), but for the flagship, 008 is effectively a cost roll-up + profit calculator, not an optimizer. Evidence: item flags in V1/V3/V5 (all intermediates AccountBound; all leaves not). Human decision (2026-08-01): keep the engine, soften the framing — the min logic stays (future-proof for Gen 2/3) but the spec no longer sells "optimizer" for Gen 1 and notes the min is structurally inert there. Spec edited accordingly (Problem, P1, a note under R4).

F2 — The Bifrost weapon-gift subtree — resolved: only four Forge recipes to curate ​

Discovery finding, now resolved. "One weapon end-to-end" first looked like ≥3 more curation layers with a "Gift of Energy" name collision. Pinning ids and querying /v2/recipes collapsed it: the two sub-gifts are plain discipline recipes (Gift of Energy → 4315 Artificer, Gift of Color → 3165 Chef) that 007's station path already resolves, and Gift of Zhaitan is a vendor item (correct gated leaf). So the entire Forge curation for the Bifrost is exactly four recipes with no API recipe of their own: Gift of Might (19672), Gift of Magic (19673), Mystic Clover (19675), Gift of The Bifrost (19654) (Gift of Fortune 19626 and Gift of Mastery 19674 are already curated).

Human decision (2026-08-01): full Bifrost end-to-end, careful ids. Discovery then showed "full" costs only those four Forge recipes — the sub-gift depth is free via the station path. Why it matters: sets P3 / R12's curation list precisely and bounds the plan's task count.

Refuted claims ​

None of the six [NEEDS VERIFICATION] claims was refuted — all confirmed (V1–V6). The two items above (F1, F2) were framing/scope challenges, not refutations of a verified fact; both were put to the human on 2026-08-01 and resolved (F1 → keep engine, soften framing; F2 → full Bifrost, which needs only four Forge recipes). The spec was edited in place to reflect those decisions rather than rebuilt, since no premise was false — only its framing (F1) and the size of one requirement (F2) changed.

Graduation ​

Candidates to move to docs/architecture/ at step 6:

  • The Bifrost forge recipe tree (item ids + contents for Might, Magic, Clover, Gift of The Bifrost, Energy, Color, Zhaitan) — a reusable domain fact for later curation specs. → docs/architecture/domain.md.
  • Mystic Clover ~31% expected yield and the fractional-outputCount modelling convention.
  • Gen 1 has no buyable-and-craftable node (F1) — a domain fact that shapes how "buy-vs-craft" is framed across generations.